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