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

KVM: arm64: selftests: Add test for SVE host corruption

Until recently, the kernel could unexpectedly discard SVE state for a
period after a KVM_RUN ioctl, when the guest did not execute any
FPSIMD/SVE/SME instructions. We fixed that issue in commit:

fbc7e61195e2 ("KVM: arm64: Unconditionally save+flush host FPSIMD/SVE/SME state")

Add a test which tries to provoke that issue by manipulating SVE state
before/after running a guest which does not execute any FPSIMD/SVE/SME
instructions. The test executes a handful of iterations to miminize
the risk that the issue is masked by preemption.

Signed-off--by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Link: https://lore.kernel.org/r/20250417-kvm-selftest-sve-signal-v1-1-6330c2f3da0c@kernel.org
[maz: Restored MR's SoB, fixed commit message according to MR's write-up]
Signed-off-by: Marc Zyngier <maz@kernel.org>

authored by

Mark Brown and committed by
Marc Zyngier
e0ccc45b bae247cc

+128
+1
tools/testing/selftests/kvm/Makefile.kvm
··· 147 147 TEST_GEN_PROGS_arm64 += arm64/aarch32_id_regs 148 148 TEST_GEN_PROGS_arm64 += arm64/arch_timer_edge_cases 149 149 TEST_GEN_PROGS_arm64 += arm64/debug-exceptions 150 + TEST_GEN_PROGS_arm64 += arm64/host_sve 150 151 TEST_GEN_PROGS_arm64 += arm64/hypercalls 151 152 TEST_GEN_PROGS_arm64 += arm64/mmio_abort 152 153 TEST_GEN_PROGS_arm64 += arm64/page_fault_test
+127
tools/testing/selftests/kvm/arm64/host_sve.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + /* 4 + * Host SVE: Check FPSIMD/SVE/SME save/restore over KVM_RUN ioctls. 5 + * 6 + * Copyright 2025 Arm, Ltd 7 + */ 8 + 9 + #include <errno.h> 10 + #include <signal.h> 11 + #include <sys/auxv.h> 12 + #include <asm/kvm.h> 13 + #include <kvm_util.h> 14 + 15 + #include "ucall_common.h" 16 + 17 + static void guest_code(void) 18 + { 19 + for (int i = 0; i < 10; i++) { 20 + GUEST_UCALL_NONE(); 21 + } 22 + 23 + GUEST_DONE(); 24 + } 25 + 26 + void handle_sigill(int sig, siginfo_t *info, void *ctx) 27 + { 28 + ucontext_t *uctx = ctx; 29 + 30 + printf(" < host signal %d >\n", sig); 31 + 32 + /* 33 + * Skip the UDF 34 + */ 35 + uctx->uc_mcontext.pc += 4; 36 + } 37 + 38 + void register_sigill_handler(void) 39 + { 40 + struct sigaction sa = { 41 + .sa_sigaction = handle_sigill, 42 + .sa_flags = SA_SIGINFO, 43 + }; 44 + sigaction(SIGILL, &sa, NULL); 45 + } 46 + 47 + static void do_sve_roundtrip(void) 48 + { 49 + unsigned long before, after; 50 + 51 + /* 52 + * Set all bits in a predicate register, force a save/restore via a 53 + * SIGILL (which handle_sigill() will recover from), then report 54 + * whether the value has changed. 55 + */ 56 + asm volatile( 57 + " .arch_extension sve\n" 58 + " ptrue p0.B\n" 59 + " cntp %[before], p0, p0.B\n" 60 + " udf #0\n" 61 + " cntp %[after], p0, p0.B\n" 62 + : [before] "=r" (before), 63 + [after] "=r" (after) 64 + : 65 + : "p0" 66 + ); 67 + 68 + if (before != after) { 69 + TEST_FAIL("Signal roundtrip discarded predicate bits (%ld => %ld)\n", 70 + before, after); 71 + } else { 72 + printf("Signal roundtrip preserved predicate bits (%ld => %ld)\n", 73 + before, after); 74 + } 75 + } 76 + 77 + static void test_run(void) 78 + { 79 + struct kvm_vcpu *vcpu; 80 + struct kvm_vm *vm; 81 + struct ucall uc; 82 + bool guest_done = false; 83 + 84 + register_sigill_handler(); 85 + 86 + vm = vm_create_with_one_vcpu(&vcpu, guest_code); 87 + 88 + do_sve_roundtrip(); 89 + 90 + while (!guest_done) { 91 + 92 + printf("Running VCPU...\n"); 93 + vcpu_run(vcpu); 94 + 95 + switch (get_ucall(vcpu, &uc)) { 96 + case UCALL_NONE: 97 + do_sve_roundtrip(); 98 + do_sve_roundtrip(); 99 + break; 100 + case UCALL_DONE: 101 + guest_done = true; 102 + break; 103 + case UCALL_ABORT: 104 + REPORT_GUEST_ASSERT(uc); 105 + break; 106 + default: 107 + TEST_FAIL("Unexpected guest exit"); 108 + } 109 + } 110 + 111 + kvm_vm_free(vm); 112 + } 113 + 114 + int main(void) 115 + { 116 + /* 117 + * This is testing the host environment, we don't care about 118 + * guest SVE support. 119 + */ 120 + if (!(getauxval(AT_HWCAP) & HWCAP_SVE)) { 121 + printf("SVE not supported\n"); 122 + return KSFT_SKIP; 123 + } 124 + 125 + test_run(); 126 + return 0; 127 + }