]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: nv: Fix PSTATE construction on illegal exception return
authorFuad Tabba <tabba@google.com>
Wed, 17 Jun 2026 14:49:07 +0000 (15:49 +0100)
committerMarc Zyngier <maz@kernel.org>
Wed, 17 Jun 2026 17:34:47 +0000 (18:34 +0100)
kvm_check_illegal_exception_return() sourced the flags {N,Z,C,V} and
masks {D,A,I,F} of the resulting PSTATE from the current PSTATE, but
R_VWJHB takes them from the SPSR being returned to and leaves
PSTATE.{EL,SP,nRW} (and EXLOCK when FEAT_GCS) unchanged. PAN, ALLINT
and PM were not applied at all.

Build the PSTATE by taking those fields from the SPSR while preserving
EL, SP, nRW and EXLOCK from the current PSTATE, then set IL.

Fixes: 47f3a2fc765a ("KVM: arm64: nv: Support virtual EL2 exceptions")
Suggested-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/all/86wlvxs5r0.wl-maz@kernel.org/
Signed-off-by: Fuad Tabba <tabba@google.com>
Link: https://patch.msgid.link/20260617144907.2972095-1-tabba@google.com
[maz: tidied things a bit]
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/emulate-nested.c

index 76c3e6c1144c8c46698d11feebe5902d997a8f62..96ebe7e3b408106bc8c51121bb469b4b59da0e80 100644 (file)
@@ -2746,17 +2746,33 @@ static u64 kvm_check_illegal_exception_return(struct kvm_vcpu *vcpu, u64 spsr)
            (spsr & PSR_MODE32_BIT) ||
            (vcpu_el2_tge_is_set(vcpu) && (mode == PSR_MODE_EL1t ||
                                           mode == PSR_MODE_EL1h))) {
+               u64 mask;
+
                /*
-                * The guest is playing with our nerves. Preserve EL, SP,
-                * masks, flags from the existing PSTATE, and set IL.
-                * The HW will then generate an Illegal State Exception
-                * immediately after ERET.
+                * On an illegal exception return, the flags and masks are
+                * taken from the SPSR while PSTATE.{EL,SP,nRW} and, if
+                * FEAT_GCS, PSTATE.EXLOCK are unchanged (R_VWJHB). Set IL
+                * so the HW generates an Illegal State Exception right
+                * after ERET.
                 */
-               spsr = *vcpu_cpsr(vcpu);
+               mask = PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT |
+                      PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT;
+
+               if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR1_EL1, PAN, IMP))
+                       mask |= PSR_PAN_BIT;
+               if (kvm_has_feat(vcpu->kvm, ID_AA64PFR1_EL1, NMI, IMP))
+                       mask |= ALLINT_ALLINT;
+               /* FEAT_SPE_EXC and FEAT_TRBE_EXC also gate PSTATE.PM one day... */
+               if (kvm_has_feat(vcpu->kvm, ID_AA64DFR1_EL1, EBEP, IMP))
+                       mask |= BIT_ULL(32);    /* SPSR_ELx.PM */
+
+               spsr &= mask;
+
+               mask = PSR_MODE_MASK | PSR_MODE32_BIT;
+               if (kvm_has_feat(vcpu->kvm, ID_AA64PFR1_EL1, GCS, IMP))
+                       mask |= BIT_ULL(34);    /* PSTATE.EXLOCK */
 
-               spsr &= (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT |
-                        PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT |
-                        PSR_MODE_MASK | PSR_MODE32_BIT);
+               spsr |= *vcpu_cpsr(vcpu) & mask;
                spsr |= PSR_IL_BIT;
        }