xref: /kvm-unit-tests/x86/xsave.c (revision badc98cafea47463b8151eefbc6d4954f6aec6a9)
1 #include "libcflat.h"
2 #include "desc.h"
3 #include "processor.h"
4 
5 #ifdef __x86_64__
6 #define uint64_t unsigned long
7 #else
8 #define uint64_t unsigned long long
9 #endif
10 
11 static int xgetbv_checking(u32 index, u64 *result)
12 {
13     u32 eax, edx;
14 
15     asm volatile(ASM_TRY("1f")
16             ".byte 0x0f,0x01,0xd0\n\t" /* xgetbv */
17             "1:"
18             : "=a" (eax), "=d" (edx)
19             : "c" (index));
20     *result = eax + ((u64)edx << 32);
21     return exception_vector();
22 }
23 
24 static int xsetbv_checking(u32 index, u64 value)
25 {
26     u32 eax = value;
27     u32 edx = value >> 32;
28 
29     asm volatile(ASM_TRY("1f")
30             ".byte 0x0f,0x01,0xd1\n\t" /* xsetbv */
31             "1:"
32             : : "a" (eax), "d" (edx), "c" (index));
33     return exception_vector();
34 }
35 
36 static uint64_t get_supported_xcr0(void)
37 {
38     struct cpuid r;
39     r = cpuid_indexed(0xd, 0);
40     printf("eax %x, ebx %x, ecx %x, edx %x\n",
41             r.a, r.b, r.c, r.d);
42     return r.a + ((u64)r.d << 32);
43 }
44 
45 #define X86_CR4_OSXSAVE			0x00040000
46 #define XCR_XFEATURE_ENABLED_MASK       0x00000000
47 #define XCR_XFEATURE_ILLEGAL_MASK       0x00000010
48 
49 #define XSTATE_FP       0x1
50 #define XSTATE_SSE      0x2
51 #define XSTATE_YMM      0x4
52 
53 static void test_xsave(void)
54 {
55     unsigned long cr4;
56     uint64_t supported_xcr0;
57     uint64_t test_bits;
58     u64 xcr0;
59 
60     printf("Legal instruction testing:\n");
61 
62     supported_xcr0 = get_supported_xcr0();
63     printf("Supported XCR0 bits: %#lx\n", supported_xcr0);
64 
65     test_bits = XSTATE_FP | XSTATE_SSE;
66     report("Check minimal XSAVE required bits",
67 		    (supported_xcr0 & test_bits) == test_bits);
68 
69     cr4 = read_cr4();
70     report("Set CR4 OSXSAVE", write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == 0);
71     report("Check CPUID.1.ECX.OSXSAVE - expect 1",
72 		    this_cpu_has(X86_FEATURE_OSXSAVE));
73 
74     printf("\tLegal tests\n");
75     test_bits = XSTATE_FP;
76     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)",
77 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0);
78 
79     test_bits = XSTATE_FP | XSTATE_SSE;
80     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)",
81 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0);
82     report("        xgetbv(XCR_XFEATURE_ENABLED_MASK)",
83 	xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0);
84 
85     printf("\tIllegal tests\n");
86     test_bits = 0;
87     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP",
88 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
89 
90     test_bits = XSTATE_SSE;
91     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP",
92 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
93 
94     if (supported_xcr0 & XSTATE_YMM) {
95         test_bits = XSTATE_YMM;
96         report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP",
97 		xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
98 
99         test_bits = XSTATE_FP | XSTATE_YMM;
100         report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP",
101 		xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
102     }
103 
104     test_bits = XSTATE_SSE;
105     report("\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP",
106 	xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR);
107 
108     test_bits = XSTATE_SSE;
109     report("\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP",
110 	xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR);
111 
112     cr4 &= ~X86_CR4_OSXSAVE;
113     report("Unset CR4 OSXSAVE", write_cr4_checking(cr4) == 0);
114     report("Check CPUID.1.ECX.OSXSAVE - expect 0",
115 	this_cpu_has(X86_FEATURE_OSXSAVE) == 0);
116 
117     printf("\tIllegal tests:\n");
118     test_bits = XSTATE_FP;
119     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD",
120 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR);
121 
122     test_bits = XSTATE_FP | XSTATE_SSE;
123     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD",
124 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR);
125 
126     printf("\tIllegal tests:\n");
127     report("\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD",
128 	xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR);
129 }
130 
131 static void test_no_xsave(void)
132 {
133     unsigned long cr4;
134     u64 xcr0;
135 
136     report("Check CPUID.1.ECX.OSXSAVE - expect 0",
137 	this_cpu_has(X86_FEATURE_OSXSAVE) == 0);
138 
139     printf("Illegal instruction testing:\n");
140 
141     cr4 = read_cr4();
142     report("Set OSXSAVE in CR4 - expect #GP",
143 	write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR);
144 
145     report("Execute xgetbv - expect #UD",
146 	xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR);
147 
148     report("Execute xsetbv - expect #UD",
149 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR);
150 }
151 
152 int main(void)
153 {
154     setup_idt();
155     if (this_cpu_has(X86_FEATURE_XSAVE)) {
156         printf("CPU has XSAVE feature\n");
157         test_xsave();
158     } else {
159         printf("CPU don't has XSAVE feature\n");
160         test_no_xsave();
161     }
162     return report_summary();
163 }
164