1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2022, Google LLC.
11 #include <sys/ioctl.h>
13 #include "test_util.h"
16 #include "processor.h"
19 * Assert that architectural dependency rules are satisfied, e.g. that AVX is
20 * supported if and only if SSE is supported.
22 #define ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0, xfeatures, dependencies) \
24 uint64_t __supported = (supported_xcr0) & ((xfeatures) | (dependencies)); \
26 __GUEST_ASSERT((__supported & (xfeatures)) != (xfeatures) || \
27 __supported == ((xfeatures) | (dependencies)), \
28 "supported = 0x%lx, xfeatures = 0x%llx, dependencies = 0x%llx", \
29 __supported, (xfeatures), (dependencies)); \
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.
40 #define ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0, xfeatures) \
42 uint64_t __supported = (supported_xcr0) & (xfeatures); \
44 __GUEST_ASSERT(!__supported || __supported == (xfeatures), \
45 "supported = 0x%lx, xfeatures = 0x%llx", \
46 __supported, (xfeatures)); \
49 static void guest_code(void)
51 uint64_t initial_xcr0
;
52 uint64_t supported_xcr0
;
55 set_cr4(get_cr4() | X86_CR4_OSXSAVE
);
57 initial_xcr0
= xgetbv(0);
58 supported_xcr0
= this_cpu_supported_xcr0();
60 GUEST_ASSERT(initial_xcr0
== supported_xcr0
);
63 ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0
,
68 ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0
,
69 XFEATURE_MASK_BNDREGS
| XFEATURE_MASK_BNDCSR
);
72 ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0
,
74 XFEATURE_MASK_SSE
| XFEATURE_MASK_YMM
);
75 ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0
,
76 XFEATURE_MASK_AVX512
);
79 ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0
,
82 vector
= xsetbv_safe(0, XFEATURE_MASK_FP
);
83 __GUEST_ASSERT(!vector
,
84 "Expected success on XSETBV(FP), got vector '0x%x'",
87 vector
= xsetbv_safe(0, supported_xcr0
);
88 __GUEST_ASSERT(!vector
,
89 "Expected success on XSETBV(0x%lx), got vector '0x%x'",
90 supported_xcr0
, vector
);
92 for (i
= 0; i
< 64; i
++) {
93 if (supported_xcr0
& BIT_ULL(i
))
96 vector
= xsetbv_safe(0, supported_xcr0
| BIT_ULL(i
));
97 __GUEST_ASSERT(vector
== GP_VECTOR
,
98 "Expected #GP on XSETBV(0x%llx), supported XCR0 = %lx, got vector '0x%x'",
99 BIT_ULL(i
), supported_xcr0
, vector
);
105 int main(int argc
, char *argv
[])
107 struct kvm_vcpu
*vcpu
;
112 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XSAVE
));
114 vm
= vm_create_with_one_vcpu(&vcpu
, guest_code
);
120 TEST_ASSERT(run
->exit_reason
== KVM_EXIT_IO
,
121 "Unexpected exit reason: %u (%s),",
123 exit_reason_str(run
->exit_reason
));
125 switch (get_ucall(vcpu
, &uc
)) {
127 REPORT_GUEST_ASSERT(uc
);
132 TEST_FAIL("Unknown ucall %lu", uc
.cmd
);