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 } 128