xref: /kvm-unit-tests/x86/xsave.c (revision 4363f1d9a646a5c7ea673bee8fc33ca6f2cddbd8)
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 void test_xsave(void)
69 {
70     unsigned long cr4;
71     uint64_t supported_xcr0;
72     uint64_t test_bits;
73     u64 xcr0;
74 
75     printf("Legal instruction testing:\n");
76 
77     supported_xcr0 = get_supported_xcr0();
78     printf("Supported XCR0 bits: %#lx\n", supported_xcr0);
79 
80     test_bits = XSTATE_FP | XSTATE_SSE;
81     report("Check minimal XSAVE required bits",
82 		    (supported_xcr0 & test_bits) == test_bits);
83 
84     cr4 = read_cr4();
85     report("Set CR4 OSXSAVE", write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == 0);
86     report("Check CPUID.1.ECX.OSXSAVE - expect 1",
87 		    check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE));
88 
89     printf("\tLegal tests\n");
90     test_bits = XSTATE_FP;
91     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)",
92 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0);
93 
94     test_bits = XSTATE_FP | XSTATE_SSE;
95     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)",
96 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0);
97     report("        xgetbv(XCR_XFEATURE_ENABLED_MASK)",
98 	xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0);
99 
100     printf("\tIllegal tests\n");
101     test_bits = 0;
102     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP",
103 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
104 
105     test_bits = XSTATE_SSE;
106     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP",
107 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
108 
109     if (supported_xcr0 & XSTATE_YMM) {
110         test_bits = XSTATE_YMM;
111         report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP",
112 		xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
113 
114         test_bits = XSTATE_FP | XSTATE_YMM;
115         report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP",
116 		xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
117     }
118 
119     test_bits = XSTATE_SSE;
120     report("\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP",
121 	xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR);
122 
123     test_bits = XSTATE_SSE;
124     report("\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP",
125 	xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR);
126 
127     cr4 &= ~X86_CR4_OSXSAVE;
128     report("Unset CR4 OSXSAVE", write_cr4_checking(cr4) == 0);
129     report("Check CPUID.1.ECX.OSXSAVE - expect 0",
130 	check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0);
131 
132     printf("\tIllegal tests:\n");
133     test_bits = XSTATE_FP;
134     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD",
135 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR);
136 
137     test_bits = XSTATE_FP | XSTATE_SSE;
138     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD",
139 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR);
140 
141     printf("\tIllegal tests:\n");
142     report("\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD",
143 	xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR);
144 }
145 
146 void test_no_xsave(void)
147 {
148     unsigned long cr4;
149     u64 xcr0;
150 
151     report("Check CPUID.1.ECX.OSXSAVE - expect 0",
152 	check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0);
153 
154     printf("Illegal instruction testing:\n");
155 
156     cr4 = read_cr4();
157     report("Set OSXSAVE in CR4 - expect #GP",
158 	write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR);
159 
160     report("Execute xgetbv - expect #UD",
161 	xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR);
162 
163     report("Execute xsetbv - expect #UD",
164 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR);
165 }
166 
167 int main(void)
168 {
169     setup_idt();
170     if (check_cpuid_1_ecx(CPUID_1_ECX_XSAVE)) {
171         printf("CPU has XSAVE feature\n");
172         test_xsave();
173     } else {
174         printf("CPU don't has XSAVE feature\n");
175         test_no_xsave();
176     }
177     return report_summary();
178 }
179