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