From: Oliver Upton Date: Tue, 8 Jul 2025 17:25:29 +0000 (-0700) Subject: KVM: arm64: selftests: Add basic SError injection test X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2858ea3083f088a76b439f5b88b6d4f032dabc0c;p=thirdparty%2Flinux.git KVM: arm64: selftests: Add basic SError injection test Add tests for SError injection considering KVM is more directly involved in delivery: - Pending SErrors are taken at the first CSE after SErrors are unmasked - Pending SErrors aren't taken and remain pending if SErrors are masked - Unmasked SErrors are taken immediately when injected (implementation detail) Reviewed-by: Marc Zyngier Link: https://lore.kernel.org/r/20250708172532.1699409-25-oliver.upton@linux.dev Signed-off-by: Oliver Upton --- diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 38b95998e1e6b..ce817a975e50a 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -156,7 +156,7 @@ TEST_GEN_PROGS_arm64 += arm64/arch_timer_edge_cases TEST_GEN_PROGS_arm64 += arm64/debug-exceptions TEST_GEN_PROGS_arm64 += arm64/host_sve TEST_GEN_PROGS_arm64 += arm64/hypercalls -TEST_GEN_PROGS_arm64 += arm64/mmio_abort +TEST_GEN_PROGS_arm64 += arm64/external_aborts TEST_GEN_PROGS_arm64 += arm64/page_fault_test TEST_GEN_PROGS_arm64 += arm64/psci_test TEST_GEN_PROGS_arm64 += arm64/set_id_regs diff --git a/tools/testing/selftests/kvm/arm64/mmio_abort.c b/tools/testing/selftests/kvm/arm64/external_aborts.c similarity index 60% rename from tools/testing/selftests/kvm/arm64/mmio_abort.c rename to tools/testing/selftests/kvm/arm64/external_aborts.c index 8b7a80a51b1c4..f49c98bda60e9 100644 --- a/tools/testing/selftests/kvm/arm64/mmio_abort.c +++ b/tools/testing/selftests/kvm/arm64/external_aborts.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * mmio_abort - Tests for userspace MMIO abort injection + * external_abort - Tests for userspace external abort injection * * Copyright (c) 2024 Google LLC */ @@ -41,7 +41,7 @@ static struct kvm_vm *vm_create_with_dabt_handler(struct kvm_vcpu **vcpu, void * return vm; } -static void vcpu_inject_extabt(struct kvm_vcpu *vcpu) +static void vcpu_inject_sea(struct kvm_vcpu *vcpu) { struct kvm_vcpu_events events = {}; @@ -49,7 +49,15 @@ static void vcpu_inject_extabt(struct kvm_vcpu *vcpu) vcpu_events_set(vcpu, &events); } -static void vcpu_run_expect_done(struct kvm_vcpu *vcpu) +static void vcpu_inject_serror(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_events events = {}; + + events.exception.serror_pending = true; + vcpu_events_set(vcpu, &events); +} + +static void __vcpu_run_expect(struct kvm_vcpu *vcpu, unsigned int cmd) { struct ucall uc; @@ -58,13 +66,24 @@ static void vcpu_run_expect_done(struct kvm_vcpu *vcpu) case UCALL_ABORT: REPORT_GUEST_ASSERT(uc); break; - case UCALL_DONE: - break; default: + if (uc.cmd == cmd) + return; + TEST_FAIL("Unexpected ucall: %lu", uc.cmd); } } +static void vcpu_run_expect_done(struct kvm_vcpu *vcpu) +{ + __vcpu_run_expect(vcpu, UCALL_DONE); +} + +static void vcpu_run_expect_sync(struct kvm_vcpu *vcpu) +{ + __vcpu_run_expect(vcpu, UCALL_SYNC); +} + extern char test_mmio_abort_insn; static void test_mmio_abort_guest(void) @@ -95,7 +114,7 @@ static void test_mmio_abort(void) TEST_ASSERT_EQ(run->mmio.len, sizeof(unsigned long)); TEST_ASSERT(!run->mmio.is_write, "Expected MMIO read"); - vcpu_inject_extabt(vcpu); + vcpu_inject_sea(vcpu); vcpu_run_expect_done(vcpu); kvm_vm_free(vm); } @@ -146,7 +165,88 @@ static void test_mmio_nisv_abort(void) TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_ARM_NISV); TEST_ASSERT_EQ(run->arm_nisv.fault_ipa, MMIO_ADDR); - vcpu_inject_extabt(vcpu); + vcpu_inject_sea(vcpu); + vcpu_run_expect_done(vcpu); + kvm_vm_free(vm); +} + +static void unexpected_serror_handler(struct ex_regs *regs) +{ + GUEST_FAIL("Took unexpected SError exception"); +} + +static void test_serror_masked_guest(void) +{ + GUEST_ASSERT(read_sysreg(isr_el1) & ISR_EL1_A); + + isb(); + + GUEST_DONE(); +} + +static void test_serror_masked(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_serror_masked_guest, + unexpected_dabt_handler); + + vm_install_exception_handler(vm, VECTOR_ERROR_CURRENT, unexpected_serror_handler); + + vcpu_inject_serror(vcpu); + vcpu_run_expect_done(vcpu); + kvm_vm_free(vm); +} + +static void expect_serror_handler(struct ex_regs *regs) +{ + GUEST_DONE(); +} + +static void test_serror_guest(void) +{ + GUEST_ASSERT(read_sysreg(isr_el1) & ISR_EL1_A); + + local_serror_enable(); + isb(); + local_serror_disable(); + + GUEST_FAIL("Should've taken pending SError exception"); +} + +static void test_serror(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_serror_guest, + unexpected_dabt_handler); + + vm_install_exception_handler(vm, VECTOR_ERROR_CURRENT, expect_serror_handler); + + vcpu_inject_serror(vcpu); + vcpu_run_expect_done(vcpu); + kvm_vm_free(vm); +} + +static void test_serror_emulated_guest(void) +{ + GUEST_ASSERT(!(read_sysreg(isr_el1) & ISR_EL1_A)); + + local_serror_enable(); + GUEST_SYNC(0); + local_serror_disable(); + + GUEST_FAIL("Should've taken unmasked SError exception"); +} + +static void test_serror_emulated(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_serror_emulated_guest, + unexpected_dabt_handler); + + vm_install_exception_handler(vm, VECTOR_ERROR_CURRENT, expect_serror_handler); + + vcpu_run_expect_sync(vcpu); + vcpu_inject_serror(vcpu); vcpu_run_expect_done(vcpu); kvm_vm_free(vm); } @@ -156,4 +256,7 @@ int main(void) test_mmio_abort(); test_mmio_nisv(); test_mmio_nisv_abort(); + test_serror(); + test_serror_masked(); + test_serror_emulated(); } diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h index b0fc0f945766f..255fed769a8a5 100644 --- a/tools/testing/selftests/kvm/include/arm64/processor.h +++ b/tools/testing/selftests/kvm/include/arm64/processor.h @@ -254,6 +254,16 @@ static inline void local_irq_disable(void) asm volatile("msr daifset, #3" : : : "memory"); } +static inline void local_serror_enable(void) +{ + asm volatile("msr daifclr, #4" : : : "memory"); +} + +static inline void local_serror_disable(void) +{ + asm volatile("msr daifset, #4" : : : "memory"); +} + /** * struct arm_smccc_res - Result from SMC/HVC call * @a0-a3 result values from registers 0 to 3