blob: 378ed059ba5b47a0d1097ed6636e51d29fda9a33 [file] [log] [blame]
Guillaume Chatelet3cc8f312020-10-12 08:55:20 +00001// Copyright 2017 Google LLC
Jeff Hammonde6983272020-09-21 00:54:58 -07002// Copyright 2020 Intel Corporation
Guillaume Chatelet439d3712018-02-01 10:03:09 +01003//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#include "cpuinfo_x86.h"
Guillaume Chatelet439d3712018-02-01 10:03:09 +010017
18#include <stdbool.h>
19#include <string.h>
20
Jeff Hammond17ffb652020-09-22 00:29:46 -070021#include "internal/bit_utils.h"
22#include "internal/cpuid_x86.h"
23
Guillaume Chatelete8e56102019-01-15 10:52:56 +010024#if !defined(CPU_FEATURES_ARCH_X86)
25#error "Cannot compile cpuinfo_x86 on a non x86 platform."
26#endif
27
Guillaume Chatelet9a8f04b2020-10-12 11:50:35 +020028// Generation of feature's getters/setters functions and kGetters, kSetters,
29// kCpuInfoFlags global tables.
Guillaume Chateletcdab59a2020-10-13 13:05:04 +020030#define DEFINE_TABLE_FEATURES \
31 FEATURE(X86_FPU, fpu, "fpu", 0, 0) \
32 FEATURE(X86_TSC, tsc, "tsc", 0, 0) \
33 FEATURE(X86_CX8, cx8, "cx8", 0, 0) \
34 FEATURE(X86_CLFSH, clfsh, "clfsh", 0, 0) \
35 FEATURE(X86_MMX, mmx, "mmx", 0, 0) \
36 FEATURE(X86_AES, aes, "aes", 0, 0) \
37 FEATURE(X86_ERMS, erms, "erms", 0, 0) \
38 FEATURE(X86_F16C, f16c, "f16c", 0, 0) \
39 FEATURE(X86_FMA4, fma4, "fma4", 0, 0) \
40 FEATURE(X86_FMA3, fma3, "fma3", 0, 0) \
41 FEATURE(X86_VAES, vaes, "vaes", 0, 0) \
42 FEATURE(X86_VPCLMULQDQ, vpclmulqdq, "vpclmulqdq", 0, 0) \
43 FEATURE(X86_BMI1, bmi1, "bmi1", 0, 0) \
44 FEATURE(X86_HLE, hle, "hle", 0, 0) \
45 FEATURE(X86_BMI2, bmi2, "bmi2", 0, 0) \
46 FEATURE(X86_RTM, rtm, "rtm", 0, 0) \
47 FEATURE(X86_RDSEED, rdseed, "rdseed", 0, 0) \
48 FEATURE(X86_CLFLUSHOPT, clflushopt, "clflushopt", 0, 0) \
49 FEATURE(X86_CLWB, clwb, "clwb", 0, 0) \
50 FEATURE(X86_SSE, sse, "sse", 0, 0) \
51 FEATURE(X86_SSE2, sse2, "sse2", 0, 0) \
52 FEATURE(X86_SSE3, sse3, "sse3", 0, 0) \
53 FEATURE(X86_SSSE3, ssse3, "ssse3", 0, 0) \
54 FEATURE(X86_SSE4_1, sse4_1, "sse4_1", 0, 0) \
55 FEATURE(X86_SSE4_2, sse4_2, "sse4_2", 0, 0) \
56 FEATURE(X86_SSE4A, sse4a, "sse4a", 0, 0) \
57 FEATURE(X86_AVX, avx, "avx", 0, 0) \
58 FEATURE(X86_AVX2, avx2, "avx2", 0, 0) \
59 FEATURE(X86_AVX512F, avx512f, "avx512f", 0, 0) \
60 FEATURE(X86_AVX512CD, avx512cd, "avx512cd", 0, 0) \
61 FEATURE(X86_AVX512ER, avx512er, "avx512er", 0, 0) \
62 FEATURE(X86_AVX512PF, avx512pf, "avx512pf", 0, 0) \
63 FEATURE(X86_AVX512BW, avx512bw, "avx512bw", 0, 0) \
64 FEATURE(X86_AVX512DQ, avx512dq, "avx512dq", 0, 0) \
65 FEATURE(X86_AVX512VL, avx512vl, "avx512vl", 0, 0) \
66 FEATURE(X86_AVX512IFMA, avx512ifma, "avx512ifma", 0, 0) \
67 FEATURE(X86_AVX512VBMI, avx512vbmi, "avx512vbmi", 0, 0) \
68 FEATURE(X86_AVX512VBMI2, avx512vbmi2, "avx512vbmi2", 0, 0) \
69 FEATURE(X86_AVX512VNNI, avx512vnni, "avx512vnni", 0, 0) \
70 FEATURE(X86_AVX512BITALG, avx512bitalg, "avx512bitalg", 0, 0) \
71 FEATURE(X86_AVX512VPOPCNTDQ, avx512vpopcntdq, "avx512vpopcntdq", 0, 0) \
72 FEATURE(X86_AVX512_4VNNIW, avx512_4vnniw, "avx512_4vnniw", 0, 0) \
73 FEATURE(X86_AVX512_4VBMI2, avx512_4vbmi2, "avx512_4vbmi2", 0, 0) \
74 FEATURE(X86_AVX512_SECOND_FMA, avx512_second_fma, "avx512_second_fma", 0, 0) \
75 FEATURE(X86_AVX512_4FMAPS, avx512_4fmaps, "avx512_4fmaps", 0, 0) \
76 FEATURE(X86_AVX512_BF16, avx512_bf16, "avx512_bf16", 0, 0) \
77 FEATURE(X86_AVX512_VP2INTERSECT, avx512_vp2intersect, "avx512_vp2intersect", \
78 0, 0) \
79 FEATURE(X86_AMX_BF16, amx_bf16, "amx_bf16", 0, 0) \
80 FEATURE(X86_AMX_TILE, amx_tile, "amx_tile", 0, 0) \
81 FEATURE(X86_AMX_INT8, amx_int8, "amx_int8", 0, 0) \
82 FEATURE(X86_PCLMULQDQ, pclmulqdq, "pclmulqdq", 0, 0) \
83 FEATURE(X86_SMX, smx, "smx", 0, 0) \
84 FEATURE(X86_SGX, sgx, "sgx", 0, 0) \
85 FEATURE(X86_CX16, cx16, "cx16", 0, 0) \
86 FEATURE(X86_SHA, sha, "sha", 0, 0) \
87 FEATURE(X86_POPCNT, popcnt, "popcnt", 0, 0) \
88 FEATURE(X86_MOVBE, movbe, "movbe", 0, 0) \
89 FEATURE(X86_RDRND, rdrnd, "rdrnd", 0, 0) \
90 FEATURE(X86_DCA, dca, "dca", 0, 0) \
91 FEATURE(X86_SS, ss, "ss", 0, 0)
Guillaume Chatelet9a8f04b2020-10-12 11:50:35 +020092#define DEFINE_TABLE_FEATURE_TYPE X86Features
Guillaume Chatelet9a8f04b2020-10-12 11:50:35 +020093#define DEFINE_TABLE_DONT_GENERATE_HWCAPS
94#include "define_tables.h"
95
Guillaume Chatelet47953732020-10-09 17:20:25 +020096// The following includes are necessary to provide SSE detections on pre-AVX
97// microarchitectures.
98#if defined(CPU_FEATURES_OS_WINDOWS)
99#include <windows.h> // IsProcessorFeaturePresent
Guillaume Chatelete63405f2020-10-09 22:40:06 +0200100#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
Guillaume Chatelet47953732020-10-09 17:20:25 +0200101#include "internal/filesystem.h" // Needed to parse /proc/cpuinfo
102#include "internal/stack_line_reader.h" // Needed to parse /proc/cpuinfo
103#include "internal/string_view.h" // Needed to parse /proc/cpuinfo
Guillaume Chatelete63405f2020-10-09 22:40:06 +0200104#elif defined(CPU_FEATURES_OS_DARWIN)
105#if !defined(HAVE_SYSCTLBYNAME)
106#error "Darwin needs support for sysctlbyname"
107#endif
Guillaume Chatelet47953732020-10-09 17:20:25 +0200108#include <sys/sysctl.h>
Guillaume Chatelete63405f2020-10-09 22:40:06 +0200109#else
110#error "Unsupported OS"
111#endif // CPU_FEATURES_OS
Guillaume Chatelet47953732020-10-09 17:20:25 +0200112
Guillaume Chatelete8e56102019-01-15 10:52:56 +0100113////////////////////////////////////////////////////////////////////////////////
114// Definitions for CpuId and GetXCR0Eax.
115////////////////////////////////////////////////////////////////////////////////
116
117#if defined(CPU_FEATURES_MOCK_CPUID_X86)
118// Implementation will be provided by test/cpuinfo_x86_test.cc.
119#elif defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
120
121#include <cpuid.h>
122
Guillaume Chatelet47953732020-10-09 17:20:25 +0200123Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
Guillaume Chatelete8e56102019-01-15 10:52:56 +0100124 Leaf leaf;
Artem Alekseevbfb4cf92019-06-21 15:13:29 +0300125 __cpuid_count(leaf_id, ecx, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
Guillaume Chatelete8e56102019-01-15 10:52:56 +0100126 return leaf;
127}
128
129uint32_t GetXCR0Eax(void) {
130 uint32_t eax, edx;
natanbc084ec5c2019-03-20 06:04:24 -0300131 /* named form of xgetbv not supported on OSX, so must use byte form, see:
132 https://github.com/asmjit/asmjit/issues/78
133 */
134 __asm(".byte 0x0F, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0));
Guillaume Chatelete8e56102019-01-15 10:52:56 +0100135 return eax;
136}
137
138#elif defined(CPU_FEATURES_COMPILER_MSC)
139
140#include <immintrin.h>
141#include <intrin.h> // For __cpuidex()
142
Guillaume Chatelet47953732020-10-09 17:20:25 +0200143Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
Guillaume Chatelete8e56102019-01-15 10:52:56 +0100144 Leaf leaf;
145 int data[4];
Artem Alekseevbfb4cf92019-06-21 15:13:29 +0300146 __cpuidex(data, leaf_id, ecx);
Guillaume Chatelete8e56102019-01-15 10:52:56 +0100147 leaf.eax = data[0];
148 leaf.ebx = data[1];
149 leaf.ecx = data[2];
150 leaf.edx = data[3];
151 return leaf;
152}
153
Leonard Mosescubdb36d92019-07-03 05:57:19 -0700154uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); }
Guillaume Chatelete8e56102019-01-15 10:52:56 +0100155
156#else
157#error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC."
158#endif
159
Guillaume Chatelet47953732020-10-09 17:20:25 +0200160static Leaf CpuId(uint32_t leaf_id) { return GetCpuidLeaf(leaf_id, 0); }
Artem Alekseevbfb4cf92019-06-21 15:13:29 +0300161
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100162static const Leaf kEmptyLeaf;
163
Artem Alekseevbfb4cf92019-06-21 15:13:29 +0300164static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100165 if (leaf_id <= max_cpuid_leaf) {
Guillaume Chatelet47953732020-10-09 17:20:25 +0200166 return GetCpuidLeaf(leaf_id, ecx);
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100167 } else {
168 return kEmptyLeaf;
169 }
170}
171
Artem Alekseevbfb4cf92019-06-21 15:13:29 +0300172static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
173 return SafeCpuIdEx(max_cpuid_leaf, leaf_id, 0);
174}
175
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100176#define MASK_XMM 0x2
177#define MASK_YMM 0x4
178#define MASK_MASKREG 0x20
179#define MASK_ZMM0_15 0x40
180#define MASK_ZMM16_31 0x80
Jeff Hammond33bd72c2020-09-21 00:56:26 -0700181#define MASK_XTILECFG 0x20000
182#define MASK_XTILEDATA 0x40000
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100183
184static bool HasMask(uint32_t value, uint32_t mask) {
185 return (value & mask) == mask;
186}
187
188// Checks that operating system saves and restores xmm registers during context
189// switches.
190static bool HasXmmOsXSave(uint32_t xcr0_eax) {
191 return HasMask(xcr0_eax, MASK_XMM);
192}
193
194// Checks that operating system saves and restores ymm registers during context
195// switches.
196static bool HasYmmOsXSave(uint32_t xcr0_eax) {
197 return HasMask(xcr0_eax, MASK_XMM | MASK_YMM);
198}
199
200// Checks that operating system saves and restores zmm registers during context
201// switches.
202static bool HasZmmOsXSave(uint32_t xcr0_eax) {
203 return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
204 MASK_ZMM16_31);
205}
206
Jeff Hammond33bd72c2020-09-21 00:56:26 -0700207// Checks that operating system saves and restores AMX/TMUL state during context
208// switches.
209static bool HasTmmOsXSave(uint32_t xcr0_eax) {
210 return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
211 MASK_ZMM16_31 | MASK_XTILECFG | MASK_XTILEDATA);
212}
213
Jeff Hammond17ffb652020-09-22 00:29:46 -0700214static bool HasSecondFMA(uint32_t model) {
215 // Skylake server
216 if (model == 0x55) {
217 char proc_name[49] = {0};
218 FillX86BrandString(proc_name);
219 // detect Xeon
220 if (proc_name[9] == 'X') {
221 // detect Silver or Bronze
222 if (proc_name[17] == 'S' || proc_name[17] == 'B') return false;
223 // detect Gold 5_20 and below, except for Gold 53__
224 if (proc_name[17] == 'G' && proc_name[22] == '5')
225 return ((proc_name[23] == '3') ||
226 (proc_name[24] == '2' && proc_name[25] == '2'));
227 // detect Xeon W 210x
228 if (proc_name[17] == 'W' && proc_name[21] == '0') return false;
229 // detect Xeon D 2xxx
230 if (proc_name[17] == 'D' && proc_name[19] == '2' && proc_name[20] == '1')
231 return false;
232 }
233 return true;
234 }
235 // Cannon Lake client
236 if (model == 0x66) return false;
237 // Ice Lake client
238 if (model == 0x7d || model == 0x7e) return false;
239 // This is the right default...
240 return true;
241}
242
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100243static void SetVendor(const Leaf leaf, char* const vendor) {
244 *(uint32_t*)(vendor) = leaf.ebx;
245 *(uint32_t*)(vendor + 4) = leaf.edx;
246 *(uint32_t*)(vendor + 8) = leaf.ecx;
247 vendor[12] = '\0';
248}
249
250static int IsVendor(const Leaf leaf, const char* const name) {
251 const uint32_t ebx = *(const uint32_t*)(name);
252 const uint32_t edx = *(const uint32_t*)(name + 4);
253 const uint32_t ecx = *(const uint32_t*)(name + 8);
254 return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
255}
256
Artem Alekseev653d5812019-07-02 17:52:25 +0300257static const CacheLevelInfo kEmptyCacheLevelInfo;
258
Artem Alekseev653d5812019-07-02 17:52:25 +0300259static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
260 const int UNDEF = -1;
261 const int KiB = 1024;
262 const int MiB = 1024 * KiB;
Artem Alekseev653d5812019-07-02 17:52:25 +0300263 switch (reg) {
264 case 0x01:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100265 return (CacheLevelInfo){.level = UNDEF,
266 .cache_type = CPU_FEATURE_CACHE_TLB,
267 .cache_size = 4 * KiB,
268 .ways = 4,
269 .line_size = UNDEF,
270 .tlb_entries = 32,
271 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300272 case 0x02:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100273 return (CacheLevelInfo){.level = UNDEF,
274 .cache_type = CPU_FEATURE_CACHE_TLB,
275 .cache_size = 4 * MiB,
276 .ways = 0xFF,
277 .line_size = UNDEF,
278 .tlb_entries = 2,
279 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300280 case 0x03:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100281 return (CacheLevelInfo){.level = UNDEF,
282 .cache_type = CPU_FEATURE_CACHE_TLB,
283 .cache_size = 4 * KiB,
284 .ways = 4,
285 .line_size = UNDEF,
286 .tlb_entries = 64,
287 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300288 case 0x04:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100289 return (CacheLevelInfo){.level = UNDEF,
290 .cache_type = CPU_FEATURE_CACHE_TLB,
291 .cache_size = 4 * MiB,
292 .ways = 4,
293 .line_size = UNDEF,
294 .tlb_entries = 8,
295 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300296 case 0x05:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100297 return (CacheLevelInfo){.level = UNDEF,
298 .cache_type = CPU_FEATURE_CACHE_TLB,
299 .cache_size = 4 * MiB,
300 .ways = 4,
301 .line_size = UNDEF,
302 .tlb_entries = 32,
303 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300304 case 0x06:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100305 return (CacheLevelInfo){.level = 1,
306 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
307 .cache_size = 8 * KiB,
308 .ways = 4,
309 .line_size = 32,
310 .tlb_entries = UNDEF,
311 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300312 case 0x08:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100313 return (CacheLevelInfo){.level = 1,
314 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
315 .cache_size = 16 * KiB,
316 .ways = 4,
317 .line_size = 32,
318 .tlb_entries = UNDEF,
319 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300320 case 0x09:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100321 return (CacheLevelInfo){.level = 1,
322 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
323 .cache_size = 32 * KiB,
324 .ways = 4,
325 .line_size = 64,
326 .tlb_entries = UNDEF,
327 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300328 case 0x0A:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100329 return (CacheLevelInfo){.level = 1,
330 .cache_type = CPU_FEATURE_CACHE_DATA,
331 .cache_size = 8 * KiB,
332 .ways = 2,
333 .line_size = 32,
334 .tlb_entries = UNDEF,
335 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300336 case 0x0B:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100337 return (CacheLevelInfo){.level = UNDEF,
338 .cache_type = CPU_FEATURE_CACHE_TLB,
339 .cache_size = 4 * MiB,
340 .ways = 4,
341 .line_size = UNDEF,
342 .tlb_entries = 4,
343 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300344 case 0x0C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100345 return (CacheLevelInfo){.level = 1,
346 .cache_type = CPU_FEATURE_CACHE_DATA,
347 .cache_size = 16 * KiB,
348 .ways = 4,
349 .line_size = 32,
350 .tlb_entries = UNDEF,
351 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300352 case 0x0D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100353 return (CacheLevelInfo){.level = 1,
354 .cache_type = CPU_FEATURE_CACHE_DATA,
355 .cache_size = 16 * KiB,
356 .ways = 4,
357 .line_size = 64,
358 .tlb_entries = UNDEF,
359 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300360 case 0x0E:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100361 return (CacheLevelInfo){.level = 1,
362 .cache_type = CPU_FEATURE_CACHE_DATA,
363 .cache_size = 24 * KiB,
364 .ways = 6,
365 .line_size = 64,
366 .tlb_entries = UNDEF,
367 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300368 case 0x1D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100369 return (CacheLevelInfo){.level = 2,
370 .cache_type = CPU_FEATURE_CACHE_DATA,
371 .cache_size = 128 * KiB,
372 .ways = 2,
373 .line_size = 64,
374 .tlb_entries = UNDEF,
375 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300376 case 0x21:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100377 return (CacheLevelInfo){.level = 2,
378 .cache_type = CPU_FEATURE_CACHE_DATA,
379 .cache_size = 256 * KiB,
380 .ways = 8,
381 .line_size = 64,
382 .tlb_entries = UNDEF,
383 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300384 case 0x22:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100385 return (CacheLevelInfo){.level = 3,
386 .cache_type = CPU_FEATURE_CACHE_DATA,
387 .cache_size = 512 * KiB,
388 .ways = 4,
389 .line_size = 64,
390 .tlb_entries = UNDEF,
391 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300392 case 0x23:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100393 return (CacheLevelInfo){.level = 3,
394 .cache_type = CPU_FEATURE_CACHE_DATA,
395 .cache_size = 1 * MiB,
396 .ways = 8,
397 .line_size = 64,
398 .tlb_entries = UNDEF,
399 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300400 case 0x24:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100401 return (CacheLevelInfo){.level = 2,
402 .cache_type = CPU_FEATURE_CACHE_DATA,
403 .cache_size = 1 * MiB,
404 .ways = 16,
405 .line_size = 64,
406 .tlb_entries = UNDEF,
407 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300408 case 0x25:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100409 return (CacheLevelInfo){.level = 3,
410 .cache_type = CPU_FEATURE_CACHE_DATA,
411 .cache_size = 2 * MiB,
412 .ways = 8,
413 .line_size = 64,
414 .tlb_entries = UNDEF,
415 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300416 case 0x29:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100417 return (CacheLevelInfo){.level = 3,
418 .cache_type = CPU_FEATURE_CACHE_DATA,
419 .cache_size = 4 * MiB,
420 .ways = 8,
421 .line_size = 64,
422 .tlb_entries = UNDEF,
423 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300424 case 0x2C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100425 return (CacheLevelInfo){.level = 1,
426 .cache_type = CPU_FEATURE_CACHE_DATA,
427 .cache_size = 32 * KiB,
428 .ways = 8,
429 .line_size = 64,
430 .tlb_entries = UNDEF,
431 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300432 case 0x30:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100433 return (CacheLevelInfo){.level = 1,
434 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
435 .cache_size = 32 * KiB,
436 .ways = 8,
437 .line_size = 64,
438 .tlb_entries = UNDEF,
439 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300440 case 0x40:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100441 return (CacheLevelInfo){.level = UNDEF,
442 .cache_type = CPU_FEATURE_CACHE_DATA,
443 .cache_size = UNDEF,
444 .ways = UNDEF,
445 .line_size = UNDEF,
446 .tlb_entries = UNDEF,
447 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300448 case 0x41:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100449 return (CacheLevelInfo){.level = 2,
450 .cache_type = CPU_FEATURE_CACHE_DATA,
451 .cache_size = 128 * KiB,
452 .ways = 4,
453 .line_size = 32,
454 .tlb_entries = UNDEF,
455 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300456 case 0x42:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100457 return (CacheLevelInfo){.level = 2,
458 .cache_type = CPU_FEATURE_CACHE_DATA,
459 .cache_size = 256 * KiB,
460 .ways = 4,
461 .line_size = 32,
462 .tlb_entries = UNDEF,
463 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300464 case 0x43:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100465 return (CacheLevelInfo){.level = 2,
466 .cache_type = CPU_FEATURE_CACHE_DATA,
467 .cache_size = 512 * KiB,
468 .ways = 4,
469 .line_size = 32,
470 .tlb_entries = UNDEF,
471 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300472 case 0x44:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100473 return (CacheLevelInfo){.level = 2,
474 .cache_type = CPU_FEATURE_CACHE_DATA,
475 .cache_size = 1 * MiB,
476 .ways = 4,
477 .line_size = 32,
478 .tlb_entries = UNDEF,
479 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300480 case 0x45:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100481 return (CacheLevelInfo){.level = 2,
482 .cache_type = CPU_FEATURE_CACHE_DATA,
483 .cache_size = 2 * MiB,
484 .ways = 4,
485 .line_size = 32,
486 .tlb_entries = UNDEF,
487 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300488 case 0x46:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100489 return (CacheLevelInfo){.level = 3,
490 .cache_type = CPU_FEATURE_CACHE_DATA,
491 .cache_size = 4 * MiB,
492 .ways = 4,
493 .line_size = 64,
494 .tlb_entries = UNDEF,
495 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300496 case 0x47:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100497 return (CacheLevelInfo){.level = 3,
498 .cache_type = CPU_FEATURE_CACHE_DATA,
499 .cache_size = 8 * MiB,
500 .ways = 8,
501 .line_size = 64,
502 .tlb_entries = UNDEF,
503 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300504 case 0x48:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100505 return (CacheLevelInfo){.level = 2,
506 .cache_type = CPU_FEATURE_CACHE_DATA,
507 .cache_size = 3 * MiB,
508 .ways = 12,
509 .line_size = 64,
510 .tlb_entries = UNDEF,
511 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300512 case 0x49:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100513 return (CacheLevelInfo){.level = 2,
514 .cache_type = CPU_FEATURE_CACHE_DATA,
515 .cache_size = 4 * MiB,
516 .ways = 16,
517 .line_size = 64,
518 .tlb_entries = UNDEF,
519 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300520 case (0x49 | (1 << 8)):
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100521 return (CacheLevelInfo){.level = 3,
522 .cache_type = CPU_FEATURE_CACHE_DATA,
523 .cache_size = 4 * MiB,
524 .ways = 16,
525 .line_size = 64,
526 .tlb_entries = UNDEF,
527 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300528 case 0x4A:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100529 return (CacheLevelInfo){.level = 3,
530 .cache_type = CPU_FEATURE_CACHE_DATA,
531 .cache_size = 6 * MiB,
532 .ways = 12,
533 .line_size = 64,
534 .tlb_entries = UNDEF,
535 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300536 case 0x4B:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100537 return (CacheLevelInfo){.level = 3,
538 .cache_type = CPU_FEATURE_CACHE_DATA,
539 .cache_size = 8 * MiB,
540 .ways = 16,
541 .line_size = 64,
542 .tlb_entries = UNDEF,
543 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300544 case 0x4C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100545 return (CacheLevelInfo){.level = 3,
546 .cache_type = CPU_FEATURE_CACHE_DATA,
547 .cache_size = 12 * MiB,
548 .ways = 12,
549 .line_size = 64,
550 .tlb_entries = UNDEF,
551 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300552 case 0x4D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100553 return (CacheLevelInfo){.level = 3,
554 .cache_type = CPU_FEATURE_CACHE_DATA,
555 .cache_size = 16 * MiB,
556 .ways = 16,
557 .line_size = 64,
558 .tlb_entries = UNDEF,
559 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300560 case 0x4E:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100561 return (CacheLevelInfo){.level = 2,
562 .cache_type = CPU_FEATURE_CACHE_DATA,
563 .cache_size = 6 * MiB,
564 .ways = 24,
565 .line_size = 64,
566 .tlb_entries = UNDEF,
567 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300568 case 0x4F:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100569 return (CacheLevelInfo){.level = UNDEF,
570 .cache_type = CPU_FEATURE_CACHE_TLB,
571 .cache_size = 4 * KiB,
572 .ways = UNDEF,
573 .line_size = UNDEF,
574 .tlb_entries = 32,
575 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300576 case 0x50:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100577 return (CacheLevelInfo){.level = UNDEF,
578 .cache_type = CPU_FEATURE_CACHE_TLB,
579 .cache_size = 4 * KiB,
580 .ways = UNDEF,
581 .line_size = UNDEF,
582 .tlb_entries = 64,
583 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300584 case 0x51:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100585 return (CacheLevelInfo){.level = UNDEF,
586 .cache_type = CPU_FEATURE_CACHE_TLB,
587 .cache_size = 4 * KiB,
588 .ways = UNDEF,
589 .line_size = UNDEF,
590 .tlb_entries = 128,
591 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300592 case 0x52:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100593 return (CacheLevelInfo){.level = UNDEF,
594 .cache_type = CPU_FEATURE_CACHE_TLB,
595 .cache_size = 4 * KiB,
596 .ways = UNDEF,
597 .line_size = UNDEF,
598 .tlb_entries = 256,
599 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300600 case 0x55:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100601 return (CacheLevelInfo){.level = UNDEF,
602 .cache_type = CPU_FEATURE_CACHE_TLB,
603 .cache_size = 2 * MiB,
604 .ways = 0xFF,
605 .line_size = UNDEF,
606 .tlb_entries = 7,
607 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300608 case 0x56:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100609 return (CacheLevelInfo){.level = UNDEF,
610 .cache_type = CPU_FEATURE_CACHE_TLB,
611 .cache_size = 4 * MiB,
612 .ways = 4,
613 .line_size = UNDEF,
614 .tlb_entries = 16,
615 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300616 case 0x57:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100617 return (CacheLevelInfo){.level = UNDEF,
618 .cache_type = CPU_FEATURE_CACHE_TLB,
619 .cache_size = 4 * KiB,
620 .ways = 4,
621 .line_size = UNDEF,
622 .tlb_entries = 16,
623 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300624 case 0x59:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100625 return (CacheLevelInfo){.level = UNDEF,
626 .cache_type = CPU_FEATURE_CACHE_TLB,
627 .cache_size = 4 * KiB,
628 .ways = 0xFF,
629 .line_size = UNDEF,
630 .tlb_entries = 16,
631 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300632 case 0x5A:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100633 return (CacheLevelInfo){.level = UNDEF,
634 .cache_type = CPU_FEATURE_CACHE_TLB,
635 .cache_size = 2 * MiB,
636 .ways = 4,
637 .line_size = UNDEF,
638 .tlb_entries = 32,
639 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300640 case 0x5B:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100641 return (CacheLevelInfo){.level = UNDEF,
642 .cache_type = CPU_FEATURE_CACHE_TLB,
643 .cache_size = 4 * KiB,
644 .ways = UNDEF,
645 .line_size = UNDEF,
646 .tlb_entries = 64,
647 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300648 case 0x5C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100649 return (CacheLevelInfo){.level = UNDEF,
650 .cache_type = CPU_FEATURE_CACHE_TLB,
651 .cache_size = 4 * KiB,
652 .ways = UNDEF,
653 .line_size = UNDEF,
654 .tlb_entries = 128,
655 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300656 case 0x5D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100657 return (CacheLevelInfo){.level = UNDEF,
658 .cache_type = CPU_FEATURE_CACHE_TLB,
659 .cache_size = 4,
660 .ways = UNDEF,
661 .line_size = UNDEF,
662 .tlb_entries = 256,
663 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300664 case 0x60:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100665 return (CacheLevelInfo){.level = 1,
666 .cache_type = CPU_FEATURE_CACHE_DATA,
667 .cache_size = 16 * KiB,
668 .ways = 8,
669 .line_size = 64,
670 .tlb_entries = UNDEF,
671 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300672 case 0x61:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100673 return (CacheLevelInfo){.level = UNDEF,
674 .cache_type = CPU_FEATURE_CACHE_TLB,
675 .cache_size = 4 * KiB,
676 .ways = 0xFF,
677 .line_size = UNDEF,
678 .tlb_entries = 48,
679 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300680 case 0x63:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100681 return (CacheLevelInfo){.level = UNDEF,
682 .cache_type = CPU_FEATURE_CACHE_TLB,
683 .cache_size = 2 * MiB,
684 .ways = 4,
685 .line_size = UNDEF,
686 .tlb_entries = 4,
687 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300688 case 0x66:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100689 return (CacheLevelInfo){.level = 1,
690 .cache_type = CPU_FEATURE_CACHE_DATA,
691 .cache_size = 8 * KiB,
692 .ways = 4,
693 .line_size = 64,
694 .tlb_entries = UNDEF,
695 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300696 case 0x67:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100697 return (CacheLevelInfo){.level = 1,
698 .cache_type = CPU_FEATURE_CACHE_DATA,
699 .cache_size = 16 * KiB,
700 .ways = 4,
701 .line_size = 64,
702 .tlb_entries = UNDEF,
703 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300704 case 0x68:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100705 return (CacheLevelInfo){.level = 1,
706 .cache_type = CPU_FEATURE_CACHE_DATA,
707 .cache_size = 32 * KiB,
708 .ways = 4,
709 .line_size = 64,
710 .tlb_entries = UNDEF,
711 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300712 case 0x70:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100713 return (CacheLevelInfo){.level = 1,
714 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
715 .cache_size = 12 * KiB,
716 .ways = 8,
717 .line_size = UNDEF,
718 .tlb_entries = UNDEF,
719 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300720 case 0x71:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100721 return (CacheLevelInfo){.level = 1,
722 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
723 .cache_size = 16 * KiB,
724 .ways = 8,
725 .line_size = UNDEF,
726 .tlb_entries = UNDEF,
727 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300728 case 0x72:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100729 return (CacheLevelInfo){.level = 1,
730 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
731 .cache_size = 32 * KiB,
732 .ways = 8,
733 .line_size = UNDEF,
734 .tlb_entries = UNDEF,
735 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300736 case 0x76:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100737 return (CacheLevelInfo){.level = UNDEF,
738 .cache_type = CPU_FEATURE_CACHE_TLB,
739 .cache_size = 2 * MiB,
740 .ways = 0xFF,
741 .line_size = UNDEF,
742 .tlb_entries = 8,
743 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300744 case 0x78:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100745 return (CacheLevelInfo){.level = 2,
746 .cache_type = CPU_FEATURE_CACHE_DATA,
747 .cache_size = 1 * MiB,
748 .ways = 4,
749 .line_size = 64,
750 .tlb_entries = UNDEF,
751 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300752 case 0x79:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100753 return (CacheLevelInfo){.level = 2,
754 .cache_type = CPU_FEATURE_CACHE_DATA,
755 .cache_size = 128 * KiB,
756 .ways = 8,
757 .line_size = 64,
758 .tlb_entries = UNDEF,
759 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300760 case 0x7A:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100761 return (CacheLevelInfo){.level = 2,
762 .cache_type = CPU_FEATURE_CACHE_DATA,
763 .cache_size = 256 * KiB,
764 .ways = 8,
765 .line_size = 64,
766 .tlb_entries = UNDEF,
767 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300768 case 0x7B:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100769 return (CacheLevelInfo){.level = 2,
770 .cache_type = CPU_FEATURE_CACHE_DATA,
771 .cache_size = 512 * KiB,
772 .ways = 8,
773 .line_size = 64,
774 .tlb_entries = UNDEF,
775 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300776 case 0x7C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100777 return (CacheLevelInfo){.level = 2,
778 .cache_type = CPU_FEATURE_CACHE_DATA,
779 .cache_size = 1 * MiB,
780 .ways = 8,
781 .line_size = 64,
782 .tlb_entries = UNDEF,
783 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300784 case 0x7D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100785 return (CacheLevelInfo){.level = 2,
786 .cache_type = CPU_FEATURE_CACHE_DATA,
787 .cache_size = 2 * MiB,
788 .ways = 8,
789 .line_size = 64,
790 .tlb_entries = UNDEF,
791 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300792 case 0x7F:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100793 return (CacheLevelInfo){.level = 2,
794 .cache_type = CPU_FEATURE_CACHE_DATA,
795 .cache_size = 512 * KiB,
796 .ways = 2,
797 .line_size = 64,
798 .tlb_entries = UNDEF,
799 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300800 case 0x80:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100801 return (CacheLevelInfo){.level = 2,
802 .cache_type = CPU_FEATURE_CACHE_DATA,
803 .cache_size = 512 * KiB,
804 .ways = 8,
805 .line_size = 64,
806 .tlb_entries = UNDEF,
807 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300808 case 0x82:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100809 return (CacheLevelInfo){.level = 2,
810 .cache_type = CPU_FEATURE_CACHE_DATA,
811 .cache_size = 256 * KiB,
812 .ways = 8,
813 .line_size = 32,
814 .tlb_entries = UNDEF,
815 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300816 case 0x83:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100817 return (CacheLevelInfo){.level = 2,
818 .cache_type = CPU_FEATURE_CACHE_DATA,
819 .cache_size = 512 * KiB,
820 .ways = 8,
821 .line_size = 32,
822 .tlb_entries = UNDEF,
823 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300824 case 0x84:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100825 return (CacheLevelInfo){.level = 2,
826 .cache_type = CPU_FEATURE_CACHE_DATA,
827 .cache_size = 1 * MiB,
828 .ways = 8,
829 .line_size = 32,
830 .tlb_entries = UNDEF,
831 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300832 case 0x85:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100833 return (CacheLevelInfo){.level = 2,
834 .cache_type = CPU_FEATURE_CACHE_DATA,
835 .cache_size = 2 * MiB,
836 .ways = 8,
837 .line_size = 32,
838 .tlb_entries = UNDEF,
839 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300840 case 0x86:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100841 return (CacheLevelInfo){.level = 2,
842 .cache_type = CPU_FEATURE_CACHE_DATA,
843 .cache_size = 512 * KiB,
844 .ways = 4,
845 .line_size = 32,
846 .tlb_entries = UNDEF,
847 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300848 case 0x87:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100849 return (CacheLevelInfo){.level = 2,
850 .cache_type = CPU_FEATURE_CACHE_DATA,
851 .cache_size = 1 * MiB,
852 .ways = 8,
853 .line_size = 64,
854 .tlb_entries = UNDEF,
855 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300856 case 0xA0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100857 return (CacheLevelInfo){.level = UNDEF,
858 .cache_type = CPU_FEATURE_CACHE_DTLB,
859 .cache_size = 4 * KiB,
860 .ways = 0xFF,
861 .line_size = UNDEF,
862 .tlb_entries = 32,
863 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300864 case 0xB0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100865 return (CacheLevelInfo){.level = UNDEF,
866 .cache_type = CPU_FEATURE_CACHE_TLB,
867 .cache_size = 4 * KiB,
868 .ways = 4,
869 .line_size = UNDEF,
870 .tlb_entries = 128,
871 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300872 case 0xB1:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100873 return (CacheLevelInfo){.level = UNDEF,
874 .cache_type = CPU_FEATURE_CACHE_TLB,
875 .cache_size = 2 * MiB,
876 .ways = 4,
877 .line_size = UNDEF,
878 .tlb_entries = 8,
879 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300880 case 0xB2:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100881 return (CacheLevelInfo){.level = UNDEF,
882 .cache_type = CPU_FEATURE_CACHE_TLB,
883 .cache_size = 4 * KiB,
884 .ways = 4,
885 .line_size = UNDEF,
886 .tlb_entries = 64,
887 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300888 case 0xB3:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100889 return (CacheLevelInfo){.level = UNDEF,
890 .cache_type = CPU_FEATURE_CACHE_TLB,
891 .cache_size = 4 * KiB,
892 .ways = 4,
893 .line_size = UNDEF,
894 .tlb_entries = 128,
895 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300896 case 0xB4:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100897 return (CacheLevelInfo){.level = UNDEF,
898 .cache_type = CPU_FEATURE_CACHE_TLB,
899 .cache_size = 4 * KiB,
900 .ways = 4,
901 .line_size = UNDEF,
902 .tlb_entries = 256,
903 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300904 case 0xB5:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100905 return (CacheLevelInfo){.level = UNDEF,
906 .cache_type = CPU_FEATURE_CACHE_TLB,
907 .cache_size = 4 * KiB,
908 .ways = 8,
909 .line_size = UNDEF,
910 .tlb_entries = 64,
911 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300912 case 0xB6:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100913 return (CacheLevelInfo){.level = UNDEF,
914 .cache_type = CPU_FEATURE_CACHE_TLB,
915 .cache_size = 4 * KiB,
916 .ways = 8,
917 .line_size = UNDEF,
918 .tlb_entries = 128,
919 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300920 case 0xBA:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100921 return (CacheLevelInfo){.level = UNDEF,
922 .cache_type = CPU_FEATURE_CACHE_TLB,
923 .cache_size = 4 * KiB,
924 .ways = 4,
925 .line_size = UNDEF,
926 .tlb_entries = 64,
927 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300928 case 0xC0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100929 return (CacheLevelInfo){.level = UNDEF,
930 .cache_type = CPU_FEATURE_CACHE_TLB,
931 .cache_size = 4 * KiB,
932 .ways = 4,
933 .line_size = UNDEF,
934 .tlb_entries = 8,
935 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300936 case 0xC1:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100937 return (CacheLevelInfo){.level = UNDEF,
938 .cache_type = CPU_FEATURE_CACHE_STLB,
939 .cache_size = 4 * KiB,
940 .ways = 8,
941 .line_size = UNDEF,
942 .tlb_entries = 1024,
943 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300944 case 0xC2:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100945 return (CacheLevelInfo){.level = UNDEF,
946 .cache_type = CPU_FEATURE_CACHE_DTLB,
947 .cache_size = 4 * KiB,
948 .ways = 4,
949 .line_size = UNDEF,
950 .tlb_entries = 16,
951 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300952 case 0xC3:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100953 return (CacheLevelInfo){.level = UNDEF,
954 .cache_type = CPU_FEATURE_CACHE_STLB,
955 .cache_size = 4 * KiB,
956 .ways = 6,
957 .line_size = UNDEF,
958 .tlb_entries = 1536,
959 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300960 case 0xCA:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100961 return (CacheLevelInfo){.level = UNDEF,
962 .cache_type = CPU_FEATURE_CACHE_STLB,
963 .cache_size = 4 * KiB,
964 .ways = 4,
965 .line_size = UNDEF,
966 .tlb_entries = 512,
967 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300968 case 0xD0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100969 return (CacheLevelInfo){.level = 3,
970 .cache_type = CPU_FEATURE_CACHE_DATA,
971 .cache_size = 512 * KiB,
972 .ways = 4,
973 .line_size = 64,
974 .tlb_entries = UNDEF,
975 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300976 case 0xD1:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100977 return (CacheLevelInfo){.level = 3,
978 .cache_type = CPU_FEATURE_CACHE_DATA,
979 .cache_size = 1 * MiB,
980 .ways = 4,
981 .line_size = 64,
982 .tlb_entries = UNDEF,
983 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300984 case 0xD2:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100985 return (CacheLevelInfo){.level = 3,
986 .cache_type = CPU_FEATURE_CACHE_DATA,
987 .cache_size = 2 * MiB,
988 .ways = 4,
989 .line_size = 64,
990 .tlb_entries = UNDEF,
991 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300992 case 0xD6:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100993 return (CacheLevelInfo){.level = 3,
994 .cache_type = CPU_FEATURE_CACHE_DATA,
995 .cache_size = 1 * MiB,
996 .ways = 8,
997 .line_size = 64,
998 .tlb_entries = UNDEF,
999 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001000 case 0xD7:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001001 return (CacheLevelInfo){.level = 3,
1002 .cache_type = CPU_FEATURE_CACHE_DATA,
1003 .cache_size = 2 * MiB,
1004 .ways = 8,
1005 .line_size = 64,
1006 .tlb_entries = UNDEF,
1007 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001008 case 0xD8:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001009 return (CacheLevelInfo){.level = 3,
1010 .cache_type = CPU_FEATURE_CACHE_DATA,
1011 .cache_size = 4 * MiB,
1012 .ways = 8,
1013 .line_size = 64,
1014 .tlb_entries = UNDEF,
1015 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001016 case 0xDC:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001017 return (CacheLevelInfo){.level = 3,
1018 .cache_type = CPU_FEATURE_CACHE_DATA,
1019 .cache_size = 1 * 1536 * KiB,
1020 .ways = 12,
1021 .line_size = 64,
1022 .tlb_entries = UNDEF,
1023 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001024 case 0xDD:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001025 return (CacheLevelInfo){.level = 3,
1026 .cache_type = CPU_FEATURE_CACHE_DATA,
1027 .cache_size = 3 * MiB,
1028 .ways = 12,
1029 .line_size = 64,
1030 .tlb_entries = UNDEF,
1031 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001032 case 0xDE:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001033 return (CacheLevelInfo){.level = 3,
1034 .cache_type = CPU_FEATURE_CACHE_DATA,
1035 .cache_size = 6 * MiB,
1036 .ways = 12,
1037 .line_size = 64,
1038 .tlb_entries = UNDEF,
1039 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001040 case 0xE2:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001041 return (CacheLevelInfo){.level = 3,
1042 .cache_type = CPU_FEATURE_CACHE_DATA,
1043 .cache_size = 2 * MiB,
1044 .ways = 16,
1045 .line_size = 64,
1046 .tlb_entries = UNDEF,
1047 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001048 case 0xE3:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001049 return (CacheLevelInfo){.level = 3,
1050 .cache_type = CPU_FEATURE_CACHE_DATA,
1051 .cache_size = 4 * MiB,
1052 .ways = 16,
1053 .line_size = 64,
1054 .tlb_entries = UNDEF,
1055 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001056 case 0xE4:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001057 return (CacheLevelInfo){.level = 3,
1058 .cache_type = CPU_FEATURE_CACHE_DATA,
1059 .cache_size = 8 * MiB,
1060 .ways = 16,
1061 .line_size = 64,
1062 .tlb_entries = UNDEF,
1063 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001064 case 0xEA:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001065 return (CacheLevelInfo){.level = 3,
1066 .cache_type = CPU_FEATURE_CACHE_DATA,
1067 .cache_size = 12 * MiB,
1068 .ways = 24,
1069 .line_size = 64,
1070 .tlb_entries = UNDEF,
1071 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001072 case 0xEB:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001073 return (CacheLevelInfo){.level = 3,
1074 .cache_type = CPU_FEATURE_CACHE_DATA,
1075 .cache_size = 18 * MiB,
1076 .ways = 24,
1077 .line_size = 64,
1078 .tlb_entries = UNDEF,
1079 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001080 case 0xEC:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001081 return (CacheLevelInfo){.level = 3,
1082 .cache_type = CPU_FEATURE_CACHE_DATA,
1083 .cache_size = 24 * MiB,
1084 .ways = 24,
1085 .line_size = 64,
1086 .tlb_entries = UNDEF,
1087 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001088 case 0xF0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001089 return (CacheLevelInfo){.level = UNDEF,
1090 .cache_type = CPU_FEATURE_CACHE_PREFETCH,
1091 .cache_size = 64 * KiB,
1092 .ways = UNDEF,
1093 .line_size = UNDEF,
1094 .tlb_entries = UNDEF,
1095 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001096 case 0xF1:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001097 return (CacheLevelInfo){.level = UNDEF,
1098 .cache_type = CPU_FEATURE_CACHE_PREFETCH,
1099 .cache_size = 128 * KiB,
1100 .ways = UNDEF,
1101 .line_size = UNDEF,
1102 .tlb_entries = UNDEF,
1103 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001104 case 0xFF:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001105 return (CacheLevelInfo){.level = UNDEF,
1106 .cache_type = CPU_FEATURE_CACHE_NULL,
1107 .cache_size = UNDEF,
1108 .ways = UNDEF,
1109 .line_size = UNDEF,
1110 .tlb_entries = UNDEF,
1111 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001112 default:
1113 return kEmptyCacheLevelInfo;
1114 }
1115}
1116
1117static void GetByteArrayFromRegister(uint32_t result[4], const uint32_t reg) {
1118 for (int i = 0; i < 4; ++i) {
1119 result[i] = ExtractBitRange(reg, (i + 1) * 8, i * 8);
1120 }
1121}
1122
1123static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) {
1124 Leaf leaf = SafeCpuId(max_cpuid_leaf, 2);
1125 uint32_t registers[] = {leaf.eax, leaf.ebx, leaf.ecx, leaf.edx};
1126 for (int i = 0; i < 4; ++i) {
Guillaume Chatelet8a6fd872019-11-13 14:39:06 +01001127 if (registers[i] & (1U << 31)) {
Artem Alekseev653d5812019-07-02 17:52:25 +03001128 continue; // register does not contains valid information
1129 }
1130 uint32_t bytes[4];
1131 GetByteArrayFromRegister(bytes, registers[i]);
Guillaume Chateletbe306b72019-11-13 11:15:40 +01001132 for (int j = 0; j < 4; ++j) {
1133 if (bytes[j] == 0xFF)
Artem Alekseev653d5812019-07-02 17:52:25 +03001134 break; // leaf 4 should be used to fetch cache information
Guillaume Chateletbe306b72019-11-13 11:15:40 +01001135 info->levels[info->size] = GetCacheLevelInfo(bytes[j]);
Artem Alekseev653d5812019-07-02 17:52:25 +03001136 }
1137 info->size++;
1138 }
1139}
1140
1141static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info) {
1142 info->size = 0;
1143 for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++) {
1144 const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, 4, cache_id);
1145 CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0);
1146 if (cache_type == CPU_FEATURE_CACHE_NULL) {
1147 info->levels[cache_id] = kEmptyCacheLevelInfo;
1148 continue;
1149 }
1150 int level = ExtractBitRange(leaf.eax, 7, 5);
1151 int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
1152 int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
1153 int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1;
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001154 int tlb_entries = leaf.ecx + 1;
1155 int cache_size = (ways * partitioning * line_size * (tlb_entries));
1156 info->levels[cache_id] = (CacheLevelInfo){.level = level,
1157 .cache_type = cache_type,
1158 .cache_size = cache_size,
1159 .ways = ways,
1160 .line_size = line_size,
1161 .tlb_entries = tlb_entries,
1162 .partitioning = partitioning};
Artem Alekseev653d5812019-07-02 17:52:25 +03001163 info->size++;
1164 }
1165}
1166
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001167// Internal structure to hold the OS support for vector operations.
1168// Avoid to recompute them since each call to cpuid is ~100 cycles.
1169typedef struct {
Guillaume Chatelet47953732020-10-09 17:20:25 +02001170 bool have_sse_via_os;
1171 bool have_sse_via_cpuid;
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001172 bool have_avx;
1173 bool have_avx512;
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001174 bool have_amx;
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001175} OsSupport;
1176
Guillaume Chatelet47953732020-10-09 17:20:25 +02001177static const OsSupport kEmptyOsSupport;
1178
1179static OsSupport CheckOsSupport(const uint32_t max_cpuid_leaf) {
1180 const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
1181 const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
1182 const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
1183 const bool have_xcr0 = have_xsave && have_osxsave;
1184
1185 OsSupport os_support = kEmptyOsSupport;
1186
1187 if (have_xcr0) {
1188 // AVX capable cpu will expose XCR0.
1189 const uint32_t xcr0_eax = GetXCR0Eax();
1190 os_support.have_sse_via_cpuid = HasXmmOsXSave(xcr0_eax);
1191 os_support.have_avx = HasYmmOsXSave(xcr0_eax);
1192 os_support.have_avx512 = HasZmmOsXSave(xcr0_eax);
1193 os_support.have_amx = HasTmmOsXSave(xcr0_eax);
1194 } else {
1195 // Atom based or older cpus need to ask the OS for sse support.
1196 os_support.have_sse_via_os = true;
1197 }
1198
1199 return os_support;
1200}
1201
1202#if defined(CPU_FEATURES_OS_WINDOWS)
1203#if defined(CPU_FEATURES_MOCK_CPUID_X86)
1204extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
1205#else // CPU_FEATURES_MOCK_CPUID_X86
1206static bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
1207 return IsProcessorFeaturePresent(ProcessorFeature);
1208}
1209#endif
1210#endif // CPU_FEATURES_OS_WINDOWS
1211
Guillaume Chatelete63405f2020-10-09 22:40:06 +02001212#if defined(CPU_FEATURES_OS_DARWIN)
Guillaume Chatelet47953732020-10-09 17:20:25 +02001213#if defined(CPU_FEATURES_MOCK_CPUID_X86)
1214extern bool GetDarwinSysCtlByName(const char*);
1215#else // CPU_FEATURES_MOCK_CPUID_X86
1216static bool GetDarwinSysCtlByName(const char* name) {
1217 int enabled;
1218 size_t enabled_len = sizeof(enabled);
1219 const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0);
1220 return failure ? false : enabled;
1221}
1222#endif
Guillaume Chatelete63405f2020-10-09 22:40:06 +02001223#endif // CPU_FEATURES_OS_DARWIN
Guillaume Chatelet47953732020-10-09 17:20:25 +02001224
1225static void DetectSseViaOs(X86Features* features) {
1226#if defined(CPU_FEATURES_OS_WINDOWS)
1227 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
1228 features->sse =
1229 GetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
1230 features->sse2 =
1231 GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
1232 features->sse3 =
1233 GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
Guillaume Chatelete63405f2020-10-09 22:40:06 +02001234#elif defined(CPU_FEATURES_OS_DARWIN)
1235 // Handling Darwin platform through sysctlbyname.
1236 features->sse = GetDarwinSysCtlByName("hw.optional.sse");
1237 features->sse2 = GetDarwinSysCtlByName("hw.optional.sse2");
1238 features->sse3 = GetDarwinSysCtlByName("hw.optional.sse3");
1239 features->ssse3 = GetDarwinSysCtlByName("hw.optional.supplementalsse3");
1240 features->sse4_1 = GetDarwinSysCtlByName("hw.optional.sse4_1");
1241 features->sse4_2 = GetDarwinSysCtlByName("hw.optional.sse4_2");
Guillaume Chatelet47953732020-10-09 17:20:25 +02001242#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
Guillaume Chatelete63405f2020-10-09 22:40:06 +02001243 // Handling Linux platform through /proc/cpuinfo.
1244 const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
1245 if (fd >= 0) {
1246 StackLineReader reader;
1247 StackLineReader_Initialize(&reader, fd);
1248 for (;;) {
1249 const LineResult result = StackLineReader_NextLine(&reader);
1250 const StringView line = result.line;
1251 StringView key, value;
1252 if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
1253 if (CpuFeatures_StringView_IsEquals(key, str("flags"))) {
1254 features->sse = CpuFeatures_StringView_HasWord(value, "sse");
1255 features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2");
1256 features->sse3 = CpuFeatures_StringView_HasWord(value, "sse3");
1257 features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3");
1258 features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1");
1259 features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2");
1260 break;
Guillaume Chatelet47953732020-10-09 17:20:25 +02001261 }
Guillaume Chatelet47953732020-10-09 17:20:25 +02001262 }
Guillaume Chatelete63405f2020-10-09 22:40:06 +02001263 if (result.eof) break;
Guillaume Chatelet47953732020-10-09 17:20:25 +02001264 }
Guillaume Chatelete63405f2020-10-09 22:40:06 +02001265 CpuFeatures_CloseFile(fd);
Guillaume Chatelet47953732020-10-09 17:20:25 +02001266 }
Guillaume Chatelete63405f2020-10-09 22:40:06 +02001267#else
Guillaume Chatelet47953732020-10-09 17:20:25 +02001268#error "Unsupported fallback detection of SSE OS support."
1269#endif
1270}
1271
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001272// Reference https://en.wikipedia.org/wiki/CPUID.
Guillaume Chatelet47953732020-10-09 17:20:25 +02001273static void ParseCpuId(const uint32_t max_cpuid_leaf,
1274 const OsSupport os_support, X86Info* info) {
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001275 const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
1276 const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001277 const Leaf leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 7, 1);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001278
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001279 const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
1280 const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
1281 const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4);
1282 const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16);
1283
1284 X86Features* const features = &info->features;
1285
1286 info->family = extended_family + family;
1287 info->model = (extended_model << 4) + model;
1288 info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
1289
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001290 features->fpu = IsBitSet(leaf_1.edx, 0);
1291 features->tsc = IsBitSet(leaf_1.edx, 4);
1292 features->cx8 = IsBitSet(leaf_1.edx, 8);
1293 features->clfsh = IsBitSet(leaf_1.edx, 19);
1294 features->mmx = IsBitSet(leaf_1.edx, 23);
Artem Alekseev3ee4a9e2019-06-19 16:06:05 +03001295 features->ss = IsBitSet(leaf_1.edx, 27);
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001296 features->pclmulqdq = IsBitSet(leaf_1.ecx, 1);
Patrik Fiedler0f1f3ac2018-02-13 11:44:40 +01001297 features->smx = IsBitSet(leaf_1.ecx, 6);
Guillaume Chatelet9b872ce2018-03-13 10:58:42 +01001298 features->cx16 = IsBitSet(leaf_1.ecx, 13);
Artem Alekseev3ee4a9e2019-06-19 16:06:05 +03001299 features->dca = IsBitSet(leaf_1.ecx, 18);
Guillaume Chateletd395dfa2019-01-22 13:19:42 +01001300 features->movbe = IsBitSet(leaf_1.ecx, 22);
1301 features->popcnt = IsBitSet(leaf_1.ecx, 23);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001302 features->aes = IsBitSet(leaf_1.ecx, 25);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001303 features->f16c = IsBitSet(leaf_1.ecx, 29);
Guillaume Chateletd395dfa2019-01-22 13:19:42 +01001304 features->rdrnd = IsBitSet(leaf_1.ecx, 30);
Patrik Fiedler0f1f3ac2018-02-13 11:44:40 +01001305 features->sgx = IsBitSet(leaf_7.ebx, 2);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001306 features->bmi1 = IsBitSet(leaf_7.ebx, 3);
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001307 features->hle = IsBitSet(leaf_7.ebx, 4);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001308 features->bmi2 = IsBitSet(leaf_7.ebx, 8);
Patrik Fiedler0f1f3ac2018-02-13 11:44:40 +01001309 features->erms = IsBitSet(leaf_7.ebx, 9);
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001310 features->rtm = IsBitSet(leaf_7.ebx, 11);
1311 features->rdseed = IsBitSet(leaf_7.ebx, 18);
1312 features->clflushopt = IsBitSet(leaf_7.ebx, 23);
1313 features->clwb = IsBitSet(leaf_7.ebx, 24);
Guillaume Chateletd395dfa2019-01-22 13:19:42 +01001314 features->sha = IsBitSet(leaf_7.ebx, 29);
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001315 features->vaes = IsBitSet(leaf_7.ecx, 9);
Guillaume Chatelet11e3e202018-02-09 08:55:11 +01001316 features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001317
Guillaume Chatelet47953732020-10-09 17:20:25 +02001318 if (os_support.have_sse_via_os) {
1319 DetectSseViaOs(features);
1320 } else if (os_support.have_sse_via_cpuid) {
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001321 features->sse = IsBitSet(leaf_1.edx, 25);
1322 features->sse2 = IsBitSet(leaf_1.edx, 26);
1323 features->sse3 = IsBitSet(leaf_1.ecx, 0);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001324 features->ssse3 = IsBitSet(leaf_1.ecx, 9);
1325 features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
1326 features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
1327 }
1328
Guillaume Chatelet47953732020-10-09 17:20:25 +02001329 if (os_support.have_avx) {
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001330 features->fma3 = IsBitSet(leaf_1.ecx, 12);
1331 features->avx = IsBitSet(leaf_1.ecx, 28);
1332 features->avx2 = IsBitSet(leaf_7.ebx, 5);
1333 }
1334
Guillaume Chatelet47953732020-10-09 17:20:25 +02001335 if (os_support.have_avx512) {
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001336 features->avx512f = IsBitSet(leaf_7.ebx, 16);
1337 features->avx512cd = IsBitSet(leaf_7.ebx, 28);
1338 features->avx512er = IsBitSet(leaf_7.ebx, 27);
1339 features->avx512pf = IsBitSet(leaf_7.ebx, 26);
1340 features->avx512bw = IsBitSet(leaf_7.ebx, 30);
1341 features->avx512dq = IsBitSet(leaf_7.ebx, 17);
1342 features->avx512vl = IsBitSet(leaf_7.ebx, 31);
1343 features->avx512ifma = IsBitSet(leaf_7.ebx, 21);
1344 features->avx512vbmi = IsBitSet(leaf_7.ecx, 1);
1345 features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6);
1346 features->avx512vnni = IsBitSet(leaf_7.ecx, 11);
1347 features->avx512bitalg = IsBitSet(leaf_7.ecx, 12);
1348 features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
1349 features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
Jeff Hammond17ffb652020-09-22 00:29:46 -07001350 features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
1351 features->avx512_second_fma = HasSecondFMA(info->model);
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001352 features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3);
1353 features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5);
1354 features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8);
1355 }
1356
Guillaume Chatelet47953732020-10-09 17:20:25 +02001357 if (os_support.have_amx) {
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001358 features->amx_bf16 = IsBitSet(leaf_7.edx, 22);
1359 features->amx_tile = IsBitSet(leaf_7.edx, 24);
1360 features->amx_int8 = IsBitSet(leaf_7.edx, 25);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001361 }
1362}
1363
Jeff Hammond17ffb652020-09-22 00:29:46 -07001364// Reference
1365// https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
Guillaume Chatelet76dafc72020-09-21 14:54:13 +02001366static void ParseExtraAMDCpuId(X86Info* info, OsSupport os_support) {
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001367 const Leaf leaf_80000000 = CpuId(0x80000000);
Guillaume Chatelet76dafc72020-09-21 14:54:13 +02001368 const uint32_t max_extended_cpuid_leaf = leaf_80000000.eax;
1369 const Leaf leaf_80000001 = SafeCpuId(max_extended_cpuid_leaf, 0x80000001);
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001370
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001371 X86Features* const features = &info->features;
1372
Guillaume Chatelet47953732020-10-09 17:20:25 +02001373 if (os_support.have_sse_via_cpuid) {
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001374 features->sse4a = IsBitSet(leaf_80000001.ecx, 6);
1375 }
1376
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001377 if (os_support.have_avx) {
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001378 features->fma4 = IsBitSet(leaf_80000001.ecx, 16);
1379 }
1380}
1381
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001382static const X86Info kEmptyX86Info;
Artem Alekseev653d5812019-07-02 17:52:25 +03001383static const CacheInfo kEmptyCacheInfo;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001384
1385X86Info GetX86Info(void) {
1386 X86Info info = kEmptyX86Info;
1387 const Leaf leaf_0 = CpuId(0);
Guillaume Chatelet76dafc72020-09-21 14:54:13 +02001388 const bool is_intel = IsVendor(leaf_0, "GenuineIntel");
1389 const bool is_amd = IsVendor(leaf_0, "AuthenticAMD");
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001390 SetVendor(leaf_0, info.vendor);
Guillaume Chatelet76dafc72020-09-21 14:54:13 +02001391 if (is_intel || is_amd) {
1392 const uint32_t max_cpuid_leaf = leaf_0.eax;
Guillaume Chatelet47953732020-10-09 17:20:25 +02001393 const OsSupport os_support = CheckOsSupport(max_cpuid_leaf);
1394 ParseCpuId(max_cpuid_leaf, os_support, &info);
1395 if (is_amd) {
1396 ParseExtraAMDCpuId(&info, os_support);
1397 }
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001398 }
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001399 return info;
1400}
1401
Artem Alekseev653d5812019-07-02 17:52:25 +03001402CacheInfo GetX86CacheInfo(void) {
1403 CacheInfo info = kEmptyCacheInfo;
1404 const Leaf leaf_0 = CpuId(0);
1405 const uint32_t max_cpuid_leaf = leaf_0.eax;
1406 if (IsVendor(leaf_0, "GenuineIntel")) {
1407 ParseLeaf2(max_cpuid_leaf, &info);
1408 ParseLeaf4(max_cpuid_leaf, &info);
1409 }
1410 return info;
1411}
1412
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +01001413#define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF))
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001414
1415X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
1416 if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) {
1417 switch (CPUID(info->family, info->model)) {
1418 case CPUID(0x06, 0x35):
1419 case CPUID(0x06, 0x36):
1420 // https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)
1421 return INTEL_ATOM_BNL;
1422 case CPUID(0x06, 0x37):
1423 case CPUID(0x06, 0x4C):
1424 // https://en.wikipedia.org/wiki/Silvermont
1425 return INTEL_ATOM_SMT;
1426 case CPUID(0x06, 0x5C):
1427 // https://en.wikipedia.org/wiki/Goldmont
1428 return INTEL_ATOM_GMT;
1429 case CPUID(0x06, 0x0F):
1430 case CPUID(0x06, 0x16):
1431 // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
1432 return INTEL_CORE;
1433 case CPUID(0x06, 0x17):
1434 case CPUID(0x06, 0x1D):
1435 // https://en.wikipedia.org/wiki/Penryn_(microarchitecture)
1436 return INTEL_PNR;
1437 case CPUID(0x06, 0x1A):
1438 case CPUID(0x06, 0x1E):
1439 case CPUID(0x06, 0x1F):
1440 case CPUID(0x06, 0x2E):
1441 // https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)
1442 return INTEL_NHM;
1443 case CPUID(0x06, 0x25):
1444 case CPUID(0x06, 0x2C):
1445 case CPUID(0x06, 0x2F):
1446 // https://en.wikipedia.org/wiki/Westmere_(microarchitecture)
1447 return INTEL_WSM;
1448 case CPUID(0x06, 0x2A):
1449 case CPUID(0x06, 0x2D):
1450 // https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings
1451 return INTEL_SNB;
1452 case CPUID(0x06, 0x3A):
1453 case CPUID(0x06, 0x3E):
1454 // https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings
1455 return INTEL_IVB;
1456 case CPUID(0x06, 0x3C):
1457 case CPUID(0x06, 0x3F):
1458 case CPUID(0x06, 0x45):
1459 case CPUID(0x06, 0x46):
1460 // https://en.wikipedia.org/wiki/Haswell_(microarchitecture)
1461 return INTEL_HSW;
1462 case CPUID(0x06, 0x3D):
1463 case CPUID(0x06, 0x47):
1464 case CPUID(0x06, 0x4F):
1465 case CPUID(0x06, 0x56):
1466 // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
1467 return INTEL_BDW;
1468 case CPUID(0x06, 0x4E):
1469 case CPUID(0x06, 0x55):
1470 case CPUID(0x06, 0x5E):
1471 // https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
1472 return INTEL_SKL;
Moxeja73a121b2020-01-05 13:15:12 +00001473 case CPUID(0x06, 0x66):
1474 // https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture)
1475 return INTEL_CNL;
Jeff Hammond17ffb652020-09-22 00:29:46 -07001476 case CPUID(0x06, 0x7D): // client
1477 case CPUID(0x06, 0x7E): // client
1478 case CPUID(0x06, 0x9D): // NNP-I
1479 case CPUID(0x06, 0x6A): // server
1480 case CPUID(0x06, 0x6C): // server
Moxeja73a121b2020-01-05 13:15:12 +00001481 // https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor)
1482 return INTEL_ICL;
Jeff Hammonde6983272020-09-21 00:54:58 -07001483 case CPUID(0x06, 0x8C):
1484 case CPUID(0x06, 0x8D):
1485 // https://en.wikipedia.org/wiki/Tiger_Lake_(microarchitecture)
1486 return INTEL_TGL;
1487 case CPUID(0x06, 0x8F):
1488 // https://en.wikipedia.org/wiki/Sapphire_Rapids
1489 return INTEL_SPR;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001490 case CPUID(0x06, 0x8E):
Moxeja73a121b2020-01-05 13:15:12 +00001491 switch (info->stepping) {
Jeff Hammond17ffb652020-09-22 00:29:46 -07001492 case 9:
1493 return INTEL_KBL; // https://en.wikipedia.org/wiki/Kaby_Lake
1494 case 10:
1495 return INTEL_CFL; // https://en.wikipedia.org/wiki/Coffee_Lake
1496 case 11:
1497 return INTEL_WHL; // https://en.wikipedia.org/wiki/Whiskey_Lake_(microarchitecture)
1498 default:
1499 return X86_UNKNOWN;
Moxeja73a121b2020-01-05 13:15:12 +00001500 }
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001501 case CPUID(0x06, 0x9E):
Moxeja73a121b2020-01-05 13:15:12 +00001502 if (info->stepping > 9) {
1503 // https://en.wikipedia.org/wiki/Coffee_Lake
1504 return INTEL_CFL;
1505 } else {
1506 // https://en.wikipedia.org/wiki/Kaby_Lake
1507 return INTEL_KBL;
1508 }
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001509 default:
1510 return X86_UNKNOWN;
1511 }
1512 }
1513 if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) {
1514 switch (info->family) {
1515 // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
1516 case 0x0F:
1517 return AMD_HAMMER;
1518 case 0x10:
1519 return AMD_K10;
1520 case 0x14:
1521 return AMD_BOBCAT;
1522 case 0x15:
1523 return AMD_BULLDOZER;
1524 case 0x16:
1525 return AMD_JAGUAR;
1526 case 0x17:
1527 return AMD_ZEN;
1528 default:
1529 return X86_UNKNOWN;
1530 }
1531 }
1532 return X86_UNKNOWN;
1533}
1534
1535static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id,
1536 char* buffer) {
1537 const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id);
1538 // We allow calling memcpy from SetString which is only called when requesting
1539 // X86BrandString.
1540 memcpy(buffer, &leaf, sizeof(Leaf));
1541}
1542
1543void FillX86BrandString(char brand_string[49]) {
1544 const Leaf leaf_ext_0 = CpuId(0x80000000);
1545 const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
1546 SetString(max_cpuid_leaf_ext, 0x80000002, brand_string);
1547 SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16);
1548 SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32);
1549 brand_string[48] = '\0';
1550}
1551
1552////////////////////////////////////////////////////////////////////////////////
1553// Introspection functions
1554
1555int GetX86FeaturesEnumValue(const X86Features* features,
1556 X86FeaturesEnum value) {
Guillaume Chatelet9a8f04b2020-10-12 11:50:35 +02001557 if (value >= X86_LAST_) return false;
1558 return kGetters[value](features);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001559}
1560
1561const char* GetX86FeaturesEnumName(X86FeaturesEnum value) {
Guillaume Chatelet9a8f04b2020-10-12 11:50:35 +02001562 if (value >= X86_LAST_) return "unknown_feature";
1563 return kCpuInfoFlags[value];
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001564}
1565
1566const char* GetX86MicroarchitectureName(X86Microarchitecture uarch) {
1567 switch (uarch) {
1568 case X86_UNKNOWN:
1569 return "X86_UNKNOWN";
1570 case INTEL_CORE:
1571 return "INTEL_CORE";
1572 case INTEL_PNR:
1573 return "INTEL_PNR";
1574 case INTEL_NHM:
1575 return "INTEL_NHM";
1576 case INTEL_ATOM_BNL:
1577 return "INTEL_ATOM_BNL";
1578 case INTEL_WSM:
1579 return "INTEL_WSM";
1580 case INTEL_SNB:
1581 return "INTEL_SNB";
1582 case INTEL_IVB:
1583 return "INTEL_IVB";
1584 case INTEL_ATOM_SMT:
1585 return "INTEL_ATOM_SMT";
1586 case INTEL_HSW:
1587 return "INTEL_HSW";
1588 case INTEL_BDW:
1589 return "INTEL_BDW";
1590 case INTEL_SKL:
1591 return "INTEL_SKL";
1592 case INTEL_ATOM_GMT:
1593 return "INTEL_ATOM_GMT";
1594 case INTEL_KBL:
1595 return "INTEL_KBL";
1596 case INTEL_CFL:
1597 return "INTEL_CFL";
Moxeja24b8a1d2020-01-06 23:01:21 +00001598 case INTEL_WHL:
1599 return "INTEL_WHL";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001600 case INTEL_CNL:
1601 return "INTEL_CNL";
Moxeja24b8a1d2020-01-06 23:01:21 +00001602 case INTEL_ICL:
1603 return "INTEL_ICL";
Jeff Hammonde6983272020-09-21 00:54:58 -07001604 case INTEL_TGL:
1605 return "INTEL_TGL";
1606 case INTEL_SPR:
1607 return "INTEL_SPR";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001608 case AMD_HAMMER:
1609 return "AMD_HAMMER";
1610 case AMD_K10:
1611 return "AMD_K10";
1612 case AMD_BOBCAT:
1613 return "AMD_BOBCAT";
1614 case AMD_BULLDOZER:
1615 return "AMD_BULLDOZER";
1616 case AMD_JAGUAR:
1617 return "AMD_JAGUAR";
1618 case AMD_ZEN:
1619 return "AMD_ZEN";
1620 }
1621 return "unknown microarchitecture";
1622}