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