1 /* CpuArch.c -- CPU specific code 2 2010-10-26: Igor Pavlov : Public domain */ 3 4 #include "CpuArch.h" 5 6 #ifdef MY_CPU_X86_OR_AMD64 7 8 #if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) 9 #define USE_ASM 10 #endif 11 12 #if defined(USE_ASM) && !defined(MY_CPU_AMD64) 13 static UInt32 CheckFlag(UInt32 flag) 14 { 15 #ifdef _MSC_VER 16 __asm pushfd; 17 __asm pop EAX; 18 __asm mov EDX, EAX; 19 __asm xor EAX, flag; 20 __asm push EAX; 21 __asm popfd; 22 __asm pushfd; 23 __asm pop EAX; 24 __asm xor EAX, EDX; 25 __asm push EDX; 26 __asm popfd; 27 __asm and flag, EAX; 28 #else 29 __asm__ __volatile__ ( 30 "pushf\n\t" 31 "pop %%EAX\n\t" 32 "movl %%EAX,%%EDX\n\t" 33 "xorl %0,%%EAX\n\t" 34 "push %%EAX\n\t" 35 "popf\n\t" 36 "pushf\n\t" 37 "pop %%EAX\n\t" 38 "xorl %%EDX,%%EAX\n\t" 39 "push %%EDX\n\t" 40 "popf\n\t" 41 "andl %%EAX, %0\n\t": 42 "=c" (flag) : "c" (flag): 43 "%eax", "%edx" ); 44 #endif 45 return flag; 46 } 47 #define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; 48 #else 49 #define CHECK_CPUID_IS_SUPPORTED 50 #endif 51 52 static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) 53 { 54 #ifdef USE_ASM 55 56 #ifdef _MSC_VER 57 58 UInt32 a2, b2, c2, d2; 59 __asm xor EBX, EBX; 60 __asm xor ECX, ECX; 61 __asm xor EDX, EDX; 62 __asm mov EAX, function; 63 __asm cpuid; 64 __asm mov a2, EAX; 65 __asm mov b2, EBX; 66 __asm mov c2, ECX; 67 __asm mov d2, EDX; 68 69 *a = a2; 70 *b = b2; 71 *c = c2; 72 *d = d2; 73 74 #else 75 76 #if defined(MY_CPU_AMD64) 77 78 __asm__ __volatile__ ( 79 "mov %%rbx, %%rdi\n" 80 "cpuid\n" 81 "xchg %%rdi, %%rbx\n" 82 : "=a" (*a) , 83 "=D" (*b) , 84 "=c" (*c) , 85 "=d" (*d) 86 : "0" (function)) ; 87 88 #else 89 90 __asm__ __volatile__ ( 91 "mov %%ebx, %%edi\n" 92 "cpuid\n" 93 "xchg %%edi, %%ebx\n" 94 : "=a" (*a) , 95 "=D" (*b) , 96 "=c" (*c) , 97 "=d" (*d) 98 : "0" (function)) ; 99 100 #endif 101 102 #endif 103 104 #else 105 106 int CPUInfo[4]; 107 __cpuid(CPUInfo, function); 108 *a = CPUInfo[0]; 109 *b = CPUInfo[1]; 110 *c = CPUInfo[2]; 111 *d = CPUInfo[3]; 112 113 #endif 114 } 115 116 Bool x86cpuid_CheckAndRead(Cx86cpuid *p) 117 { 118 CHECK_CPUID_IS_SUPPORTED 119 MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); 120 MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); 121 return True; 122 } 123 124 static UInt32 kVendors[][3] = 125 { 126 { 0x756E6547, 0x49656E69, 0x6C65746E}, 127 { 0x68747541, 0x69746E65, 0x444D4163}, 128 { 0x746E6543, 0x48727561, 0x736C7561} 129 }; 130 131 int x86cpuid_GetFirm(const Cx86cpuid *p) 132 { 133 unsigned i; 134 for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) 135 { 136 const UInt32 *v = kVendors[i]; 137 if (v[0] == p->vendor[0] && 138 v[1] == p->vendor[1] && 139 v[2] == p->vendor[2]) 140 return (int)i; 141 } 142 return -1; 143 } 144 145 Bool CPU_Is_InOrder() 146 { 147 Cx86cpuid p; 148 int firm; 149 UInt32 family, model; 150 if (!x86cpuid_CheckAndRead(&p)) 151 return True; 152 family = x86cpuid_GetFamily(&p); 153 model = x86cpuid_GetModel(&p); 154 firm = x86cpuid_GetFirm(&p); 155 switch (firm) 156 { 157 case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C)); 158 case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); 159 case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); 160 } 161 return True; 162 } 163 164 #if !defined(MY_CPU_AMD64) && defined(_WIN32) 165 static Bool CPU_Sys_Is_SSE_Supported() 166 { 167 OSVERSIONINFO vi; 168 vi.dwOSVersionInfoSize = sizeof(vi); 169 if (!GetVersionEx(&vi)) 170 return False; 171 return (vi.dwMajorVersion >= 5); 172 } 173 #define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; 174 #else 175 #define CHECK_SYS_SSE_SUPPORT 176 #endif 177 178 Bool CPU_Is_Aes_Supported() 179 { 180 Cx86cpuid p; 181 CHECK_SYS_SSE_SUPPORT 182 if (!x86cpuid_CheckAndRead(&p)) 183 return False; 184 return (p.c >> 25) & 1; 185 } 186 187 #endif 188