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 | #endif |
44 | return flag; |
45 | } |
46 | #define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; |
47 | #else |
48 | #define CHECK_CPUID_IS_SUPPORTED |
49 | #endif |
50 | |
51 | static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) |
52 | { |
53 | #ifdef USE_ASM |
54 | |
55 | #ifdef _MSC_VER |
56 | |
57 | UInt32 a2, b2, c2, d2; |
58 | __asm xor EBX, EBX; |
59 | __asm xor ECX, ECX; |
60 | __asm xor EDX, EDX; |
61 | __asm mov EAX, function; |
62 | __asm cpuid; |
63 | __asm mov a2, EAX; |
64 | __asm mov b2, EBX; |
65 | __asm mov c2, ECX; |
66 | __asm mov d2, EDX; |
67 | |
68 | *a = a2; |
69 | *b = b2; |
70 | *c = c2; |
71 | *d = d2; |
72 | |
73 | #else |
74 | |
75 | __asm__ __volatile__ ( |
76 | "cpuid" |
77 | : "=a" (*a) , |
78 | "=b" (*b) , |
79 | "=c" (*c) , |
80 | "=d" (*d) |
81 | : "0" (function)) ; |
82 | |
83 | #endif |
84 | |
85 | #else |
86 | |
87 | int CPUInfo[4]; |
88 | __cpuid(CPUInfo, function); |
89 | *a = CPUInfo[0]; |
90 | *b = CPUInfo[1]; |
91 | *c = CPUInfo[2]; |
92 | *d = CPUInfo[3]; |
93 | |
94 | #endif |
95 | } |
96 | |
97 | Bool x86cpuid_CheckAndRead(Cx86cpuid *p) |
98 | { |
99 | CHECK_CPUID_IS_SUPPORTED |
100 | MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); |
101 | MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); |
102 | return True; |
103 | } |
104 | |
105 | static UInt32 kVendors[][3] = |
106 | { |
107 | { 0x756E6547, 0x49656E69, 0x6C65746E}, |
108 | { 0x68747541, 0x69746E65, 0x444D4163}, |
109 | { 0x746E6543, 0x48727561, 0x736C7561} |
110 | }; |
111 | |
112 | int x86cpuid_GetFirm(const Cx86cpuid *p) |
113 | { |
114 | unsigned i; |
115 | for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) |
116 | { |
117 | const UInt32 *v = kVendors[i]; |
118 | if (v[0] == p->vendor[0] && |
119 | v[1] == p->vendor[1] && |
120 | v[2] == p->vendor[2]) |
121 | return (int)i; |
122 | } |
123 | return -1; |
124 | } |
125 | |
126 | Bool CPU_Is_InOrder() |
127 | { |
128 | Cx86cpuid p; |
129 | int firm; |
130 | UInt32 family, model; |
131 | if (!x86cpuid_CheckAndRead(&p)) |
132 | return True; |
133 | family = x86cpuid_GetFamily(&p); |
134 | model = x86cpuid_GetModel(&p); |
135 | firm = x86cpuid_GetFirm(&p); |
136 | switch (firm) |
137 | { |
138 | case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C)); |
139 | case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); |
140 | case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); |
141 | } |
142 | return True; |
143 | } |
144 | |
145 | #if !defined(MY_CPU_AMD64) && defined(_WIN32) |
146 | static Bool CPU_Sys_Is_SSE_Supported() |
147 | { |
148 | OSVERSIONINFO vi; |
149 | vi.dwOSVersionInfoSize = sizeof(vi); |
150 | if (!GetVersionEx(&vi)) |
151 | return False; |
152 | return (vi.dwMajorVersion >= 5); |
153 | } |
154 | #define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; |
155 | #else |
156 | #define CHECK_SYS_SSE_SUPPORT |
157 | #endif |
158 | |
159 | Bool CPU_Is_Aes_Supported() |
160 | { |
161 | Cx86cpuid p; |
162 | CHECK_SYS_SSE_SUPPORT |
163 | if (!x86cpuid_CheckAndRead(&p)) |
164 | return False; |
165 | return (p.c >> 25) & 1; |
166 | } |
167 | |
168 | #endif |
169 | |