1*7d36db35SAvi Kivity #include "libcflat.h" 2*7d36db35SAvi Kivity #include "idt.h" 3*7d36db35SAvi Kivity 4*7d36db35SAvi Kivity #ifdef __x86_64__ 5*7d36db35SAvi Kivity #define uint64_t unsigned long 6*7d36db35SAvi Kivity #else 7*7d36db35SAvi Kivity #define uint64_t unsigned long long 8*7d36db35SAvi Kivity #endif 9*7d36db35SAvi Kivity 10*7d36db35SAvi Kivity static inline void __cpuid(unsigned int *eax, unsigned int *ebx, 11*7d36db35SAvi Kivity unsigned int *ecx, unsigned int *edx) 12*7d36db35SAvi Kivity { 13*7d36db35SAvi Kivity /* ecx is often an input as well as an output. */ 14*7d36db35SAvi Kivity asm volatile("cpuid" 15*7d36db35SAvi Kivity : "=a" (*eax), 16*7d36db35SAvi Kivity "=b" (*ebx), 17*7d36db35SAvi Kivity "=c" (*ecx), 18*7d36db35SAvi Kivity "=d" (*edx) 19*7d36db35SAvi Kivity : "0" (*eax), "2" (*ecx)); 20*7d36db35SAvi Kivity } 21*7d36db35SAvi Kivity 22*7d36db35SAvi Kivity /* 23*7d36db35SAvi Kivity * Generic CPUID function 24*7d36db35SAvi Kivity * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx 25*7d36db35SAvi Kivity * resulting in stale register contents being returned. 26*7d36db35SAvi Kivity */ 27*7d36db35SAvi Kivity void cpuid(unsigned int op, 28*7d36db35SAvi Kivity unsigned int *eax, unsigned int *ebx, 29*7d36db35SAvi Kivity unsigned int *ecx, unsigned int *edx) 30*7d36db35SAvi Kivity { 31*7d36db35SAvi Kivity *eax = op; 32*7d36db35SAvi Kivity *ecx = 0; 33*7d36db35SAvi Kivity __cpuid(eax, ebx, ecx, edx); 34*7d36db35SAvi Kivity } 35*7d36db35SAvi Kivity 36*7d36db35SAvi Kivity /* Some CPUID calls want 'count' to be placed in ecx */ 37*7d36db35SAvi Kivity void cpuid_count(unsigned int op, int count, 38*7d36db35SAvi Kivity unsigned int *eax, unsigned int *ebx, 39*7d36db35SAvi Kivity unsigned int *ecx, unsigned int *edx) 40*7d36db35SAvi Kivity { 41*7d36db35SAvi Kivity *eax = op; 42*7d36db35SAvi Kivity *ecx = count; 43*7d36db35SAvi Kivity __cpuid(eax, ebx, ecx, edx); 44*7d36db35SAvi Kivity } 45*7d36db35SAvi Kivity 46*7d36db35SAvi Kivity int xgetbv_checking(u32 index, u64 *result) 47*7d36db35SAvi Kivity { 48*7d36db35SAvi Kivity u32 eax, edx; 49*7d36db35SAvi Kivity 50*7d36db35SAvi Kivity asm volatile(ASM_TRY("1f") 51*7d36db35SAvi Kivity ".byte 0x0f,0x01,0xd0\n\t" /* xgetbv */ 52*7d36db35SAvi Kivity "1:" 53*7d36db35SAvi Kivity : "=a" (eax), "=d" (edx) 54*7d36db35SAvi Kivity : "c" (index)); 55*7d36db35SAvi Kivity *result = eax + ((u64)edx << 32); 56*7d36db35SAvi Kivity return exception_vector(); 57*7d36db35SAvi Kivity } 58*7d36db35SAvi Kivity 59*7d36db35SAvi Kivity int xsetbv_checking(u32 index, u64 value) 60*7d36db35SAvi Kivity { 61*7d36db35SAvi Kivity u32 eax = value; 62*7d36db35SAvi Kivity u32 edx = value >> 32; 63*7d36db35SAvi Kivity 64*7d36db35SAvi Kivity asm volatile(ASM_TRY("1f") 65*7d36db35SAvi Kivity ".byte 0x0f,0x01,0xd1\n\t" /* xsetbv */ 66*7d36db35SAvi Kivity "1:" 67*7d36db35SAvi Kivity : : "a" (eax), "d" (edx), "c" (index)); 68*7d36db35SAvi Kivity return exception_vector(); 69*7d36db35SAvi Kivity } 70*7d36db35SAvi Kivity 71*7d36db35SAvi Kivity unsigned long read_cr4(void) 72*7d36db35SAvi Kivity { 73*7d36db35SAvi Kivity unsigned long val; 74*7d36db35SAvi Kivity asm volatile("mov %%cr4,%0" : "=r" (val)); 75*7d36db35SAvi Kivity return val; 76*7d36db35SAvi Kivity } 77*7d36db35SAvi Kivity 78*7d36db35SAvi Kivity int write_cr4_checking(unsigned long val) 79*7d36db35SAvi Kivity { 80*7d36db35SAvi Kivity asm volatile(ASM_TRY("1f") 81*7d36db35SAvi Kivity "mov %0,%%cr4\n\t" 82*7d36db35SAvi Kivity "1:": : "r" (val)); 83*7d36db35SAvi Kivity return exception_vector(); 84*7d36db35SAvi Kivity } 85*7d36db35SAvi Kivity 86*7d36db35SAvi Kivity #define CPUID_1_ECX_XSAVE (1 << 26) 87*7d36db35SAvi Kivity #define CPUID_1_ECX_OSXSAVE (1 << 27) 88*7d36db35SAvi Kivity int check_cpuid_1_ecx(unsigned int bit) 89*7d36db35SAvi Kivity { 90*7d36db35SAvi Kivity unsigned int eax, ebx, ecx, edx; 91*7d36db35SAvi Kivity cpuid(1, &eax, &ebx, &ecx, &edx); 92*7d36db35SAvi Kivity if (ecx & bit) 93*7d36db35SAvi Kivity return 1; 94*7d36db35SAvi Kivity return 0; 95*7d36db35SAvi Kivity } 96*7d36db35SAvi Kivity 97*7d36db35SAvi Kivity uint64_t get_supported_xcr0(void) 98*7d36db35SAvi Kivity { 99*7d36db35SAvi Kivity unsigned int eax, ebx, ecx, edx; 100*7d36db35SAvi Kivity cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx); 101*7d36db35SAvi Kivity printf("eax %x, ebx %x, ecx %x, edx %x\n", 102*7d36db35SAvi Kivity eax, ebx, ecx, edx); 103*7d36db35SAvi Kivity return eax + ((u64)edx << 32); 104*7d36db35SAvi Kivity } 105*7d36db35SAvi Kivity 106*7d36db35SAvi Kivity #define X86_CR4_OSXSAVE 0x00040000 107*7d36db35SAvi Kivity #define XCR_XFEATURE_ENABLED_MASK 0x00000000 108*7d36db35SAvi Kivity #define XCR_XFEATURE_ILLEGAL_MASK 0x00000010 109*7d36db35SAvi Kivity 110*7d36db35SAvi Kivity #define XSTATE_FP 0x1 111*7d36db35SAvi Kivity #define XSTATE_SSE 0x2 112*7d36db35SAvi Kivity #define XSTATE_YMM 0x4 113*7d36db35SAvi Kivity 114*7d36db35SAvi Kivity static int total_tests, fail_tests; 115*7d36db35SAvi Kivity 116*7d36db35SAvi Kivity void pass_if(int condition) 117*7d36db35SAvi Kivity { 118*7d36db35SAvi Kivity total_tests ++; 119*7d36db35SAvi Kivity if (condition) 120*7d36db35SAvi Kivity printf("Pass!\n"); 121*7d36db35SAvi Kivity else { 122*7d36db35SAvi Kivity printf("Fail!\n"); 123*7d36db35SAvi Kivity fail_tests ++; 124*7d36db35SAvi Kivity } 125*7d36db35SAvi Kivity } 126*7d36db35SAvi Kivity 127*7d36db35SAvi Kivity void test_xsave(void) 128*7d36db35SAvi Kivity { 129*7d36db35SAvi Kivity unsigned long cr4; 130*7d36db35SAvi Kivity uint64_t supported_xcr0; 131*7d36db35SAvi Kivity uint64_t test_bits; 132*7d36db35SAvi Kivity u64 xcr0; 133*7d36db35SAvi Kivity int r; 134*7d36db35SAvi Kivity 135*7d36db35SAvi Kivity printf("Legal instruction testing:\n"); 136*7d36db35SAvi Kivity supported_xcr0 = get_supported_xcr0(); 137*7d36db35SAvi Kivity printf("Supported XCR0 bits: 0x%x\n", supported_xcr0); 138*7d36db35SAvi Kivity 139*7d36db35SAvi Kivity printf("Check minimal XSAVE required bits: "); 140*7d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 141*7d36db35SAvi Kivity pass_if((supported_xcr0 & test_bits) == test_bits); 142*7d36db35SAvi Kivity 143*7d36db35SAvi Kivity printf("Set CR4 OSXSAVE: "); 144*7d36db35SAvi Kivity cr4 = read_cr4(); 145*7d36db35SAvi Kivity r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE); 146*7d36db35SAvi Kivity pass_if(r == 0); 147*7d36db35SAvi Kivity 148*7d36db35SAvi Kivity printf("Check CPUID.1.ECX.OSXSAVE - expect 1: "); 149*7d36db35SAvi Kivity pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE)); 150*7d36db35SAvi Kivity 151*7d36db35SAvi Kivity printf(" Legal tests\n"); 152*7d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP): "); 153*7d36db35SAvi Kivity test_bits = XSTATE_FP; 154*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 155*7d36db35SAvi Kivity pass_if(r == 0); 156*7d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 157*7d36db35SAvi Kivity "XSTATE_FP | XSTATE_SSE): "); 158*7d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 159*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 160*7d36db35SAvi Kivity pass_if(r == 0); 161*7d36db35SAvi Kivity printf(" xgetbv(XCR_XFEATURE_ENABLED_MASK): "); 162*7d36db35SAvi Kivity r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0); 163*7d36db35SAvi Kivity pass_if(r == 0); 164*7d36db35SAvi Kivity printf(" Illegal tests\n"); 165*7d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP: "); 166*7d36db35SAvi Kivity test_bits = 0; 167*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 168*7d36db35SAvi Kivity pass_if(r == GP_VECTOR); 169*7d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) " 170*7d36db35SAvi Kivity "- expect #GP: "); 171*7d36db35SAvi Kivity test_bits = XSTATE_SSE; 172*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 173*7d36db35SAvi Kivity pass_if(r == GP_VECTOR); 174*7d36db35SAvi Kivity if (supported_xcr0 & XSTATE_YMM) { 175*7d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 176*7d36db35SAvi Kivity "XSTATE_YMM) - expect #GP: "); 177*7d36db35SAvi Kivity test_bits = XSTATE_YMM; 178*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 179*7d36db35SAvi Kivity pass_if(r == GP_VECTOR); 180*7d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 181*7d36db35SAvi Kivity "XSTATE_FP | XSTATE_YMM) - expect #GP: "); 182*7d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_YMM; 183*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 184*7d36db35SAvi Kivity pass_if(r == GP_VECTOR); 185*7d36db35SAvi Kivity } 186*7d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) " 187*7d36db35SAvi Kivity "- expect #GP: "); 188*7d36db35SAvi Kivity test_bits = XSTATE_SSE; 189*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits); 190*7d36db35SAvi Kivity pass_if(r == GP_VECTOR); 191*7d36db35SAvi Kivity printf(" xgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) " 192*7d36db35SAvi Kivity "- expect #GP: "); 193*7d36db35SAvi Kivity test_bits = XSTATE_SSE; 194*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits); 195*7d36db35SAvi Kivity pass_if(r == GP_VECTOR); 196*7d36db35SAvi Kivity 197*7d36db35SAvi Kivity printf("Unset CR4 OSXSAVE: "); 198*7d36db35SAvi Kivity cr4 &= ~X86_CR4_OSXSAVE; 199*7d36db35SAvi Kivity r = write_cr4_checking(cr4); 200*7d36db35SAvi Kivity pass_if(r == 0); 201*7d36db35SAvi Kivity printf("Check CPUID.1.ECX.OSXSAVE - expect 0: "); 202*7d36db35SAvi Kivity pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 203*7d36db35SAvi Kivity printf(" Illegal tests:\n"); 204*7d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD: "); 205*7d36db35SAvi Kivity test_bits = XSTATE_FP; 206*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 207*7d36db35SAvi Kivity pass_if(r == UD_VECTOR); 208*7d36db35SAvi Kivity printf(" xsetbv(XCR_XFEATURE_ENABLED_MASK, " 209*7d36db35SAvi Kivity "XSTATE_FP | XSTATE_SSE) - expect #UD: "); 210*7d36db35SAvi Kivity test_bits = XSTATE_FP | XSTATE_SSE; 211*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits); 212*7d36db35SAvi Kivity pass_if(r == UD_VECTOR); 213*7d36db35SAvi Kivity printf(" Illegal tests:\n"); 214*7d36db35SAvi Kivity printf(" xgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD: "); 215*7d36db35SAvi Kivity r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0); 216*7d36db35SAvi Kivity pass_if(r == UD_VECTOR); 217*7d36db35SAvi Kivity } 218*7d36db35SAvi Kivity 219*7d36db35SAvi Kivity void test_no_xsave(void) 220*7d36db35SAvi Kivity { 221*7d36db35SAvi Kivity unsigned long cr4; 222*7d36db35SAvi Kivity u64 xcr0; 223*7d36db35SAvi Kivity int r; 224*7d36db35SAvi Kivity 225*7d36db35SAvi Kivity printf("Check CPUID.1.ECX.OSXSAVE - expect 0: "); 226*7d36db35SAvi Kivity pass_if(check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 227*7d36db35SAvi Kivity 228*7d36db35SAvi Kivity printf("Illegal instruction testing:\n"); 229*7d36db35SAvi Kivity 230*7d36db35SAvi Kivity printf("Set OSXSAVE in CR4 - expect #GP: "); 231*7d36db35SAvi Kivity cr4 = read_cr4(); 232*7d36db35SAvi Kivity r = write_cr4_checking(cr4 | X86_CR4_OSXSAVE); 233*7d36db35SAvi Kivity pass_if(r == GP_VECTOR); 234*7d36db35SAvi Kivity 235*7d36db35SAvi Kivity printf("Execute xgetbv - expect #UD: "); 236*7d36db35SAvi Kivity r = xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0); 237*7d36db35SAvi Kivity pass_if(r == UD_VECTOR); 238*7d36db35SAvi Kivity 239*7d36db35SAvi Kivity printf("Execute xsetbv - expect #UD: "); 240*7d36db35SAvi Kivity r = xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3); 241*7d36db35SAvi Kivity pass_if(r == UD_VECTOR); 242*7d36db35SAvi Kivity } 243*7d36db35SAvi Kivity 244*7d36db35SAvi Kivity int main(void) 245*7d36db35SAvi Kivity { 246*7d36db35SAvi Kivity setup_idt(); 247*7d36db35SAvi Kivity if (check_cpuid_1_ecx(CPUID_1_ECX_XSAVE)) { 248*7d36db35SAvi Kivity printf("CPU has XSAVE feature\n"); 249*7d36db35SAvi Kivity test_xsave(); 250*7d36db35SAvi Kivity } else { 251*7d36db35SAvi Kivity printf("CPU don't has XSAVE feature\n"); 252*7d36db35SAvi Kivity test_no_xsave(); 253*7d36db35SAvi Kivity } 254*7d36db35SAvi Kivity printf("Total test: %d\n", total_tests); 255*7d36db35SAvi Kivity if (fail_tests == 0) 256*7d36db35SAvi Kivity printf("ALL PASS!\n"); 257*7d36db35SAvi Kivity else { 258*7d36db35SAvi Kivity printf("Fail %d tests.\n", fail_tests); 259*7d36db35SAvi Kivity return 1; 260*7d36db35SAvi Kivity } 261*7d36db35SAvi Kivity return 0; 262*7d36db35SAvi Kivity } 263