1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * XCR0 cpuid test
4  *
5  * Copyright (C) 2022, Google LLC.
6  */
7 
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/ioctl.h>
13 
14 #include "test_util.h"
15 
16 #include "kvm_util.h"
17 #include "processor.h"
18 
19 /*
20  * Assert that architectural dependency rules are satisfied, e.g. that AVX is
21  * supported if and only if SSE is supported.
22  */
23 #define ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0, xfeatures, dependencies)	  \
24 do {										  \
25 	uint64_t __supported = (supported_xcr0) & ((xfeatures) | (dependencies)); \
26 										  \
27 	GUEST_ASSERT_3((__supported & (xfeatures)) != (xfeatures) ||		  \
28 		       __supported == ((xfeatures) | (dependencies)),		  \
29 		       __supported, (xfeatures), (dependencies));		  \
30 } while (0)
31 
32 /*
33  * Assert that KVM reports a sane, usable as-is XCR0.  Architecturally, a CPU
34  * isn't strictly required to _support_ all XFeatures related to a feature, but
35  * at the same time XSETBV will #GP if bundled XFeatures aren't enabled and
36  * disabled coherently.  E.g. a CPU can technically enumerate supported for
37  * XTILE_CFG but not XTILE_DATA, but attempting to enable XTILE_CFG without
38  * XTILE_DATA will #GP.
39  */
40 #define ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0, xfeatures)		\
41 do {									\
42 	uint64_t __supported = (supported_xcr0) & (xfeatures);		\
43 									\
44 	GUEST_ASSERT_2(!__supported || __supported == (xfeatures),	\
45 		       __supported, (xfeatures));			\
46 } while (0)
47 
48 static void guest_code(void)
49 {
50 	uint64_t xcr0_reset;
51 	uint64_t supported_xcr0;
52 	int i, vector;
53 
54 	set_cr4(get_cr4() | X86_CR4_OSXSAVE);
55 
56 	xcr0_reset = xgetbv(0);
57 	supported_xcr0 = this_cpu_supported_xcr0();
58 
59 	GUEST_ASSERT(xcr0_reset == XFEATURE_MASK_FP);
60 
61 	/* Check AVX */
62 	ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0,
63 				     XFEATURE_MASK_YMM,
64 				     XFEATURE_MASK_SSE);
65 
66 	/* Check MPX */
67 	ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0,
68 				    XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR);
69 
70 	/* Check AVX-512 */
71 	ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0,
72 				     XFEATURE_MASK_AVX512,
73 				     XFEATURE_MASK_SSE | XFEATURE_MASK_YMM);
74 	ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0,
75 				    XFEATURE_MASK_AVX512);
76 
77 	/* Check AMX */
78 	ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0,
79 				    XFEATURE_MASK_XTILE);
80 
81 	vector = xsetbv_safe(0, supported_xcr0);
82 	GUEST_ASSERT_2(!vector, supported_xcr0, vector);
83 
84 	for (i = 0; i < 64; i++) {
85 		if (supported_xcr0 & BIT_ULL(i))
86 			continue;
87 
88 		vector = xsetbv_safe(0, supported_xcr0 | BIT_ULL(i));
89 		GUEST_ASSERT_3(vector == GP_VECTOR, supported_xcr0, vector, BIT_ULL(i));
90 	}
91 
92 	GUEST_DONE();
93 }
94 
95 int main(int argc, char *argv[])
96 {
97 	struct kvm_vcpu *vcpu;
98 	struct kvm_run *run;
99 	struct kvm_vm *vm;
100 	struct ucall uc;
101 
102 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XSAVE));
103 
104 	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
105 	run = vcpu->run;
106 
107 	vm_init_descriptor_tables(vm);
108 	vcpu_init_descriptor_tables(vcpu);
109 
110 	while (1) {
111 		vcpu_run(vcpu);
112 
113 		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
114 			    "Unexpected exit reason: %u (%s),\n",
115 			    run->exit_reason,
116 			    exit_reason_str(run->exit_reason));
117 
118 		switch (get_ucall(vcpu, &uc)) {
119 		case UCALL_ABORT:
120 			REPORT_GUEST_ASSERT_3(uc, "0x%lx 0x%lx 0x%lx");
121 			break;
122 		case UCALL_DONE:
123 			goto done;
124 		default:
125 			TEST_FAIL("Unknown ucall %lu", uc.cmd);
126 		}
127 	}
128 
129 done:
130 	kvm_vm_free(vm);
131 	return 0;
132 }
133