Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * XCR0 cpuid test
4 *
5 * Copyright (C) 2022, Google LLC.
6 */
7#include <fcntl.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/ioctl.h>
12
13#include "test_util.h"
14
15#include "kvm_util.h"
16#include "processor.h"
17
18/*
19 * Assert that architectural dependency rules are satisfied, e.g. that AVX is
20 * supported if and only if SSE is supported.
21 */
22#define ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0, xfeatures, dependencies) \
23do { \
24 u64 __supported = (supported_xcr0) & ((xfeatures) | (dependencies)); \
25 \
26 __GUEST_ASSERT((__supported & (xfeatures)) != (xfeatures) || \
27 __supported == ((xfeatures) | (dependencies)), \
28 "supported = 0x%lx, xfeatures = 0x%llx, dependencies = 0x%llx", \
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) \
41do { \
42 u64 __supported = (supported_xcr0) & (xfeatures); \
43 \
44 __GUEST_ASSERT(!__supported || __supported == (xfeatures), \
45 "supported = 0x%lx, xfeatures = 0x%llx", \
46 __supported, (xfeatures)); \
47} while (0)
48
49static void guest_code(void)
50{
51 u64 initial_xcr0;
52 u64 supported_xcr0;
53 int i, vector;
54
55 set_cr4(get_cr4() | X86_CR4_OSXSAVE);
56
57 initial_xcr0 = xgetbv(0);
58 supported_xcr0 = this_cpu_supported_xcr0();
59
60 GUEST_ASSERT(initial_xcr0 == supported_xcr0);
61
62 /* Check AVX */
63 ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0,
64 XFEATURE_MASK_YMM,
65 XFEATURE_MASK_SSE);
66
67 /* Check MPX */
68 ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0,
69 XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR);
70
71 /* Check AVX-512 */
72 ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0,
73 XFEATURE_MASK_AVX512,
74 XFEATURE_MASK_SSE | XFEATURE_MASK_YMM);
75 ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0,
76 XFEATURE_MASK_AVX512);
77
78 /* Check AMX */
79 ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0,
80 XFEATURE_MASK_XTILE);
81
82 vector = xsetbv_safe(0, XFEATURE_MASK_FP);
83 __GUEST_ASSERT(!vector,
84 "Expected success on XSETBV(FP), got %s",
85 ex_str(vector));
86
87 vector = xsetbv_safe(0, supported_xcr0);
88 __GUEST_ASSERT(!vector,
89 "Expected success on XSETBV(0x%lx), got %s",
90 supported_xcr0, ex_str(vector));
91
92 for (i = 0; i < 64; i++) {
93 if (supported_xcr0 & BIT_ULL(i))
94 continue;
95
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 %s",
99 BIT_ULL(i), supported_xcr0, ex_str(vector));
100 }
101
102 GUEST_DONE();
103}
104
105int main(int argc, char *argv[])
106{
107 struct kvm_vcpu *vcpu;
108 struct kvm_run *run;
109 struct kvm_vm *vm;
110 struct ucall uc;
111
112 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XSAVE));
113
114 vm = vm_create_with_one_vcpu(&vcpu, guest_code);
115 run = vcpu->run;
116
117 while (1) {
118 vcpu_run(vcpu);
119
120 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
121 "Unexpected exit reason: %u (%s),",
122 run->exit_reason,
123 exit_reason_str(run->exit_reason));
124
125 switch (get_ucall(vcpu, &uc)) {
126 case UCALL_ABORT:
127 REPORT_GUEST_ASSERT(uc);
128 break;
129 case UCALL_DONE:
130 goto done;
131 default:
132 TEST_FAIL("Unknown ucall %lu", uc.cmd);
133 }
134 }
135
136done:
137 kvm_vm_free(vm);
138 return 0;
139}