]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: selftests: Cope with arch silliness in EL2 selftest
authorOliver Upton <oliver.upton@linux.dev>
Tue, 23 Sep 2025 17:30:06 +0000 (10:30 -0700)
committerMarc Zyngier <maz@kernel.org>
Wed, 24 Sep 2025 18:24:02 +0000 (19:24 +0100)
Implementations without FEAT_FGT aren't required to trap the entire ID
register space when HCR_EL2.TID3 is set. This is a terrible idea, as the
hypervisor may need to advertise the absence of a feature to the VM
using a negative value in a signed field, FEAT_E2H0 being a great
example of this.

Cope with uncooperative implementations in the EL2 selftest by accepting
a zero value when FEAT_FGT is absent and otherwise only tolerating the
expected nonzero value.

Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>
tools/testing/selftests/kvm/arm64/hello_el2.c

index 3c1f44e43f65753d60d79f4166cb70a47cd6e0de..bbe6862c6ab16ec1c1d4713f93d35dac7d763739 100644 (file)
 
 static void guest_code(void)
 {
+       u64 mmfr0 = read_sysreg_s(SYS_ID_AA64MMFR0_EL1);
        u64 mmfr1 = read_sysreg_s(SYS_ID_AA64MMFR1_EL1);
        u64 mmfr4 = read_sysreg_s(SYS_ID_AA64MMFR4_EL1);
+       u8 e2h0 = SYS_FIELD_GET(ID_AA64MMFR4_EL1, E2H0, mmfr4);
 
        GUEST_ASSERT_EQ(get_current_el(), 2);
        GUEST_ASSERT(read_sysreg(hcr_el2) & HCR_EL2_E2H);
        GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR1_EL1, VH, mmfr1),
                        ID_AA64MMFR1_EL1_VH_IMP);
-       GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR4_EL1, E2H0, mmfr4),
-                       ID_AA64MMFR4_EL1_E2H0_NI_NV1);
+
+       /*
+        * Traps of the complete ID register space are IMPDEF without FEAT_FGT,
+        * which is really annoying to deal with in KVM describing E2H as RES1.
+        *
+        * If the implementation doesn't honor the trap then expect the register
+        * to return all zeros.
+        */
+       if (e2h0 == ID_AA64MMFR4_EL1_E2H0_IMP)
+               GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR0_EL1, FGT, mmfr0),
+                               ID_AA64MMFR0_EL1_FGT_NI);
+       else
+               GUEST_ASSERT_EQ(e2h0, ID_AA64MMFR4_EL1_E2H0_NI_NV1);
 
        GUEST_DONE();
 }