]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: Disable hierarchical permissions when POE is enabled
authorMarc Zyngier <maz@kernel.org>
Wed, 23 Oct 2024 14:53:42 +0000 (15:53 +0100)
committerOliver Upton <oliver.upton@linux.dev>
Thu, 31 Oct 2024 02:44:22 +0000 (02:44 +0000)
The hierarchical permissions must be disabled when POE is enabled
in the translation regime used for a given table walk.

We store the two enable bits in the s1_walk_info structure so that
they can be retrieved down the line, as they will be useful.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Link: https://lore.kernel.org/r/20241023145345.1613824-35-maz@kernel.org
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/at.c

index ef1643faedeb450b4fc097d0b7fa14bf1d59b5a3..8d1dc6327ec5b886f3c706fd44ccfd5cded6c2c2 100644 (file)
@@ -24,6 +24,8 @@ struct s1_walk_info {
        unsigned int            txsz;
        int                     sl;
        bool                    hpd;
+       bool                    e0poe;
+       bool                    poe;
        bool                    be;
        bool                    s2;
 };
@@ -110,6 +112,34 @@ static bool s1pie_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime)
        }
 }
 
+static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi)
+{
+       u64 val;
+
+       if (!kvm_has_s1poe(vcpu->kvm)) {
+               wi->poe = wi->e0poe = false;
+               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 = __vcpu_sys_reg(vcpu, TCR2_EL1);
+               wi->poe = val & TCR2_EL1x_POE;
+               wi->e0poe = val & TCR2_EL1x_E0POE;
+       }
+}
+
 static int setup_s1_walk(struct kvm_vcpu *vcpu, u32 op, struct s1_walk_info *wi,
                         struct s1_walk_result *wr, u64 va)
 {
@@ -206,6 +236,12 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, u32 op, struct s1_walk_info *wi,
        /* R_JHSVW */
        wi->hpd |= s1pie_enabled(vcpu, wi->regime);
 
+       /* Do we have POE? */
+       compute_s1poe(vcpu, wi);
+
+       /* R_BVXDG */
+       wi->hpd |= (wi->poe || wi->e0poe);
+
        /* Someone was silly enough to encode TG0/TG1 differently */
        if (va55) {
                wi->txsz = FIELD_GET(TCR_T1SZ_MASK, tcr);