17d36db35SAvi Kivity #include "libcflat.h" 2e7c37968SGleb Natapov #include "desc.h" 3*985ab97eSPaolo 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 { 48*985ab97eSPaolo Bonzini return (cpuid(1).c & bit) != 0; 497d36db35SAvi Kivity } 507d36db35SAvi Kivity 517d36db35SAvi Kivity uint64_t get_supported_xcr0(void) 527d36db35SAvi Kivity { 53*985ab97eSPaolo Bonzini struct cpuid r; 54*985ab97eSPaolo Bonzini r = cpuid_indexed(0xd, 0); 557d36db35SAvi Kivity printf("eax %x, ebx %x, ecx %x, edx %x\n", 56*985ab97eSPaolo Bonzini r.a, r.b, r.c, r.d); 57*985ab97eSPaolo 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 static int total_tests, fail_tests; 697d36db35SAvi Kivity 707d36db35SAvi Kivity void pass_if(int condition) 717d36db35SAvi Kivity { 727d36db35SAvi Kivity total_tests ++; 737d36db35SAvi Kivity if (condition) 747d36db35SAvi Kivity printf("Pass!\n"); 757d36db35SAvi Kivity else { 767d36db35SAvi Kivity printf("Fail!\n"); 777d36db35SAvi Kivity fail_tests ++; 787d36db35SAvi Kivity } 797d36db35SAvi Kivity } 807d36db35SAvi Kivity 817d36db35SAvi Kivity void test_xsave(void) 827d36db35SAvi Kivity { 837d36db35SAvi Kivity unsigned long cr4; 847d36db35SAvi Kivity uint64_t supported_xcr0; 857d36db35SAvi Kivity uint64_t test_bits; 867d36db35SAvi Kivity u64 xcr0; 877d36db35SAvi Kivity int r; 887d36db35SAvi Kivity 897d36db35SAvi Kivity printf("Legal instruction testing:\n"); 907d36db35SAvi Kivity supported_xcr0 = get_supported_xcr0(); 917d36db35SAvi Kivity printf("Supported XCR0 bits: 0x%x\n", supported_xcr0); 927d36db35SAvi Kivity 937d36db35SAvi Kivity printf("Check minimal XSAVE required bits: "); 947d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 957d36db35SAvi Kivity pass_if((supported_xcr0 & test_bits) == test_bits); 967d36db35SAvi Kivity 977d36db35SAvi Kivity printf("Set CR4 OSXSAVE: "); 987d36db35SAvi Kivity cr4 = read_cr4(); 997d36db35SAvi Kivity r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE); 1007d36db35SAvi Kivity pass_if(r == 0); 1017d36db35SAvi Kivity 1027d36db35SAvi Kivity printf("Check CPUID.1.ECX.OSXSAVE - expect 1: "); 1037d36db35SAvi Kivity pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE)); 1047d36db35SAvi Kivity 1057d36db35SAvi Kivity printf(" Legal tests\n"); 1067d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP): "); 1077d36db35SAvi Kivity test_bits = XSTATE_FP; 1087d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1097d36db35SAvi Kivity pass_if(r == 0); 1107d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 1117d36db35SAvi Kivity "XSTATE_FP | XSTATE_SSE): "); 1127d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 1137d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1147d36db35SAvi Kivity pass_if(r == 0); 1157d36db35SAvi Kivity printf(" xgetbv(XCR_XFEATURE_ENABLED_MASK): "); 1167d36db35SAvi Kivity r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0); 1177d36db35SAvi Kivity pass_if(r == 0); 1187d36db35SAvi Kivity printf(" Illegal tests\n"); 1197d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP: "); 1207d36db35SAvi Kivity test_bits = 0; 1217d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1227d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1237d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) " 1247d36db35SAvi Kivity "- expect #GP: "); 1257d36db35SAvi Kivity test_bits = XSTATE_SSE; 1267d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1277d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1287d36db35SAvi Kivity if (supported_xcr0 & XSTATE_YMM) { 1297d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 1307d36db35SAvi Kivity "XSTATE_YMM) - expect #GP: "); 1317d36db35SAvi Kivity test_bits = XSTATE_YMM; 1327d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1337d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1347d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 1357d36db35SAvi Kivity "XSTATE_FP | XSTATE_YMM) - expect #GP: "); 1367d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_YMM; 1377d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1387d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1397d36db35SAvi Kivity } 1407d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) " 1417d36db35SAvi Kivity "- expect #GP: "); 1427d36db35SAvi Kivity test_bits = XSTATE_SSE; 1437d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits); 1447d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1457d36db35SAvi Kivity printf(" xgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) " 1467d36db35SAvi Kivity "- expect #GP: "); 1477d36db35SAvi Kivity test_bits = XSTATE_SSE; 1487d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits); 1497d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1507d36db35SAvi Kivity 1517d36db35SAvi Kivity printf("Unset CR4 OSXSAVE: "); 1527d36db35SAvi Kivity cr4 &= ~X86_CR4_OSXSAVE; 1537d36db35SAvi Kivity r = write_cr4_checking(cr4); 1547d36db35SAvi Kivity pass_if(r == 0); 1557d36db35SAvi Kivity printf("Check CPUID.1.ECX.OSXSAVE - expect 0: "); 1567d36db35SAvi Kivity pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 1577d36db35SAvi Kivity printf(" Illegal tests:\n"); 1587d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD: "); 1597d36db35SAvi Kivity test_bits = XSTATE_FP; 1607d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1617d36db35SAvi Kivity pass_if(r == UD_VECTOR); 1627d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 1637d36db35SAvi Kivity "XSTATE_FP | XSTATE_SSE) - expect #UD: "); 1647d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 1657d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1667d36db35SAvi Kivity pass_if(r == UD_VECTOR); 1677d36db35SAvi Kivity printf(" Illegal tests:\n"); 1687d36db35SAvi Kivity printf(" xgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD: "); 1697d36db35SAvi Kivity r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0); 1707d36db35SAvi Kivity pass_if(r == UD_VECTOR); 1717d36db35SAvi Kivity } 1727d36db35SAvi Kivity 1737d36db35SAvi Kivity void test_no_xsave(void) 1747d36db35SAvi Kivity { 1757d36db35SAvi Kivity unsigned long cr4; 1767d36db35SAvi Kivity u64 xcr0; 1777d36db35SAvi Kivity int r; 1787d36db35SAvi Kivity 1797d36db35SAvi Kivity printf("Check CPUID.1.ECX.OSXSAVE - expect 0: "); 1807d36db35SAvi Kivity pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 1817d36db35SAvi Kivity 1827d36db35SAvi Kivity printf("Illegal instruction testing:\n"); 1837d36db35SAvi Kivity 1847d36db35SAvi Kivity printf("Set OSXSAVE in CR4 - expect #GP: "); 1857d36db35SAvi Kivity cr4 = read_cr4(); 1867d36db35SAvi Kivity r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE); 1877d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1887d36db35SAvi Kivity 1897d36db35SAvi Kivity printf("Execute xgetbv - expect #UD: "); 1907d36db35SAvi Kivity r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0); 1917d36db35SAvi Kivity pass_if(r == UD_VECTOR); 1927d36db35SAvi Kivity 1937d36db35SAvi Kivity printf("Execute xsetbv - expect #UD: "); 1947d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3); 1957d36db35SAvi Kivity pass_if(r == UD_VECTOR); 1967d36db35SAvi Kivity } 1977d36db35SAvi Kivity 1987d36db35SAvi Kivity int main(void) 1997d36db35SAvi Kivity { 2007d36db35SAvi Kivity setup_idt(); 2017d36db35SAvi Kivity if (check_cpuid_1_ecx(CPUID_1_ECX_XSAVE)) { 2027d36db35SAvi Kivity printf("CPU has XSAVE feature\n"); 2037d36db35SAvi Kivity test_xsave(); 2047d36db35SAvi Kivity } else { 2057d36db35SAvi Kivity printf("CPU don't has XSAVE feature\n"); 2067d36db35SAvi Kivity test_no_xsave(); 2077d36db35SAvi Kivity } 2087d36db35SAvi Kivity printf("Total test: %d\n", total_tests); 2097d36db35SAvi Kivity if (fail_tests == 0) 2107d36db35SAvi Kivity printf("ALL PASS!\n"); 2117d36db35SAvi Kivity else { 2127d36db35SAvi Kivity printf("Fail %d tests.\n", fail_tests); 2137d36db35SAvi Kivity return 1; 2147d36db35SAvi Kivity } 2157d36db35SAvi Kivity return 0; 2167d36db35SAvi Kivity } 217