SME adds a new thread ID register, TPIDR2_EL0. This is used in userspace
for delayed saving of the ZA state but in terms of the architecture is
not really connected to SME other than being part of FEAT_SME. It has an
independent fine grained trap and the runtime connection with the rest
of SME is purely software defined.

Expose the register as a system register if the guest supports SME,
context switching it along with the other EL0 TPIDRs.

Signed-off-by: Mark Brown <broo...@kernel.org>
---
 arch/arm64/include/asm/kvm_host.h          |  1 +
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 15 +++++++++++++++
 arch/arm64/kvm/sys_regs.c                  |  9 ++++++---
 3 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 
f987698f88acf7b01e08e44b46a0982e36cced95..c770ed6138164fcd3e11b8517ef4120b4f4486b9
 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -429,6 +429,7 @@ enum vcpu_sysreg {
        CSSELR_EL1,     /* Cache Size Selection Register */
        TPIDR_EL0,      /* Thread ID, User R/W */
        TPIDRRO_EL0,    /* Thread ID, User R/O */
+       TPIDR2_EL0,     /* Thread ID, Register 2 */
        TPIDR_EL1,      /* Thread ID, Privileged */
        CNTKCTL_EL1,    /* Timer Control Register (EL1) */
        PAR_EL1,        /* Physical Address Register */
diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h 
b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
index 
7a4ad8a4c3727e4628b375cbefc5e0d3533687de..8141e4785161d0f610f1aa161d8448ca2f50312c
 100644
--- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
+++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
@@ -81,6 +81,17 @@ static inline u64 *ctxt_mdscr_el1(struct kvm_cpu_context 
*ctxt)
        return &ctxt_sys_reg(ctxt, MDSCR_EL1);
 }
 
+static inline bool ctxt_has_sme(struct kvm_cpu_context *ctxt)
+{
+       struct kvm_vcpu *vcpu;
+
+       if (!system_supports_sme())
+               return false;
+
+       vcpu = ctxt_to_vcpu(ctxt);
+       return kvm_has_sme(kern_hyp_va(vcpu->kvm));
+}
+
 static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
 {
        *ctxt_mdscr_el1(ctxt)   = read_sysreg(mdscr_el1);
@@ -94,6 +105,8 @@ static inline void __sysreg_save_user_state(struct 
kvm_cpu_context *ctxt)
 {
        ctxt_sys_reg(ctxt, TPIDR_EL0)   = read_sysreg(tpidr_el0);
        ctxt_sys_reg(ctxt, TPIDRRO_EL0) = read_sysreg(tpidrro_el0);
+       if (ctxt_has_sme(ctxt))
+               ctxt_sys_reg(ctxt, TPIDR2_EL0)  = read_sysreg_s(SYS_TPIDR2_EL0);
 }
 
 static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
@@ -163,6 +176,8 @@ static inline void __sysreg_restore_user_state(struct 
kvm_cpu_context *ctxt)
 {
        write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL0),     tpidr_el0);
        write_sysreg(ctxt_sys_reg(ctxt, TPIDRRO_EL0),   tpidrro_el0);
+       if (ctxt_has_sme(ctxt))
+               write_sysreg_s(ctxt_sys_reg(ctxt, TPIDR2_EL0), SYS_TPIDR2_EL0);
 }
 
 static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 
597d6a33826d001268d53174581ef8e61e7dd946..eece67141480b8d4bbd2bac0f02f9208c7f86f8b
 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2901,7 +2901,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
          .visibility = s1poe_visibility },
        { SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 },
        { SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 },
-       { SYS_DESC(SYS_TPIDR2_EL0), undef_access },
+       { SYS_DESC(SYS_TPIDR2_EL0), NULL, reset_unknown, TPIDR2_EL0,
+         .visibility = sme_visibility},
 
        { SYS_DESC(SYS_SCXTNUM_EL0), undef_access },
 
@@ -5033,8 +5034,7 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
                                       HFGxTR_EL2_nMAIR2_EL1            |
                                       HFGxTR_EL2_nS2POR_EL1            |
                                       HFGxTR_EL2_nACCDATA_EL1          |
-                                      HFGxTR_EL2_nSMPRI_EL1_MASK       |
-                                      HFGxTR_EL2_nTPIDR2_EL0_MASK);
+                                      HFGxTR_EL2_nSMPRI_EL1_MASK);
 
        if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS))
                kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_TLBIRVAALE1OS|
@@ -5089,6 +5089,9 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
                                                HFGITR_EL2_nBRBIALL);
        }
 
+       if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, SME, IMP))
+               kvm->arch.fgu[HFGxTR_GROUP] |= HFGxTR_EL2_nTPIDR2_EL0;
+
        set_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags);
 out:
        mutex_unlock(&kvm->arch.config_lock);

-- 
2.39.5


Reply via email to