KVM: arm64: AArch32: Fix spurious trapping of conditional instructions
authorMarc Zyngier <maz@kernel.org>
Fri, 24 May 2024 14:19:56 +0000 (15:19 +0100)
committerMarc Zyngier <maz@kernel.org>
Mon, 27 May 2024 16:46:09 +0000 (17:46 +0100)
We recently upgraded the view of ESR_EL2 to 64bit, in keeping with
the requirements of the architecture.

However, the AArch32 emulation code was left unaudited, and the
(already dodgy) code that triages whether a trap is spurious or not
(because the condition code failed) broke in a subtle way:

If ESR_EL2.ISS2 is ever non-zero (unlikely, but hey, this is the ARM
architecture we're talking about), the hack that tests the top bits
of ESR_EL2.EC will break in an interesting way.

Instead, use kvm_vcpu_trap_get_class() to obtain the EC, and list
all the possible ECs that can fail a condition code check.

While we're at it, add SMC32 to the list, as it is explicitly listed
as being allowed to trap despite failing a condition code check (as
described in the HCR_EL2.TSC documentation).

Fixes: 0b12620fddb8 ("KVM: arm64: Treat ESR_EL2 as a 64-bit register")
Cc: stable@vger.kernel.org
Acked-by: Oliver Upton <oliver.upton@linux.dev>
Link: https://lore.kernel.org/r/20240524141956.1450304-4-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/hyp/aarch32.c

index 8d9670e6615dc8767e3b1524e04fcd96ae6f63c8..449fa58cf3b63b1cc3d990b76e3d07d4180dc06b 100644 (file)
@@ -50,9 +50,23 @@ bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
        u32 cpsr_cond;
        int cond;
 
-       /* Top two bits non-zero?  Unconditional. */
-       if (kvm_vcpu_get_esr(vcpu) >> 30)
+       /*
+        * These are the exception classes that could fire with a
+        * conditional instruction.
+        */
+       switch (kvm_vcpu_trap_get_class(vcpu)) {
+       case ESR_ELx_EC_CP15_32:
+       case ESR_ELx_EC_CP15_64:
+       case ESR_ELx_EC_CP14_MR:
+       case ESR_ELx_EC_CP14_LS:
+       case ESR_ELx_EC_FP_ASIMD:
+       case ESR_ELx_EC_CP10_ID:
+       case ESR_ELx_EC_CP14_64:
+       case ESR_ELx_EC_SVC32:
+               break;
+       default:
                return true;
+       }
 
        /* Is condition field valid? */
        cond = kvm_vcpu_get_condition(vcpu);