xref: /kvm-unit-tests/x86/xsave.c (revision a322d4c597bb7a4de7985e7b51b80504f7e4fdda)
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 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 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 int write_cr4_checking(unsigned long val)
37 {
38     asm volatile(ASM_TRY("1f")
39             "mov %0,%%cr4\n\t"
40             "1:": : "r" (val));
41     return exception_vector();
42 }
43 
44 #define CPUID_1_ECX_XSAVE	    (1 << 26)
45 #define CPUID_1_ECX_OSXSAVE	    (1 << 27)
46 int check_cpuid_1_ecx(unsigned int bit)
47 {
48     return (cpuid(1).c & bit) != 0;
49 }
50 
51 uint64_t get_supported_xcr0(void)
52 {
53     struct cpuid r;
54     r = cpuid_indexed(0xd, 0);
55     printf("eax %x, ebx %x, ecx %x, edx %x\n",
56             r.a, r.b, r.c, r.d);
57     return r.a + ((u64)r.d << 32);
58 }
59 
60 #define X86_CR4_OSXSAVE			0x00040000
61 #define XCR_XFEATURE_ENABLED_MASK       0x00000000
62 #define XCR_XFEATURE_ILLEGAL_MASK       0x00000010
63 
64 #define XSTATE_FP       0x1
65 #define XSTATE_SSE      0x2
66 #define XSTATE_YMM      0x4
67 
68 static int total_tests, fail_tests;
69 
70 void pass_if(int condition)
71 {
72     total_tests ++;
73     if (condition)
74         printf("Pass!\n");
75     else {
76         printf("Fail!\n");
77         fail_tests ++;
78     }
79 }
80 
81 void test_xsave(void)
82 {
83     unsigned long cr4;
84     uint64_t supported_xcr0;
85     uint64_t test_bits;
86     u64 xcr0;
87     int r;
88 
89     printf("Legal instruction testing:\n");
90     supported_xcr0 = get_supported_xcr0();
91     printf("Supported XCR0 bits: 0x%x\n", supported_xcr0);
92 
93     printf("Check minimal XSAVE required bits: ");
94     test_bits = XSTATE_FP | XSTATE_SSE;
95     pass_if((supported_xcr0 & test_bits) == test_bits);
96 
97     printf("Set CR4 OSXSAVE: ");
98     cr4 = read_cr4();
99     r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE);
100     pass_if(r == 0);
101 
102     printf("Check CPUID.1.ECX.OSXSAVE - expect 1: ");
103     pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE));
104 
105     printf("    Legal tests\n");
106     printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP): ");
107     test_bits = XSTATE_FP;
108     r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
109     pass_if(r == 0);
110     printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, "
111             "XSTATE_FP | XSTATE_SSE): ");
112     test_bits = XSTATE_FP | XSTATE_SSE;
113     r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
114     pass_if(r == 0);
115     printf("        xgetbv(XCR_XFEATURE_ENABLED_MASK): ");
116     r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0);
117     pass_if(r == 0);
118     printf("    Illegal tests\n");
119     printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP: ");
120     test_bits = 0;
121     r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
122     pass_if(r == GP_VECTOR);
123     printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) "
124             "- expect #GP: ");
125     test_bits = XSTATE_SSE;
126     r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
127     pass_if(r == GP_VECTOR);
128     if (supported_xcr0 & XSTATE_YMM) {
129         printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, "
130                 "XSTATE_YMM) - expect #GP: ");
131         test_bits = XSTATE_YMM;
132         r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
133         pass_if(r == GP_VECTOR);
134         printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, "
135                 "XSTATE_FP | XSTATE_YMM) - expect #GP: ");
136         test_bits = XSTATE_FP | XSTATE_YMM;
137         r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
138         pass_if(r == GP_VECTOR);
139     }
140     printf("        xsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) "
141             "- expect #GP: ");
142     test_bits = XSTATE_SSE;
143     r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits);
144     pass_if(r == GP_VECTOR);
145     printf("        xgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) "
146             "- expect #GP: ");
147     test_bits = XSTATE_SSE;
148     r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits);
149     pass_if(r == GP_VECTOR);
150 
151     printf("Unset CR4 OSXSAVE: ");
152     cr4 &= ~X86_CR4_OSXSAVE;
153     r = write_cr4_checking(cr4);
154     pass_if(r == 0);
155     printf("Check CPUID.1.ECX.OSXSAVE - expect 0: ");
156     pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0);
157     printf("    Illegal tests:\n");
158     printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD: ");
159     test_bits = XSTATE_FP;
160     r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
161     pass_if(r == UD_VECTOR);
162     printf("        xsetbv(XCR_XFEATURE_ENABLED_MASK, "
163             "XSTATE_FP | XSTATE_SSE) - expect #UD: ");
164     test_bits = XSTATE_FP | XSTATE_SSE;
165     r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits);
166     pass_if(r == UD_VECTOR);
167     printf("    Illegal tests:\n");
168     printf("	xgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD: ");
169     r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0);
170     pass_if(r == UD_VECTOR);
171 }
172 
173 void test_no_xsave(void)
174 {
175     unsigned long cr4;
176     u64 xcr0;
177     int r;
178 
179     printf("Check CPUID.1.ECX.OSXSAVE - expect 0: ");
180     pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0);
181 
182     printf("Illegal instruction testing:\n");
183 
184     printf("Set OSXSAVE in CR4 - expect #GP: ");
185     cr4 = read_cr4();
186     r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE);
187     pass_if(r == GP_VECTOR);
188 
189     printf("Execute xgetbv - expect #UD: ");
190     r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0);
191     pass_if(r == UD_VECTOR);
192 
193     printf("Execute xsetbv - expect #UD: ");
194     r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3);
195     pass_if(r == UD_VECTOR);
196 }
197 
198 int main(void)
199 {
200     setup_idt();
201     if (check_cpuid_1_ecx(CPUID_1_ECX_XSAVE)) {
202         printf("CPU has XSAVE feature\n");
203         test_xsave();
204     } else {
205         printf("CPU don't has XSAVE feature\n");
206         test_no_xsave();
207     }
208     printf("Total test: %d\n", total_tests);
209     if (fail_tests == 0)
210         printf("ALL PASS!\n");
211     else {
212         printf("Fail %d tests.\n", fail_tests);
213         return 1;
214     }
215     return 0;
216 }
217