xref: /kvm-unit-tests/x86/xsave.c (revision a299895b7abb54e7ba6bb4108f202acbb484ac65)
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 
11db4898e8SThomas Huth static 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 
24db4898e8SThomas Huth static 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 
36db4898e8SThomas Huth static uint64_t get_supported_xcr0(void)
377d36db35SAvi Kivity {
38985ab97eSPaolo Bonzini     struct cpuid r;
39985ab97eSPaolo Bonzini     r = cpuid_indexed(0xd, 0);
407d36db35SAvi Kivity     printf("eax %x, ebx %x, ecx %x, edx %x\n",
41985ab97eSPaolo Bonzini             r.a, r.b, r.c, r.d);
42985ab97eSPaolo Bonzini     return r.a + ((u64)r.d << 32);
437d36db35SAvi Kivity }
447d36db35SAvi Kivity 
457d36db35SAvi Kivity #define X86_CR4_OSXSAVE			0x00040000
467d36db35SAvi Kivity #define XCR_XFEATURE_ENABLED_MASK       0x00000000
477d36db35SAvi Kivity #define XCR_XFEATURE_ILLEGAL_MASK       0x00000010
487d36db35SAvi Kivity 
497d36db35SAvi Kivity #define XSTATE_FP       0x1
507d36db35SAvi Kivity #define XSTATE_SSE      0x2
517d36db35SAvi Kivity #define XSTATE_YMM      0x4
527d36db35SAvi Kivity 
53db4898e8SThomas Huth static void test_xsave(void)
547d36db35SAvi Kivity {
557d36db35SAvi Kivity     unsigned long cr4;
567d36db35SAvi Kivity     uint64_t supported_xcr0;
577d36db35SAvi Kivity     uint64_t test_bits;
587d36db35SAvi Kivity     u64 xcr0;
597d36db35SAvi Kivity 
607d36db35SAvi Kivity     printf("Legal instruction testing:\n");
618b1e9483SAndrew Jones 
627d36db35SAvi Kivity     supported_xcr0 = get_supported_xcr0();
63fd6aada0SRadim Krčmář     printf("Supported XCR0 bits: %#lx\n", supported_xcr0);
647d36db35SAvi Kivity 
657d36db35SAvi Kivity     test_bits = XSTATE_FP | XSTATE_SSE;
66*a299895bSThomas Huth     report((supported_xcr0 & test_bits) == test_bits,
67*a299895bSThomas Huth            "Check minimal XSAVE required bits");
687d36db35SAvi Kivity 
697d36db35SAvi Kivity     cr4 = read_cr4();
70*a299895bSThomas Huth     report(write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == 0, "Set CR4 OSXSAVE");
71*a299895bSThomas Huth     report(this_cpu_has(X86_FEATURE_OSXSAVE),
72*a299895bSThomas Huth            "Check CPUID.1.ECX.OSXSAVE - expect 1");
737d36db35SAvi Kivity 
748b1e9483SAndrew Jones     printf("\tLegal tests\n");
757d36db35SAvi Kivity     test_bits = XSTATE_FP;
76*a299895bSThomas Huth     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0,
77*a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)");
788b1e9483SAndrew Jones 
797d36db35SAvi Kivity     test_bits = XSTATE_FP | XSTATE_SSE;
80*a299895bSThomas Huth     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0,
81*a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)");
82*a299895bSThomas Huth     report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0,
83*a299895bSThomas Huth            "        xgetbv(XCR_XFEATURE_ENABLED_MASK)");
848b1e9483SAndrew Jones 
858b1e9483SAndrew Jones     printf("\tIllegal tests\n");
867d36db35SAvi Kivity     test_bits = 0;
87*a299895bSThomas Huth     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
88*a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP");
897d36db35SAvi Kivity 
908b1e9483SAndrew Jones     test_bits = XSTATE_SSE;
91*a299895bSThomas Huth     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
92*a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP");
938b1e9483SAndrew Jones 
948b1e9483SAndrew Jones     if (supported_xcr0 & XSTATE_YMM) {
958b1e9483SAndrew Jones         test_bits = XSTATE_YMM;
96*a299895bSThomas Huth         report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
97*a299895bSThomas Huth                "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP");
988b1e9483SAndrew Jones 
998b1e9483SAndrew Jones         test_bits = XSTATE_FP | XSTATE_YMM;
100*a299895bSThomas Huth         report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
101*a299895bSThomas Huth                "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP");
1028b1e9483SAndrew Jones     }
1038b1e9483SAndrew Jones 
1048b1e9483SAndrew Jones     test_bits = XSTATE_SSE;
105*a299895bSThomas Huth     report(xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR,
106*a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP");
1078b1e9483SAndrew Jones 
1088b1e9483SAndrew Jones     test_bits = XSTATE_SSE;
109*a299895bSThomas Huth     report(xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR,
110*a299895bSThomas Huth            "\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP");
1118b1e9483SAndrew Jones 
1127d36db35SAvi Kivity     cr4 &= ~X86_CR4_OSXSAVE;
113*a299895bSThomas Huth     report(write_cr4_checking(cr4) == 0, "Unset CR4 OSXSAVE");
114*a299895bSThomas Huth     report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0,
115*a299895bSThomas Huth            "Check CPUID.1.ECX.OSXSAVE - expect 0");
1168b1e9483SAndrew Jones 
1178b1e9483SAndrew Jones     printf("\tIllegal tests:\n");
1187d36db35SAvi Kivity     test_bits = XSTATE_FP;
119*a299895bSThomas Huth     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR,
120*a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD");
1218b1e9483SAndrew Jones 
1227d36db35SAvi Kivity     test_bits = XSTATE_FP | XSTATE_SSE;
123*a299895bSThomas Huth     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR,
124*a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD");
1258b1e9483SAndrew Jones 
1268b1e9483SAndrew Jones     printf("\tIllegal tests:\n");
127*a299895bSThomas Huth     report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR,
128*a299895bSThomas Huth            "\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD");
1297d36db35SAvi Kivity }
1307d36db35SAvi Kivity 
131db4898e8SThomas Huth static void test_no_xsave(void)
1327d36db35SAvi Kivity {
1337d36db35SAvi Kivity     unsigned long cr4;
1347d36db35SAvi Kivity     u64 xcr0;
1357d36db35SAvi Kivity 
136*a299895bSThomas Huth     report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0,
137*a299895bSThomas Huth            "Check CPUID.1.ECX.OSXSAVE - expect 0");
1387d36db35SAvi Kivity 
1397d36db35SAvi Kivity     printf("Illegal instruction testing:\n");
1407d36db35SAvi Kivity 
1417d36db35SAvi Kivity     cr4 = read_cr4();
142*a299895bSThomas Huth     report(write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR,
143*a299895bSThomas Huth            "Set OSXSAVE in CR4 - expect #GP");
1447d36db35SAvi Kivity 
145*a299895bSThomas Huth     report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR,
146*a299895bSThomas Huth            "Execute xgetbv - expect #UD");
1477d36db35SAvi Kivity 
148*a299895bSThomas Huth     report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR,
149*a299895bSThomas Huth            "Execute xsetbv - expect #UD");
1507d36db35SAvi Kivity }
1517d36db35SAvi Kivity 
1527d36db35SAvi Kivity int main(void)
1537d36db35SAvi Kivity {
1547d36db35SAvi Kivity     setup_idt();
155badc98caSKrish Sadhukhan     if (this_cpu_has(X86_FEATURE_XSAVE)) {
1567d36db35SAvi Kivity         printf("CPU has XSAVE feature\n");
1577d36db35SAvi Kivity         test_xsave();
1587d36db35SAvi Kivity     } else {
1597d36db35SAvi Kivity         printf("CPU don't has XSAVE feature\n");
1607d36db35SAvi Kivity         test_no_xsave();
1617d36db35SAvi Kivity     }
1628b1e9483SAndrew Jones     return report_summary();
1637d36db35SAvi Kivity }
164