1 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <assert.h> 6 7 // This file determines x86/AMD64 features a processor supports. 8 // 9 // We return: 10 // - 0 if the machine matches the asked-for feature. 11 // - 1 if the machine does not. 12 // - 2 if the asked-for feature isn't recognised (this will be the case for 13 // any feature if run on a non-x86/AMD64 machine). 14 // - 3 if there was a usage error (it also prints an error message). 15 // viz: 16 #define FEATURE_PRESENT 0 17 #define FEATURE_NOT_PRESENT 1 18 #define UNRECOGNISED_FEATURE 2 19 #define USAGE_ERROR 3 20 21 22 #define False 0 23 #define True 1 24 typedef int Bool; 25 26 27 #if defined(VGA_x86) || defined(VGA_amd64) 28 static void cpuid ( unsigned int n, 29 unsigned int* a, unsigned int* b, 30 unsigned int* c, unsigned int* d ) 31 { 32 __asm__ __volatile__ ( 33 "cpuid" 34 : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d) /* output */ 35 : "0" (n) /* input */ 36 ); 37 } 38 39 static Bool vendorStringEquals ( char* str ) 40 { 41 char vstr[13]; 42 unsigned int a, b, c, d; 43 cpuid(0, &a, &b, &c, &d); 44 memcpy(&vstr[0], &b, 4); 45 memcpy(&vstr[4], &d, 4); 46 memcpy(&vstr[8], &c, 4); 47 vstr[12] = 0; 48 return 0 == strcmp(vstr, str); 49 } 50 51 static Bool have_xgetbv ( void ) 52 { 53 #if defined(VGA_amd64) 54 unsigned long long int w; 55 __asm__ __volatile__("movq $0,%%rcx ; " 56 ".byte 0x0F,0x01,0xD0 ; " /* xgetbv */ 57 "movq %%rax,%0" 58 :/*OUT*/"=r"(w) :/*IN*/ 59 :/*TRASH*/"rdx","rcx"); 60 if ((w & 6) == 6) { 61 /* OS has enabled both XMM and YMM state support */ 62 return True; 63 } else { 64 return False; 65 } 66 #else 67 return False; 68 #endif 69 } 70 71 static Bool go(char* cpu) 72 { 73 unsigned int level = 0, cmask = 0, dmask = 0, a, b, c, d; 74 Bool require_amd = False; 75 Bool require_xgetbv = False; 76 if ( strcmp( cpu, "x86-fpu" ) == 0 ) { 77 level = 1; 78 dmask = 1 << 0; 79 } else if ( strcmp( cpu, "x86-cmov" ) == 0 ) { 80 level = 1; 81 dmask = 1 << 15; 82 } else if ( strcmp( cpu, "x86-mmx" ) == 0 ) { 83 level = 1; 84 dmask = 1 << 23; 85 } else if ( strcmp( cpu, "x86-mmxext" ) == 0 ) { 86 level = 0x80000001; 87 dmask = 1 << 22; 88 } else if ( strcmp( cpu, "x86-sse" ) == 0 ) { 89 level = 1; 90 dmask = 1 << 25; 91 } else if ( strcmp( cpu, "x86-sse2" ) == 0 ) { 92 level = 1; 93 dmask = 1 << 26; 94 } else if ( strcmp( cpu, "x86-sse3" ) == 0 ) { 95 level = 1; 96 cmask = 1 << 0; 97 } else if ( strcmp( cpu, "x86-ssse3" ) == 0 ) { 98 level = 1; 99 cmask = 1 << 9; 100 } else if ( strcmp( cpu, "x86-lzcnt" ) == 0 ) { 101 level = 0x80000001; 102 cmask = 1 << 5; 103 require_amd = True; 104 #if defined(VGA_amd64) 105 } else if ( strcmp( cpu, "amd64-sse3" ) == 0 ) { 106 level = 1; 107 cmask = 1 << 0; 108 } else if ( strcmp( cpu, "amd64-pclmulqdq" ) == 0 ) { 109 level = 1; 110 cmask = 1 << 1; 111 } else if ( strcmp( cpu, "amd64-ssse3" ) == 0 ) { 112 level = 1; 113 cmask = 1 << 9; 114 } else if ( strcmp( cpu, "amd64-cx16" ) == 0 ) { 115 level = 1; 116 cmask = 1 << 13; 117 } else if ( strcmp( cpu, "amd64-lzcnt" ) == 0 ) { 118 level = 0x80000001; 119 cmask = 1 << 5; 120 require_amd = True; 121 } else if ( strcmp( cpu, "amd64-sse42" ) == 0 ) { 122 level = 1; 123 cmask = 1 << 20; 124 } else if ( strcmp( cpu, "amd64-avx" ) == 0 ) { 125 level = 1; 126 cmask = (1 << 27) | (1 << 28); 127 require_xgetbv = True; 128 } else if (strcmp (cpu, "amd64-fma4" ) == 0) { 129 level = 0x80000001; 130 cmask = 1 << 16; 131 require_amd = True; 132 #endif 133 } else { 134 return UNRECOGNISED_FEATURE; 135 } 136 137 assert( !(cmask != 0 && dmask != 0) ); 138 assert( !(cmask == 0 && dmask == 0) ); 139 140 if (require_amd && !vendorStringEquals("AuthenticAMD")) 141 return FEATURE_NOT_PRESENT; 142 // regardless of what that feature actually is 143 144 cpuid( level & 0x80000000, &a, &b, &c, &d ); 145 146 if ( a >= level ) { 147 cpuid( level, &a, &b, &c, &d ); 148 149 if (dmask > 0 && (d & dmask) == dmask) { 150 if (require_xgetbv && !have_xgetbv()) 151 return FEATURE_NOT_PRESENT; 152 else 153 return FEATURE_PRESENT; 154 } 155 if (cmask > 0 && (c & cmask) == cmask) { 156 if (require_xgetbv && !have_xgetbv()) 157 return FEATURE_NOT_PRESENT; 158 else 159 return FEATURE_PRESENT; 160 } 161 } 162 return FEATURE_NOT_PRESENT; 163 } 164 165 #else 166 167 static Bool go(char* cpu) 168 { 169 // Feature not recognised (non-x86/AMD64 machine!) 170 return UNRECOGNISED_FEATURE; 171 } 172 173 #endif // defined(VGA_x86) || defined(VGA_amd64) 174 175 176 //--------------------------------------------------------------------------- 177 // main 178 //--------------------------------------------------------------------------- 179 int main(int argc, char **argv) 180 { 181 if ( argc != 2 ) { 182 fprintf( stderr, "usage: x86_amd64_features <feature>\n" ); 183 exit(USAGE_ERROR); 184 } 185 return go(argv[1]); 186 } 187