]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: nv: Snapshot S1 ASID tagging information during walk
authorMarc Zyngier <maz@kernel.org>
Wed, 14 May 2025 10:34:47 +0000 (11:34 +0100)
committerMarc Zyngier <maz@kernel.org>
Mon, 19 May 2025 06:59:46 +0000 (07:59 +0100)
We currently completely ignore any sort of ASID tagging during a S1
walk, as AT doesn't care about it.

However, such information is required if we are going to create
anything that looks like a TLB from this walk.

Let's capture it both the nG and ASID information while walking
the page tables.

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

index c8a779b393c28a64b51af0f73413107cb02a4f27..4ba3780cb7806b93e7ebc844070b85bb1f67cebc 100644 (file)
@@ -274,6 +274,8 @@ struct s1_walk_result {
                        u64     pa;
                        s8      level;
                        u8      APTable;
+                       bool    nG;
+                       u16     asid;
                        bool    UXNTable;
                        bool    PXNTable;
                        bool    uwxn;
index 71406908d4f44deea6aeacb10148a46263293a67..da5359668b9c93d1cf53d9bf1855fbb61d772852 100644 (file)
@@ -414,6 +414,33 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
        wr->pa = desc & GENMASK(47, va_bottom);
        wr->pa |= va & GENMASK_ULL(va_bottom - 1, 0);
 
+       wr->nG = (wi->regime != TR_EL2) && (desc & PTE_NG);
+       if (wr->nG) {
+               u64 asid_ttbr, tcr;
+
+               switch (wi->regime) {
+               case TR_EL10:
+                       tcr = vcpu_read_sys_reg(vcpu, TCR_EL1);
+                       asid_ttbr = ((tcr & TCR_A1) ?
+                                    vcpu_read_sys_reg(vcpu, TTBR1_EL1) :
+                                    vcpu_read_sys_reg(vcpu, TTBR0_EL1));
+                       break;
+               case TR_EL20:
+                       tcr = vcpu_read_sys_reg(vcpu, TCR_EL2);
+                       asid_ttbr = ((tcr & TCR_A1) ?
+                                    vcpu_read_sys_reg(vcpu, TTBR1_EL2) :
+                                    vcpu_read_sys_reg(vcpu, TTBR0_EL2));
+                       break;
+               default:
+                       BUG();
+               }
+
+               wr->asid = FIELD_GET(TTBR_ASID_MASK, asid_ttbr);
+               if (!kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR0_EL1, ASIDBITS, 16) ||
+                   !(tcr & TCR_ASID16))
+                       wr->asid &= GENMASK(7, 0);
+       }
+
        return 0;
 
 addrsz: