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 16 #define False 0 17 #define True 1 18 typedef int Bool; 19 20 21 #if defined(VGA_x86) || defined(VGA_amd64) 22 static void cpuid ( unsigned int n, 23 unsigned int* a, unsigned int* b, 24 unsigned int* c, unsigned int* d ) 25 { 26 __asm__ __volatile__ ( 27 "cpuid" 28 : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d) /* output */ 29 : "0" (n) /* input */ 30 ); 31 } 32 33 static Bool vendorStringEquals ( char* str ) 34 { 35 char vstr[13]; 36 unsigned int a, b, c, d; 37 cpuid(0, &a, &b, &c, &d); 38 memcpy(&vstr[0], &b, 4); 39 memcpy(&vstr[4], &d, 4); 40 memcpy(&vstr[8], &c, 4); 41 vstr[12] = 0; 42 return 0 == strcmp(vstr, str); 43 } 44 45 static Bool go(char* cpu) 46 { 47 unsigned int level = 0, cmask = 0, dmask = 0, a, b, c, d; 48 Bool require_amd = False; 49 50 if ( strcmp( cpu, "x86-fpu" ) == 0 ) { 51 level = 1; 52 dmask = 1 << 0; 53 } else if ( strcmp( cpu, "x86-cmov" ) == 0 ) { 54 level = 1; 55 dmask = 1 << 15; 56 } else if ( strcmp( cpu, "x86-mmx" ) == 0 ) { 57 level = 1; 58 dmask = 1 << 23; 59 } else if ( strcmp( cpu, "x86-mmxext" ) == 0 ) { 60 level = 0x80000001; 61 dmask = 1 << 22; 62 } else if ( strcmp( cpu, "x86-sse" ) == 0 ) { 63 level = 1; 64 dmask = 1 << 25; 65 } else if ( strcmp( cpu, "x86-sse2" ) == 0 ) { 66 level = 1; 67 dmask = 1 << 26; 68 } else if ( strcmp( cpu, "x86-sse3" ) == 0 ) { 69 level = 1; 70 cmask = 1 << 0; 71 } else if ( strcmp( cpu, "x86-ssse3" ) == 0 ) { 72 level = 1; 73 cmask = 1 << 9; 74 } else if ( strcmp( cpu, "x86-lzcnt" ) == 0 ) { 75 level = 0x80000001; 76 cmask = 1 << 5; 77 require_amd = True; 78 #if defined(VGA_amd64) 79 } else if ( strcmp( cpu, "amd64-sse3" ) == 0 ) { 80 level = 1; 81 cmask = 1 << 0; 82 } else if ( strcmp( cpu, "amd64-pclmulqdq" ) == 0 ) { 83 level = 1; 84 cmask = 1 << 1; 85 } else if ( strcmp( cpu, "amd64-ssse3" ) == 0 ) { 86 level = 1; 87 cmask = 1 << 9; 88 } else if ( strcmp( cpu, "amd64-cx16" ) == 0 ) { 89 level = 1; 90 cmask = 1 << 13; 91 } else if ( strcmp( cpu, "amd64-lzcnt" ) == 0 ) { 92 level = 0x80000001; 93 cmask = 1 << 5; 94 require_amd = True; 95 } else if ( strcmp( cpu, "amd64-sse42" ) == 0 ) { 96 level = 1; 97 cmask = 1 << 20; 98 #endif 99 } else { 100 return 2; // Unrecognised feature. 101 } 102 103 assert( !(cmask != 0 && dmask != 0) ); 104 assert( !(cmask == 0 && dmask == 0) ); 105 106 if (require_amd && !vendorStringEquals("AuthenticAMD")) 107 return 1; // Feature not present 108 // regardless of what that feature actually is 109 110 cpuid( level & 0x80000000, &a, &b, &c, &d ); 111 112 if ( a >= level ) { 113 cpuid( level, &a, &b, &c, &d ); 114 115 if (dmask > 0 && (d & dmask) != 0) return 0; // Feature present. 116 if (cmask > 0 && (c & cmask) != 0) return 0; // Feature present. 117 } 118 return 1; // Feature not present. 119 } 120 121 #else 122 123 static Bool go(char* cpu) 124 { 125 return 2; // Feature not recognised (non-x86/AMD64 machine!) 126 } 127 128 #endif // defined(VGA_x86) || defined(VGA_amd64) 129 130 131 //--------------------------------------------------------------------------- 132 // main 133 //--------------------------------------------------------------------------- 134 int main(int argc, char **argv) 135 { 136 if ( argc != 2 ) { 137 fprintf( stderr, "usage: x86_amd64_features <feature>\n" ); 138 exit(3); // Usage error. 139 } 140 return go(argv[1]); 141 } 142