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