17d36db35SAvi Kivity #include "libcflat.h" 2*e7c37968SGleb Natapov #include "desc.h" 37d36db35SAvi Kivity 47d36db35SAvi Kivity #ifdef __x86_64__ 57d36db35SAvi Kivity #define uint64_t unsigned long 67d36db35SAvi Kivity #else 77d36db35SAvi Kivity #define uint64_t unsigned long long 87d36db35SAvi Kivity #endif 97d36db35SAvi Kivity 107d36db35SAvi Kivity static inline void __cpuid(unsigned int *eax, unsigned int *ebx, 117d36db35SAvi Kivity unsigned int *ecx, unsigned int *edx) 127d36db35SAvi Kivity { 137d36db35SAvi Kivity /* ecx is often an input as well as an output. */ 147d36db35SAvi Kivity asm volatile("cpuid" 157d36db35SAvi Kivity : "=a" (*eax), 167d36db35SAvi Kivity "=b" (*ebx), 177d36db35SAvi Kivity "=c" (*ecx), 187d36db35SAvi Kivity "=d" (*edx) 197d36db35SAvi Kivity : "0" (*eax), "2" (*ecx)); 207d36db35SAvi Kivity } 217d36db35SAvi Kivity 227d36db35SAvi Kivity /* 237d36db35SAvi Kivity * Generic CPUID function 247d36db35SAvi Kivity * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx 257d36db35SAvi Kivity * resulting in stale register contents being returned. 267d36db35SAvi Kivity */ 277d36db35SAvi Kivity void cpuid(unsigned int op, 287d36db35SAvi Kivity unsigned int *eax, unsigned int *ebx, 297d36db35SAvi Kivity unsigned int *ecx, unsigned int *edx) 307d36db35SAvi Kivity { 317d36db35SAvi Kivity *eax = op; 327d36db35SAvi Kivity *ecx = 0; 337d36db35SAvi Kivity __cpuid(eax, ebx, ecx, edx); 347d36db35SAvi Kivity } 357d36db35SAvi Kivity 367d36db35SAvi Kivity /* Some CPUID calls want 'count' to be placed in ecx */ 377d36db35SAvi Kivity void cpuid_count(unsigned int op, int count, 387d36db35SAvi Kivity unsigned int *eax, unsigned int *ebx, 397d36db35SAvi Kivity unsigned int *ecx, unsigned int *edx) 407d36db35SAvi Kivity { 417d36db35SAvi Kivity *eax = op; 427d36db35SAvi Kivity *ecx = count; 437d36db35SAvi Kivity __cpuid(eax, ebx, ecx, edx); 447d36db35SAvi Kivity } 457d36db35SAvi Kivity 467d36db35SAvi Kivity int xgetbv_checking(u32 index, u64 *result) 477d36db35SAvi Kivity { 487d36db35SAvi Kivity u32 eax, edx; 497d36db35SAvi Kivity 507d36db35SAvi Kivity asm volatile(ASM_TRY("1f") 517d36db35SAvi Kivity ".byte 0x0f,0x01,0xd0\n\t" /* xgetbv */ 527d36db35SAvi Kivity "1:" 537d36db35SAvi Kivity : "=a" (eax), "=d" (edx) 547d36db35SAvi Kivity : "c" (index)); 557d36db35SAvi Kivity *result = eax + ((u64)edx << 32); 567d36db35SAvi Kivity return exception_vector(); 577d36db35SAvi Kivity } 587d36db35SAvi Kivity 597d36db35SAvi Kivity int xsetbv_checking(u32 index, u64 value) 607d36db35SAvi Kivity { 617d36db35SAvi Kivity u32 eax = value; 627d36db35SAvi Kivity u32 edx = value >> 32; 637d36db35SAvi Kivity 647d36db35SAvi Kivity asm volatile(ASM_TRY("1f") 657d36db35SAvi Kivity ".byte 0x0f,0x01,0xd1\n\t" /* xsetbv */ 667d36db35SAvi Kivity "1:" 677d36db35SAvi Kivity : : "a" (eax), "d" (edx), "c" (index)); 687d36db35SAvi Kivity return exception_vector(); 697d36db35SAvi Kivity } 707d36db35SAvi Kivity 717d36db35SAvi Kivity unsigned long read_cr4(void) 727d36db35SAvi Kivity { 737d36db35SAvi Kivity unsigned long val; 747d36db35SAvi Kivity asm volatile("mov %%cr4,%0" : "=r" (val)); 757d36db35SAvi Kivity return val; 767d36db35SAvi Kivity } 777d36db35SAvi Kivity 787d36db35SAvi Kivity int write_cr4_checking(unsigned long val) 797d36db35SAvi Kivity { 807d36db35SAvi Kivity asm volatile(ASM_TRY("1f") 817d36db35SAvi Kivity "mov %0,%%cr4\n\t" 827d36db35SAvi Kivity "1:": : "r" (val)); 837d36db35SAvi Kivity return exception_vector(); 847d36db35SAvi Kivity } 857d36db35SAvi Kivity 867d36db35SAvi Kivity #define CPUID_1_ECX_XSAVE (1 << 26) 877d36db35SAvi Kivity #define CPUID_1_ECX_OSXSAVE (1 << 27) 887d36db35SAvi Kivity int check_cpuid_1_ecx(unsigned int bit) 897d36db35SAvi Kivity { 907d36db35SAvi Kivity unsigned int eax, ebx, ecx, edx; 917d36db35SAvi Kivity cpuid(1, &eax, &ebx, &ecx, &edx); 927d36db35SAvi Kivity if (ecx & bit) 937d36db35SAvi Kivity return 1; 947d36db35SAvi Kivity return 0; 957d36db35SAvi Kivity } 967d36db35SAvi Kivity 977d36db35SAvi Kivity uint64_t get_supported_xcr0(void) 987d36db35SAvi Kivity { 997d36db35SAvi Kivity unsigned int eax, ebx, ecx, edx; 1007d36db35SAvi Kivity cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx); 1017d36db35SAvi Kivity printf("eax %x, ebx %x, ecx %x, edx %x\n", 1027d36db35SAvi Kivity eax, ebx, ecx, edx); 1037d36db35SAvi Kivity return eax + ((u64)edx << 32); 1047d36db35SAvi Kivity } 1057d36db35SAvi Kivity 1067d36db35SAvi Kivity #define X86_CR4_OSXSAVE 0x00040000 1077d36db35SAvi Kivity #define XCR_XFEATURE_ENABLED_MASK 0x00000000 1087d36db35SAvi Kivity #define XCR_XFEATURE_ILLEGAL_MASK 0x00000010 1097d36db35SAvi Kivity 1107d36db35SAvi Kivity #define XSTATE_FP 0x1 1117d36db35SAvi Kivity #define XSTATE_SSE 0x2 1127d36db35SAvi Kivity #define XSTATE_YMM 0x4 1137d36db35SAvi Kivity 1147d36db35SAvi Kivity static int total_tests, fail_tests; 1157d36db35SAvi Kivity 1167d36db35SAvi Kivity void pass_if(int condition) 1177d36db35SAvi Kivity { 1187d36db35SAvi Kivity total_tests ++; 1197d36db35SAvi Kivity if (condition) 1207d36db35SAvi Kivity printf("Pass!\n"); 1217d36db35SAvi Kivity else { 1227d36db35SAvi Kivity printf("Fail!\n"); 1237d36db35SAvi Kivity fail_tests ++; 1247d36db35SAvi Kivity } 1257d36db35SAvi Kivity } 1267d36db35SAvi Kivity 1277d36db35SAvi Kivity void test_xsave(void) 1287d36db35SAvi Kivity { 1297d36db35SAvi Kivity unsigned long cr4; 1307d36db35SAvi Kivity uint64_t supported_xcr0; 1317d36db35SAvi Kivity uint64_t test_bits; 1327d36db35SAvi Kivity u64 xcr0; 1337d36db35SAvi Kivity int r; 1347d36db35SAvi Kivity 1357d36db35SAvi Kivity printf("Legal instruction testing:\n"); 1367d36db35SAvi Kivity supported_xcr0 = get_supported_xcr0(); 1377d36db35SAvi Kivity printf("Supported XCR0 bits: 0x%x\n", supported_xcr0); 1387d36db35SAvi Kivity 1397d36db35SAvi Kivity printf("Check minimal XSAVE required bits: "); 1407d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 1417d36db35SAvi Kivity pass_if((supported_xcr0 & test_bits) == test_bits); 1427d36db35SAvi Kivity 1437d36db35SAvi Kivity printf("Set CR4 OSXSAVE: "); 1447d36db35SAvi Kivity cr4 = read_cr4(); 1457d36db35SAvi Kivity r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE); 1467d36db35SAvi Kivity pass_if(r == 0); 1477d36db35SAvi Kivity 1487d36db35SAvi Kivity printf("Check CPUID.1.ECX.OSXSAVE - expect 1: "); 1497d36db35SAvi Kivity pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE)); 1507d36db35SAvi Kivity 1517d36db35SAvi Kivity printf(" Legal tests\n"); 1527d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP): "); 1537d36db35SAvi Kivity test_bits = XSTATE_FP; 1547d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1557d36db35SAvi Kivity pass_if(r == 0); 1567d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 1577d36db35SAvi Kivity "XSTATE_FP | XSTATE_SSE): "); 1587d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 1597d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1607d36db35SAvi Kivity pass_if(r == 0); 1617d36db35SAvi Kivity printf(" xgetbv(XCR_XFEATURE_ENABLED_MASK): "); 1627d36db35SAvi Kivity r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0); 1637d36db35SAvi Kivity pass_if(r == 0); 1647d36db35SAvi Kivity printf(" Illegal tests\n"); 1657d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP: "); 1667d36db35SAvi Kivity test_bits = 0; 1677d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1687d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1697d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) " 1707d36db35SAvi Kivity "- expect #GP: "); 1717d36db35SAvi Kivity test_bits = XSTATE_SSE; 1727d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1737d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1747d36db35SAvi Kivity if (supported_xcr0 & XSTATE_YMM) { 1757d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 1767d36db35SAvi Kivity "XSTATE_YMM) - expect #GP: "); 1777d36db35SAvi Kivity test_bits = XSTATE_YMM; 1787d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1797d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1807d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 1817d36db35SAvi Kivity "XSTATE_FP | XSTATE_YMM) - expect #GP: "); 1827d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_YMM; 1837d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 1847d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1857d36db35SAvi Kivity } 1867d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) " 1877d36db35SAvi Kivity "- expect #GP: "); 1887d36db35SAvi Kivity test_bits = XSTATE_SSE; 1897d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits); 1907d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1917d36db35SAvi Kivity printf(" xgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) " 1927d36db35SAvi Kivity "- expect #GP: "); 1937d36db35SAvi Kivity test_bits = XSTATE_SSE; 1947d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits); 1957d36db35SAvi Kivity pass_if(r == GP_VECTOR); 1967d36db35SAvi Kivity 1977d36db35SAvi Kivity printf("Unset CR4 OSXSAVE: "); 1987d36db35SAvi Kivity cr4 &= ~X86_CR4_OSXSAVE; 1997d36db35SAvi Kivity r = write_cr4_checking(cr4); 2007d36db35SAvi Kivity pass_if(r == 0); 2017d36db35SAvi Kivity printf("Check CPUID.1.ECX.OSXSAVE - expect 0: "); 2027d36db35SAvi Kivity pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 2037d36db35SAvi Kivity printf(" Illegal tests:\n"); 2047d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD: "); 2057d36db35SAvi Kivity test_bits = XSTATE_FP; 2067d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 2077d36db35SAvi Kivity pass_if(r == UD_VECTOR); 2087d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 2097d36db35SAvi Kivity "XSTATE_FP | XSTATE_SSE) - expect #UD: "); 2107d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 2117d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 2127d36db35SAvi Kivity pass_if(r == UD_VECTOR); 2137d36db35SAvi Kivity printf(" Illegal tests:\n"); 2147d36db35SAvi Kivity printf(" xgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD: "); 2157d36db35SAvi Kivity r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0); 2167d36db35SAvi Kivity pass_if(r == UD_VECTOR); 2177d36db35SAvi Kivity } 2187d36db35SAvi Kivity 2197d36db35SAvi Kivity void test_no_xsave(void) 2207d36db35SAvi Kivity { 2217d36db35SAvi Kivity unsigned long cr4; 2227d36db35SAvi Kivity u64 xcr0; 2237d36db35SAvi Kivity int r; 2247d36db35SAvi Kivity 2257d36db35SAvi Kivity printf("Check CPUID.1.ECX.OSXSAVE - expect 0: "); 2267d36db35SAvi Kivity pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 2277d36db35SAvi Kivity 2287d36db35SAvi Kivity printf("Illegal instruction testing:\n"); 2297d36db35SAvi Kivity 2307d36db35SAvi Kivity printf("Set OSXSAVE in CR4 - expect #GP: "); 2317d36db35SAvi Kivity cr4 = read_cr4(); 2327d36db35SAvi Kivity r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE); 2337d36db35SAvi Kivity pass_if(r == GP_VECTOR); 2347d36db35SAvi Kivity 2357d36db35SAvi Kivity printf("Execute xgetbv - expect #UD: "); 2367d36db35SAvi Kivity r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0); 2377d36db35SAvi Kivity pass_if(r == UD_VECTOR); 2387d36db35SAvi Kivity 2397d36db35SAvi Kivity printf("Execute xsetbv - expect #UD: "); 2407d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3); 2417d36db35SAvi Kivity pass_if(r == UD_VECTOR); 2427d36db35SAvi Kivity } 2437d36db35SAvi Kivity 2447d36db35SAvi Kivity int main(void) 2457d36db35SAvi Kivity { 2467d36db35SAvi Kivity setup_idt(); 2477d36db35SAvi Kivity if (check_cpuid_1_ecx(CPUID_1_ECX_XSAVE)) { 2487d36db35SAvi Kivity printf("CPU has XSAVE feature\n"); 2497d36db35SAvi Kivity test_xsave(); 2507d36db35SAvi Kivity } else { 2517d36db35SAvi Kivity printf("CPU don't has XSAVE feature\n"); 2527d36db35SAvi Kivity test_no_xsave(); 2537d36db35SAvi Kivity } 2547d36db35SAvi Kivity printf("Total test: %d\n", total_tests); 2557d36db35SAvi Kivity if (fail_tests == 0) 2567d36db35SAvi Kivity printf("ALL PASS!\n"); 2577d36db35SAvi Kivity else { 2587d36db35SAvi Kivity printf("Fail %d tests.\n", fail_tests); 2597d36db35SAvi Kivity return 1; 2607d36db35SAvi Kivity } 2617d36db35SAvi Kivity return 0; 2627d36db35SAvi Kivity } 263