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
21struct cpuid_leaf _cpuid[MAX_SUPPORTED_CPUID + 1];
22struct cpuid_leaf _cpuid_hyp[MAX_SUPPORTED_CPUID_HYP - X86_CPUID_HYP_BASE + 1];
23struct cpuid_leaf _cpuid_ext[MAX_SUPPORTED_CPUID_EXT - X86_CPUID_EXT_BASE + 1];
24uint32_t max_cpuid = 0;
25uint32_t max_hyp_cpuid = 0;
26uint32_t max_ext_cpuid = 0;
27
28enum x86_vendor_list x86_vendor;
29enum x86_microarch_list x86_microarch;
30const x86_microarch_config_t* x86_microarch_config;
31
32static struct x86_model_info model_info;
33
34bool g_x86_feature_fsgsbase;
35
36enum x86_hypervisor_list x86_hypervisor;
37
38static int initialized = 0;
39
40static enum x86_microarch_list get_microarch(struct x86_model_info* info);
41static void select_microarch_config(void);
42
43static enum x86_hypervisor_list get_hypervisor();
44
45void 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
134static 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
185static 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
206bool 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
219bool 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
235const struct x86_model_info* x86_get_model(void) {
236    return &model_info;
237}
238
239void 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
374static 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
386static 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
394static 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
408static 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
419static uint64_t unknown_freq() {
420    return 0;
421}
422
423static 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
435static 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
465static 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
476static void unknown_reboot_system(void) {
477    return;
478}
479
480static void hsw_reboot_system(void) {
481    // 100-Series Chipset Reset Control Register: CPU + SYS Reset
482    outp(0xcf9, 0x06);
483}
484
485// Intel microarches
486static 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};
492static 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};
498static 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};
504static 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};
510static 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};
516static 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};
522static 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};
528static 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};
534static 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};
540static 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
548static 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};
554static 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};
560static 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};
566static 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
574static 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
581void 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