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 void test_xsave(void) 69 { 70 unsigned long cr4; 71 uint64_t supported_xcr0; 72 uint64_t test_bits; 73 u64 xcr0; 74 75 printf("Legal instruction testing:\n"); 76 77 supported_xcr0 = get_supported_xcr0(); 78 printf("Supported XCR0 bits: %#lx\n", supported_xcr0); 79 80 test_bits = XSTATE_FP | XSTATE_SSE; 81 report("Check minimal XSAVE required bits", 82 (supported_xcr0 & test_bits) == test_bits); 83 84 cr4 = read_cr4(); 85 report("Set CR4 OSXSAVE", write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == 0); 86 report("Check CPUID.1.ECX.OSXSAVE - expect 1", 87 check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE)); 88 89 printf("\tLegal tests\n"); 90 test_bits = XSTATE_FP; 91 report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)", 92 xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0); 93 94 test_bits = XSTATE_FP | XSTATE_SSE; 95 report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)", 96 xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0); 97 report(" xgetbv(XCR_XFEATURE_ENABLED_MASK)", 98 xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0); 99 100 printf("\tIllegal tests\n"); 101 test_bits = 0; 102 report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP", 103 xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR); 104 105 test_bits = XSTATE_SSE; 106 report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP", 107 xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR); 108 109 if (supported_xcr0 & XSTATE_YMM) { 110 test_bits = XSTATE_YMM; 111 report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP", 112 xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR); 113 114 test_bits = XSTATE_FP | XSTATE_YMM; 115 report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP", 116 xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR); 117 } 118 119 test_bits = XSTATE_SSE; 120 report("\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP", 121 xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR); 122 123 test_bits = XSTATE_SSE; 124 report("\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP", 125 xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR); 126 127 cr4 &= ~X86_CR4_OSXSAVE; 128 report("Unset CR4 OSXSAVE", write_cr4_checking(cr4) == 0); 129 report("Check CPUID.1.ECX.OSXSAVE - expect 0", 130 check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 131 132 printf("\tIllegal tests:\n"); 133 test_bits = XSTATE_FP; 134 report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD", 135 xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR); 136 137 test_bits = XSTATE_FP | XSTATE_SSE; 138 report("\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD", 139 xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR); 140 141 printf("\tIllegal tests:\n"); 142 report("\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD", 143 xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR); 144 } 145 146 void test_no_xsave(void) 147 { 148 unsigned long cr4; 149 u64 xcr0; 150 151 report("Check CPUID.1.ECX.OSXSAVE - expect 0", 152 check_cpuid_1_ecx(CPUID_1_ECX_OSXSAVE) == 0); 153 154 printf("Illegal instruction testing:\n"); 155 156 cr4 = read_cr4(); 157 report("Set OSXSAVE in CR4 - expect #GP", 158 write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR); 159 160 report("Execute xgetbv - expect #UD", 161 xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR); 162 163 report("Execute xsetbv - expect #UD", 164 xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR); 165 } 166 167 int main(void) 168 { 169 setup_idt(); 170 if (check_cpuid_1_ecx(CPUID_1_ECX_XSAVE)) { 171 printf("CPU has XSAVE feature\n"); 172 test_xsave(); 173 } else { 174 printf("CPU don't has XSAVE feature\n"); 175 test_no_xsave(); 176 } 177 return report_summary(); 178 } 179