xref: /linux/tools/testing/selftests/kvm/arm64/host_sve.c (revision 43db1111073049220381944af4a3b8a5400eda71)
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