xref: /kvm-unit-tests/x86/xsave.c (revision fa68c03765ce1668cf057f76677c5d76ca99edcf)
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 uint64_t get_supported_xcr0(void)
127d36db35SAvi Kivity {
13985ab97eSPaolo Bonzini     struct cpuid r;
14985ab97eSPaolo Bonzini     r = cpuid_indexed(0xd, 0);
157d36db35SAvi Kivity     printf("eax %x, ebx %x, ecx %x, edx %x\n",
16985ab97eSPaolo Bonzini             r.a, r.b, r.c, r.d);
17985ab97eSPaolo Bonzini     return r.a + ((u64)r.d << 32);
187d36db35SAvi Kivity }
197d36db35SAvi Kivity 
207d36db35SAvi Kivity #define XCR_XFEATURE_ENABLED_MASK       0x00000000
217d36db35SAvi Kivity #define XCR_XFEATURE_ILLEGAL_MASK       0x00000010
227d36db35SAvi Kivity 
237d36db35SAvi Kivity #define XSTATE_FP       0x1
247d36db35SAvi Kivity #define XSTATE_SSE      0x2
257d36db35SAvi Kivity #define XSTATE_YMM      0x4
267d36db35SAvi Kivity 
27db4898e8SThomas Huth static void test_xsave(void)
287d36db35SAvi Kivity {
297d36db35SAvi Kivity     unsigned long cr4;
307d36db35SAvi Kivity     uint64_t supported_xcr0;
317d36db35SAvi Kivity     uint64_t test_bits;
327d36db35SAvi Kivity     u64 xcr0;
337d36db35SAvi Kivity 
347d36db35SAvi Kivity     printf("Legal instruction testing:\n");
358b1e9483SAndrew Jones 
367d36db35SAvi Kivity     supported_xcr0 = get_supported_xcr0();
37fd6aada0SRadim Krčmář     printf("Supported XCR0 bits: %#lx\n", supported_xcr0);
387d36db35SAvi Kivity 
397d36db35SAvi Kivity     test_bits = XSTATE_FP | XSTATE_SSE;
40a299895bSThomas Huth     report((supported_xcr0 & test_bits) == test_bits,
41a299895bSThomas Huth            "Check minimal XSAVE required bits");
427d36db35SAvi Kivity 
437d36db35SAvi Kivity     cr4 = read_cr4();
444143fbfdSSean Christopherson     report(write_cr4_safe(cr4 | X86_CR4_OSXSAVE) == 0, "Set CR4 OSXSAVE");
45a299895bSThomas Huth     report(this_cpu_has(X86_FEATURE_OSXSAVE),
46a299895bSThomas Huth            "Check CPUID.1.ECX.OSXSAVE - expect 1");
477d36db35SAvi Kivity 
488b1e9483SAndrew Jones     printf("\tLegal tests\n");
497d36db35SAvi Kivity     test_bits = XSTATE_FP;
504143fbfdSSean Christopherson     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0,
51a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)");
528b1e9483SAndrew Jones 
537d36db35SAvi Kivity     test_bits = XSTATE_FP | XSTATE_SSE;
544143fbfdSSean Christopherson     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0,
55a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)");
56*fa68c037SSean Christopherson     report(xgetbv_safe(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0,
57a299895bSThomas Huth            "        xgetbv(XCR_XFEATURE_ENABLED_MASK)");
588b1e9483SAndrew Jones 
598b1e9483SAndrew Jones     printf("\tIllegal tests\n");
607d36db35SAvi Kivity     test_bits = 0;
614143fbfdSSean Christopherson     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
62a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP");
637d36db35SAvi Kivity 
648b1e9483SAndrew Jones     test_bits = XSTATE_SSE;
654143fbfdSSean Christopherson     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
66a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP");
678b1e9483SAndrew Jones 
688b1e9483SAndrew Jones     if (supported_xcr0 & XSTATE_YMM) {
698b1e9483SAndrew Jones         test_bits = XSTATE_YMM;
704143fbfdSSean Christopherson         report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
71a299895bSThomas Huth                "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP");
728b1e9483SAndrew Jones 
738b1e9483SAndrew Jones         test_bits = XSTATE_FP | XSTATE_YMM;
744143fbfdSSean Christopherson         report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR,
75a299895bSThomas Huth                "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP");
768b1e9483SAndrew Jones     }
778b1e9483SAndrew Jones 
788b1e9483SAndrew Jones     test_bits = XSTATE_SSE;
794143fbfdSSean Christopherson     report(xsetbv_safe(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR,
80a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP");
818b1e9483SAndrew Jones 
828b1e9483SAndrew Jones     test_bits = XSTATE_SSE;
834143fbfdSSean Christopherson     report(xsetbv_safe(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR,
84a299895bSThomas Huth            "\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP");
858b1e9483SAndrew Jones 
867d36db35SAvi Kivity     cr4 &= ~X86_CR4_OSXSAVE;
874143fbfdSSean Christopherson     report(write_cr4_safe(cr4) == 0, "Unset CR4 OSXSAVE");
88a299895bSThomas Huth     report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0,
89a299895bSThomas Huth            "Check CPUID.1.ECX.OSXSAVE - expect 0");
908b1e9483SAndrew Jones 
918b1e9483SAndrew Jones     printf("\tIllegal tests:\n");
927d36db35SAvi Kivity     test_bits = XSTATE_FP;
934143fbfdSSean Christopherson     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR,
94a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD");
958b1e9483SAndrew Jones 
967d36db35SAvi Kivity     test_bits = XSTATE_FP | XSTATE_SSE;
974143fbfdSSean Christopherson     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR,
98a299895bSThomas Huth            "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD");
998b1e9483SAndrew Jones 
1008b1e9483SAndrew Jones     printf("\tIllegal tests:\n");
101*fa68c037SSean Christopherson     report(xgetbv_safe(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR,
102a299895bSThomas Huth            "\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD");
1037d36db35SAvi Kivity }
1047d36db35SAvi Kivity 
105db4898e8SThomas Huth static void test_no_xsave(void)
1067d36db35SAvi Kivity {
1077d36db35SAvi Kivity     unsigned long cr4;
1087d36db35SAvi Kivity     u64 xcr0;
1097d36db35SAvi Kivity 
110a299895bSThomas Huth     report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0,
111a299895bSThomas Huth            "Check CPUID.1.ECX.OSXSAVE - expect 0");
1127d36db35SAvi Kivity 
1137d36db35SAvi Kivity     printf("Illegal instruction testing:\n");
1147d36db35SAvi Kivity 
1157d36db35SAvi Kivity     cr4 = read_cr4();
1164143fbfdSSean Christopherson     report(write_cr4_safe(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR,
117a299895bSThomas Huth            "Set OSXSAVE in CR4 - expect #GP");
1187d36db35SAvi Kivity 
119*fa68c037SSean Christopherson     report(xgetbv_safe(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR,
120a299895bSThomas Huth            "Execute xgetbv - expect #UD");
1217d36db35SAvi Kivity 
1224143fbfdSSean Christopherson     report(xsetbv_safe(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR,
123a299895bSThomas Huth            "Execute xsetbv - expect #UD");
1247d36db35SAvi Kivity }
1257d36db35SAvi Kivity 
1267d36db35SAvi Kivity int main(void)
1277d36db35SAvi Kivity {
128badc98caSKrish Sadhukhan     if (this_cpu_has(X86_FEATURE_XSAVE)) {
1297d36db35SAvi Kivity         printf("CPU has XSAVE feature\n");
1307d36db35SAvi Kivity         test_xsave();
1317d36db35SAvi Kivity     } else {
1327d36db35SAvi Kivity         printf("CPU don't has XSAVE feature\n");
1337d36db35SAvi Kivity         test_no_xsave();
1347d36db35SAvi Kivity     }
1358b1e9483SAndrew Jones     return report_summary();
1367d36db35SAvi Kivity }
137