b24e7fce |
1 | /* CpuArch.c -- CPU specific code |
2 | 2018-02-18: 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) |
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 | |
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 | |
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 | |
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 | |
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> |
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 | |
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 | BoolInt CPU_IsSupported_PageGB() |
201 | { |
202 | Cx86cpuid cpuid; |
203 | if (!x86cpuid_CheckAndRead(&cpuid)) |
204 | return False; |
205 | { |
206 | UInt32 d[4] = { 0 }; |
207 | MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]); |
208 | if (d[0] < 0x80000001) |
209 | return False; |
210 | } |
211 | { |
212 | UInt32 d[4] = { 0 }; |
213 | MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]); |
214 | return (d[3] >> 26) & 1; |
215 | } |
216 | } |
217 | |
218 | #endif |