2 * Copyright (c) 2013 Ahmed Samy <f.fallen45@gmail.com>
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * This file has been written with some help from wikipedia:
23 * http://en.wikipedia.org/wiki/CPUID
26 /* Only compile this file if we're on a x86 machine. */
27 #if defined(__i386__) || defined(__i386) || defined(__x86_64) \
28 || defined(_M_AMD64) || defined(__M_X64)
34 CPUID_PROC_BRAND_STRING_INTERNAL0 = 0x80000003,
35 CPUID_PROC_BRAND_STRING_INTERNAL1 = 0x80000004
39 static void ___cpuid(cpuid_t info, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
42 "xchg %%ebx, %%edi\n\t" /* 32bit PIC: Don't clobber ebx. */
44 "xchg %%ebx, %%edi\n\t"
45 : "=a"(*eax), "=D"(*ebx), "=c"(*ecx), "=d"(*edx)
52 static void ___cpuid(cpuid_t info, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
54 uint32_t registers[4];
55 __cpuid(registers, info);
64 bool cpuid_is_supported(void)
67 #if defined(__GNUC__) || defined(__clang__)
68 /* The following assembly code uses EAX as the return value,
69 * but we store the value of EAX into ret since GCC uses EAX
70 * as the return register for every C function. That's a double
71 * operation, but there's no other way to do this unless doing this
72 * function entirely in assembly.
74 * The following assembly code has been shamelessly stolen from:
75 * http://wiki.osdev.org/CPUID
76 * and converted to work with AT&T syntax.
78 * This check is to make sure that the compiler is actually compiling
81 * The compiler can be 32-bit and the system 64-bit so the
82 * following would be true:
83 * #if defined(__x86_64) ...
86 #if UINTPTR_MAX == 0xffffffffffffffff
87 #define ASM_PUSHF "pushfq\n\t"
88 #define ASM_POPF "popfq\n\t"
89 #define ASM_PUSHEAX "pushq %%rax\n\t"
90 #define ASM_POPEAX "popq %%rax\n\t"
91 #define ASM_PUSHECX "pushq %%rcx\n\t"
92 #elif UINTPTR_MAX == 0xffffffff
93 #define ASM_PUSHF "pushfl\n\t"
94 #define ASM_POPF "popfl\n\t"
95 #define ASM_PUSHEAX "pushl %%eax\n\t"
96 #define ASM_POPEAX "popl %%eax\n\t"
97 #define ASM_PUSHECX "pushl %%ecx\n\t"
103 "movl %%eax, %%ecx\n\t"
104 "xorl $0x200000, %%eax\n\t"
109 "xorl %%ecx, %%eax\n\t"
110 "shrl $21, %%eax\n\t"
122 #elif defined _MSC_VER
145 bool cpuid_test_feature(cpuid_t feature)
147 if (feature > CPUID_VIRT_PHYS_ADDR_SIZES || feature < CPUID_EXTENDED_PROC_INFO_FEATURE_BITS)
150 return (feature <= cpuid_highest_ext_func_supported());
153 bool cpuid_has_ecxfeature(int feature)
155 static uint32_t _ecx;
157 #if defined(__GNUC__) || defined(__clang__)
161 : "a" (CPUID_PROCINFO_AND_FEATUREBITS)
163 #elif defined _MSC_VER
165 mov eax, CPUID_PROCINFO_AND_FEATUREBITS
172 return (_ecx & feature) == feature;
175 bool cpuid_has_edxfeature(int feature)
177 static uint32_t _edx;
179 #if defined(__GNUC__) || defined(__clang__)
183 : "a" (CPUID_PROCINFO_AND_FEATUREBITS)
185 #elif defined _MSC_VER
187 mov eax, CPUID_PROCINFO_AND_FEATUREBITS
194 return (_edx & feature) == feature;
197 static const char *const cpuids[] = {
216 cputype_t cpuid_get_cpu_type(void)
218 static cputype_t cputype;
219 if (cputype == CT_NONE) {
226 ___cpuid(CPUID_VENDORID, &i, &u.bufu32[0], &u.bufu32[2], &u.bufu32[1]);
227 for (i = 0; i < sizeof(cpuids) / sizeof(cpuids[0]); ++i) {
228 if (strncmp(cpuids[i], u.buf, 12) == 0) {
229 cputype = (cputype_t)i;
238 bool cpuid_sprintf_cputype(const cputype_t cputype, char *buf)
240 if (cputype == CT_NONE)
243 memcpy(buf, cpuids[(int)cputype], 12);
248 uint32_t cpuid_highest_ext_func_supported(void)
250 static uint32_t highest;
253 #if defined(__GNUC__) || defined(__clang__)
257 : "a" (CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED)
259 #elif defined _MSC_VER
261 mov eax, CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED
271 void cpuid(cpuid_t info, uint32_t *buf)
273 /* Sanity checks, make sure we're not trying to do something
274 * invalid or we are trying to get information that isn't supported
276 if (info > CPUID_VIRT_PHYS_ADDR_SIZES || (info > CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED
277 && !cpuid_test_feature(info)))
280 if (info == CPUID_PROC_BRAND_STRING) {
281 static char cached[48] = { 0 };
282 if (cached[0] == '\0') {
283 ___cpuid(CPUID_PROC_BRAND_STRING, &buf[0], &buf[1], &buf[2], &buf[3]);
284 ___cpuid(CPUID_PROC_BRAND_STRING_INTERNAL0, &buf[4], &buf[5], &buf[6], &buf[7]);
285 ___cpuid(CPUID_PROC_BRAND_STRING_INTERNAL1, &buf[8], &buf[9], &buf[10], &buf[11]);
287 memcpy(cached, buf, sizeof cached);
289 buf = (uint32_t *)cached;
292 } else if (info == CPUID_HIGHEST_EXTENDED_FUNCTION_SUPPORTED) {
293 *buf = cpuid_highest_ext_func_supported();
297 uint32_t eax, ebx, ecx, edx;
298 ___cpuid(info, &eax, &ebx, &ecx, &edx);
306 case CPUID_PROCINFO_AND_FEATUREBITS:
307 buf[0] = (eax & 0x0F); /* Stepping */
308 buf[1] = (eax >> 4) & 0x0F; /* Model */
309 buf[2] = (eax >> 8) & 0x0F; /* Family */
310 buf[3] = (eax >> 16) & 0x0F; /* Extended Model. */
311 buf[4] = (eax >> 24) & 0x0F; /* Extended Family. */
313 /* Additional Feature information. */
315 buf[6] = (ebx >> 8) & 0xFF;
316 buf[7] = (ebx >> 16) & 0xFF;
317 buf[8] = (ebx >> 24) & 0xFF;
319 case CPUID_CACHE_AND_TLBD_INFO:
325 case CPUID_EXTENDED_PROC_INFO_FEATURE_BITS:
329 case CPUID_L1_CACHE_AND_TLB_IDS:
331 buf[1] = (eax >> 8) & 0xFF;
332 buf[2] = (eax >> 16) & 0xFF;
333 buf[3] = (eax >> 24) & 0xFF;
336 buf[5] = (ebx >> 8) & 0xFF;
337 buf[6] = (ebx >> 16) & 0xFF;
338 buf[7] = (ebx >> 24) & 0xFF;
341 buf[9] = (ecx >> 8) & 0xFF;
342 buf[10] = (ecx >> 16) & 0xFF;
343 buf[11] = (ecx >> 24) & 0xFF;
345 buf[12] = edx & 0xFF;
346 buf[13] = (edx >> 8) & 0xFF;
347 buf[14] = (edx >> 16) & 0xFF;
348 buf[15] = (edx >> 24) & 0xFF;
350 case CPUID_EXTENDED_L2_CACHE_FEATURES:
351 buf[0] = ecx & 0xFF; /* Line size. */
352 buf[1] = (ecx >> 12) & 0xFF; /* Associativity. */
353 buf[2] = ecx >> 16; /* Cache size. */
355 case CPUID_ADV_POWER_MGT_INFO:
358 case CPUID_VIRT_PHYS_ADDR_SIZES:
359 buf[0] = eax & 0xFF; /* physical. */
360 buf[1] = (eax >> 8) & 0xFF; /* virtual. */