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