]> www.infradead.org Git - users/hch/misc.git/commitdiff
KVM: arm64: Allow use of S1 PTW for non-NV vcpus
authorMarc Zyngier <maz@kernel.org>
Tue, 29 Jul 2025 11:06:14 +0000 (12:06 +0100)
committerMarc Zyngier <maz@kernel.org>
Sat, 20 Sep 2025 10:05:13 +0000 (11:05 +0100)
As we are about to use the S1 PTW in non-NV contexts, we must make
sure that we don't evaluate the EL2 state when dealing with the EL1&0
translation regime.

Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/at.c

index 7b9711021db0d69a21f5f826b2440d5f3dedda69..9baa929c102f54ccbe2220f133ffb3cb0bb7a399 100644 (file)
@@ -98,21 +98,26 @@ static enum trans_regime compute_translation_regime(struct kvm_vcpu *vcpu, u32 o
        }
 }
 
+static u64 effective_tcr2(struct kvm_vcpu *vcpu, enum trans_regime regime)
+{
+       if (regime == TR_EL10) {
+               if (vcpu_has_nv(vcpu) &&
+                   !(__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En))
+                       return 0;
+
+               return __vcpu_sys_reg(vcpu, TCR2_EL1);
+       }
+
+       return vcpu_read_sys_reg(vcpu, TCR2_EL2);
+}
+
 static bool s1pie_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime)
 {
        if (!kvm_has_s1pie(vcpu->kvm))
                return false;
 
-       switch (regime) {
-       case TR_EL2:
-       case TR_EL20:
-               return vcpu_read_sys_reg(vcpu, TCR2_EL2) & TCR2_EL2_PIE;
-       case TR_EL10:
-               return  (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En) &&
-                       (__vcpu_sys_reg(vcpu, TCR2_EL1) & TCR2_EL1_PIE);
-       default:
-               BUG();
-       }
+       /* Abuse TCR2_EL1_PIE and use it for EL2 as well */
+       return effective_tcr2(vcpu, regime) & TCR2_EL1_PIE;
 }
 
 static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi)
@@ -124,23 +129,11 @@ static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi)
                return;
        }
 
-       switch (wi->regime) {
-       case TR_EL2:
-       case TR_EL20:
-               val = vcpu_read_sys_reg(vcpu, TCR2_EL2);
-               wi->poe = val & TCR2_EL2_POE;
-               wi->e0poe = (wi->regime == TR_EL20) && (val & TCR2_EL2_E0POE);
-               break;
-       case TR_EL10:
-               if (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En) {
-                       wi->poe = wi->e0poe = false;
-                       return;
-               }
+       val = effective_tcr2(vcpu, wi->regime);
 
-               val = __vcpu_sys_reg(vcpu, TCR2_EL1);
-               wi->poe = val & TCR2_EL1_POE;
-               wi->e0poe = val & TCR2_EL1_E0POE;
-       }
+       /* Abuse TCR2_EL1_* for EL2 */
+       wi->poe = val & TCR2_EL1_POE;
+       wi->e0poe = (wi->regime != TR_EL2) && (val & TCR2_EL1_E0POE);
 }
 
 static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
@@ -150,11 +143,16 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
        unsigned int stride, x;
        bool va55, tbi, lva;
 
-       hcr = __vcpu_sys_reg(vcpu, HCR_EL2);
-
        va55 = va & BIT(55);
 
-       wi->s2 = wi->regime == TR_EL10 && (hcr & (HCR_VM | HCR_DC));
+       if (vcpu_has_nv(vcpu)) {
+               hcr = __vcpu_sys_reg(vcpu, HCR_EL2);
+               wi->s2 = wi->regime == TR_EL10 && (hcr & (HCR_VM | HCR_DC));
+       } else {
+               WARN_ON_ONCE(wi->regime != TR_EL10);
+               wi->s2 = false;
+               hcr = 0;
+       }
 
        switch (wi->regime) {
        case TR_EL10:
@@ -851,7 +849,7 @@ static u64 compute_par_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
                par  = SYS_PAR_EL1_NSE;
                par |= wr->pa & SYS_PAR_EL1_PA;
 
-               if (wi->regime == TR_EL10 &&
+               if (wi->regime == TR_EL10 && vcpu_has_nv(vcpu) &&
                    (__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_DC)) {
                        par |= FIELD_PREP(SYS_PAR_EL1_ATTR,
                                          MEMATTR(WbRaWa, WbRaWa));