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 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 { 48985ab97eSPaolo Bonzini return (cpuid(1).c & bit) != 0; 497d36db35SAvi Kivity } 507d36db35SAvi Kivity 517d36db35SAvi Kivity uint64_t get_supported_xcr0(void) 527d36db35SAvi Kivity { 53985ab97eSPaolo Bonzini struct cpuid r; 54985ab97eSPaolo Bonzini r = cpuid_indexed(0xd, 0); 557d36db35SAvi Kivity printf("eax %x, ebx %x, ecx %x, edx %x\n", 56985ab97eSPaolo Bonzini r.a, r.b, r.c, r.d); 57985ab97eSPaolo 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 void test_xsave(void) 697d36db35SAvi Kivity { 707d36db35SAvi Kivity unsigned long cr4; 717d36db35SAvi Kivity uint64_t supported_xcr0; 727d36db35SAvi Kivity uint64_t test_bits; 737d36db35SAvi Kivity u64 xcr0; 747d36db35SAvi Kivity 757d36db35SAvi Kivity printf("Legal instruction testing:\n"); 768b1e9483SAndrew Jones 777d36db35SAvi Kivity supported_xcr0 = get_supported_xcr0(); 78*fd6aada0SRadim Krčmář printf("Supported XCR0 bits: %#lx\n", supported_xcr0); 797d36db35SAvi Kivity 807d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 818b1e9483SAndrew Jones report("Check minimal XSAVE required bits", 828b1e9483SAndrew Jones (supported_xcr0 & test_bits) == test_bits); 837d36db35SAvi Kivity 847d36db35SAvi Kivity cr4 = read_cr4(); 858b1e9483SAndrew Jones report("Set CR4 OSXSAVE", write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == 0); 868b1e9483SAndrew Jones report("Check CPUID.1.ECX.OSXSAVE - expect 1", 878b1e9483SAndrew Jones check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE)); 887d36db35SAvi Kivity 898b1e9483SAndrew Jones printf("\tLegal tests\n"); 907d36db35SAvi Kivity test_bits = XSTATE_FP; 918b1e9483SAndrew Jones report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)", 928b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0); 938b1e9483SAndrew Jones 947d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 958b1e9483SAndrew Jones report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)", 968b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0); 978b1e9483SAndrew Jones report(" xgetbv(XCR_XFEATURE_ENABLED_MASK)", 988b1e9483SAndrew Jones xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0); 998b1e9483SAndrew Jones 1008b1e9483SAndrew Jones printf("\tIllegal tests\n"); 1017d36db35SAvi Kivity test_bits = 0; 1028b1e9483SAndrew Jones report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP", 1038b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR); 1047d36db35SAvi Kivity 1058b1e9483SAndrew Jones test_bits = XSTATE_SSE; 1068b1e9483SAndrew Jones report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP", 1078b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR); 1088b1e9483SAndrew Jones 1098b1e9483SAndrew Jones if (supported_xcr0 & XSTATE_YMM) { 1108b1e9483SAndrew Jones test_bits = XSTATE_YMM; 1118b1e9483SAndrew Jones report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP", 1128b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR); 1138b1e9483SAndrew Jones 1148b1e9483SAndrew Jones test_bits = XSTATE_FP | XSTATE_YMM; 1158b1e9483SAndrew Jones report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP", 1168b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR); 1178b1e9483SAndrew Jones } 1188b1e9483SAndrew Jones 1198b1e9483SAndrew Jones test_bits = XSTATE_SSE; 1208b1e9483SAndrew Jones report("\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP", 1218b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR); 1228b1e9483SAndrew Jones 1238b1e9483SAndrew Jones test_bits = XSTATE_SSE; 1248b1e9483SAndrew Jones report("\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP", 1258b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR); 1268b1e9483SAndrew Jones 1277d36db35SAvi Kivity cr4 &= ~X86_CR4_OSXSAVE; 1288b1e9483SAndrew Jones report("Unset CR4 OSXSAVE", write_cr4_checking(cr4) == 0); 1298b1e9483SAndrew Jones report("Check CPUID.1.ECX.OSXSAVE - expect 0", 1308b1e9483SAndrew Jones check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 1318b1e9483SAndrew Jones 1328b1e9483SAndrew Jones printf("\tIllegal tests:\n"); 1337d36db35SAvi Kivity test_bits = XSTATE_FP; 1348b1e9483SAndrew Jones report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD", 1358b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR); 1368b1e9483SAndrew Jones 1377d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 1388b1e9483SAndrew Jones report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD", 1398b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR); 1408b1e9483SAndrew Jones 1418b1e9483SAndrew Jones printf("\tIllegal tests:\n"); 1428b1e9483SAndrew Jones report("\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD", 1438b1e9483SAndrew Jones xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR); 1447d36db35SAvi Kivity } 1457d36db35SAvi Kivity 1467d36db35SAvi Kivity void test_no_xsave(void) 1477d36db35SAvi Kivity { 1487d36db35SAvi Kivity unsigned long cr4; 1497d36db35SAvi Kivity u64 xcr0; 1507d36db35SAvi Kivity 1518b1e9483SAndrew Jones report("Check CPUID.1.ECX.OSXSAVE - expect 0", 1528b1e9483SAndrew Jones check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 1537d36db35SAvi Kivity 1547d36db35SAvi Kivity printf("Illegal instruction testing:\n"); 1557d36db35SAvi Kivity 1567d36db35SAvi Kivity cr4 = read_cr4(); 1578b1e9483SAndrew Jones report("Set OSXSAVE in CR4 - expect #GP", 1588b1e9483SAndrew Jones write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR); 1597d36db35SAvi Kivity 1608b1e9483SAndrew Jones report("Execute xgetbv - expect #UD", 1618b1e9483SAndrew Jones xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR); 1627d36db35SAvi Kivity 1638b1e9483SAndrew Jones report("Execute xsetbv - expect #UD", 1648b1e9483SAndrew Jones xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR); 1657d36db35SAvi Kivity } 1667d36db35SAvi Kivity 1677d36db35SAvi Kivity int main(void) 1687d36db35SAvi Kivity { 1697d36db35SAvi Kivity setup_idt(); 1707d36db35SAvi Kivity if (check_cpuid_1_ecx(CPUID_1_ECX_XSAVE)) { 1717d36db35SAvi Kivity printf("CPU has XSAVE feature\n"); 1727d36db35SAvi Kivity test_xsave(); 1737d36db35SAvi Kivity } else { 1747d36db35SAvi Kivity printf("CPU don't has XSAVE feature\n"); 1757d36db35SAvi Kivity test_no_xsave(); 1767d36db35SAvi Kivity } 1778b1e9483SAndrew Jones return report_summary(); 1787d36db35SAvi Kivity } 179