1 /* CpuArch.c -- CPU specific code
2 2018-07-04: 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 "%eax", "%edx");
50 #endif
51 return flag;
52 }
53 #define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
54 #else
55 #define CHECK_CPUID_IS_SUPPORTED
56 #endif
57
MyCPUID(UInt32 function,UInt32 * a,UInt32 * b,UInt32 * c,UInt32 * d)58 void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
59 {
60 #ifdef USE_ASM
61
62 #ifdef _MSC_VER
63
64 UInt32 a2, b2, c2, d2;
65 __asm xor EBX, EBX;
66 __asm xor ECX, ECX;
67 __asm xor EDX, EDX;
68 __asm mov EAX, function;
69 __asm cpuid;
70 __asm mov a2, EAX;
71 __asm mov b2, EBX;
72 __asm mov c2, ECX;
73 __asm mov d2, EDX;
74
75 *a = a2;
76 *b = b2;
77 *c = c2;
78 *d = d2;
79
80 #else
81
82 __asm__ __volatile__ (
83 #if defined(MY_CPU_AMD64) && defined(__PIC__)
84 "mov %%rbx, %%rdi;"
85 "cpuid;"
86 "xchg %%rbx, %%rdi;"
87 : "=a" (*a) ,
88 "=D" (*b) ,
89 #elif defined(MY_CPU_X86) && defined(__PIC__)
90 "mov %%ebx, %%edi;"
91 "cpuid;"
92 "xchgl %%ebx, %%edi;"
93 : "=a" (*a) ,
94 "=D" (*b) ,
95 #else
96 "cpuid"
97 : "=a" (*a) ,
98 "=b" (*b) ,
99 #endif
100 "=c" (*c) ,
101 "=d" (*d)
102 : "0" (function)) ;
103
104 #endif
105
106 #else
107
108 int CPUInfo[4];
109 __cpuid(CPUInfo, function);
110 *a = CPUInfo[0];
111 *b = CPUInfo[1];
112 *c = CPUInfo[2];
113 *d = CPUInfo[3];
114
115 #endif
116 }
117
x86cpuid_CheckAndRead(Cx86cpuid * p)118 BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p)
119 {
120 CHECK_CPUID_IS_SUPPORTED
121 MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
122 MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
123 return True;
124 }
125
126 static const UInt32 kVendors[][3] =
127 {
128 { 0x756E6547, 0x49656E69, 0x6C65746E},
129 { 0x68747541, 0x69746E65, 0x444D4163},
130 { 0x746E6543, 0x48727561, 0x736C7561}
131 };
132
x86cpuid_GetFirm(const Cx86cpuid * p)133 int x86cpuid_GetFirm(const Cx86cpuid *p)
134 {
135 unsigned i;
136 for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
137 {
138 const UInt32 *v = kVendors[i];
139 if (v[0] == p->vendor[0] &&
140 v[1] == p->vendor[1] &&
141 v[2] == p->vendor[2])
142 return (int)i;
143 }
144 return -1;
145 }
146
CPU_Is_InOrder()147 BoolInt CPU_Is_InOrder()
148 {
149 Cx86cpuid p;
150 int firm;
151 UInt32 family, model;
152 if (!x86cpuid_CheckAndRead(&p))
153 return True;
154
155 family = x86cpuid_GetFamily(p.ver);
156 model = x86cpuid_GetModel(p.ver);
157
158 firm = x86cpuid_GetFirm(&p);
159
160 switch (firm)
161 {
162 case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
163 /* In-Order Atom CPU */
164 model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
165 || model == 0x26 /* 45 nm, Z6xx */
166 || model == 0x27 /* 32 nm, Z2460 */
167 || model == 0x35 /* 32 nm, Z2760 */
168 || model == 0x36 /* 32 nm, N2xxx, D2xxx */
169 )));
170 case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
171 case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
172 }
173 return True;
174 }
175
176 #if !defined(MY_CPU_AMD64) && defined(_WIN32)
177 #include <windows.h>
CPU_Sys_Is_SSE_Supported()178 static BoolInt CPU_Sys_Is_SSE_Supported()
179 {
180 OSVERSIONINFO vi;
181 vi.dwOSVersionInfoSize = sizeof(vi);
182 if (!GetVersionEx(&vi))
183 return False;
184 return (vi.dwMajorVersion >= 5);
185 }
186 #define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
187 #else
188 #define CHECK_SYS_SSE_SUPPORT
189 #endif
190
CPU_Is_Aes_Supported()191 BoolInt CPU_Is_Aes_Supported()
192 {
193 Cx86cpuid p;
194 CHECK_SYS_SSE_SUPPORT
195 if (!x86cpuid_CheckAndRead(&p))
196 return False;
197 return (p.c >> 25) & 1;
198 }
199
200 #endif
201