]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: Add helper computing the state of 52bit PA support
authorMarc Zyngier <maz@kernel.org>
Sat, 26 Jul 2025 10:38:09 +0000 (11:38 +0100)
committerMarc Zyngier <maz@kernel.org>
Sat, 20 Sep 2025 10:05:12 +0000 (11:05 +0100)
Track whether the guest is using 52bit PAs, either LPA or LPA2.
This further simplifies the handling of LVA for 4k and 16k pages,
as LPA2 implies LVA in this case.

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

index 7fd76f41c296af8a785ac0bed3b2561fcacdbebb..038e35430bb2cb84b6f8b3143422ff342244b9fe 100644 (file)
@@ -299,6 +299,7 @@ struct s1_walk_info {
        bool                    pan;
        bool                    be;
        bool                    s2;
+       bool                    pa52bit;
 };
 
 struct s1_walk_result {
index d71ca4ddc9d1e522b9e05e685f89b3c95ba41516..8e275ea68cfa8ba924bcc0bcc2010db1c58ae99e 100644 (file)
@@ -31,6 +31,29 @@ static bool check_output_size(u64 ipa, struct s1_walk_info *wi)
        return wi->max_oa_bits < 48 && (ipa & GENMASK_ULL(47, wi->max_oa_bits));
 }
 
+static bool has_52bit_pa(struct kvm_vcpu *vcpu, struct s1_walk_info *wi, u64 tcr)
+{
+       switch (BIT(wi->pgshift)) {
+       case SZ_64K:
+       default:                /* IMPDEF: treat any other value as 64k */
+               if (!kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR0_EL1, PARANGE, 52))
+                       return false;
+               return ((wi->regime == TR_EL2 ?
+                        FIELD_GET(TCR_EL2_PS_MASK, tcr) :
+                        FIELD_GET(TCR_IPS_MASK, tcr)) == 0b0110);
+       case SZ_16K:
+               if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT))
+                       return false;
+               break;
+       case SZ_4K:
+               if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT))
+                       return false;
+               break;
+       }
+
+       return (tcr & (wi->regime == TR_EL2 ? TCR_EL2_DS : TCR_DS));
+}
+
 /* Return the translation regime that applies to an AT instruction */
 static enum trans_regime compute_translation_regime(struct kvm_vcpu *vcpu, u32 op)
 {
@@ -232,15 +255,13 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
                        goto transfault_l0;
        }
 
+       wi->pa52bit = has_52bit_pa(vcpu, wi, tcr);
+
        /* R_GTJBY, R_SXWGM */
        switch (BIT(wi->pgshift)) {
        case SZ_4K:
-               lva = kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, TGRAN4, 52_BIT);
-               lva &= tcr & (wi->regime == TR_EL2 ? TCR_EL2_DS : TCR_DS);
-               break;
        case SZ_16K:
-               lva = kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, TGRAN16, 52_BIT);
-               lva &= tcr & (wi->regime == TR_EL2 ? TCR_EL2_DS : TCR_DS);
+               lva = wi->pa52bit;
                break;
        case SZ_64K:
                lva = kvm_has_feat(vcpu->kvm, ID_AA64MMFR2_EL1, VARange, 52);