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 CPU_PROC_BRAND_STRING_INTERNAL0 = 0x80000003,
35 CPU_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);
67 bool use_edx; /* ecx will be used if false. */
69 { CF_MMX, 1 << 23, true },
70 { CF_SSE, 1 << 25, true },
71 { CF_SSE2, 1 << 26, true },
72 { CF_SSE3, 1 << 9, false },
73 { CF_FPU, 1 << 0, true },
75 { CF_TSC, 1 << 4, true },
76 { CF_MSR, 1 << 5, true },
78 { CF_SSSE3, 1 << 9, false },
79 { CF_AVX, 1 << 28, false },
82 { CEF_x64, 1 << 30, true },
83 { CEF_FPU, 1 << 0, true },
84 { CEF_DE, 1 << 2, true },
85 { CEF_SYSCALLRET, 1 << 11, true },
86 { CEF_CMOV, 1 << 15, true },
88 { CEF_SSE4a, 1 << 6, false },
89 { CEF_FMA4, 1 << 16, false },
90 { CEF_XOP, 1 << 11, false }
93 static bool has_feature(int feature, uint32_t ecx, uint32_t edx)
97 for (i = 0; i < sizeof(features) / sizeof(features[0]); ++i) {
98 if (features[i].feature == feature) {
99 if (features[i].use_edx)
100 return (edx & features[i].mask);
102 return (ecx & features[i].mask);
109 bool cpuid_is_supported(void)
116 "movl %%eax, %%ecx\n\t"
117 "xorl $0x200000, %%eax\n\t"
123 "xorl %%ecx, %%eax\n\t"
124 "shrl $21, %%eax\n\t"
135 bool cpuid_test_feature(cpuid_t feature)
137 if (feature > CPU_VIRT_PHYS_ADDR_SIZES || feature < CPU_EXTENDED_PROC_INFO_FEATURE_BITS)
140 return (feature <= cpuid_highest_ext_func_supported());
143 bool cpuid_has_feature(int feature, bool extended)
145 uint32_t eax, ebx, ecx, edx;
148 ___cpuid(CPU_PROCINFO_AND_FEATUREBITS, &eax, &ebx, &ecx, &edx);
150 ___cpuid(CPU_EXTENDED_PROC_INFO_FEATURE_BITS, &eax, &ebx, &ecx, &edx);
152 return has_feature(feature, ecx, edx);
155 static const char *const cpuids[] = {
174 cputype_t cpuid_get_cpu_type(void)
176 static cputype_t cputype;
177 if (cputype == CT_NONE) {
184 ___cpuid(CPU_VENDORID, &i, &u.bufu32[0], &u.bufu32[2], &u.bufu32[1]);
187 for (i = 0; i < sizeof(cpuids) / sizeof(cpuids[0]); ++i) {
188 if (strncmp(cpuids[i], u.buf, 12) == 0) {
189 cputype = (cputype_t)i;
198 const char *cpuid_get_cpu_type_string(const cputype_t cputype)
200 return cpuids[(int)cputype];
203 uint32_t cpuid_highest_ext_func_supported(void)
205 static uint32_t highest;
211 : "a" (CPU_HIGHEST_EXTENDED_FUNCTION_SUPPORTED)
218 void cpuid(cpuid_t info, uint32_t *buf)
220 /* Sanity checks, make sure we're not trying to do something
221 * invalid or we are trying to get information that isn't supported
223 if (info > CPU_VIRT_PHYS_ADDR_SIZES || (info > CPU_HIGHEST_EXTENDED_FUNCTION_SUPPORTED
224 && !cpuid_test_feature(info)))
227 if (info == CPU_PROC_BRAND_STRING) {
228 ___cpuid(CPU_PROC_BRAND_STRING, &buf[0], &buf[1], &buf[2], &buf[3]);
229 ___cpuid(CPU_PROC_BRAND_STRING_INTERNAL0, &buf[4], &buf[5], &buf[6], &buf[7]);
230 ___cpuid(CPU_PROC_BRAND_STRING_INTERNAL1, &buf[8], &buf[9], &buf[10], &buf[11]);
232 } else if (info == CPU_HIGHEST_EXTENDED_FUNCTION_SUPPORTED) {
233 *buf = cpuid_highest_ext_func_supported();
237 uint32_t eax, ebx, ecx, edx;
238 ___cpuid(info, &eax, &ebx, &ecx, &edx);
246 case CPU_PROCINFO_AND_FEATUREBITS:
247 buf[0] = eax; /* The so called "signature" of the CPU. */
248 buf[1] = edx; /* Feature flags #1. */
249 buf[2] = ecx; /* Feature flags #2. */
250 buf[3] = ebx; /* Additional feature information. */
252 case CPU_CACHE_AND_TLBD_INFO:
258 case CPU_EXTENDED_PROC_INFO_FEATURE_BITS:
262 case CPU_L1_CACHE_AND_TLB_IDS:
268 case CPU_EXTENDED_L2_CACHE_FEATURES:
271 case CPU_ADV_POWER_MGT_INFO:
274 case CPU_VIRT_PHYS_ADDR_SIZES: