]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: arm64: Route SEAs to the SError vector when EASE is set
authorOliver Upton <oliver.upton@linux.dev>
Tue, 8 Jul 2025 17:25:22 +0000 (10:25 -0700)
committerOliver Upton <oliver.upton@linux.dev>
Tue, 8 Jul 2025 18:36:35 +0000 (11:36 -0700)
One of the finest additions of FEAT_DoubleFault2 is the ability for
software to request *synchronous* external aborts be taken to the
SError vector, which of coure are *asynchronous* in nature.

Opinions be damned, implement the architecture and send SEAs to the
SError vector if EASE is set for the target context.

Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250708172532.1699409-18-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/emulate-nested.c
arch/arm64/kvm/hyp/exception.c
arch/arm64/kvm/inject_fault.c

index ff53109caa058f389c77591ad5f28fe7c85d817f..90cb4b7ae0ff748453a6495b7dca1c2eb9db3893 100644 (file)
@@ -2834,6 +2834,10 @@ int kvm_inject_nested_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr)
        esr |= ESR_ELx_FSC_EXTABT | ESR_ELx_IL;
 
        vcpu_write_sys_reg(vcpu, FAR_EL2, addr);
+
+       if (__vcpu_sys_reg(vcpu, SCTLR2_EL2) & SCTLR2_EL1_EASE)
+               return kvm_inject_nested(vcpu, esr, except_type_serror);
+
        return kvm_inject_nested_sync(vcpu, esr);
 }
 
index 592adc78b1496881aa0378e408797239013f7f78..7dafd10e52e8c6e2b0b77ded7ee13d4127a4c985 100644 (file)
@@ -339,6 +339,10 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu)
                        enter_exception64(vcpu, PSR_MODE_EL1h, except_type_sync);
                        break;
 
+               case unpack_vcpu_flag(EXCEPT_AA64_EL1_SERR):
+                       enter_exception64(vcpu, PSR_MODE_EL1h, except_type_serror);
+                       break;
+
                case unpack_vcpu_flag(EXCEPT_AA64_EL2_SYNC):
                        enter_exception64(vcpu, PSR_MODE_EL2h, except_type_sync);
                        break;
@@ -353,7 +357,7 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu)
 
                default:
                        /*
-                        * Only EL1_SYNC and EL2_{SYNC,IRQ,SERR} makes
+                        * Only EL1_{SYNC,SERR} and EL2_{SYNC,IRQ,SERR} makes
                         * sense so far. Everything else gets silently
                         * ignored.
                         */
index 88bc85ecdbb04b21f6712750e574235a64e31972..cab14a926bc6c3518ce2954da8fd280e93cfef06 100644 (file)
@@ -65,13 +65,49 @@ static void pend_sync_exception(struct kvm_vcpu *vcpu)
                kvm_pend_exception(vcpu, EXCEPT_AA64_EL2_SYNC);
 }
 
+static void pend_serror_exception(struct kvm_vcpu *vcpu)
+{
+       if (exception_target_el(vcpu) == PSR_MODE_EL1h)
+               kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SERR);
+       else
+               kvm_pend_exception(vcpu, EXCEPT_AA64_EL2_SERR);
+}
+
+static bool __effective_sctlr2_bit(struct kvm_vcpu *vcpu, unsigned int idx)
+{
+       u64 sctlr2;
+
+       if (!kvm_has_sctlr2(vcpu->kvm))
+               return false;
+
+       if (is_nested_ctxt(vcpu) &&
+           !(__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_SCTLR2En))
+               return false;
+
+       if (exception_target_el(vcpu) == PSR_MODE_EL1h)
+               sctlr2 = vcpu_read_sys_reg(vcpu, SCTLR2_EL1);
+       else
+               sctlr2 = vcpu_read_sys_reg(vcpu, SCTLR2_EL2);
+
+       return sctlr2 & BIT(idx);
+}
+
+static bool effective_sctlr2_ease(struct kvm_vcpu *vcpu)
+{
+       return __effective_sctlr2_bit(vcpu, SCTLR2_EL1_EASE_SHIFT);
+}
+
 static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
 {
        unsigned long cpsr = *vcpu_cpsr(vcpu);
        bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
        u64 esr = 0;
 
-       pend_sync_exception(vcpu);
+       /* This delight is brought to you by FEAT_DoubleFault2. */
+       if (effective_sctlr2_ease(vcpu))
+               pend_serror_exception(vcpu);
+       else
+               pend_sync_exception(vcpu);
 
        /*
         * Build an {i,d}abort, depending on the level and the