blob: d5edd3052ea3efbd83b47746cf19f1fb952e1cf3 [file] [log] [blame]
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001// Copyright 2017 Google Inc.
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
28////////////////////////////////////////////////////////////////////////////////
29// Definitions for CpuId and GetXCR0Eax.
30////////////////////////////////////////////////////////////////////////////////
31
32#if defined(CPU_FEATURES_MOCK_CPUID_X86)
33// Implementation will be provided by test/cpuinfo_x86_test.cc.
34#elif defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
35
36#include <cpuid.h>
37
Artem Alekseevbfb4cf92019-06-21 15:13:29 +030038Leaf CpuIdEx(uint32_t leaf_id, int ecx) {
Guillaume Chatelete8e56102019-01-15 10:52:56 +010039 Leaf leaf;
Artem Alekseevbfb4cf92019-06-21 15:13:29 +030040 __cpuid_count(leaf_id, ecx, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
Guillaume Chatelete8e56102019-01-15 10:52:56 +010041 return leaf;
42}
43
44uint32_t GetXCR0Eax(void) {
45 uint32_t eax, edx;
natanbc084ec5c2019-03-20 06:04:24 -030046 /* named form of xgetbv not supported on OSX, so must use byte form, see:
47 https://github.com/asmjit/asmjit/issues/78
48 */
49 __asm(".byte 0x0F, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0));
Guillaume Chatelete8e56102019-01-15 10:52:56 +010050 return eax;
51}
52
53#elif defined(CPU_FEATURES_COMPILER_MSC)
54
55#include <immintrin.h>
56#include <intrin.h> // For __cpuidex()
57
Artem Alekseevbfb4cf92019-06-21 15:13:29 +030058Leaf CpuIdEx(uint32_t leaf_id, int ecx) {
Guillaume Chatelete8e56102019-01-15 10:52:56 +010059 Leaf leaf;
60 int data[4];
Artem Alekseevbfb4cf92019-06-21 15:13:29 +030061 __cpuidex(data, leaf_id, ecx);
Guillaume Chatelete8e56102019-01-15 10:52:56 +010062 leaf.eax = data[0];
63 leaf.ebx = data[1];
64 leaf.ecx = data[2];
65 leaf.edx = data[3];
66 return leaf;
67}
68
Leonard Mosescubdb36d92019-07-03 05:57:19 -070069uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); }
Guillaume Chatelete8e56102019-01-15 10:52:56 +010070
71#else
72#error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC."
73#endif
74
Artem Alekseev653d5812019-07-02 17:52:25 +030075static Leaf CpuId(uint32_t leaf_id) { return CpuIdEx(leaf_id, 0); }
Artem Alekseevbfb4cf92019-06-21 15:13:29 +030076
Guillaume Chatelet439d3712018-02-01 10:03:09 +010077static const Leaf kEmptyLeaf;
78
Artem Alekseevbfb4cf92019-06-21 15:13:29 +030079static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
Guillaume Chatelet439d3712018-02-01 10:03:09 +010080 if (leaf_id <= max_cpuid_leaf) {
Artem Alekseevbfb4cf92019-06-21 15:13:29 +030081 return CpuIdEx(leaf_id, ecx);
Guillaume Chatelet439d3712018-02-01 10:03:09 +010082 } else {
83 return kEmptyLeaf;
84 }
85}
86
Artem Alekseevbfb4cf92019-06-21 15:13:29 +030087static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
88 return SafeCpuIdEx(max_cpuid_leaf, leaf_id, 0);
89}
90
Guillaume Chatelet439d3712018-02-01 10:03:09 +010091#define MASK_XMM 0x2
92#define MASK_YMM 0x4
93#define MASK_MASKREG 0x20
94#define MASK_ZMM0_15 0x40
95#define MASK_ZMM16_31 0x80
Jeff Hammond33bd72c2020-09-21 00:56:26 -070096#define MASK_XTILECFG 0x20000
97#define MASK_XTILEDATA 0x40000
Guillaume Chatelet439d3712018-02-01 10:03:09 +010098
99static bool HasMask(uint32_t value, uint32_t mask) {
100 return (value & mask) == mask;
101}
102
103// Checks that operating system saves and restores xmm registers during context
104// switches.
105static bool HasXmmOsXSave(uint32_t xcr0_eax) {
106 return HasMask(xcr0_eax, MASK_XMM);
107}
108
109// Checks that operating system saves and restores ymm registers during context
110// switches.
111static bool HasYmmOsXSave(uint32_t xcr0_eax) {
112 return HasMask(xcr0_eax, MASK_XMM | MASK_YMM);
113}
114
115// Checks that operating system saves and restores zmm registers during context
116// switches.
117static bool HasZmmOsXSave(uint32_t xcr0_eax) {
118 return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
119 MASK_ZMM16_31);
120}
121
Jeff Hammond33bd72c2020-09-21 00:56:26 -0700122// Checks that operating system saves and restores AMX/TMUL state during context
123// switches.
124static bool HasTmmOsXSave(uint32_t xcr0_eax) {
125 return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
126 MASK_ZMM16_31 | MASK_XTILECFG | MASK_XTILEDATA);
127}
128
Jeff Hammond17ffb652020-09-22 00:29:46 -0700129static bool HasSecondFMA(uint32_t model) {
130 // Skylake server
131 if (model == 0x55) {
132 char proc_name[49] = {0};
133 FillX86BrandString(proc_name);
134 // detect Xeon
135 if (proc_name[9] == 'X') {
136 // detect Silver or Bronze
137 if (proc_name[17] == 'S' || proc_name[17] == 'B') return false;
138 // detect Gold 5_20 and below, except for Gold 53__
139 if (proc_name[17] == 'G' && proc_name[22] == '5')
140 return ((proc_name[23] == '3') ||
141 (proc_name[24] == '2' && proc_name[25] == '2'));
142 // detect Xeon W 210x
143 if (proc_name[17] == 'W' && proc_name[21] == '0') return false;
144 // detect Xeon D 2xxx
145 if (proc_name[17] == 'D' && proc_name[19] == '2' && proc_name[20] == '1')
146 return false;
147 }
148 return true;
149 }
150 // Cannon Lake client
151 if (model == 0x66) return false;
152 // Ice Lake client
153 if (model == 0x7d || model == 0x7e) return false;
154 // This is the right default...
155 return true;
156}
157
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100158static void SetVendor(const Leaf leaf, char* const vendor) {
159 *(uint32_t*)(vendor) = leaf.ebx;
160 *(uint32_t*)(vendor + 4) = leaf.edx;
161 *(uint32_t*)(vendor + 8) = leaf.ecx;
162 vendor[12] = '\0';
163}
164
165static int IsVendor(const Leaf leaf, const char* const name) {
166 const uint32_t ebx = *(const uint32_t*)(name);
167 const uint32_t edx = *(const uint32_t*)(name + 4);
168 const uint32_t ecx = *(const uint32_t*)(name + 8);
169 return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
170}
171
Artem Alekseev653d5812019-07-02 17:52:25 +0300172static const CacheLevelInfo kEmptyCacheLevelInfo;
173
Artem Alekseev653d5812019-07-02 17:52:25 +0300174static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
175 const int UNDEF = -1;
176 const int KiB = 1024;
177 const int MiB = 1024 * KiB;
Artem Alekseev653d5812019-07-02 17:52:25 +0300178 switch (reg) {
179 case 0x01:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100180 return (CacheLevelInfo){.level = UNDEF,
181 .cache_type = CPU_FEATURE_CACHE_TLB,
182 .cache_size = 4 * KiB,
183 .ways = 4,
184 .line_size = UNDEF,
185 .tlb_entries = 32,
186 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300187 case 0x02:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100188 return (CacheLevelInfo){.level = UNDEF,
189 .cache_type = CPU_FEATURE_CACHE_TLB,
190 .cache_size = 4 * MiB,
191 .ways = 0xFF,
192 .line_size = UNDEF,
193 .tlb_entries = 2,
194 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300195 case 0x03:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100196 return (CacheLevelInfo){.level = UNDEF,
197 .cache_type = CPU_FEATURE_CACHE_TLB,
198 .cache_size = 4 * KiB,
199 .ways = 4,
200 .line_size = UNDEF,
201 .tlb_entries = 64,
202 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300203 case 0x04:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100204 return (CacheLevelInfo){.level = UNDEF,
205 .cache_type = CPU_FEATURE_CACHE_TLB,
206 .cache_size = 4 * MiB,
207 .ways = 4,
208 .line_size = UNDEF,
209 .tlb_entries = 8,
210 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300211 case 0x05:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100212 return (CacheLevelInfo){.level = UNDEF,
213 .cache_type = CPU_FEATURE_CACHE_TLB,
214 .cache_size = 4 * MiB,
215 .ways = 4,
216 .line_size = UNDEF,
217 .tlb_entries = 32,
218 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300219 case 0x06:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100220 return (CacheLevelInfo){.level = 1,
221 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
222 .cache_size = 8 * KiB,
223 .ways = 4,
224 .line_size = 32,
225 .tlb_entries = UNDEF,
226 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300227 case 0x08:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100228 return (CacheLevelInfo){.level = 1,
229 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
230 .cache_size = 16 * KiB,
231 .ways = 4,
232 .line_size = 32,
233 .tlb_entries = UNDEF,
234 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300235 case 0x09:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100236 return (CacheLevelInfo){.level = 1,
237 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
238 .cache_size = 32 * KiB,
239 .ways = 4,
240 .line_size = 64,
241 .tlb_entries = UNDEF,
242 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300243 case 0x0A:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100244 return (CacheLevelInfo){.level = 1,
245 .cache_type = CPU_FEATURE_CACHE_DATA,
246 .cache_size = 8 * KiB,
247 .ways = 2,
248 .line_size = 32,
249 .tlb_entries = UNDEF,
250 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300251 case 0x0B:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100252 return (CacheLevelInfo){.level = UNDEF,
253 .cache_type = CPU_FEATURE_CACHE_TLB,
254 .cache_size = 4 * MiB,
255 .ways = 4,
256 .line_size = UNDEF,
257 .tlb_entries = 4,
258 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300259 case 0x0C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100260 return (CacheLevelInfo){.level = 1,
261 .cache_type = CPU_FEATURE_CACHE_DATA,
262 .cache_size = 16 * KiB,
263 .ways = 4,
264 .line_size = 32,
265 .tlb_entries = UNDEF,
266 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300267 case 0x0D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100268 return (CacheLevelInfo){.level = 1,
269 .cache_type = CPU_FEATURE_CACHE_DATA,
270 .cache_size = 16 * KiB,
271 .ways = 4,
272 .line_size = 64,
273 .tlb_entries = UNDEF,
274 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300275 case 0x0E:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100276 return (CacheLevelInfo){.level = 1,
277 .cache_type = CPU_FEATURE_CACHE_DATA,
278 .cache_size = 24 * KiB,
279 .ways = 6,
280 .line_size = 64,
281 .tlb_entries = UNDEF,
282 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300283 case 0x1D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100284 return (CacheLevelInfo){.level = 2,
285 .cache_type = CPU_FEATURE_CACHE_DATA,
286 .cache_size = 128 * KiB,
287 .ways = 2,
288 .line_size = 64,
289 .tlb_entries = UNDEF,
290 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300291 case 0x21:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100292 return (CacheLevelInfo){.level = 2,
293 .cache_type = CPU_FEATURE_CACHE_DATA,
294 .cache_size = 256 * KiB,
295 .ways = 8,
296 .line_size = 64,
297 .tlb_entries = UNDEF,
298 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300299 case 0x22:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100300 return (CacheLevelInfo){.level = 3,
301 .cache_type = CPU_FEATURE_CACHE_DATA,
302 .cache_size = 512 * KiB,
303 .ways = 4,
304 .line_size = 64,
305 .tlb_entries = UNDEF,
306 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300307 case 0x23:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100308 return (CacheLevelInfo){.level = 3,
309 .cache_type = CPU_FEATURE_CACHE_DATA,
310 .cache_size = 1 * MiB,
311 .ways = 8,
312 .line_size = 64,
313 .tlb_entries = UNDEF,
314 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300315 case 0x24:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100316 return (CacheLevelInfo){.level = 2,
317 .cache_type = CPU_FEATURE_CACHE_DATA,
318 .cache_size = 1 * MiB,
319 .ways = 16,
320 .line_size = 64,
321 .tlb_entries = UNDEF,
322 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300323 case 0x25:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100324 return (CacheLevelInfo){.level = 3,
325 .cache_type = CPU_FEATURE_CACHE_DATA,
326 .cache_size = 2 * MiB,
327 .ways = 8,
328 .line_size = 64,
329 .tlb_entries = UNDEF,
330 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300331 case 0x29:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100332 return (CacheLevelInfo){.level = 3,
333 .cache_type = CPU_FEATURE_CACHE_DATA,
334 .cache_size = 4 * MiB,
335 .ways = 8,
336 .line_size = 64,
337 .tlb_entries = UNDEF,
338 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300339 case 0x2C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100340 return (CacheLevelInfo){.level = 1,
341 .cache_type = CPU_FEATURE_CACHE_DATA,
342 .cache_size = 32 * KiB,
343 .ways = 8,
344 .line_size = 64,
345 .tlb_entries = UNDEF,
346 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300347 case 0x30:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100348 return (CacheLevelInfo){.level = 1,
349 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
350 .cache_size = 32 * KiB,
351 .ways = 8,
352 .line_size = 64,
353 .tlb_entries = UNDEF,
354 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300355 case 0x40:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100356 return (CacheLevelInfo){.level = UNDEF,
357 .cache_type = CPU_FEATURE_CACHE_DATA,
358 .cache_size = UNDEF,
359 .ways = UNDEF,
360 .line_size = UNDEF,
361 .tlb_entries = UNDEF,
362 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300363 case 0x41:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100364 return (CacheLevelInfo){.level = 2,
365 .cache_type = CPU_FEATURE_CACHE_DATA,
366 .cache_size = 128 * KiB,
367 .ways = 4,
368 .line_size = 32,
369 .tlb_entries = UNDEF,
370 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300371 case 0x42:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100372 return (CacheLevelInfo){.level = 2,
373 .cache_type = CPU_FEATURE_CACHE_DATA,
374 .cache_size = 256 * KiB,
375 .ways = 4,
376 .line_size = 32,
377 .tlb_entries = UNDEF,
378 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300379 case 0x43:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100380 return (CacheLevelInfo){.level = 2,
381 .cache_type = CPU_FEATURE_CACHE_DATA,
382 .cache_size = 512 * KiB,
383 .ways = 4,
384 .line_size = 32,
385 .tlb_entries = UNDEF,
386 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300387 case 0x44:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100388 return (CacheLevelInfo){.level = 2,
389 .cache_type = CPU_FEATURE_CACHE_DATA,
390 .cache_size = 1 * MiB,
391 .ways = 4,
392 .line_size = 32,
393 .tlb_entries = UNDEF,
394 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300395 case 0x45:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100396 return (CacheLevelInfo){.level = 2,
397 .cache_type = CPU_FEATURE_CACHE_DATA,
398 .cache_size = 2 * MiB,
399 .ways = 4,
400 .line_size = 32,
401 .tlb_entries = UNDEF,
402 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300403 case 0x46:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100404 return (CacheLevelInfo){.level = 3,
405 .cache_type = CPU_FEATURE_CACHE_DATA,
406 .cache_size = 4 * MiB,
407 .ways = 4,
408 .line_size = 64,
409 .tlb_entries = UNDEF,
410 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300411 case 0x47:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100412 return (CacheLevelInfo){.level = 3,
413 .cache_type = CPU_FEATURE_CACHE_DATA,
414 .cache_size = 8 * MiB,
415 .ways = 8,
416 .line_size = 64,
417 .tlb_entries = UNDEF,
418 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300419 case 0x48:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100420 return (CacheLevelInfo){.level = 2,
421 .cache_type = CPU_FEATURE_CACHE_DATA,
422 .cache_size = 3 * MiB,
423 .ways = 12,
424 .line_size = 64,
425 .tlb_entries = UNDEF,
426 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300427 case 0x49:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100428 return (CacheLevelInfo){.level = 2,
429 .cache_type = CPU_FEATURE_CACHE_DATA,
430 .cache_size = 4 * MiB,
431 .ways = 16,
432 .line_size = 64,
433 .tlb_entries = UNDEF,
434 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300435 case (0x49 | (1 << 8)):
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100436 return (CacheLevelInfo){.level = 3,
437 .cache_type = CPU_FEATURE_CACHE_DATA,
438 .cache_size = 4 * MiB,
439 .ways = 16,
440 .line_size = 64,
441 .tlb_entries = UNDEF,
442 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300443 case 0x4A:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100444 return (CacheLevelInfo){.level = 3,
445 .cache_type = CPU_FEATURE_CACHE_DATA,
446 .cache_size = 6 * MiB,
447 .ways = 12,
448 .line_size = 64,
449 .tlb_entries = UNDEF,
450 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300451 case 0x4B:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100452 return (CacheLevelInfo){.level = 3,
453 .cache_type = CPU_FEATURE_CACHE_DATA,
454 .cache_size = 8 * MiB,
455 .ways = 16,
456 .line_size = 64,
457 .tlb_entries = UNDEF,
458 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300459 case 0x4C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100460 return (CacheLevelInfo){.level = 3,
461 .cache_type = CPU_FEATURE_CACHE_DATA,
462 .cache_size = 12 * MiB,
463 .ways = 12,
464 .line_size = 64,
465 .tlb_entries = UNDEF,
466 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300467 case 0x4D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100468 return (CacheLevelInfo){.level = 3,
469 .cache_type = CPU_FEATURE_CACHE_DATA,
470 .cache_size = 16 * MiB,
471 .ways = 16,
472 .line_size = 64,
473 .tlb_entries = UNDEF,
474 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300475 case 0x4E:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100476 return (CacheLevelInfo){.level = 2,
477 .cache_type = CPU_FEATURE_CACHE_DATA,
478 .cache_size = 6 * MiB,
479 .ways = 24,
480 .line_size = 64,
481 .tlb_entries = UNDEF,
482 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300483 case 0x4F:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100484 return (CacheLevelInfo){.level = UNDEF,
485 .cache_type = CPU_FEATURE_CACHE_TLB,
486 .cache_size = 4 * KiB,
487 .ways = UNDEF,
488 .line_size = UNDEF,
489 .tlb_entries = 32,
490 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300491 case 0x50:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100492 return (CacheLevelInfo){.level = UNDEF,
493 .cache_type = CPU_FEATURE_CACHE_TLB,
494 .cache_size = 4 * KiB,
495 .ways = UNDEF,
496 .line_size = UNDEF,
497 .tlb_entries = 64,
498 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300499 case 0x51:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100500 return (CacheLevelInfo){.level = UNDEF,
501 .cache_type = CPU_FEATURE_CACHE_TLB,
502 .cache_size = 4 * KiB,
503 .ways = UNDEF,
504 .line_size = UNDEF,
505 .tlb_entries = 128,
506 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300507 case 0x52:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100508 return (CacheLevelInfo){.level = UNDEF,
509 .cache_type = CPU_FEATURE_CACHE_TLB,
510 .cache_size = 4 * KiB,
511 .ways = UNDEF,
512 .line_size = UNDEF,
513 .tlb_entries = 256,
514 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300515 case 0x55:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100516 return (CacheLevelInfo){.level = UNDEF,
517 .cache_type = CPU_FEATURE_CACHE_TLB,
518 .cache_size = 2 * MiB,
519 .ways = 0xFF,
520 .line_size = UNDEF,
521 .tlb_entries = 7,
522 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300523 case 0x56:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100524 return (CacheLevelInfo){.level = UNDEF,
525 .cache_type = CPU_FEATURE_CACHE_TLB,
526 .cache_size = 4 * MiB,
527 .ways = 4,
528 .line_size = UNDEF,
529 .tlb_entries = 16,
530 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300531 case 0x57:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100532 return (CacheLevelInfo){.level = UNDEF,
533 .cache_type = CPU_FEATURE_CACHE_TLB,
534 .cache_size = 4 * KiB,
535 .ways = 4,
536 .line_size = UNDEF,
537 .tlb_entries = 16,
538 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300539 case 0x59:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100540 return (CacheLevelInfo){.level = UNDEF,
541 .cache_type = CPU_FEATURE_CACHE_TLB,
542 .cache_size = 4 * KiB,
543 .ways = 0xFF,
544 .line_size = UNDEF,
545 .tlb_entries = 16,
546 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300547 case 0x5A:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100548 return (CacheLevelInfo){.level = UNDEF,
549 .cache_type = CPU_FEATURE_CACHE_TLB,
550 .cache_size = 2 * MiB,
551 .ways = 4,
552 .line_size = UNDEF,
553 .tlb_entries = 32,
554 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300555 case 0x5B:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100556 return (CacheLevelInfo){.level = UNDEF,
557 .cache_type = CPU_FEATURE_CACHE_TLB,
558 .cache_size = 4 * KiB,
559 .ways = UNDEF,
560 .line_size = UNDEF,
561 .tlb_entries = 64,
562 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300563 case 0x5C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100564 return (CacheLevelInfo){.level = UNDEF,
565 .cache_type = CPU_FEATURE_CACHE_TLB,
566 .cache_size = 4 * KiB,
567 .ways = UNDEF,
568 .line_size = UNDEF,
569 .tlb_entries = 128,
570 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300571 case 0x5D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100572 return (CacheLevelInfo){.level = UNDEF,
573 .cache_type = CPU_FEATURE_CACHE_TLB,
574 .cache_size = 4,
575 .ways = UNDEF,
576 .line_size = UNDEF,
577 .tlb_entries = 256,
578 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300579 case 0x60:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100580 return (CacheLevelInfo){.level = 1,
581 .cache_type = CPU_FEATURE_CACHE_DATA,
582 .cache_size = 16 * KiB,
583 .ways = 8,
584 .line_size = 64,
585 .tlb_entries = UNDEF,
586 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300587 case 0x61:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100588 return (CacheLevelInfo){.level = UNDEF,
589 .cache_type = CPU_FEATURE_CACHE_TLB,
590 .cache_size = 4 * KiB,
591 .ways = 0xFF,
592 .line_size = UNDEF,
593 .tlb_entries = 48,
594 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300595 case 0x63:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100596 return (CacheLevelInfo){.level = UNDEF,
597 .cache_type = CPU_FEATURE_CACHE_TLB,
598 .cache_size = 2 * MiB,
599 .ways = 4,
600 .line_size = UNDEF,
601 .tlb_entries = 4,
602 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300603 case 0x66:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100604 return (CacheLevelInfo){.level = 1,
605 .cache_type = CPU_FEATURE_CACHE_DATA,
606 .cache_size = 8 * KiB,
607 .ways = 4,
608 .line_size = 64,
609 .tlb_entries = UNDEF,
610 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300611 case 0x67:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100612 return (CacheLevelInfo){.level = 1,
613 .cache_type = CPU_FEATURE_CACHE_DATA,
614 .cache_size = 16 * KiB,
615 .ways = 4,
616 .line_size = 64,
617 .tlb_entries = UNDEF,
618 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300619 case 0x68:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100620 return (CacheLevelInfo){.level = 1,
621 .cache_type = CPU_FEATURE_CACHE_DATA,
622 .cache_size = 32 * KiB,
623 .ways = 4,
624 .line_size = 64,
625 .tlb_entries = UNDEF,
626 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300627 case 0x70:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100628 return (CacheLevelInfo){.level = 1,
629 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
630 .cache_size = 12 * KiB,
631 .ways = 8,
632 .line_size = UNDEF,
633 .tlb_entries = UNDEF,
634 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300635 case 0x71:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100636 return (CacheLevelInfo){.level = 1,
637 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
638 .cache_size = 16 * KiB,
639 .ways = 8,
640 .line_size = UNDEF,
641 .tlb_entries = UNDEF,
642 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300643 case 0x72:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100644 return (CacheLevelInfo){.level = 1,
645 .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
646 .cache_size = 32 * KiB,
647 .ways = 8,
648 .line_size = UNDEF,
649 .tlb_entries = UNDEF,
650 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300651 case 0x76:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100652 return (CacheLevelInfo){.level = UNDEF,
653 .cache_type = CPU_FEATURE_CACHE_TLB,
654 .cache_size = 2 * MiB,
655 .ways = 0xFF,
656 .line_size = UNDEF,
657 .tlb_entries = 8,
658 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300659 case 0x78:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100660 return (CacheLevelInfo){.level = 2,
661 .cache_type = CPU_FEATURE_CACHE_DATA,
662 .cache_size = 1 * MiB,
663 .ways = 4,
664 .line_size = 64,
665 .tlb_entries = UNDEF,
666 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300667 case 0x79:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100668 return (CacheLevelInfo){.level = 2,
669 .cache_type = CPU_FEATURE_CACHE_DATA,
670 .cache_size = 128 * KiB,
671 .ways = 8,
672 .line_size = 64,
673 .tlb_entries = UNDEF,
674 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300675 case 0x7A:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100676 return (CacheLevelInfo){.level = 2,
677 .cache_type = CPU_FEATURE_CACHE_DATA,
678 .cache_size = 256 * KiB,
679 .ways = 8,
680 .line_size = 64,
681 .tlb_entries = UNDEF,
682 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300683 case 0x7B:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100684 return (CacheLevelInfo){.level = 2,
685 .cache_type = CPU_FEATURE_CACHE_DATA,
686 .cache_size = 512 * KiB,
687 .ways = 8,
688 .line_size = 64,
689 .tlb_entries = UNDEF,
690 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300691 case 0x7C:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100692 return (CacheLevelInfo){.level = 2,
693 .cache_type = CPU_FEATURE_CACHE_DATA,
694 .cache_size = 1 * MiB,
695 .ways = 8,
696 .line_size = 64,
697 .tlb_entries = UNDEF,
698 .partitioning = 2};
Artem Alekseev653d5812019-07-02 17:52:25 +0300699 case 0x7D:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100700 return (CacheLevelInfo){.level = 2,
701 .cache_type = CPU_FEATURE_CACHE_DATA,
702 .cache_size = 2 * MiB,
703 .ways = 8,
704 .line_size = 64,
705 .tlb_entries = UNDEF,
706 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300707 case 0x7F:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100708 return (CacheLevelInfo){.level = 2,
709 .cache_type = CPU_FEATURE_CACHE_DATA,
710 .cache_size = 512 * KiB,
711 .ways = 2,
712 .line_size = 64,
713 .tlb_entries = UNDEF,
714 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300715 case 0x80:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100716 return (CacheLevelInfo){.level = 2,
717 .cache_type = CPU_FEATURE_CACHE_DATA,
718 .cache_size = 512 * KiB,
719 .ways = 8,
720 .line_size = 64,
721 .tlb_entries = UNDEF,
722 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300723 case 0x82:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100724 return (CacheLevelInfo){.level = 2,
725 .cache_type = CPU_FEATURE_CACHE_DATA,
726 .cache_size = 256 * KiB,
727 .ways = 8,
728 .line_size = 32,
729 .tlb_entries = UNDEF,
730 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300731 case 0x83:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100732 return (CacheLevelInfo){.level = 2,
733 .cache_type = CPU_FEATURE_CACHE_DATA,
734 .cache_size = 512 * KiB,
735 .ways = 8,
736 .line_size = 32,
737 .tlb_entries = UNDEF,
738 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300739 case 0x84:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100740 return (CacheLevelInfo){.level = 2,
741 .cache_type = CPU_FEATURE_CACHE_DATA,
742 .cache_size = 1 * MiB,
743 .ways = 8,
744 .line_size = 32,
745 .tlb_entries = UNDEF,
746 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300747 case 0x85:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100748 return (CacheLevelInfo){.level = 2,
749 .cache_type = CPU_FEATURE_CACHE_DATA,
750 .cache_size = 2 * MiB,
751 .ways = 8,
752 .line_size = 32,
753 .tlb_entries = UNDEF,
754 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300755 case 0x86:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100756 return (CacheLevelInfo){.level = 2,
757 .cache_type = CPU_FEATURE_CACHE_DATA,
758 .cache_size = 512 * KiB,
759 .ways = 4,
760 .line_size = 32,
761 .tlb_entries = UNDEF,
762 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300763 case 0x87:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100764 return (CacheLevelInfo){.level = 2,
765 .cache_type = CPU_FEATURE_CACHE_DATA,
766 .cache_size = 1 * MiB,
767 .ways = 8,
768 .line_size = 64,
769 .tlb_entries = UNDEF,
770 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300771 case 0xA0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100772 return (CacheLevelInfo){.level = UNDEF,
773 .cache_type = CPU_FEATURE_CACHE_DTLB,
774 .cache_size = 4 * KiB,
775 .ways = 0xFF,
776 .line_size = UNDEF,
777 .tlb_entries = 32,
778 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300779 case 0xB0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100780 return (CacheLevelInfo){.level = UNDEF,
781 .cache_type = CPU_FEATURE_CACHE_TLB,
782 .cache_size = 4 * KiB,
783 .ways = 4,
784 .line_size = UNDEF,
785 .tlb_entries = 128,
786 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300787 case 0xB1:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100788 return (CacheLevelInfo){.level = UNDEF,
789 .cache_type = CPU_FEATURE_CACHE_TLB,
790 .cache_size = 2 * MiB,
791 .ways = 4,
792 .line_size = UNDEF,
793 .tlb_entries = 8,
794 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300795 case 0xB2:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100796 return (CacheLevelInfo){.level = UNDEF,
797 .cache_type = CPU_FEATURE_CACHE_TLB,
798 .cache_size = 4 * KiB,
799 .ways = 4,
800 .line_size = UNDEF,
801 .tlb_entries = 64,
802 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300803 case 0xB3:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100804 return (CacheLevelInfo){.level = UNDEF,
805 .cache_type = CPU_FEATURE_CACHE_TLB,
806 .cache_size = 4 * KiB,
807 .ways = 4,
808 .line_size = UNDEF,
809 .tlb_entries = 128,
810 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300811 case 0xB4:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100812 return (CacheLevelInfo){.level = UNDEF,
813 .cache_type = CPU_FEATURE_CACHE_TLB,
814 .cache_size = 4 * KiB,
815 .ways = 4,
816 .line_size = UNDEF,
817 .tlb_entries = 256,
818 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300819 case 0xB5:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100820 return (CacheLevelInfo){.level = UNDEF,
821 .cache_type = CPU_FEATURE_CACHE_TLB,
822 .cache_size = 4 * KiB,
823 .ways = 8,
824 .line_size = UNDEF,
825 .tlb_entries = 64,
826 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300827 case 0xB6:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100828 return (CacheLevelInfo){.level = UNDEF,
829 .cache_type = CPU_FEATURE_CACHE_TLB,
830 .cache_size = 4 * KiB,
831 .ways = 8,
832 .line_size = UNDEF,
833 .tlb_entries = 128,
834 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300835 case 0xBA:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100836 return (CacheLevelInfo){.level = UNDEF,
837 .cache_type = CPU_FEATURE_CACHE_TLB,
838 .cache_size = 4 * KiB,
839 .ways = 4,
840 .line_size = UNDEF,
841 .tlb_entries = 64,
842 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300843 case 0xC0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100844 return (CacheLevelInfo){.level = UNDEF,
845 .cache_type = CPU_FEATURE_CACHE_TLB,
846 .cache_size = 4 * KiB,
847 .ways = 4,
848 .line_size = UNDEF,
849 .tlb_entries = 8,
850 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300851 case 0xC1:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100852 return (CacheLevelInfo){.level = UNDEF,
853 .cache_type = CPU_FEATURE_CACHE_STLB,
854 .cache_size = 4 * KiB,
855 .ways = 8,
856 .line_size = UNDEF,
857 .tlb_entries = 1024,
858 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300859 case 0xC2:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100860 return (CacheLevelInfo){.level = UNDEF,
861 .cache_type = CPU_FEATURE_CACHE_DTLB,
862 .cache_size = 4 * KiB,
863 .ways = 4,
864 .line_size = UNDEF,
865 .tlb_entries = 16,
866 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300867 case 0xC3:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100868 return (CacheLevelInfo){.level = UNDEF,
869 .cache_type = CPU_FEATURE_CACHE_STLB,
870 .cache_size = 4 * KiB,
871 .ways = 6,
872 .line_size = UNDEF,
873 .tlb_entries = 1536,
874 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300875 case 0xCA:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100876 return (CacheLevelInfo){.level = UNDEF,
877 .cache_type = CPU_FEATURE_CACHE_STLB,
878 .cache_size = 4 * KiB,
879 .ways = 4,
880 .line_size = UNDEF,
881 .tlb_entries = 512,
882 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300883 case 0xD0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100884 return (CacheLevelInfo){.level = 3,
885 .cache_type = CPU_FEATURE_CACHE_DATA,
886 .cache_size = 512 * KiB,
887 .ways = 4,
888 .line_size = 64,
889 .tlb_entries = UNDEF,
890 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300891 case 0xD1:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100892 return (CacheLevelInfo){.level = 3,
893 .cache_type = CPU_FEATURE_CACHE_DATA,
894 .cache_size = 1 * MiB,
895 .ways = 4,
896 .line_size = 64,
897 .tlb_entries = UNDEF,
898 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300899 case 0xD2:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100900 return (CacheLevelInfo){.level = 3,
901 .cache_type = CPU_FEATURE_CACHE_DATA,
902 .cache_size = 2 * MiB,
903 .ways = 4,
904 .line_size = 64,
905 .tlb_entries = UNDEF,
906 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300907 case 0xD6:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100908 return (CacheLevelInfo){.level = 3,
909 .cache_type = CPU_FEATURE_CACHE_DATA,
910 .cache_size = 1 * MiB,
911 .ways = 8,
912 .line_size = 64,
913 .tlb_entries = UNDEF,
914 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300915 case 0xD7:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100916 return (CacheLevelInfo){.level = 3,
917 .cache_type = CPU_FEATURE_CACHE_DATA,
918 .cache_size = 2 * MiB,
919 .ways = 8,
920 .line_size = 64,
921 .tlb_entries = UNDEF,
922 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300923 case 0xD8:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100924 return (CacheLevelInfo){.level = 3,
925 .cache_type = CPU_FEATURE_CACHE_DATA,
926 .cache_size = 4 * MiB,
927 .ways = 8,
928 .line_size = 64,
929 .tlb_entries = UNDEF,
930 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300931 case 0xDC:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100932 return (CacheLevelInfo){.level = 3,
933 .cache_type = CPU_FEATURE_CACHE_DATA,
934 .cache_size = 1 * 1536 * KiB,
935 .ways = 12,
936 .line_size = 64,
937 .tlb_entries = UNDEF,
938 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300939 case 0xDD:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100940 return (CacheLevelInfo){.level = 3,
941 .cache_type = CPU_FEATURE_CACHE_DATA,
942 .cache_size = 3 * MiB,
943 .ways = 12,
944 .line_size = 64,
945 .tlb_entries = UNDEF,
946 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300947 case 0xDE:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100948 return (CacheLevelInfo){.level = 3,
949 .cache_type = CPU_FEATURE_CACHE_DATA,
950 .cache_size = 6 * MiB,
951 .ways = 12,
952 .line_size = 64,
953 .tlb_entries = UNDEF,
954 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300955 case 0xE2:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100956 return (CacheLevelInfo){.level = 3,
957 .cache_type = CPU_FEATURE_CACHE_DATA,
958 .cache_size = 2 * MiB,
959 .ways = 16,
960 .line_size = 64,
961 .tlb_entries = UNDEF,
962 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300963 case 0xE3:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100964 return (CacheLevelInfo){.level = 3,
965 .cache_type = CPU_FEATURE_CACHE_DATA,
966 .cache_size = 4 * MiB,
967 .ways = 16,
968 .line_size = 64,
969 .tlb_entries = UNDEF,
970 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300971 case 0xE4:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100972 return (CacheLevelInfo){.level = 3,
973 .cache_type = CPU_FEATURE_CACHE_DATA,
974 .cache_size = 8 * MiB,
975 .ways = 16,
976 .line_size = 64,
977 .tlb_entries = UNDEF,
978 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300979 case 0xEA:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100980 return (CacheLevelInfo){.level = 3,
981 .cache_type = CPU_FEATURE_CACHE_DATA,
982 .cache_size = 12 * MiB,
983 .ways = 24,
984 .line_size = 64,
985 .tlb_entries = UNDEF,
986 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300987 case 0xEB:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100988 return (CacheLevelInfo){.level = 3,
989 .cache_type = CPU_FEATURE_CACHE_DATA,
990 .cache_size = 18 * MiB,
991 .ways = 24,
992 .line_size = 64,
993 .tlb_entries = UNDEF,
994 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +0300995 case 0xEC:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +0100996 return (CacheLevelInfo){.level = 3,
997 .cache_type = CPU_FEATURE_CACHE_DATA,
998 .cache_size = 24 * MiB,
999 .ways = 24,
1000 .line_size = 64,
1001 .tlb_entries = UNDEF,
1002 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001003 case 0xF0:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001004 return (CacheLevelInfo){.level = UNDEF,
1005 .cache_type = CPU_FEATURE_CACHE_PREFETCH,
1006 .cache_size = 64 * KiB,
1007 .ways = UNDEF,
1008 .line_size = UNDEF,
1009 .tlb_entries = UNDEF,
1010 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001011 case 0xF1:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001012 return (CacheLevelInfo){.level = UNDEF,
1013 .cache_type = CPU_FEATURE_CACHE_PREFETCH,
1014 .cache_size = 128 * KiB,
1015 .ways = UNDEF,
1016 .line_size = UNDEF,
1017 .tlb_entries = UNDEF,
1018 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001019 case 0xFF:
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001020 return (CacheLevelInfo){.level = UNDEF,
1021 .cache_type = CPU_FEATURE_CACHE_NULL,
1022 .cache_size = UNDEF,
1023 .ways = UNDEF,
1024 .line_size = UNDEF,
1025 .tlb_entries = UNDEF,
1026 .partitioning = 0};
Artem Alekseev653d5812019-07-02 17:52:25 +03001027 default:
1028 return kEmptyCacheLevelInfo;
1029 }
1030}
1031
1032static void GetByteArrayFromRegister(uint32_t result[4], const uint32_t reg) {
1033 for (int i = 0; i < 4; ++i) {
1034 result[i] = ExtractBitRange(reg, (i + 1) * 8, i * 8);
1035 }
1036}
1037
1038static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) {
1039 Leaf leaf = SafeCpuId(max_cpuid_leaf, 2);
1040 uint32_t registers[] = {leaf.eax, leaf.ebx, leaf.ecx, leaf.edx};
1041 for (int i = 0; i < 4; ++i) {
Guillaume Chatelet8a6fd872019-11-13 14:39:06 +01001042 if (registers[i] & (1U << 31)) {
Artem Alekseev653d5812019-07-02 17:52:25 +03001043 continue; // register does not contains valid information
1044 }
1045 uint32_t bytes[4];
1046 GetByteArrayFromRegister(bytes, registers[i]);
Guillaume Chateletbe306b72019-11-13 11:15:40 +01001047 for (int j = 0; j < 4; ++j) {
1048 if (bytes[j] == 0xFF)
Artem Alekseev653d5812019-07-02 17:52:25 +03001049 break; // leaf 4 should be used to fetch cache information
Guillaume Chateletbe306b72019-11-13 11:15:40 +01001050 info->levels[info->size] = GetCacheLevelInfo(bytes[j]);
Artem Alekseev653d5812019-07-02 17:52:25 +03001051 }
1052 info->size++;
1053 }
1054}
1055
1056static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info) {
1057 info->size = 0;
1058 for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++) {
1059 const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, 4, cache_id);
1060 CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0);
1061 if (cache_type == CPU_FEATURE_CACHE_NULL) {
1062 info->levels[cache_id] = kEmptyCacheLevelInfo;
1063 continue;
1064 }
1065 int level = ExtractBitRange(leaf.eax, 7, 5);
1066 int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
1067 int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
1068 int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1;
Guillaume Chatelete50d7db2020-01-29 11:04:48 +01001069 int tlb_entries = leaf.ecx + 1;
1070 int cache_size = (ways * partitioning * line_size * (tlb_entries));
1071 info->levels[cache_id] = (CacheLevelInfo){.level = level,
1072 .cache_type = cache_type,
1073 .cache_size = cache_size,
1074 .ways = ways,
1075 .line_size = line_size,
1076 .tlb_entries = tlb_entries,
1077 .partitioning = partitioning};
Artem Alekseev653d5812019-07-02 17:52:25 +03001078 info->size++;
1079 }
1080}
1081
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001082// Internal structure to hold the OS support for vector operations.
1083// Avoid to recompute them since each call to cpuid is ~100 cycles.
1084typedef struct {
1085 bool have_sse;
1086 bool have_avx;
1087 bool have_avx512;
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001088 bool have_amx;
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001089} OsSupport;
1090
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001091// Reference https://en.wikipedia.org/wiki/CPUID.
Jeff Hammond17ffb652020-09-22 00:29:46 -07001092static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
1093 OsSupport* os_support) {
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001094 const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
1095 const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001096 const Leaf leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 7, 1);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001097
1098 const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
1099 const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
1100 const uint32_t xcr0_eax = (have_xsave && have_osxsave) ? GetXCR0Eax() : 0;
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001101 os_support->have_sse = HasXmmOsXSave(xcr0_eax);
1102 os_support->have_avx = HasYmmOsXSave(xcr0_eax);
1103 os_support->have_avx512 = HasZmmOsXSave(xcr0_eax);
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001104 os_support->have_amx = HasTmmOsXSave(xcr0_eax);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001105
1106 const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
1107 const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
1108 const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4);
1109 const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16);
1110
1111 X86Features* const features = &info->features;
1112
1113 info->family = extended_family + family;
1114 info->model = (extended_model << 4) + model;
1115 info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
1116
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001117 features->fpu = IsBitSet(leaf_1.edx, 0);
1118 features->tsc = IsBitSet(leaf_1.edx, 4);
1119 features->cx8 = IsBitSet(leaf_1.edx, 8);
1120 features->clfsh = IsBitSet(leaf_1.edx, 19);
1121 features->mmx = IsBitSet(leaf_1.edx, 23);
Artem Alekseev3ee4a9e2019-06-19 16:06:05 +03001122 features->ss = IsBitSet(leaf_1.edx, 27);
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001123 features->pclmulqdq = IsBitSet(leaf_1.ecx, 1);
Patrik Fiedler0f1f3ac2018-02-13 11:44:40 +01001124 features->smx = IsBitSet(leaf_1.ecx, 6);
Guillaume Chatelet9b872ce2018-03-13 10:58:42 +01001125 features->cx16 = IsBitSet(leaf_1.ecx, 13);
Artem Alekseev3ee4a9e2019-06-19 16:06:05 +03001126 features->dca = IsBitSet(leaf_1.ecx, 18);
Guillaume Chateletd395dfa2019-01-22 13:19:42 +01001127 features->movbe = IsBitSet(leaf_1.ecx, 22);
1128 features->popcnt = IsBitSet(leaf_1.ecx, 23);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001129 features->aes = IsBitSet(leaf_1.ecx, 25);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001130 features->f16c = IsBitSet(leaf_1.ecx, 29);
Guillaume Chateletd395dfa2019-01-22 13:19:42 +01001131 features->rdrnd = IsBitSet(leaf_1.ecx, 30);
Patrik Fiedler0f1f3ac2018-02-13 11:44:40 +01001132 features->sgx = IsBitSet(leaf_7.ebx, 2);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001133 features->bmi1 = IsBitSet(leaf_7.ebx, 3);
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001134 features->hle = IsBitSet(leaf_7.ebx, 4);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001135 features->bmi2 = IsBitSet(leaf_7.ebx, 8);
Patrik Fiedler0f1f3ac2018-02-13 11:44:40 +01001136 features->erms = IsBitSet(leaf_7.ebx, 9);
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001137 features->rtm = IsBitSet(leaf_7.ebx, 11);
1138 features->rdseed = IsBitSet(leaf_7.ebx, 18);
1139 features->clflushopt = IsBitSet(leaf_7.ebx, 23);
1140 features->clwb = IsBitSet(leaf_7.ebx, 24);
Guillaume Chateletd395dfa2019-01-22 13:19:42 +01001141 features->sha = IsBitSet(leaf_7.ebx, 29);
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001142 features->vaes = IsBitSet(leaf_7.ecx, 9);
Guillaume Chatelet11e3e202018-02-09 08:55:11 +01001143 features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001144
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001145 if (os_support->have_sse) {
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001146 features->sse = IsBitSet(leaf_1.edx, 25);
1147 features->sse2 = IsBitSet(leaf_1.edx, 26);
1148 features->sse3 = IsBitSet(leaf_1.ecx, 0);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001149 features->ssse3 = IsBitSet(leaf_1.ecx, 9);
1150 features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
1151 features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
1152 }
1153
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001154 if (os_support->have_avx) {
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001155 features->fma3 = IsBitSet(leaf_1.ecx, 12);
1156 features->avx = IsBitSet(leaf_1.ecx, 28);
1157 features->avx2 = IsBitSet(leaf_7.ebx, 5);
1158 }
1159
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001160 if (os_support->have_avx512) {
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001161 features->avx512f = IsBitSet(leaf_7.ebx, 16);
1162 features->avx512cd = IsBitSet(leaf_7.ebx, 28);
1163 features->avx512er = IsBitSet(leaf_7.ebx, 27);
1164 features->avx512pf = IsBitSet(leaf_7.ebx, 26);
1165 features->avx512bw = IsBitSet(leaf_7.ebx, 30);
1166 features->avx512dq = IsBitSet(leaf_7.ebx, 17);
1167 features->avx512vl = IsBitSet(leaf_7.ebx, 31);
1168 features->avx512ifma = IsBitSet(leaf_7.ebx, 21);
1169 features->avx512vbmi = IsBitSet(leaf_7.ecx, 1);
1170 features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6);
1171 features->avx512vnni = IsBitSet(leaf_7.ecx, 11);
1172 features->avx512bitalg = IsBitSet(leaf_7.ecx, 12);
1173 features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
1174 features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
Jeff Hammond17ffb652020-09-22 00:29:46 -07001175 features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
1176 features->avx512_second_fma = HasSecondFMA(info->model);
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001177 features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3);
1178 features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5);
1179 features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8);
1180 }
1181
1182 if (os_support->have_amx) {
1183 features->amx_bf16 = IsBitSet(leaf_7.edx, 22);
1184 features->amx_tile = IsBitSet(leaf_7.edx, 24);
1185 features->amx_int8 = IsBitSet(leaf_7.edx, 25);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001186 }
1187}
1188
Jeff Hammond17ffb652020-09-22 00:29:46 -07001189// Reference
1190// https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
Guillaume Chatelet76dafc72020-09-21 14:54:13 +02001191static void ParseExtraAMDCpuId(X86Info* info, OsSupport os_support) {
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001192 const Leaf leaf_80000000 = CpuId(0x80000000);
Guillaume Chatelet76dafc72020-09-21 14:54:13 +02001193 const uint32_t max_extended_cpuid_leaf = leaf_80000000.eax;
1194 const Leaf leaf_80000001 = SafeCpuId(max_extended_cpuid_leaf, 0x80000001);
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001195
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001196 X86Features* const features = &info->features;
1197
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001198 if (os_support.have_sse) {
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001199 features->sse4a = IsBitSet(leaf_80000001.ecx, 6);
1200 }
1201
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001202 if (os_support.have_avx) {
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001203 features->fma4 = IsBitSet(leaf_80000001.ecx, 16);
1204 }
1205}
1206
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001207static const X86Info kEmptyX86Info;
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001208static const OsSupport kEmptyOsSupport;
Artem Alekseev653d5812019-07-02 17:52:25 +03001209static const CacheInfo kEmptyCacheInfo;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001210
1211X86Info GetX86Info(void) {
1212 X86Info info = kEmptyX86Info;
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001213 OsSupport os_support = kEmptyOsSupport;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001214 const Leaf leaf_0 = CpuId(0);
Guillaume Chatelet76dafc72020-09-21 14:54:13 +02001215 const bool is_intel = IsVendor(leaf_0, "GenuineIntel");
1216 const bool is_amd = IsVendor(leaf_0, "AuthenticAMD");
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001217 SetVendor(leaf_0, info.vendor);
Guillaume Chatelet76dafc72020-09-21 14:54:13 +02001218 if (is_intel || is_amd) {
1219 const uint32_t max_cpuid_leaf = leaf_0.eax;
Corentin Le Molgat339bfd32020-03-12 10:56:06 +01001220 ParseCpuId(max_cpuid_leaf, &info, &os_support);
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001221 }
Guillaume Chatelet76dafc72020-09-21 14:54:13 +02001222 if (is_amd) {
1223 ParseExtraAMDCpuId(&info, os_support);
Corentin Le Molgat404e4622020-03-12 10:18:11 +01001224 }
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001225 return info;
1226}
1227
Artem Alekseev653d5812019-07-02 17:52:25 +03001228CacheInfo GetX86CacheInfo(void) {
1229 CacheInfo info = kEmptyCacheInfo;
1230 const Leaf leaf_0 = CpuId(0);
1231 const uint32_t max_cpuid_leaf = leaf_0.eax;
1232 if (IsVendor(leaf_0, "GenuineIntel")) {
1233 ParseLeaf2(max_cpuid_leaf, &info);
1234 ParseLeaf4(max_cpuid_leaf, &info);
1235 }
1236 return info;
1237}
1238
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +01001239#define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF))
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001240
1241X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
1242 if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) {
1243 switch (CPUID(info->family, info->model)) {
1244 case CPUID(0x06, 0x35):
1245 case CPUID(0x06, 0x36):
1246 // https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)
1247 return INTEL_ATOM_BNL;
1248 case CPUID(0x06, 0x37):
1249 case CPUID(0x06, 0x4C):
1250 // https://en.wikipedia.org/wiki/Silvermont
1251 return INTEL_ATOM_SMT;
1252 case CPUID(0x06, 0x5C):
1253 // https://en.wikipedia.org/wiki/Goldmont
1254 return INTEL_ATOM_GMT;
1255 case CPUID(0x06, 0x0F):
1256 case CPUID(0x06, 0x16):
1257 // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
1258 return INTEL_CORE;
1259 case CPUID(0x06, 0x17):
1260 case CPUID(0x06, 0x1D):
1261 // https://en.wikipedia.org/wiki/Penryn_(microarchitecture)
1262 return INTEL_PNR;
1263 case CPUID(0x06, 0x1A):
1264 case CPUID(0x06, 0x1E):
1265 case CPUID(0x06, 0x1F):
1266 case CPUID(0x06, 0x2E):
1267 // https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)
1268 return INTEL_NHM;
1269 case CPUID(0x06, 0x25):
1270 case CPUID(0x06, 0x2C):
1271 case CPUID(0x06, 0x2F):
1272 // https://en.wikipedia.org/wiki/Westmere_(microarchitecture)
1273 return INTEL_WSM;
1274 case CPUID(0x06, 0x2A):
1275 case CPUID(0x06, 0x2D):
1276 // https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings
1277 return INTEL_SNB;
1278 case CPUID(0x06, 0x3A):
1279 case CPUID(0x06, 0x3E):
1280 // https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings
1281 return INTEL_IVB;
1282 case CPUID(0x06, 0x3C):
1283 case CPUID(0x06, 0x3F):
1284 case CPUID(0x06, 0x45):
1285 case CPUID(0x06, 0x46):
1286 // https://en.wikipedia.org/wiki/Haswell_(microarchitecture)
1287 return INTEL_HSW;
1288 case CPUID(0x06, 0x3D):
1289 case CPUID(0x06, 0x47):
1290 case CPUID(0x06, 0x4F):
1291 case CPUID(0x06, 0x56):
1292 // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
1293 return INTEL_BDW;
1294 case CPUID(0x06, 0x4E):
1295 case CPUID(0x06, 0x55):
1296 case CPUID(0x06, 0x5E):
1297 // https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
1298 return INTEL_SKL;
Moxeja73a121b2020-01-05 13:15:12 +00001299 case CPUID(0x06, 0x66):
1300 // https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture)
1301 return INTEL_CNL;
Jeff Hammond17ffb652020-09-22 00:29:46 -07001302 case CPUID(0x06, 0x7D): // client
1303 case CPUID(0x06, 0x7E): // client
1304 case CPUID(0x06, 0x9D): // NNP-I
1305 case CPUID(0x06, 0x6A): // server
1306 case CPUID(0x06, 0x6C): // server
Moxeja73a121b2020-01-05 13:15:12 +00001307 // https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor)
1308 return INTEL_ICL;
Jeff Hammonde6983272020-09-21 00:54:58 -07001309 case CPUID(0x06, 0x8C):
1310 case CPUID(0x06, 0x8D):
1311 // https://en.wikipedia.org/wiki/Tiger_Lake_(microarchitecture)
1312 return INTEL_TGL;
1313 case CPUID(0x06, 0x8F):
1314 // https://en.wikipedia.org/wiki/Sapphire_Rapids
1315 return INTEL_SPR;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001316 case CPUID(0x06, 0x8E):
Moxeja73a121b2020-01-05 13:15:12 +00001317 switch (info->stepping) {
Jeff Hammond17ffb652020-09-22 00:29:46 -07001318 case 9:
1319 return INTEL_KBL; // https://en.wikipedia.org/wiki/Kaby_Lake
1320 case 10:
1321 return INTEL_CFL; // https://en.wikipedia.org/wiki/Coffee_Lake
1322 case 11:
1323 return INTEL_WHL; // https://en.wikipedia.org/wiki/Whiskey_Lake_(microarchitecture)
1324 default:
1325 return X86_UNKNOWN;
Moxeja73a121b2020-01-05 13:15:12 +00001326 }
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001327 case CPUID(0x06, 0x9E):
Moxeja73a121b2020-01-05 13:15:12 +00001328 if (info->stepping > 9) {
1329 // https://en.wikipedia.org/wiki/Coffee_Lake
1330 return INTEL_CFL;
1331 } else {
1332 // https://en.wikipedia.org/wiki/Kaby_Lake
1333 return INTEL_KBL;
1334 }
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001335 default:
1336 return X86_UNKNOWN;
1337 }
1338 }
1339 if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) {
1340 switch (info->family) {
1341 // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
1342 case 0x0F:
1343 return AMD_HAMMER;
1344 case 0x10:
1345 return AMD_K10;
1346 case 0x14:
1347 return AMD_BOBCAT;
1348 case 0x15:
1349 return AMD_BULLDOZER;
1350 case 0x16:
1351 return AMD_JAGUAR;
1352 case 0x17:
1353 return AMD_ZEN;
1354 default:
1355 return X86_UNKNOWN;
1356 }
1357 }
1358 return X86_UNKNOWN;
1359}
1360
1361static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id,
1362 char* buffer) {
1363 const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id);
1364 // We allow calling memcpy from SetString which is only called when requesting
1365 // X86BrandString.
1366 memcpy(buffer, &leaf, sizeof(Leaf));
1367}
1368
1369void FillX86BrandString(char brand_string[49]) {
1370 const Leaf leaf_ext_0 = CpuId(0x80000000);
1371 const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
1372 SetString(max_cpuid_leaf_ext, 0x80000002, brand_string);
1373 SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16);
1374 SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32);
1375 brand_string[48] = '\0';
1376}
1377
1378////////////////////////////////////////////////////////////////////////////////
1379// Introspection functions
1380
1381int GetX86FeaturesEnumValue(const X86Features* features,
1382 X86FeaturesEnum value) {
1383 switch (value) {
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001384 case X86_FPU:
1385 return features->fpu;
1386 case X86_TSC:
1387 return features->tsc;
1388 case X86_CX8:
1389 return features->cx8;
1390 case X86_CLFSH:
1391 return features->clfsh;
1392 case X86_MMX:
1393 return features->mmx;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001394 case X86_AES:
1395 return features->aes;
1396 case X86_ERMS:
1397 return features->erms;
1398 case X86_F16C:
1399 return features->f16c;
gadoofou873262a552020-03-11 18:44:49 +05001400 case X86_FMA4:
1401 return features->fma4;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001402 case X86_FMA3:
1403 return features->fma3;
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001404 case X86_VAES:
1405 return features->vaes;
Guillaume Chatelet11e3e202018-02-09 08:55:11 +01001406 case X86_VPCLMULQDQ:
1407 return features->vpclmulqdq;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001408 case X86_BMI1:
1409 return features->bmi1;
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001410 case X86_HLE:
1411 return features->hle;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001412 case X86_BMI2:
1413 return features->bmi2;
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001414 case X86_RTM:
1415 return features->rtm;
1416 case X86_RDSEED:
1417 return features->rdseed;
1418 case X86_CLFLUSHOPT:
1419 return features->clflushopt;
1420 case X86_CLWB:
1421 return features->clwb;
1422 case X86_SSE:
1423 return features->sse;
1424 case X86_SSE2:
1425 return features->sse2;
1426 case X86_SSE3:
1427 return features->sse3;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001428 case X86_SSSE3:
1429 return features->ssse3;
1430 case X86_SSE4_1:
1431 return features->sse4_1;
1432 case X86_SSE4_2:
1433 return features->sse4_2;
gadoofou873262a552020-03-11 18:44:49 +05001434 case X86_SSE4A:
1435 return features->sse4a;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001436 case X86_AVX:
1437 return features->avx;
1438 case X86_AVX2:
1439 return features->avx2;
1440 case X86_AVX512F:
1441 return features->avx512f;
1442 case X86_AVX512CD:
1443 return features->avx512cd;
1444 case X86_AVX512ER:
1445 return features->avx512er;
1446 case X86_AVX512PF:
1447 return features->avx512pf;
1448 case X86_AVX512BW:
1449 return features->avx512bw;
1450 case X86_AVX512DQ:
1451 return features->avx512dq;
1452 case X86_AVX512VL:
1453 return features->avx512vl;
1454 case X86_AVX512IFMA:
1455 return features->avx512ifma;
1456 case X86_AVX512VBMI:
1457 return features->avx512vbmi;
1458 case X86_AVX512VBMI2:
1459 return features->avx512vbmi2;
1460 case X86_AVX512VNNI:
1461 return features->avx512vnni;
1462 case X86_AVX512BITALG:
1463 return features->avx512bitalg;
1464 case X86_AVX512VPOPCNTDQ:
1465 return features->avx512vpopcntdq;
1466 case X86_AVX512_4VNNIW:
1467 return features->avx512_4vnniw;
Jeff Hammond17ffb652020-09-22 00:29:46 -07001468 case X86_AVX512_4VBMI2:
1469 return features->avx512_4vbmi2;
1470 case X86_AVX512_SECOND_FMA:
1471 return features->avx512_second_fma;
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001472 case X86_AVX512_4FMAPS:
1473 return features->avx512_4fmaps;
1474 case X86_AVX512_BF16:
1475 return features->avx512_bf16;
1476 case X86_AVX512_VP2INTERSECT:
1477 return features->avx512_vp2intersect;
1478 case X86_AMX_BF16:
1479 return features->amx_bf16;
1480 case X86_AMX_TILE:
1481 return features->amx_tile;
1482 case X86_AMX_INT8:
1483 return features->amx_int8;
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001484 case X86_PCLMULQDQ:
1485 return features->pclmulqdq;
Patrik Fiedler3ee0d622018-02-13 11:14:32 +01001486 case X86_SMX:
1487 return features->smx;
1488 case X86_SGX:
1489 return features->sgx;
Guillaume Chatelet9b872ce2018-03-13 10:58:42 +01001490 case X86_CX16:
1491 return features->cx16;
Guillaume Chateletd395dfa2019-01-22 13:19:42 +01001492 case X86_SHA:
1493 return features->sha;
1494 case X86_POPCNT:
1495 return features->popcnt;
1496 case X86_MOVBE:
1497 return features->movbe;
1498 case X86_RDRND:
1499 return features->rdrnd;
Artem Alekseev3ee4a9e2019-06-19 16:06:05 +03001500 case X86_DCA:
1501 return features->dca;
1502 case X86_SS:
1503 return features->ss;
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001504 case X86_LAST_:
1505 break;
1506 }
1507 return false;
1508}
1509
1510const char* GetX86FeaturesEnumName(X86FeaturesEnum value) {
1511 switch (value) {
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001512 case X86_FPU:
1513 return "fpu";
1514 case X86_TSC:
1515 return "tsc";
1516 case X86_CX8:
1517 return "cx8";
1518 case X86_CLFSH:
1519 return "clfsh";
1520 case X86_MMX:
1521 return "mmx";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001522 case X86_AES:
1523 return "aes";
1524 case X86_ERMS:
1525 return "erms";
1526 case X86_F16C:
1527 return "f16c";
gadoofou873262a552020-03-11 18:44:49 +05001528 case X86_FMA4:
1529 return "fma4";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001530 case X86_FMA3:
1531 return "fma3";
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001532 case X86_VAES:
1533 return "vaes";
Guillaume Chatelet11e3e202018-02-09 08:55:11 +01001534 case X86_VPCLMULQDQ:
1535 return "vpclmulqdq";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001536 case X86_BMI1:
1537 return "bmi1";
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001538 case X86_HLE:
1539 return "hle";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001540 case X86_BMI2:
1541 return "bmi2";
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001542 case X86_RTM:
1543 return "rtm";
1544 case X86_RDSEED:
1545 return "rdseed";
1546 case X86_CLFLUSHOPT:
1547 return "clflushopt";
1548 case X86_CLWB:
1549 return "clwb";
1550 case X86_SSE:
1551 return "sse";
1552 case X86_SSE2:
1553 return "sse2";
1554 case X86_SSE3:
1555 return "sse3";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001556 case X86_SSSE3:
1557 return "ssse3";
1558 case X86_SSE4_1:
1559 return "sse4_1";
1560 case X86_SSE4_2:
1561 return "sse4_2";
gadoofou873262a552020-03-11 18:44:49 +05001562 case X86_SSE4A:
1563 return "sse4a";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001564 case X86_AVX:
1565 return "avx";
1566 case X86_AVX2:
1567 return "avx2";
1568 case X86_AVX512F:
1569 return "avx512f";
1570 case X86_AVX512CD:
1571 return "avx512cd";
1572 case X86_AVX512ER:
1573 return "avx512er";
1574 case X86_AVX512PF:
1575 return "avx512pf";
1576 case X86_AVX512BW:
1577 return "avx512bw";
1578 case X86_AVX512DQ:
1579 return "avx512dq";
1580 case X86_AVX512VL:
1581 return "avx512vl";
1582 case X86_AVX512IFMA:
1583 return "avx512ifma";
1584 case X86_AVX512VBMI:
1585 return "avx512vbmi";
1586 case X86_AVX512VBMI2:
1587 return "avx512vbmi2";
1588 case X86_AVX512VNNI:
1589 return "avx512vnni";
1590 case X86_AVX512BITALG:
1591 return "avx512bitalg";
1592 case X86_AVX512VPOPCNTDQ:
1593 return "avx512vpopcntdq";
1594 case X86_AVX512_4VNNIW:
1595 return "avx512_4vnniw";
Jeff Hammond17ffb652020-09-22 00:29:46 -07001596 case X86_AVX512_4VBMI2:
1597 return "avx512_4vbmi2";
1598 case X86_AVX512_SECOND_FMA:
1599 return "avx512_second_fma";
Jeff Hammond33bd72c2020-09-21 00:56:26 -07001600 case X86_AVX512_4FMAPS:
1601 return "avx512_4fmaps";
1602 case X86_AVX512_BF16:
1603 return "avx512_bf16";
1604 case X86_AVX512_VP2INTERSECT:
1605 return "avx512_vp2intersect";
1606 case X86_AMX_BF16:
1607 return "amx_bf16";
1608 case X86_AMX_TILE:
1609 return "amx_tile";
1610 case X86_AMX_INT8:
1611 return "amx_int8";
Dr.-Ing. Patrick Siegl367bc422019-06-13 11:53:39 +02001612 case X86_PCLMULQDQ:
1613 return "pclmulqdq";
Patrik Fiedler3ee0d622018-02-13 11:14:32 +01001614 case X86_SMX:
1615 return "smx";
1616 case X86_SGX:
1617 return "sgx";
Guillaume Chatelet9b872ce2018-03-13 10:58:42 +01001618 case X86_CX16:
1619 return "cx16";
Guillaume Chateletd395dfa2019-01-22 13:19:42 +01001620 case X86_SHA:
1621 return "sha";
1622 case X86_POPCNT:
1623 return "popcnt";
1624 case X86_MOVBE:
1625 return "movbe";
1626 case X86_RDRND:
1627 return "rdrnd";
Artem Alekseev3ee4a9e2019-06-19 16:06:05 +03001628 case X86_DCA:
1629 return "dca";
1630 case X86_SS:
1631 return "ss";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001632 case X86_LAST_:
1633 break;
1634 }
1635 return "unknown_feature";
1636}
1637
1638const char* GetX86MicroarchitectureName(X86Microarchitecture uarch) {
1639 switch (uarch) {
1640 case X86_UNKNOWN:
1641 return "X86_UNKNOWN";
1642 case INTEL_CORE:
1643 return "INTEL_CORE";
1644 case INTEL_PNR:
1645 return "INTEL_PNR";
1646 case INTEL_NHM:
1647 return "INTEL_NHM";
1648 case INTEL_ATOM_BNL:
1649 return "INTEL_ATOM_BNL";
1650 case INTEL_WSM:
1651 return "INTEL_WSM";
1652 case INTEL_SNB:
1653 return "INTEL_SNB";
1654 case INTEL_IVB:
1655 return "INTEL_IVB";
1656 case INTEL_ATOM_SMT:
1657 return "INTEL_ATOM_SMT";
1658 case INTEL_HSW:
1659 return "INTEL_HSW";
1660 case INTEL_BDW:
1661 return "INTEL_BDW";
1662 case INTEL_SKL:
1663 return "INTEL_SKL";
1664 case INTEL_ATOM_GMT:
1665 return "INTEL_ATOM_GMT";
1666 case INTEL_KBL:
1667 return "INTEL_KBL";
1668 case INTEL_CFL:
1669 return "INTEL_CFL";
Moxeja24b8a1d2020-01-06 23:01:21 +00001670 case INTEL_WHL:
1671 return "INTEL_WHL";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001672 case INTEL_CNL:
1673 return "INTEL_CNL";
Moxeja24b8a1d2020-01-06 23:01:21 +00001674 case INTEL_ICL:
1675 return "INTEL_ICL";
Jeff Hammonde6983272020-09-21 00:54:58 -07001676 case INTEL_TGL:
1677 return "INTEL_TGL";
1678 case INTEL_SPR:
1679 return "INTEL_SPR";
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001680 case AMD_HAMMER:
1681 return "AMD_HAMMER";
1682 case AMD_K10:
1683 return "AMD_K10";
1684 case AMD_BOBCAT:
1685 return "AMD_BOBCAT";
1686 case AMD_BULLDOZER:
1687 return "AMD_BULLDOZER";
1688 case AMD_JAGUAR:
1689 return "AMD_JAGUAR";
1690 case AMD_ZEN:
1691 return "AMD_ZEN";
1692 }
1693 return "unknown microarchitecture";
1694}