[PATCH v4] KVM: arm64: selftests: Check the pending SError state in external_aborts

From: Fuad Tabba

Date: Tue Oct 06 2026 - 05:33:30 EST


None of the external abort tests look at the vCPU events once the guest
is done, so an SError left pending after the guest took it, or dropped
while the guest had it masked, goes unnoticed.

Read the vCPU events back at the end of every test that runs the guest.
The SError must still be pending in the masked case, with the injected
ESR when the vCPU has RAS, and no SError, injected or spurious, may be
pending in any of the others.

Signed-off-by: Fuad Tabba <fuad.tabba@xxxxxxxxx>
---
The check that no SError is left pending after the guest took it is
what fails without commit 3708f6342f01 ("KVM: arm64: Sync HCR_EL2.VSE
back to the host vCPU under pKVM"), in kvmarm/next.

Changes since v3 [1]:
- Check the SError pending state at the end of every test that runs the
guest, and assert it is still pending, with the injected ESR, in the
masked case (Oliver [2]).

[1] https://lore.kernel.org/all/20261005050349.836795-1-fuad.tabba@xxxxxxxxx/
[2] https://lore.kernel.org/all/asNdAXGkxagm88Su@xxxxxxxxxx/

.../selftests/kvm/arm64/external_aborts.c | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/tools/testing/selftests/kvm/arm64/external_aborts.c b/tools/testing/selftests/kvm/arm64/external_aborts.c
index 7836756a38a6c..1a858d0d82968 100644
--- a/tools/testing/selftests/kvm/arm64/external_aborts.c
+++ b/tools/testing/selftests/kvm/arm64/external_aborts.c
@@ -75,6 +75,17 @@ static void vcpu_inject_serror(struct kvm_vcpu *vcpu)
vcpu_events_set(vcpu, &events);
}

+static void vcpu_assert_serror_pending(struct kvm_vcpu *vcpu, bool pending)
+{
+ struct kvm_vcpu_events events;
+
+ vcpu_events_get(vcpu, &events);
+ TEST_ASSERT_EQ(events.exception.serror_pending, pending);
+
+ if (pending && vcpu_has_ras(vcpu))
+ TEST_ASSERT_EQ(events.exception.serror_esr, EXPECTED_SERROR_ISS);
+}
+
static void __vcpu_run_expect(struct kvm_vcpu *vcpu, unsigned int cmd)
{
struct ucall uc;
@@ -134,6 +145,7 @@ static void test_mmio_abort(void)

vcpu_inject_sea(vcpu);
vcpu_run_expect_done(vcpu);
+ vcpu_assert_serror_pending(vcpu, false);
kvm_vm_free(vm);
}

@@ -162,6 +174,7 @@ static void test_mmio_nisv(void)

TEST_ASSERT(_vcpu_run(vcpu), "Expected nonzero return code from KVM_RUN");
TEST_ASSERT_EQ(errno, ENOSYS);
+ vcpu_assert_serror_pending(vcpu, false);

kvm_vm_free(vm);
}
@@ -185,6 +198,7 @@ static void test_mmio_nisv_abort(void)

vcpu_inject_sea(vcpu);
vcpu_run_expect_done(vcpu);
+ vcpu_assert_serror_pending(vcpu, false);
kvm_vm_free(vm);
}

@@ -212,6 +226,7 @@ static void test_serror_masked(void)

vcpu_inject_serror(vcpu);
vcpu_run_expect_done(vcpu);
+ vcpu_assert_serror_pending(vcpu, true);
kvm_vm_free(vm);
}

@@ -247,6 +262,7 @@ static void test_serror(void)

vcpu_inject_serror(vcpu);
vcpu_run_expect_done(vcpu);
+ vcpu_assert_serror_pending(vcpu, false);
kvm_vm_free(vm);
}

@@ -288,6 +304,7 @@ static void test_s1ptw_abort(void)
*ptep |= bad_pa;

vcpu_run_expect_done(vcpu);
+ vcpu_assert_serror_pending(vcpu, false);
kvm_vm_free(vm);
}

@@ -313,6 +330,7 @@ static void test_serror_emulated(void)
vcpu_run_expect_sync(vcpu);
vcpu_inject_serror(vcpu);
vcpu_run_expect_done(vcpu);
+ vcpu_assert_serror_pending(vcpu, false);
kvm_vm_free(vm);
}

@@ -356,6 +374,7 @@ static void test_mmio_ease(void)

vcpu_inject_sea(vcpu);
vcpu_run_expect_done(vcpu);
+ vcpu_assert_serror_pending(vcpu, false);
done:
kvm_vm_free(vm);
}
@@ -395,6 +414,7 @@ static void test_serror_amo(void)
vcpu_run_expect_sync(vcpu);
vcpu_inject_serror(vcpu);
vcpu_run_expect_done(vcpu);
+ vcpu_assert_serror_pending(vcpu, false);
kvm_vm_free(vm);
}


base-commit: fa22cd9947fc245d71bc40482f7f78eb0d5a4af0
--
2.39.5