+cpuid_set_info(void)
+{
+ i386_cpu_info_t *info_p = &cpuid_cpu_info;
+ boolean_t enable_x86_64h = TRUE;
+
+ /* Perform pre-cpuid workarounds (since their effects impact values returned via cpuid) */
+ cpuid_do_precpuid_was();
+
+ cpuid_set_generic_info(info_p);
+
+ /* verify we are running on a supported CPU */
+ if ((strncmp(CPUID_VID_INTEL, info_p->cpuid_vendor,
+ min(strlen(CPUID_STRING_UNKNOWN) + 1,
+ sizeof(info_p->cpuid_vendor)))) ||
+ (cpuid_set_cpufamily(info_p) == CPUFAMILY_UNKNOWN)) {
+ panic("Unsupported CPU");
+ }
+
+ info_p->cpuid_cpu_type = CPU_TYPE_X86;
+
+ if (!PE_parse_boot_argn("-enable_x86_64h", &enable_x86_64h, sizeof(enable_x86_64h))) {
+ boolean_t disable_x86_64h = FALSE;
+
+ if (PE_parse_boot_argn("-disable_x86_64h", &disable_x86_64h, sizeof(disable_x86_64h))) {
+ enable_x86_64h = FALSE;
+ }
+ }
+
+ if (enable_x86_64h &&
+ ((info_p->cpuid_features & CPUID_X86_64_H_FEATURE_SUBSET) == CPUID_X86_64_H_FEATURE_SUBSET) &&
+ ((info_p->cpuid_extfeatures & CPUID_X86_64_H_EXTFEATURE_SUBSET) == CPUID_X86_64_H_EXTFEATURE_SUBSET) &&
+ ((info_p->cpuid_leaf7_features & CPUID_X86_64_H_LEAF7_FEATURE_SUBSET) == CPUID_X86_64_H_LEAF7_FEATURE_SUBSET)) {
+ info_p->cpuid_cpu_subtype = CPU_SUBTYPE_X86_64_H;
+ } else {
+ info_p->cpuid_cpu_subtype = CPU_SUBTYPE_X86_ARCH1;
+ }
+ /* cpuid_set_cache_info must be invoked after set_generic_info */
+
+ /*
+ * Find the number of enabled cores and threads
+ * (which determines whether SMT/Hyperthreading is active).
+ */
+
+ /*
+ * Not all VMMs emulate MSR_CORE_THREAD_COUNT (0x35).
+ */
+ if (0 != (info_p->cpuid_features & CPUID_FEATURE_VMM) &&
+ PE_parse_boot_argn("-nomsr35h", NULL, 0)) {
+ info_p->core_count = 1;
+ info_p->thread_count = 1;
+ cpuid_set_cache_info(info_p);
+ } else {
+ switch (info_p->cpuid_cpufamily) {
+ case CPUFAMILY_INTEL_PENRYN:
+ cpuid_set_cache_info(info_p);
+ info_p->core_count = info_p->cpuid_cores_per_package;
+ info_p->thread_count = info_p->cpuid_logical_per_package;
+ break;
+ case CPUFAMILY_INTEL_WESTMERE: {
+ /*
+ * This should be the same as Nehalem but an A0 silicon bug returns
+ * invalid data in the top 12 bits. Hence, we use only bits [19..16]
+ * rather than [31..16] for core count - which actually can't exceed 8.
+ */
+ uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT);
+ if (0 == msr) {
+ /* Provide a non-zero default for some VMMs */
+ msr = (1 << 16) | 1;
+ }
+ info_p->core_count = bitfield32((uint32_t)msr, 19, 16);
+ info_p->thread_count = bitfield32((uint32_t)msr, 15, 0);
+ cpuid_set_cache_info(info_p);
+ break;
+ }
+ default: {
+ uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT);
+ if (0 == msr) {
+ /* Provide a non-zero default for some VMMs */
+ msr = (1 << 16) | 1;
+ }
+ info_p->core_count = bitfield32((uint32_t)msr, 31, 16);
+ info_p->thread_count = bitfield32((uint32_t)msr, 15, 0);
+ cpuid_set_cache_info(info_p);
+ break;
+ }
+ }
+ }
+
+ DBG("cpuid_set_info():\n");
+ DBG(" core_count : %d\n", info_p->core_count);
+ DBG(" thread_count : %d\n", info_p->thread_count);
+ DBG(" cpu_type: 0x%08x\n", info_p->cpuid_cpu_type);
+ DBG(" cpu_subtype: 0x%08x\n", info_p->cpuid_cpu_subtype);
+
+ info_p->cpuid_model_string = ""; /* deprecated */
+
+ /* Init CPU LBRs */
+ i386_lbr_init(info_p, true);
+
+ do_cwas(info_p, FALSE);
+}
+
+static struct table {
+ uint64_t mask;
+ const char *name;
+} feature_map[] = {
+ {CPUID_FEATURE_FPU, "FPU"},
+ {CPUID_FEATURE_VME, "VME"},
+ {CPUID_FEATURE_DE, "DE"},
+ {CPUID_FEATURE_PSE, "PSE"},
+ {CPUID_FEATURE_TSC, "TSC"},
+ {CPUID_FEATURE_MSR, "MSR"},
+ {CPUID_FEATURE_PAE, "PAE"},
+ {CPUID_FEATURE_MCE, "MCE"},
+ {CPUID_FEATURE_CX8, "CX8"},
+ {CPUID_FEATURE_APIC, "APIC"},
+ {CPUID_FEATURE_SEP, "SEP"},
+ {CPUID_FEATURE_MTRR, "MTRR"},
+ {CPUID_FEATURE_PGE, "PGE"},
+ {CPUID_FEATURE_MCA, "MCA"},
+ {CPUID_FEATURE_CMOV, "CMOV"},
+ {CPUID_FEATURE_PAT, "PAT"},
+ {CPUID_FEATURE_PSE36, "PSE36"},
+ {CPUID_FEATURE_PSN, "PSN"},
+ {CPUID_FEATURE_CLFSH, "CLFSH"},
+ {CPUID_FEATURE_DS, "DS"},
+ {CPUID_FEATURE_ACPI, "ACPI"},
+ {CPUID_FEATURE_MMX, "MMX"},
+ {CPUID_FEATURE_FXSR, "FXSR"},
+ {CPUID_FEATURE_SSE, "SSE"},
+ {CPUID_FEATURE_SSE2, "SSE2"},
+ {CPUID_FEATURE_SS, "SS"},
+ {CPUID_FEATURE_HTT, "HTT"},
+ {CPUID_FEATURE_TM, "TM"},
+ {CPUID_FEATURE_PBE, "PBE"},
+ {CPUID_FEATURE_SSE3, "SSE3"},
+ {CPUID_FEATURE_PCLMULQDQ, "PCLMULQDQ"},
+ {CPUID_FEATURE_DTES64, "DTES64"},
+ {CPUID_FEATURE_MONITOR, "MON"},
+ {CPUID_FEATURE_DSCPL, "DSCPL"},
+ {CPUID_FEATURE_VMX, "VMX"},
+ {CPUID_FEATURE_SMX, "SMX"},
+ {CPUID_FEATURE_EST, "EST"},
+ {CPUID_FEATURE_TM2, "TM2"},
+ {CPUID_FEATURE_SSSE3, "SSSE3"},
+ {CPUID_FEATURE_CID, "CID"},
+ {CPUID_FEATURE_FMA, "FMA"},
+ {CPUID_FEATURE_CX16, "CX16"},
+ {CPUID_FEATURE_xTPR, "TPR"},
+ {CPUID_FEATURE_PDCM, "PDCM"},
+ {CPUID_FEATURE_SSE4_1, "SSE4.1"},
+ {CPUID_FEATURE_SSE4_2, "SSE4.2"},
+ {CPUID_FEATURE_x2APIC, "x2APIC"},
+ {CPUID_FEATURE_MOVBE, "MOVBE"},
+ {CPUID_FEATURE_POPCNT, "POPCNT"},
+ {CPUID_FEATURE_AES, "AES"},
+ {CPUID_FEATURE_VMM, "VMM"},
+ {CPUID_FEATURE_PCID, "PCID"},
+ {CPUID_FEATURE_XSAVE, "XSAVE"},
+ {CPUID_FEATURE_OSXSAVE, "OSXSAVE"},
+ {CPUID_FEATURE_SEGLIM64, "SEGLIM64"},
+ {CPUID_FEATURE_TSCTMR, "TSCTMR"},
+ {CPUID_FEATURE_AVX1_0, "AVX1.0"},
+ {CPUID_FEATURE_RDRAND, "RDRAND"},
+ {CPUID_FEATURE_F16C, "F16C"},
+ {0, 0}
+},
+ extfeature_map[] = {
+ {CPUID_EXTFEATURE_SYSCALL, "SYSCALL"},
+ {CPUID_EXTFEATURE_XD, "XD"},
+ {CPUID_EXTFEATURE_1GBPAGE, "1GBPAGE"},
+ {CPUID_EXTFEATURE_EM64T, "EM64T"},
+ {CPUID_EXTFEATURE_LAHF, "LAHF"},
+ {CPUID_EXTFEATURE_LZCNT, "LZCNT"},
+ {CPUID_EXTFEATURE_PREFETCHW, "PREFETCHW"},
+ {CPUID_EXTFEATURE_RDTSCP, "RDTSCP"},
+ {CPUID_EXTFEATURE_TSCI, "TSCI"},
+ {0, 0}
+},
+ leaf7_feature_map[] = {
+ {CPUID_LEAF7_FEATURE_RDWRFSGS, "RDWRFSGS"},
+ {CPUID_LEAF7_FEATURE_TSCOFF, "TSC_THREAD_OFFSET"},
+ {CPUID_LEAF7_FEATURE_SGX, "SGX"},
+ {CPUID_LEAF7_FEATURE_BMI1, "BMI1"},
+ {CPUID_LEAF7_FEATURE_HLE, "HLE"},
+ {CPUID_LEAF7_FEATURE_AVX2, "AVX2"},
+ {CPUID_LEAF7_FEATURE_FDPEO, "FDPEO"},
+ {CPUID_LEAF7_FEATURE_SMEP, "SMEP"},
+ {CPUID_LEAF7_FEATURE_BMI2, "BMI2"},
+ {CPUID_LEAF7_FEATURE_ERMS, "ERMS"},
+ {CPUID_LEAF7_FEATURE_INVPCID, "INVPCID"},
+ {CPUID_LEAF7_FEATURE_RTM, "RTM"},
+ {CPUID_LEAF7_FEATURE_PQM, "PQM"},
+ {CPUID_LEAF7_FEATURE_FPU_CSDS, "FPU_CSDS"},
+ {CPUID_LEAF7_FEATURE_MPX, "MPX"},
+ {CPUID_LEAF7_FEATURE_PQE, "PQE"},
+ {CPUID_LEAF7_FEATURE_AVX512F, "AVX512F"},
+ {CPUID_LEAF7_FEATURE_AVX512DQ, "AVX512DQ"},
+ {CPUID_LEAF7_FEATURE_RDSEED, "RDSEED"},
+ {CPUID_LEAF7_FEATURE_ADX, "ADX"},
+ {CPUID_LEAF7_FEATURE_SMAP, "SMAP"},
+ {CPUID_LEAF7_FEATURE_AVX512IFMA, "AVX512IFMA"},
+ {CPUID_LEAF7_FEATURE_CLFSOPT, "CLFSOPT"},
+ {CPUID_LEAF7_FEATURE_CLWB, "CLWB"},
+ {CPUID_LEAF7_FEATURE_IPT, "IPT"},
+ {CPUID_LEAF7_FEATURE_AVX512CD, "AVX512CD"},
+ {CPUID_LEAF7_FEATURE_SHA, "SHA"},
+ {CPUID_LEAF7_FEATURE_AVX512BW, "AVX512BW"},
+ {CPUID_LEAF7_FEATURE_AVX512VL, "AVX512VL"},
+ {CPUID_LEAF7_FEATURE_PREFETCHWT1, "PREFETCHWT1"},
+ {CPUID_LEAF7_FEATURE_AVX512VBMI, "AVX512VBMI"},
+ {CPUID_LEAF7_FEATURE_UMIP, "UMIP"},
+ {CPUID_LEAF7_FEATURE_PKU, "PKU"},
+ {CPUID_LEAF7_FEATURE_OSPKE, "OSPKE"},
+ {CPUID_LEAF7_FEATURE_WAITPKG, "WAITPKG"},
+ {CPUID_LEAF7_FEATURE_GFNI, "GFNI"},
+ {CPUID_LEAF7_FEATURE_VAES, "VAES"},
+ {CPUID_LEAF7_FEATURE_VPCLMULQDQ, "VPCLMULQDQ"},
+ {CPUID_LEAF7_FEATURE_AVX512VNNI, "AVX512VNNI"},
+ {CPUID_LEAF7_FEATURE_AVX512BITALG, "AVX512BITALG"},
+ {CPUID_LEAF7_FEATURE_AVX512VPCDQ, "AVX512VPOPCNTDQ"},
+ {CPUID_LEAF7_FEATURE_RDPID, "RDPID"},
+ {CPUID_LEAF7_FEATURE_CLDEMOTE, "CLDEMOTE"},
+ {CPUID_LEAF7_FEATURE_MOVDIRI, "MOVDIRI"},
+ {CPUID_LEAF7_FEATURE_MOVDIRI64B, "MOVDIRI64B"},
+ {CPUID_LEAF7_FEATURE_SGXLC, "SGXLC"},
+ {0, 0}
+},
+ leaf7_extfeature_map[] = {
+ { CPUID_LEAF7_EXTFEATURE_AVX5124VNNIW, "AVX5124VNNIW" },
+ { CPUID_LEAF7_EXTFEATURE_AVX5124FMAPS, "AVX5124FMAPS" },
+ { CPUID_LEAF7_EXTFEATURE_FSREPMOV, "FSREPMOV" },
+ { CPUID_LEAF7_EXTFEATURE_MDCLEAR, "MDCLEAR" },
+ { CPUID_LEAF7_EXTFEATURE_TSXFA, "TSXFA" },
+ { CPUID_LEAF7_EXTFEATURE_IBRS, "IBRS" },
+ { CPUID_LEAF7_EXTFEATURE_STIBP, "STIBP" },
+ { CPUID_LEAF7_EXTFEATURE_L1DF, "L1DF" },
+ { CPUID_LEAF7_EXTFEATURE_ACAPMSR, "ACAPMSR" },
+ { CPUID_LEAF7_EXTFEATURE_CCAPMSR, "CCAPMSR" },
+ { CPUID_LEAF7_EXTFEATURE_SSBD, "SSBD" },
+ {0, 0}
+};
+
+static char *
+cpuid_get_names(struct table *map, uint64_t bits, char *buf, unsigned buf_len)
+{
+ size_t len = 0;
+ char *p = buf;
+ int i;
+
+ for (i = 0; map[i].mask != 0; i++) {
+ if ((bits & map[i].mask) == 0) {
+ continue;
+ }
+ if (len && ((size_t) (p - buf) < (buf_len - 1))) {
+ *p++ = ' ';
+ }
+ len = min(strlen(map[i].name), (size_t)((buf_len - 1) - (p - buf)));
+ if (len == 0) {
+ break;
+ }
+ bcopy(map[i].name, p, len);
+ p += len;
+ }
+ *p = '\0';
+ return buf;
+}
+
+i386_cpu_info_t *
+cpuid_info(void)
+{
+ /* Set-up the cpuid_info stucture lazily */
+ if (cpuid_cpu_infop == NULL) {
+ PE_parse_boot_argn("-cpuid", &cpuid_dbg, sizeof(cpuid_dbg));
+ cpuid_set_info();
+ cpuid_cpu_infop = &cpuid_cpu_info;
+ }
+ return cpuid_cpu_infop;
+}
+
+char *
+cpuid_get_feature_names(uint64_t features, char *buf, unsigned buf_len)
+{
+ return cpuid_get_names(feature_map, features, buf, buf_len);
+}
+
+char *
+cpuid_get_extfeature_names(uint64_t extfeatures, char *buf, unsigned buf_len)
+{
+ return cpuid_get_names(extfeature_map, extfeatures, buf, buf_len);
+}
+
+char *
+cpuid_get_leaf7_feature_names(uint64_t features, char *buf, unsigned buf_len)
+{
+ return cpuid_get_names(leaf7_feature_map, features, buf, buf_len);
+}
+
+char *
+cpuid_get_leaf7_extfeature_names(uint64_t features, char *buf, unsigned buf_len)
+{
+ return cpuid_get_names(leaf7_extfeature_map, features, buf, buf_len);
+}
+
+void
+cpuid_feature_display(
+ const char *header)
+{
+ char buf[320];
+
+ kprintf("%s: %s", header,
+ cpuid_get_feature_names(cpuid_features(), buf, sizeof(buf)));
+ if (cpuid_leaf7_features()) {
+ kprintf(" %s", cpuid_get_leaf7_feature_names(
+ cpuid_leaf7_features(), buf, sizeof(buf)));
+ }
+ if (cpuid_leaf7_extfeatures()) {
+ kprintf(" %s", cpuid_get_leaf7_extfeature_names(
+ cpuid_leaf7_extfeatures(), buf, sizeof(buf)));
+ }
+ kprintf("\n");
+ if (cpuid_features() & CPUID_FEATURE_HTT) {
+#define s_if_plural(n) ((n > 1) ? "s" : "")
+ kprintf(" HTT: %d core%s per package;"
+ " %d logical cpu%s per package\n",
+ cpuid_cpu_infop->cpuid_cores_per_package,
+ s_if_plural(cpuid_cpu_infop->cpuid_cores_per_package),
+ cpuid_cpu_infop->cpuid_logical_per_package,
+ s_if_plural(cpuid_cpu_infop->cpuid_logical_per_package));
+ }
+}
+
+void
+cpuid_extfeature_display(
+ const char *header)
+{
+ char buf[256];
+
+ kprintf("%s: %s\n", header,
+ cpuid_get_extfeature_names(cpuid_extfeatures(),
+ buf, sizeof(buf)));
+}
+
+void
+cpuid_cpu_display(
+ const char *header)
+{
+ if (cpuid_cpu_infop->cpuid_brand_string[0] != '\0') {
+ kprintf("%s: %s\n", header, cpuid_cpu_infop->cpuid_brand_string);
+ }
+}
+
+unsigned int
+cpuid_family(void)
+{
+ return cpuid_info()->cpuid_family;
+}
+
+uint32_t
+cpuid_cpufamily(void)
+{
+ return cpuid_info()->cpuid_cpufamily;
+}
+
+cpu_type_t
+cpuid_cputype(void)
+{
+ return cpuid_info()->cpuid_cpu_type;
+}
+
+cpu_subtype_t
+cpuid_cpusubtype(void)
+{
+ return cpuid_info()->cpuid_cpu_subtype;
+}
+
+uint64_t
+cpuid_features(void)
+{
+ static int checked = 0;
+ char fpu_arg[20] = { 0 };
+
+ (void) cpuid_info();
+ if (!checked) {
+ /* check for boot-time fpu limitations */
+ if (PE_parse_boot_argn("_fpu", &fpu_arg[0], sizeof(fpu_arg))) {
+ printf("limiting fpu features to: %s\n", fpu_arg);
+ if (!strncmp("387", fpu_arg, sizeof("387")) || !strncmp("mmx", fpu_arg, sizeof("mmx"))) {
+ printf("no sse or sse2\n");
+ cpuid_cpu_infop->cpuid_features &= ~(CPUID_FEATURE_SSE | CPUID_FEATURE_SSE2 | CPUID_FEATURE_FXSR);
+ } else if (!strncmp("sse", fpu_arg, sizeof("sse"))) {
+ printf("no sse2\n");
+ cpuid_cpu_infop->cpuid_features &= ~(CPUID_FEATURE_SSE2);
+ }
+ }
+ checked = 1;
+ }
+ return cpuid_cpu_infop->cpuid_features;
+}
+
+uint64_t
+cpuid_extfeatures(void)
+{
+ return cpuid_info()->cpuid_extfeatures;
+}
+
+uint64_t
+cpuid_leaf7_features(void)
+{
+ return cpuid_info()->cpuid_leaf7_features;
+}
+
+uint64_t
+cpuid_leaf7_extfeatures(void)
+{
+ return cpuid_info()->cpuid_leaf7_extfeatures;
+}
+
+const char *
+cpuid_vmm_family_string(void)
+{
+ switch (cpuid_vmm_info()->cpuid_vmm_family) {
+ case CPUID_VMM_FAMILY_NONE:
+ return "None";
+
+ case CPUID_VMM_FAMILY_VMWARE:
+ return "VMWare";
+
+ case CPUID_VMM_FAMILY_PARALLELS:
+ return "Parallels";
+
+ case CPUID_VMM_FAMILY_HYVE:
+ return "xHyve";
+
+ case CPUID_VMM_FAMILY_HVF:
+ return "HVF";
+
+ case CPUID_VMM_FAMILY_KVM:
+ return "KVM";
+
+ case CPUID_VMM_FAMILY_UNKNOWN:
+ /*FALLTHROUGH*/
+ default:
+ return "Unknown VMM";
+ }
+}
+
+static i386_vmm_info_t *_cpuid_vmm_infop = NULL;
+static i386_vmm_info_t _cpuid_vmm_info;
+
+static void
+cpuid_init_vmm_info(i386_vmm_info_t *info_p)
+{
+ uint32_t reg[4], maxbasic_regs[4];
+ uint32_t max_vmm_leaf;
+
+ bzero(info_p, sizeof(*info_p));
+
+ if (!cpuid_vmm_present()) {
+ return;
+ }
+
+ DBG("cpuid_init_vmm_info(%p)\n", info_p);
+
+ /*
+ * Get the highest basic leaf value, then save the cpuid details for that leaf
+ * for comparison with the [ostensible] VMM leaf.
+ */
+ cpuid_fn(0, reg);
+ cpuid_fn(reg[eax], maxbasic_regs);
+
+ /* do cpuid 0x40000000 to get VMM vendor */
+ cpuid_fn(0x40000000, reg);
+
+ /*
+ * If leaf 0x40000000 is non-existent, cpuid will return the values as
+ * if the highest basic leaf was requested, so compare to those values
+ * we just retrieved to see if no vmm is present.
+ */
+ if (bcmp(reg, maxbasic_regs, sizeof(reg)) == 0) {
+ info_p->cpuid_vmm_family = CPUID_VMM_FAMILY_NONE;
+ DBG(" vmm_vendor : NONE\n");
+ return;
+ }
+
+ max_vmm_leaf = reg[eax];
+ bcopy((char *)®[ebx], &info_p->cpuid_vmm_vendor[0], 4);
+ bcopy((char *)®[ecx], &info_p->cpuid_vmm_vendor[4], 4);
+ bcopy((char *)®[edx], &info_p->cpuid_vmm_vendor[8], 4);
+ info_p->cpuid_vmm_vendor[12] = '\0';
+
+ if (0 == strcmp(info_p->cpuid_vmm_vendor, CPUID_VMM_ID_VMWARE)) {
+ /* VMware identification string: kb.vmware.com/kb/1009458 */
+ info_p->cpuid_vmm_family = CPUID_VMM_FAMILY_VMWARE;
+ } else if (0 == bcmp(info_p->cpuid_vmm_vendor, CPUID_VMM_ID_PARALLELS, 12)) {
+ /* Parallels identification string */
+ info_p->cpuid_vmm_family = CPUID_VMM_FAMILY_PARALLELS;
+ } else if (0 == bcmp(info_p->cpuid_vmm_vendor, CPUID_VMM_ID_HYVE, 12)) {
+ /* bhyve/xhyve identification string */
+ info_p->cpuid_vmm_family = CPUID_VMM_FAMILY_HYVE;
+ } else if (0 == bcmp(info_p->cpuid_vmm_vendor, CPUID_VMM_ID_HVF, 12)) {
+ /* HVF identification string */
+ info_p->cpuid_vmm_family = CPUID_VMM_FAMILY_HVF;
+ } else if (0 == bcmp(info_p->cpuid_vmm_vendor, CPUID_VMM_ID_KVM, 12)) {
+ /* KVM identification string */
+ info_p->cpuid_vmm_family = CPUID_VMM_FAMILY_KVM;
+ } else {
+ info_p->cpuid_vmm_family = CPUID_VMM_FAMILY_UNKNOWN;
+ }
+
+ /* VMM generic leaves: https://lkml.org/lkml/2008/10/1/246 */
+ if (max_vmm_leaf >= 0x40000010) {
+ cpuid_fn(0x40000010, reg);
+
+ info_p->cpuid_vmm_tsc_frequency = reg[eax];
+ info_p->cpuid_vmm_bus_frequency = reg[ebx];
+ }
+
+ DBG(" vmm_vendor : %s\n", info_p->cpuid_vmm_vendor);
+ DBG(" vmm_family : %u\n", info_p->cpuid_vmm_family);
+ DBG(" vmm_bus_frequency : %u\n", info_p->cpuid_vmm_bus_frequency);
+ DBG(" vmm_tsc_frequency : %u\n", info_p->cpuid_vmm_tsc_frequency);
+}
+
+boolean_t
+cpuid_vmm_present(void)
+{
+ return (cpuid_features() & CPUID_FEATURE_VMM) ? TRUE : FALSE;
+}
+
+i386_vmm_info_t *
+cpuid_vmm_info(void)
+{
+ if (_cpuid_vmm_infop == NULL) {
+ cpuid_init_vmm_info(&_cpuid_vmm_info);
+ _cpuid_vmm_infop = &_cpuid_vmm_info;
+ }
+ return _cpuid_vmm_infop;
+}
+
+uint32_t
+cpuid_vmm_family(void)
+{
+ return cpuid_vmm_info()->cpuid_vmm_family;
+}
+
+cwa_classifier_e
+cpuid_wa_required(cpu_wa_e wa)
+{
+ i386_cpu_info_t *info_p = &cpuid_cpu_info;
+ static uint64_t bootarg_cpu_wa_enables = 0;
+ static uint64_t bootarg_cpu_wa_disables = 0;
+ static int bootargs_overrides_processed = 0;
+ uint32_t reg[4];
+
+ if (!bootargs_overrides_processed) {
+ if (!PE_parse_boot_argn("cwae", &bootarg_cpu_wa_enables, sizeof(bootarg_cpu_wa_enables))) {
+ bootarg_cpu_wa_enables = 0;
+ }
+
+ if (!PE_parse_boot_argn("cwad", &bootarg_cpu_wa_disables, sizeof(bootarg_cpu_wa_disables))) {
+ bootarg_cpu_wa_disables = 0;
+ }
+ bootargs_overrides_processed = 1;
+ }
+
+ if (bootarg_cpu_wa_enables & (1 << wa)) {
+ return CWA_FORCE_ON;
+ }
+
+ if (bootarg_cpu_wa_disables & (1 << wa)) {
+ return CWA_FORCE_OFF;
+ }
+
+ switch (wa) {
+ case CPU_INTEL_SEGCHK:
+ /* First, check to see if this CPU requires the workaround */
+ if ((info_p->cpuid_leaf7_extfeatures & CPUID_LEAF7_EXTFEATURE_ACAPMSR) != 0) {
+ /* We have ARCHCAP, so check it for either RDCL_NO or MDS_NO */
+ uint64_t archcap_msr = rdmsr64(MSR_IA32_ARCH_CAPABILITIES);
+ if ((archcap_msr & (MSR_IA32_ARCH_CAPABILITIES_RDCL_NO | MSR_IA32_ARCH_CAPABILITIES_MDS_NO)) != 0) {
+ /* Workaround not needed */
+ return CWA_OFF;
+ }
+ }
+
+ if ((info_p->cpuid_leaf7_extfeatures & CPUID_LEAF7_EXTFEATURE_MDCLEAR) != 0) {
+ return CWA_ON;
+ }
+
+ /*
+ * If the CPU supports the ARCHCAP MSR and neither the RDCL_NO bit nor the MDS_NO
+ * bit are set, OR the CPU does not support the ARCHCAP MSR and the CPU does
+ * not enumerate the presence of the enhanced VERW instruction, report
+ * that the workaround should not be enabled.
+ */
+ break;
+
+ case CPU_INTEL_TSXFA:
+ /*
+ * Note that if TSX was disabled in cpuid_do_precpuid_was(), the cached cpuid
+ * info will indicate that RTM is *not* supported and this workaround will not
+ * be enabled.
+ */
+ /*
+ * Otherwise, if the CPU supports both TSX(HLE) and FORCE_ABORT, return that
+ * the workaround should be enabled.
+ */
+ if ((info_p->cpuid_leaf7_extfeatures & CPUID_LEAF7_EXTFEATURE_TSXFA) != 0 &&
+ (info_p->cpuid_leaf7_features & CPUID_LEAF7_FEATURE_RTM) != 0) {
+ return CWA_ON;
+ }
+ break;
+
+ case CPU_INTEL_TSXDA:
+ /*
+ * Since this workaround might be requested before cpuid_set_info() is complete,
+ * we need to invoke cpuid directly when looking for the required bits.
+ */
+ cpuid_fn(0x7, reg);
+ if (reg[edx] & CPUID_LEAF7_EXTFEATURE_ACAPMSR) {
+ uint64_t archcap_msr = rdmsr64(MSR_IA32_ARCH_CAPABILITIES);
+ /*
+ * If this CPU supports TSX (HLE being the proxy for TSX detection) AND it does
+ * not include a hardware fix for TAA and it supports the TSX_CTRL MSR, disable TSX entirely.
+ * (Note this can be overridden (above) if the cwad boot-arg's value has bit 2 set.)
+ */
+ if ((reg[ebx] & CPUID_LEAF7_FEATURE_HLE) != 0 &&
+ (archcap_msr & (MSR_IA32_ARCH_CAPABILITIES_TAA_NO | MSR_IA32_ARCH_CAPABILITIES_TSX_CTRL))
+ == MSR_IA32_ARCH_CAPABILITIES_TSX_CTRL) {
+ return CWA_ON;
+ }
+ }
+ break;
+
+ case CPU_INTEL_SRBDS:
+ /*
+ * SRBDS mitigations are enabled by default. CWA_ON returned here indicates
+ * the caller should disable the mitigation. Mitigations should be disabled
+ * at least for CPUs that advertise MDS_NO *and* (either TAA_NO is set OR TSX
+ * has been disabled).
+ */
+ if ((info_p->cpuid_leaf7_extfeatures & CPUID_LEAF7_EXTFEATURE_SRBDS_CTRL) != 0) {
+ if ((info_p->cpuid_leaf7_extfeatures & CPUID_LEAF7_EXTFEATURE_ACAPMSR) != 0) {
+ uint64_t archcap_msr = rdmsr64(MSR_IA32_ARCH_CAPABILITIES);
+ if ((archcap_msr & MSR_IA32_ARCH_CAPABILITIES_MDS_NO) != 0 &&
+ ((archcap_msr & MSR_IA32_ARCH_CAPABILITIES_TAA_NO) != 0 ||
+ cpuid_tsx_disabled)) {
+ return CWA_ON;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return CWA_OFF;
+}
+
+static void
+cpuid_do_precpuid_was(void)
+{
+ /*
+ * Note that care must be taken not to use any data from the cached cpuid data since it is
+ * likely uninitialized at this point. That includes calling functions that make use of
+ * that data as well.
+ */
+
+ /* Note the TSX disablement, we do not support force-on since it depends on MSRs being present */
+ if (cpuid_wa_required(CPU_INTEL_TSXDA) == CWA_ON) {
+ /* This must be executed on all logical processors */
+ wrmsr64(MSR_IA32_TSX_CTRL, MSR_IA32_TSXCTRL_TSX_CPU_CLEAR | MSR_IA32_TSXCTRL_RTM_DISABLE);
+ cpuid_tsx_disabled = true;