Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <maz@kernel.org>
Link: https://lore.kernel.org/r/20250708172532.1699409-25-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>

+121 -8
+1 -1
tools/testing/selftests/kvm/Makefile.kvm
··· 156 156 TEST_GEN_PROGS_arm64 += arm64/debug-exceptions 157 157 TEST_GEN_PROGS_arm64 += arm64/host_sve 158 158 TEST_GEN_PROGS_arm64 += arm64/hypercalls 159 - TEST_GEN_PROGS_arm64 += arm64/mmio_abort 159 + TEST_GEN_PROGS_arm64 += arm64/external_aborts 160 160 TEST_GEN_PROGS_arm64 += arm64/page_fault_test 161 161 TEST_GEN_PROGS_arm64 += arm64/psci_test 162 162 TEST_GEN_PROGS_arm64 += arm64/set_id_regs
+110 -7
tools/testing/selftests/kvm/arm64/mmio_abort.c tools/testing/selftests/kvm/arm64/external_aborts.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 - * mmio_abort - Tests for userspace MMIO abort injection 3 + * external_abort - Tests for userspace external abort injection 4 4 * 5 5 * Copyright (c) 2024 Google LLC 6 6 */ ··· 41 41 return vm; 42 42 } 43 43 44 - static void vcpu_inject_extabt(struct kvm_vcpu *vcpu) 44 + static void vcpu_inject_sea(struct kvm_vcpu *vcpu) 45 45 { 46 46 struct kvm_vcpu_events events = {}; 47 47 ··· 49 49 vcpu_events_set(vcpu, &events); 50 50 } 51 51 52 - static void vcpu_run_expect_done(struct kvm_vcpu *vcpu) 52 + static void vcpu_inject_serror(struct kvm_vcpu *vcpu) 53 + { 54 + struct kvm_vcpu_events events = {}; 55 + 56 + events.exception.serror_pending = true; 57 + vcpu_events_set(vcpu, &events); 58 + } 59 + 60 + static void __vcpu_run_expect(struct kvm_vcpu *vcpu, unsigned int cmd) 53 61 { 54 62 struct ucall uc; 55 63 ··· 66 58 case UCALL_ABORT: 67 59 REPORT_GUEST_ASSERT(uc); 68 60 break; 69 - case UCALL_DONE: 70 - break; 71 61 default: 62 + if (uc.cmd == cmd) 63 + return; 64 + 72 65 TEST_FAIL("Unexpected ucall: %lu", uc.cmd); 73 66 } 67 + } 68 + 69 + static void vcpu_run_expect_done(struct kvm_vcpu *vcpu) 70 + { 71 + __vcpu_run_expect(vcpu, UCALL_DONE); 72 + } 73 + 74 + static void vcpu_run_expect_sync(struct kvm_vcpu *vcpu) 75 + { 76 + __vcpu_run_expect(vcpu, UCALL_SYNC); 74 77 } 75 78 76 79 extern char test_mmio_abort_insn; ··· 114 95 TEST_ASSERT_EQ(run->mmio.len, sizeof(unsigned long)); 115 96 TEST_ASSERT(!run->mmio.is_write, "Expected MMIO read"); 116 97 117 - vcpu_inject_extabt(vcpu); 98 + vcpu_inject_sea(vcpu); 118 99 vcpu_run_expect_done(vcpu); 119 100 kvm_vm_free(vm); 120 101 } ··· 165 146 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_ARM_NISV); 166 147 TEST_ASSERT_EQ(run->arm_nisv.fault_ipa, MMIO_ADDR); 167 148 168 - vcpu_inject_extabt(vcpu); 149 + vcpu_inject_sea(vcpu); 150 + vcpu_run_expect_done(vcpu); 151 + kvm_vm_free(vm); 152 + } 153 + 154 + static void unexpected_serror_handler(struct ex_regs *regs) 155 + { 156 + GUEST_FAIL("Took unexpected SError exception"); 157 + } 158 + 159 + static void test_serror_masked_guest(void) 160 + { 161 + GUEST_ASSERT(read_sysreg(isr_el1) & ISR_EL1_A); 162 + 163 + isb(); 164 + 165 + GUEST_DONE(); 166 + } 167 + 168 + static void test_serror_masked(void) 169 + { 170 + struct kvm_vcpu *vcpu; 171 + struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_serror_masked_guest, 172 + unexpected_dabt_handler); 173 + 174 + vm_install_exception_handler(vm, VECTOR_ERROR_CURRENT, unexpected_serror_handler); 175 + 176 + vcpu_inject_serror(vcpu); 177 + vcpu_run_expect_done(vcpu); 178 + kvm_vm_free(vm); 179 + } 180 + 181 + static void expect_serror_handler(struct ex_regs *regs) 182 + { 183 + GUEST_DONE(); 184 + } 185 + 186 + static void test_serror_guest(void) 187 + { 188 + GUEST_ASSERT(read_sysreg(isr_el1) & ISR_EL1_A); 189 + 190 + local_serror_enable(); 191 + isb(); 192 + local_serror_disable(); 193 + 194 + GUEST_FAIL("Should've taken pending SError exception"); 195 + } 196 + 197 + static void test_serror(void) 198 + { 199 + struct kvm_vcpu *vcpu; 200 + struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_serror_guest, 201 + unexpected_dabt_handler); 202 + 203 + vm_install_exception_handler(vm, VECTOR_ERROR_CURRENT, expect_serror_handler); 204 + 205 + vcpu_inject_serror(vcpu); 206 + vcpu_run_expect_done(vcpu); 207 + kvm_vm_free(vm); 208 + } 209 + 210 + static void test_serror_emulated_guest(void) 211 + { 212 + GUEST_ASSERT(!(read_sysreg(isr_el1) & ISR_EL1_A)); 213 + 214 + local_serror_enable(); 215 + GUEST_SYNC(0); 216 + local_serror_disable(); 217 + 218 + GUEST_FAIL("Should've taken unmasked SError exception"); 219 + } 220 + 221 + static void test_serror_emulated(void) 222 + { 223 + struct kvm_vcpu *vcpu; 224 + struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_serror_emulated_guest, 225 + unexpected_dabt_handler); 226 + 227 + vm_install_exception_handler(vm, VECTOR_ERROR_CURRENT, expect_serror_handler); 228 + 229 + vcpu_run_expect_sync(vcpu); 230 + vcpu_inject_serror(vcpu); 169 231 vcpu_run_expect_done(vcpu); 170 232 kvm_vm_free(vm); 171 233 } ··· 256 156 test_mmio_abort(); 257 157 test_mmio_nisv(); 258 158 test_mmio_nisv_abort(); 159 + test_serror(); 160 + test_serror_masked(); 161 + test_serror_emulated(); 259 162 }
+10
tools/testing/selftests/kvm/include/arm64/processor.h
··· 254 254 asm volatile("msr daifset, #3" : : : "memory"); 255 255 } 256 256 257 + static inline void local_serror_enable(void) 258 + { 259 + asm volatile("msr daifclr, #4" : : : "memory"); 260 + } 261 + 262 + static inline void local_serror_disable(void) 263 + { 264 + asm volatile("msr daifset, #4" : : : "memory"); 265 + } 266 + 257 267 /** 258 268 * struct arm_smccc_res - Result from SMC/HVC call 259 269 * @a0-a3 result values from registers 0 to 3