1 // Copyright 2016 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <arch/x86/feature.h>
8 
9 #include <assert.h>
10 #include <bits.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <trace.h>
14 
15 #include <arch/ops.h>
16 
17 #include <fbl/algorithm.h>
18 
19 #define LOCAL_TRACE 0
20 
21 struct cpuid_leaf _cpuid[MAX_SUPPORTED_CPUID + 1];
22 struct cpuid_leaf _cpuid_hyp[MAX_SUPPORTED_CPUID_HYP - X86_CPUID_HYP_BASE + 1];
23 struct cpuid_leaf _cpuid_ext[MAX_SUPPORTED_CPUID_EXT - X86_CPUID_EXT_BASE + 1];
24 uint32_t max_cpuid = 0;
25 uint32_t max_hyp_cpuid = 0;
26 uint32_t max_ext_cpuid = 0;
27 
28 enum x86_vendor_list x86_vendor;
29 enum x86_microarch_list x86_microarch;
30 const x86_microarch_config_t* x86_microarch_config;
31 
32 static struct x86_model_info model_info;
33 
34 bool g_x86_feature_fsgsbase;
35 
36 enum x86_hypervisor_list x86_hypervisor;
37 
38 static int initialized = 0;
39 
40 static enum x86_microarch_list get_microarch(struct x86_model_info* info);
41 static void select_microarch_config(void);
42 
43 static enum x86_hypervisor_list get_hypervisor();
44 
x86_feature_init(void)45 void x86_feature_init(void) {
46     if (atomic_swap(&initialized, 1)) {
47         return;
48     }
49     /* test for cpuid count */
50     cpuid(0, &_cpuid[0].a, &_cpuid[0].b, &_cpuid[0].c, &_cpuid[0].d);
51 
52     max_cpuid = _cpuid[0].a;
53     if (max_cpuid > MAX_SUPPORTED_CPUID)
54         max_cpuid = MAX_SUPPORTED_CPUID;
55 
56     LTRACEF("max cpuid 0x%x\n", max_cpuid);
57 
58     /* figure out the vendor */
59     union {
60         uint32_t vendor_id[3];
61         char vendor_string[12];
62     } vu;
63     vu.vendor_id[0] = _cpuid[0].b;
64     vu.vendor_id[1] = _cpuid[0].d;
65     vu.vendor_id[2] = _cpuid[0].c;
66     if (!memcmp(vu.vendor_string, "GenuineIntel", sizeof(vu.vendor_string))) {
67         x86_vendor = X86_VENDOR_INTEL;
68     } else if (!memcmp(vu.vendor_string, "AuthenticAMD", sizeof(vu.vendor_string))) {
69         x86_vendor = X86_VENDOR_AMD;
70     } else {
71         x86_vendor = X86_VENDOR_UNKNOWN;
72     }
73 
74     /* read in the base cpuids */
75     for (uint32_t i = 1; i <= max_cpuid; i++) {
76         cpuid_c(i, 0, &_cpuid[i].a, &_cpuid[i].b, &_cpuid[i].c, &_cpuid[i].d);
77     }
78 
79     /* test for extended cpuid count */
80     cpuid(X86_CPUID_EXT_BASE, &_cpuid_ext[0].a, &_cpuid_ext[0].b, &_cpuid_ext[0].c,
81           &_cpuid_ext[0].d);
82 
83     max_ext_cpuid = _cpuid_ext[0].a;
84     LTRACEF("max extended cpuid 0x%x\n", max_ext_cpuid);
85     if (max_ext_cpuid > MAX_SUPPORTED_CPUID_EXT)
86         max_ext_cpuid = MAX_SUPPORTED_CPUID_EXT;
87 
88     /* read in the extended cpuids */
89     for (uint32_t i = X86_CPUID_EXT_BASE + 1; i - 1 < max_ext_cpuid; i++) {
90         uint32_t index = i - X86_CPUID_EXT_BASE;
91         cpuid_c(i, 0, &_cpuid_ext[index].a, &_cpuid_ext[index].b, &_cpuid_ext[index].c,
92                 &_cpuid_ext[index].d);
93     }
94 
95     /* read in the hypervisor cpuids. the maximum leaf is reported at X86_CPUID_HYP_BASE. */
96     cpuid(X86_CPUID_HYP_VENDOR, &_cpuid_ext[0].a, &_cpuid_ext[0].b, &_cpuid_ext[0].c,
97           &_cpuid_ext[0].d);
98     max_hyp_cpuid = _cpuid_ext[0].a;
99     if (max_hyp_cpuid > MAX_SUPPORTED_CPUID_HYP)
100       max_hyp_cpuid = MAX_SUPPORTED_CPUID_HYP;
101     for (uint32_t i = X86_CPUID_HYP_BASE; i <= max_hyp_cpuid; i++) {
102         uint32_t index = i - X86_CPUID_HYP_BASE;
103         cpuid(i, &_cpuid_hyp[index].a, &_cpuid_hyp[index].b, &_cpuid_hyp[index].c,
104               &_cpuid_hyp[index].d);
105     }
106 
107     /* populate the model info */
108     const struct cpuid_leaf* leaf = x86_get_cpuid_leaf(X86_CPUID_MODEL_FEATURES);
109     if (leaf) {
110         model_info.processor_type = (uint8_t)BITS_SHIFT(leaf->a, 13, 12);
111         model_info.family = (uint8_t)BITS_SHIFT(leaf->a, 11, 8);
112         model_info.model = (uint8_t)BITS_SHIFT(leaf->a, 7, 4);
113         model_info.stepping = (uint8_t)BITS_SHIFT(leaf->a, 3, 0);
114         model_info.display_family = model_info.family;
115         model_info.display_model = model_info.model;
116 
117         if (model_info.family == 0xf) {
118             model_info.display_family += BITS_SHIFT(leaf->a, 27, 20);
119         }
120 
121         if (model_info.family == 0xf || model_info.family == 0x6) {
122             model_info.display_model += BITS_SHIFT(leaf->a, 19, 16) << 4;
123         }
124 
125         x86_microarch = get_microarch(&model_info);
126     }
127     select_microarch_config();
128 
129     g_x86_feature_fsgsbase = x86_feature_test(X86_FEATURE_FSGSBASE);
130 
131     x86_hypervisor = get_hypervisor();
132 }
133 
get_microarch(struct x86_model_info * info)134 static enum x86_microarch_list get_microarch(struct x86_model_info* info) {
135     if (x86_vendor == X86_VENDOR_INTEL && info->family == 0x6) {
136         switch (info->display_model) {
137         case 0x1a: /* Nehalem */
138         case 0x1e: /* Nehalem */
139         case 0x1f: /* Nehalem */
140         case 0x2e: /* Nehalem */
141             return X86_MICROARCH_INTEL_NEHALEM;
142         case 0x25: /* Westmere */
143         case 0x2c: /* Westmere */
144         case 0x2f: /* Westmere */
145             return X86_MICROARCH_INTEL_WESTMERE;
146         case 0x2a: /* Sandy Bridge */
147         case 0x2d: /* Sandy Bridge EP */
148             return X86_MICROARCH_INTEL_SANDY_BRIDGE;
149         case 0x3a: /* Ivy Bridge */
150         case 0x3e: /* Ivy Bridge EP */
151             return X86_MICROARCH_INTEL_IVY_BRIDGE;
152         case 0x3c: /* Haswell DT */
153         case 0x3f: /* Haswell MB */
154         case 0x45: /* Haswell ULT */
155         case 0x46: /* Haswell ULX */
156             return X86_MICROARCH_INTEL_HASWELL;
157         case 0x3d: /* Broadwell */
158         case 0x47: /* Broadwell H */
159         case 0x56: /* Broadwell EP */
160         case 0x4f: /* Broadwell EX */
161             return X86_MICROARCH_INTEL_BROADWELL;
162         case 0x4e: /* Skylake Y/U */
163         case 0x5e: /* Skylake H/S */
164         case 0x55: /* Skylake E */
165             return X86_MICROARCH_INTEL_SKYLAKE;
166         case 0x8e: /* Kabylake Y/U */
167         case 0x9e: /* Kabylake H/S */
168             return X86_MICROARCH_INTEL_KABYLAKE;
169         case 0x4d: /* Silvermont */
170             return X86_MICROARCH_INTEL_SILVERMONT;
171         }
172     } else if (x86_vendor == X86_VENDOR_AMD && info->family == 0xf) {
173         switch (info->display_family) { // zen
174         case 0x15:                      /* Bulldozer */
175             return X86_MICROARCH_AMD_BULLDOZER;
176         case 0x16: /* Jaguar */
177             return X86_MICROARCH_AMD_JAGUAR;
178         case 0x17: /* Zen */
179             return X86_MICROARCH_AMD_ZEN;
180         }
181     }
182     return X86_MICROARCH_UNKNOWN;
183 }
184 
get_hypervisor()185 static enum x86_hypervisor_list get_hypervisor() {
186     if (!x86_feature_test(X86_FEATURE_HYPERVISOR)) {
187         return X86_HYPERVISOR_UNKNOWN;
188     }
189     uint32_t a, b, c, d;
190     cpuid(X86_CPUID_HYP_VENDOR, &a, &b, &c, &d);
191     union {
192         uint32_t vendor_id[3];
193         char vendor_string[12];
194     } vu;
195     vu.vendor_id[0] = b;
196     vu.vendor_id[1] = c;
197     vu.vendor_id[2] = d;
198     if (a >= X86_CPUID_KVM_FEATURES &&
199         !memcmp(vu.vendor_string, "KVMKVMKVM\0\0\0", sizeof(vu.vendor_string))) {
200         return X86_HYPERVISOR_KVM;
201     } else {
202         return X86_HYPERVISOR_UNKNOWN;
203     }
204 }
205 
x86_get_cpuid_subleaf(enum x86_cpuid_leaf_num num,uint32_t subleaf,struct cpuid_leaf * leaf)206 bool x86_get_cpuid_subleaf(
207     enum x86_cpuid_leaf_num num, uint32_t subleaf, struct cpuid_leaf* leaf) {
208     if (num < X86_CPUID_EXT_BASE) {
209         if (num > max_cpuid)
210             return false;
211     } else if (num > max_ext_cpuid) {
212         return false;
213     }
214 
215     cpuid_c((uint32_t)num, subleaf, &leaf->a, &leaf->b, &leaf->c, &leaf->d);
216     return true;
217 }
218 
x86_topology_enumerate(uint8_t level,struct x86_topology_level * info)219 bool x86_topology_enumerate(uint8_t level, struct x86_topology_level* info) {
220     DEBUG_ASSERT(info);
221 
222     uint32_t eax, ebx, ecx, edx;
223     cpuid_c(X86_CPUID_TOPOLOGY, level, &eax, &ebx, &ecx, &edx);
224 
225     uint8_t type = (ecx >> 8) & 0xff;
226     if (type == X86_TOPOLOGY_INVALID) {
227         return false;
228     }
229 
230     info->right_shift = eax & 0x1f;
231     info->type = type;
232     return true;
233 }
234 
x86_get_model(void)235 const struct x86_model_info* x86_get_model(void) {
236     return &model_info;
237 }
238 
x86_feature_debug(void)239 void x86_feature_debug(void) {
240     const struct {
241         struct x86_cpuid_bit bit;
242         const char* name;
243     } features[] = {
244         {X86_FEATURE_FPU, "fpu"},
245         {X86_FEATURE_SSE, "sse"},
246         {X86_FEATURE_SSE2, "sse2"},
247         {X86_FEATURE_SSE3, "sse3"},
248         {X86_FEATURE_SSSE3, "ssse3"},
249         {X86_FEATURE_SSE4_1, "sse4.1"},
250         {X86_FEATURE_SSE4_2, "sse4.2"},
251         {X86_FEATURE_MMX, "mmx"},
252         {X86_FEATURE_AVX, "avx"},
253         {X86_FEATURE_AVX2, "avx2"},
254         {X86_FEATURE_FXSR, "fxsr"},
255         {X86_FEATURE_PCID, "pcid"},
256         {X86_FEATURE_XSAVE, "xsave"},
257         {X86_FEATURE_MON, "mon"},
258         {X86_FEATURE_AESNI, "aesni"},
259         {X86_FEATURE_CLFLUSH, "clflush"},
260         {X86_FEATURE_CLFLUSHOPT, "clflushopt"},
261         {X86_FEATURE_CLWB, "clwb"},
262         {X86_FEATURE_FSGSBASE, "fsgsbase"},
263         {X86_FEATURE_TSC_ADJUST, "tsc_adj"},
264         {X86_FEATURE_SMEP, "smep"},
265         {X86_FEATURE_SMAP, "smap"},
266         {X86_FEATURE_ERMS, "erms"},
267         {X86_FEATURE_RDRAND, "rdrand"},
268         {X86_FEATURE_RDSEED, "rdseed"},
269         {X86_FEATURE_UMIP, "umip"},
270         {X86_FEATURE_PKU, "pku"},
271         {X86_FEATURE_SYSCALL, "syscall"},
272         {X86_FEATURE_NX, "nx"},
273         {X86_FEATURE_HUGE_PAGE, "huge"},
274         {X86_FEATURE_RDTSCP, "rdtscp"},
275         {X86_FEATURE_INVAR_TSC, "invar_tsc"},
276         {X86_FEATURE_TSC_DEADLINE, "tsc_deadline"},
277         {X86_FEATURE_X2APIC, "x2apic"},
278         {X86_FEATURE_VMX, "vmx"},
279         {X86_FEATURE_HYPERVISOR, "hypervisor"},
280         {X86_FEATURE_PT, "pt"},
281         {X86_FEATURE_HWP, "hwp"},
282     };
283 
284     const char* vendor_string = nullptr;
285     switch (x86_vendor) {
286     case X86_VENDOR_UNKNOWN:
287         vendor_string = "unknown";
288         break;
289     case X86_VENDOR_INTEL:
290         vendor_string = "Intel";
291         break;
292     case X86_VENDOR_AMD:
293         vendor_string = "AMD";
294         break;
295     }
296     printf("Vendor: %s\n", vendor_string);
297 
298     const char* microarch_string = nullptr;
299     switch (x86_microarch) {
300     case X86_MICROARCH_UNKNOWN:
301         microarch_string = "unknown";
302         break;
303     case X86_MICROARCH_INTEL_NEHALEM:
304         microarch_string = "Nehalem";
305         break;
306     case X86_MICROARCH_INTEL_WESTMERE:
307         microarch_string = "Westmere";
308         break;
309     case X86_MICROARCH_INTEL_SANDY_BRIDGE:
310         microarch_string = "Sandy Bridge";
311         break;
312     case X86_MICROARCH_INTEL_IVY_BRIDGE:
313         microarch_string = "Ivy Bridge";
314         break;
315     case X86_MICROARCH_INTEL_BROADWELL:
316         microarch_string = "Broadwell";
317         break;
318     case X86_MICROARCH_INTEL_HASWELL:
319         microarch_string = "Haswell";
320         break;
321     case X86_MICROARCH_INTEL_SKYLAKE:
322         microarch_string = "Skylake";
323         break;
324     case X86_MICROARCH_INTEL_KABYLAKE:
325         microarch_string = "Kaby Lake";
326         break;
327     case X86_MICROARCH_INTEL_SILVERMONT:
328         microarch_string = "Silvermont";
329         break;
330     case X86_MICROARCH_AMD_BULLDOZER:
331         microarch_string = "Bulldozer";
332         break;
333     case X86_MICROARCH_AMD_JAGUAR:
334         microarch_string = "Jaguar";
335         break;
336     case X86_MICROARCH_AMD_ZEN:
337         microarch_string = "Zen";
338         break;
339     }
340     printf("Microarch: %s\n", microarch_string);
341     printf("F/M/S: %x/%x/%x\n", model_info.display_family, model_info.display_model,
342            model_info.stepping);
343 
344     char brand_string[50];
345     memset(brand_string, 0, sizeof(brand_string));
346     const struct cpuid_leaf* leaf;
347     uint32_t leaf_num = X86_CPUID_BRAND;
348     for (int i = 0; i < 3; i++) {
349         leaf = x86_get_cpuid_leaf((enum x86_cpuid_leaf_num)(leaf_num + i));
350         if (!leaf) {
351             break;
352         }
353         memcpy(brand_string + (i * 16), &leaf->a, sizeof(uint32_t));
354         memcpy(brand_string + (i * 16) + 4, &leaf->b, sizeof(uint32_t));
355         memcpy(brand_string + (i * 16) + 8, &leaf->c, sizeof(uint32_t));
356         memcpy(brand_string + (i * 16) + 12, &leaf->d, sizeof(uint32_t));
357     }
358     printf("Brand: %s\n", brand_string);
359 
360     printf("Features: ");
361     uint col = 0;
362     for (uint i = 0; i < fbl::count_of(features); ++i) {
363         if (x86_feature_test(features[i].bit))
364             col += printf("%s ", features[i].name);
365         if (col >= 80) {
366             printf("\n");
367             col = 0;
368         }
369     }
370     if (col > 0)
371         printf("\n");
372 }
373 
default_apic_freq()374 static uint64_t default_apic_freq() {
375     // The APIC frequency is the core crystal clock frequency if it is
376     // enumerated in the CPUID leaf 0x15, or the processor's bus clock
377     // frequency.
378 
379     const struct cpuid_leaf* tsc_leaf = x86_get_cpuid_leaf(X86_CPUID_TSC);
380     if (tsc_leaf && tsc_leaf->c != 0) {
381         return tsc_leaf->c;
382     }
383     return 0;
384 }
385 
kbl_apic_freq()386 static uint64_t kbl_apic_freq() {
387     uint64_t v = default_apic_freq();
388     if (v != 0) {
389         return v;
390     }
391     return 24ul * 1000 * 1000;
392 }
393 
bdw_apic_freq()394 static uint64_t bdw_apic_freq() {
395     uint64_t v = default_apic_freq();
396     if (v != 0) {
397         return v;
398     }
399     uint64_t platform_info;
400     const uint32_t msr_platform_info = 0xce;
401     if (read_msr_safe(msr_platform_info, &platform_info) == ZX_OK) {
402         uint64_t bus_freq_mult = (platform_info >> 8) & 0xf;
403         return bus_freq_mult * 100 * 1000 * 1000;
404     }
405     return 0;
406 }
407 
bulldozer_apic_freq()408 static uint64_t bulldozer_apic_freq() {
409     uint64_t v = default_apic_freq();
410     if (v != 0) {
411         return v;
412     }
413 
414     // 15h-17h BKDGs mention the APIC timer rate is 2xCLKIN,
415     // which experimentally appears to be 100Mhz always
416     return 100ul * 1000 * 1000;
417 }
418 
unknown_freq()419 static uint64_t unknown_freq() {
420     return 0;
421 }
422 
intel_tsc_freq()423 static uint64_t intel_tsc_freq() {
424     const uint64_t core_crystal_clock_freq = x86_get_microarch_config()->get_apic_freq();
425 
426     // If this leaf is present, then 18.18.3 (Determining the Processor Base
427     // Frequency) documents this as the nominal TSC frequency.
428     const struct cpuid_leaf* tsc_leaf = x86_get_cpuid_leaf(X86_CPUID_TSC);
429     if (tsc_leaf && tsc_leaf->a) {
430         return (core_crystal_clock_freq * tsc_leaf->b) / tsc_leaf->a;
431     }
432     return 0;
433 }
434 
amd_compute_p_state_clock(uint64_t p_state_msr)435 static uint64_t amd_compute_p_state_clock(uint64_t p_state_msr) {
436     // is it valid?
437     if (!BIT(p_state_msr, 63))
438         return 0;
439 
440     // different AMD microarchitectures use slightly different formulas to compute
441     // the effective clock rate of a P state
442     uint64_t clock = 0;
443     switch (x86_microarch) {
444     case X86_MICROARCH_AMD_BULLDOZER:
445     case X86_MICROARCH_AMD_JAGUAR: {
446         uint64_t did = BITS_SHIFT(p_state_msr, 8, 6);
447         uint64_t fid = BITS(p_state_msr, 5, 0);
448 
449         clock = (100 * (fid + 0x10) / (1 << did)) * 1000 * 1000;
450         break;
451     }
452     case X86_MICROARCH_AMD_ZEN: {
453         uint64_t fid = BITS(p_state_msr, 7, 0);
454 
455         clock = (fid * 25) * 1000 * 1000;
456         break;
457     }
458     default:
459         break;
460     }
461 
462     return clock;
463 }
464 
zen_tsc_freq()465 static uint64_t zen_tsc_freq() {
466     const uint32_t p0_state_msr = 0xc0010064; // base P-state MSR
467     // According to the Family 17h PPR, the first P-state MSR is indeed
468     // P0 state and appears to be experimentally so
469     uint64_t p0_state;
470     if (read_msr_safe(p0_state_msr, &p0_state) != ZX_OK)
471         return 0;
472 
473     return amd_compute_p_state_clock(p0_state);
474 }
475 
unknown_reboot_system(void)476 static void unknown_reboot_system(void) {
477     return;
478 }
479 
hsw_reboot_system(void)480 static void hsw_reboot_system(void) {
481     // 100-Series Chipset Reset Control Register: CPU + SYS Reset
482     outp(0xcf9, 0x06);
483 }
484 
485 // Intel microarches
486 static const x86_microarch_config_t kbl_config{
487     .get_apic_freq = kbl_apic_freq,
488     .get_tsc_freq = intel_tsc_freq,
489     .reboot_system = hsw_reboot_system,
490     .disable_c1e = true,
491 };
492 static const x86_microarch_config_t skl_config{
493     .get_apic_freq = kbl_apic_freq,
494     .get_tsc_freq = intel_tsc_freq,
495     .reboot_system = hsw_reboot_system,
496     .disable_c1e = true,
497 };
498 static const x86_microarch_config_t bdw_config{
499     .get_apic_freq = bdw_apic_freq,
500     .get_tsc_freq = intel_tsc_freq,
501     .reboot_system = hsw_reboot_system,
502     .disable_c1e = true,
503 };
504 static const x86_microarch_config_t hsw_config{
505     .get_apic_freq = bdw_apic_freq,
506     .get_tsc_freq = intel_tsc_freq,
507     .reboot_system = hsw_reboot_system,
508     .disable_c1e = true,
509 };
510 static const x86_microarch_config_t ivb_config{
511     .get_apic_freq = bdw_apic_freq,
512     .get_tsc_freq = intel_tsc_freq,
513     .reboot_system = unknown_reboot_system,
514     .disable_c1e = true,
515 };
516 static const x86_microarch_config_t snb_config{
517     .get_apic_freq = bdw_apic_freq,
518     .get_tsc_freq = intel_tsc_freq,
519     .reboot_system = unknown_reboot_system,
520     .disable_c1e = true,
521 };
522 static const x86_microarch_config_t westmere_config{
523     .get_apic_freq = default_apic_freq,
524     .get_tsc_freq = intel_tsc_freq,
525     .reboot_system = unknown_reboot_system,
526     .disable_c1e = true,
527 };
528 static const x86_microarch_config_t nehalem_config{
529     .get_apic_freq = default_apic_freq,
530     .get_tsc_freq = intel_tsc_freq,
531     .reboot_system = unknown_reboot_system,
532     .disable_c1e = true,
533 };
534 static const x86_microarch_config_t smt_config{
535     .get_apic_freq = default_apic_freq,
536     .get_tsc_freq = intel_tsc_freq,
537     .reboot_system = unknown_reboot_system,
538     .disable_c1e = false,
539 };
540 static const x86_microarch_config_t intel_default_config{
541     .get_apic_freq = default_apic_freq,
542     .get_tsc_freq = intel_tsc_freq,
543     .reboot_system = unknown_reboot_system,
544     .disable_c1e = false,
545 };
546 
547 // AMD microarches
548 static const x86_microarch_config_t zen_config{
549     .get_apic_freq = bulldozer_apic_freq,
550     .get_tsc_freq = zen_tsc_freq,
551     .reboot_system = unknown_reboot_system,
552     .disable_c1e = false,
553 };
554 static const x86_microarch_config_t jaguar_config{
555     .get_apic_freq = bulldozer_apic_freq,
556     .get_tsc_freq = unknown_freq,
557     .reboot_system = unknown_reboot_system,
558     .disable_c1e = false,
559 };
560 static const x86_microarch_config_t bulldozer_config{
561     .get_apic_freq = bulldozer_apic_freq,
562     .get_tsc_freq = unknown_freq,
563     .reboot_system = unknown_reboot_system,
564     .disable_c1e = false,
565 };
566 static const x86_microarch_config_t amd_default_config{
567     .get_apic_freq = default_apic_freq,
568     .get_tsc_freq = unknown_freq,
569     .reboot_system = unknown_reboot_system,
570     .disable_c1e = false,
571 };
572 
573 // Unknown vendor config
574 static const x86_microarch_config_t unknown_vendor_config{
575     .get_apic_freq = unknown_freq,
576     .get_tsc_freq = unknown_freq,
577     .reboot_system = unknown_reboot_system,
578     .disable_c1e = false,
579 };
580 
select_microarch_config(void)581 void select_microarch_config(void) {
582     switch (x86_microarch) {
583     case X86_MICROARCH_INTEL_NEHALEM:
584         x86_microarch_config = &nehalem_config;
585         break;
586     case X86_MICROARCH_INTEL_WESTMERE:
587         x86_microarch_config = &westmere_config;
588         break;
589     case X86_MICROARCH_INTEL_SANDY_BRIDGE:
590         x86_microarch_config = &snb_config;
591         break;
592     case X86_MICROARCH_INTEL_IVY_BRIDGE:
593         x86_microarch_config = &ivb_config;
594         break;
595     case X86_MICROARCH_INTEL_BROADWELL:
596         x86_microarch_config = &bdw_config;
597         break;
598     case X86_MICROARCH_INTEL_HASWELL:
599         x86_microarch_config = &hsw_config;
600         break;
601     case X86_MICROARCH_INTEL_SKYLAKE:
602         x86_microarch_config = &skl_config;
603         break;
604     case X86_MICROARCH_INTEL_KABYLAKE:
605         x86_microarch_config = &kbl_config;
606         break;
607     case X86_MICROARCH_INTEL_SILVERMONT:
608         x86_microarch_config = &smt_config;
609         break;
610     case X86_MICROARCH_AMD_BULLDOZER:
611         x86_microarch_config = &bulldozer_config;
612         break;
613     case X86_MICROARCH_AMD_JAGUAR:
614         x86_microarch_config = &jaguar_config;
615         break;
616     case X86_MICROARCH_AMD_ZEN:
617         x86_microarch_config = &zen_config;
618         break;
619     case X86_MICROARCH_UNKNOWN: {
620         printf("WARNING: Could not identify microarch.\n");
621         printf("Please file a bug with your boot log and description of hardware.\n");
622         switch (x86_vendor) {
623         case X86_VENDOR_INTEL:
624             x86_microarch_config = &intel_default_config;
625             break;
626         case X86_VENDOR_AMD:
627             x86_microarch_config = &amd_default_config;
628             break;
629         case X86_VENDOR_UNKNOWN:
630             x86_microarch_config = &unknown_vendor_config;
631             break;
632         }
633     }
634     }
635 }
636