xref: /kvm-unit-tests/x86/xsave.c (revision 8b1e9483b64a9f246bb3d6595892fd8672d700ec)
17d36db35SAvi Kivity #include "libcflat.h"
2e7c37968SGleb Natapov #include "desc.h"
3985ab97eSPaolo Bonzini #include "processor.h"
47d36db35SAvi Kivity 
57d36db35SAvi Kivity #ifdef __x86_64__
67d36db35SAvi Kivity #define uint64_t unsigned long
77d36db35SAvi Kivity #else
87d36db35SAvi Kivity #define uint64_t unsigned long long
97d36db35SAvi Kivity #endif
107d36db35SAvi Kivity 
117d36db35SAvi Kivity int xgetbv_checking(u32 index, u64 *result)
127d36db35SAvi Kivity {
137d36db35SAvi Kivity     u32 eax, edx;
147d36db35SAvi Kivity 
157d36db35SAvi Kivity     asm volatile(ASM_TRY("1f")
167d36db35SAvi Kivity             ".byte 0x0f,0x01,0xd0\n\t" /* xgetbv */
177d36db35SAvi Kivity             "1:"
187d36db35SAvi Kivity             : "=a" (eax), "=d" (edx)
197d36db35SAvi Kivity             : "c" (index));
207d36db35SAvi Kivity     *result = eax + ((u64)edx << 32);
217d36db35SAvi Kivity     return exception_vector();
227d36db35SAvi Kivity }
237d36db35SAvi Kivity 
247d36db35SAvi Kivity int xsetbv_checking(u32 index, u64 value)
257d36db35SAvi Kivity {
267d36db35SAvi Kivity     u32 eax = value;
277d36db35SAvi Kivity     u32 edx = value >> 32;
287d36db35SAvi Kivity 
297d36db35SAvi Kivity     asm volatile(ASM_TRY("1f")
307d36db35SAvi Kivity             ".byte 0x0f,0x01,0xd1\n\t" /* xsetbv */
317d36db35SAvi Kivity             "1:"
327d36db35SAvi Kivity             : : "a" (eax), "d" (edx), "c" (index));
337d36db35SAvi Kivity     return exception_vector();
347d36db35SAvi Kivity }
357d36db35SAvi Kivity 
367d36db35SAvi Kivity int write_cr4_checking(unsigned long val)
377d36db35SAvi Kivity {
387d36db35SAvi Kivity     asm volatile(ASM_TRY("1f")
397d36db35SAvi Kivity             "mov %0,%%cr4\n\t"
407d36db35SAvi Kivity             "1:": : "r" (val));
417d36db35SAvi Kivity     return exception_vector();
427d36db35SAvi Kivity }
437d36db35SAvi Kivity 
447d36db35SAvi Kivity #define CPUID_1_ECX_XSAVE	    (1 << 26)
457d36db35SAvi Kivity #define CPUID_1_ECX_OSXSAVE	    (1 << 27)
467d36db35SAvi Kivity int check_cpuid_1_ecx(unsigned int bit)
477d36db35SAvi Kivity {
48985ab97eSPaolo Bonzini     return (cpuid(1).c & bit) != 0;
497d36db35SAvi Kivity }
507d36db35SAvi Kivity 
517d36db35SAvi Kivity uint64_t get_supported_xcr0(void)
527d36db35SAvi Kivity {
53985ab97eSPaolo Bonzini     struct cpuid r;
54985ab97eSPaolo Bonzini     r = cpuid_indexed(0xd, 0);
557d36db35SAvi Kivity     printf("eax %x, ebx %x, ecx %x, edx %x\n",
56985ab97eSPaolo Bonzini             r.a, r.b, r.c, r.d);
57985ab97eSPaolo Bonzini     return r.a + ((u64)r.d << 32);
587d36db35SAvi Kivity }
597d36db35SAvi Kivity 
607d36db35SAvi Kivity #define X86_CR4_OSXSAVE			0x00040000
617d36db35SAvi Kivity #define XCR_XFEATURE_ENABLED_MASK       0x00000000
627d36db35SAvi Kivity #define XCR_XFEATURE_ILLEGAL_MASK       0x00000010
637d36db35SAvi Kivity 
647d36db35SAvi Kivity #define XSTATE_FP       0x1
657d36db35SAvi Kivity #define XSTATE_SSE      0x2
667d36db35SAvi Kivity #define XSTATE_YMM      0x4
677d36db35SAvi Kivity 
687d36db35SAvi Kivity void test_xsave(void)
697d36db35SAvi Kivity {
707d36db35SAvi Kivity     unsigned long cr4;
717d36db35SAvi Kivity     uint64_t supported_xcr0;
727d36db35SAvi Kivity     uint64_t test_bits;
737d36db35SAvi Kivity     u64 xcr0;
747d36db35SAvi Kivity 
757d36db35SAvi Kivity     printf("Legal instruction testing:\n");
76*8b1e9483SAndrew Jones 
777d36db35SAvi Kivity     supported_xcr0 = get_supported_xcr0();
787d36db35SAvi Kivity     printf("Supported XCR0 bits: 0x%x\n", supported_xcr0);
797d36db35SAvi Kivity 
807d36db35SAvi Kivity     test_bits = XSTATE_FP | XSTATE_SSE;
81*8b1e9483SAndrew Jones     report("Check minimal XSAVE required bits",
82*8b1e9483SAndrew Jones 		    (supported_xcr0 & test_bits) == test_bits);
837d36db35SAvi Kivity 
847d36db35SAvi Kivity     cr4 = read_cr4();
85*8b1e9483SAndrew Jones     report("Set CR4 OSXSAVE", write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == 0);
86*8b1e9483SAndrew Jones     report("Check CPUID.1.ECX.OSXSAVE - expect 1",
87*8b1e9483SAndrew Jones 		    check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE));
887d36db35SAvi Kivity 
89*8b1e9483SAndrew Jones     printf("\tLegal tests\n");
907d36db35SAvi Kivity     test_bits = XSTATE_FP;
91*8b1e9483SAndrew Jones     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)",
92*8b1e9483SAndrew Jones 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0);
93*8b1e9483SAndrew Jones 
947d36db35SAvi Kivity     test_bits = XSTATE_FP | XSTATE_SSE;
95*8b1e9483SAndrew Jones     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)",
96*8b1e9483SAndrew Jones 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0);
97*8b1e9483SAndrew Jones     report("        xgetbv(XCR_XFEATURE_ENABLED_MASK)",
98*8b1e9483SAndrew Jones 	xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0);
99*8b1e9483SAndrew Jones 
100*8b1e9483SAndrew Jones     printf("\tIllegal tests\n");
1017d36db35SAvi Kivity     test_bits = 0;
102*8b1e9483SAndrew Jones     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP",
103*8b1e9483SAndrew Jones 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
1047d36db35SAvi Kivity 
105*8b1e9483SAndrew Jones     test_bits = XSTATE_SSE;
106*8b1e9483SAndrew Jones     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP",
107*8b1e9483SAndrew Jones 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
108*8b1e9483SAndrew Jones 
109*8b1e9483SAndrew Jones     if (supported_xcr0 & XSTATE_YMM) {
110*8b1e9483SAndrew Jones         test_bits = XSTATE_YMM;
111*8b1e9483SAndrew Jones         report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP",
112*8b1e9483SAndrew Jones 		xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
113*8b1e9483SAndrew Jones 
114*8b1e9483SAndrew Jones         test_bits = XSTATE_FP | XSTATE_YMM;
115*8b1e9483SAndrew Jones         report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP",
116*8b1e9483SAndrew Jones 		xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR);
117*8b1e9483SAndrew Jones     }
118*8b1e9483SAndrew Jones 
119*8b1e9483SAndrew Jones     test_bits = XSTATE_SSE;
120*8b1e9483SAndrew Jones     report("\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP",
121*8b1e9483SAndrew Jones 	xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR);
122*8b1e9483SAndrew Jones 
123*8b1e9483SAndrew Jones     test_bits = XSTATE_SSE;
124*8b1e9483SAndrew Jones     report("\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP",
125*8b1e9483SAndrew Jones 	xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR);
126*8b1e9483SAndrew Jones 
1277d36db35SAvi Kivity     cr4 &= ~X86_CR4_OSXSAVE;
128*8b1e9483SAndrew Jones     report("Unset CR4 OSXSAVE", write_cr4_checking(cr4) == 0);
129*8b1e9483SAndrew Jones     report("Check CPUID.1.ECX.OSXSAVE - expect 0",
130*8b1e9483SAndrew Jones 	check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0);
131*8b1e9483SAndrew Jones 
132*8b1e9483SAndrew Jones     printf("\tIllegal tests:\n");
1337d36db35SAvi Kivity     test_bits = XSTATE_FP;
134*8b1e9483SAndrew Jones     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD",
135*8b1e9483SAndrew Jones 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR);
136*8b1e9483SAndrew Jones 
1377d36db35SAvi Kivity     test_bits = XSTATE_FP | XSTATE_SSE;
138*8b1e9483SAndrew Jones     report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD",
139*8b1e9483SAndrew Jones 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR);
140*8b1e9483SAndrew Jones 
141*8b1e9483SAndrew Jones     printf("\tIllegal tests:\n");
142*8b1e9483SAndrew Jones     report("\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD",
143*8b1e9483SAndrew Jones 	xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR);
1447d36db35SAvi Kivity }
1457d36db35SAvi Kivity 
1467d36db35SAvi Kivity void test_no_xsave(void)
1477d36db35SAvi Kivity {
1487d36db35SAvi Kivity     unsigned long cr4;
1497d36db35SAvi Kivity     u64 xcr0;
1507d36db35SAvi Kivity 
151*8b1e9483SAndrew Jones     report("Check CPUID.1.ECX.OSXSAVE - expect 0",
152*8b1e9483SAndrew Jones 	check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0);
1537d36db35SAvi Kivity 
1547d36db35SAvi Kivity     printf("Illegal instruction testing:\n");
1557d36db35SAvi Kivity 
1567d36db35SAvi Kivity     cr4 = read_cr4();
157*8b1e9483SAndrew Jones     report("Set OSXSAVE in CR4 - expect #GP",
158*8b1e9483SAndrew Jones 	write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR);
1597d36db35SAvi Kivity 
160*8b1e9483SAndrew Jones     report("Execute xgetbv - expect #UD",
161*8b1e9483SAndrew Jones 	xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR);
1627d36db35SAvi Kivity 
163*8b1e9483SAndrew Jones     report("Execute xsetbv - expect #UD",
164*8b1e9483SAndrew Jones 	xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR);
1657d36db35SAvi Kivity }
1667d36db35SAvi Kivity 
1677d36db35SAvi Kivity int main(void)
1687d36db35SAvi Kivity {
1697d36db35SAvi Kivity     setup_idt();
1707d36db35SAvi Kivity     if (check_cpuid_1_ecx(CPUID_1_ECX_XSAVE)) {
1717d36db35SAvi Kivity         printf("CPU has XSAVE feature\n");
1727d36db35SAvi Kivity         test_xsave();
1737d36db35SAvi Kivity     } else {
1747d36db35SAvi Kivity         printf("CPU don't has XSAVE feature\n");
1757d36db35SAvi Kivity         test_no_xsave();
1767d36db35SAvi Kivity     }
177*8b1e9483SAndrew Jones     return report_summary();
1787d36db35SAvi Kivity }
179