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
guest_code(void)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
handle_sigill(int sig,siginfo_t * info,void * ctx)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
register_sigill_handler(void)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
do_sve_roundtrip(void)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
test_run(void)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
main(void)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