X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/b7266188b87f3620ec3f9f717e57194a7dd989fe..22ba694c5857e62b5a553b1505dcf2e509177f28:/osfmk/i386/cpuid.c diff --git a/osfmk/i386/cpuid.c b/osfmk/i386/cpuid.c index 1ddb1469e..fb171c4dc 100644 --- a/osfmk/i386/cpuid.c +++ b/osfmk/i386/cpuid.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2012 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -29,21 +29,22 @@ * @OSF_COPYRIGHT@ */ #include -#include #include #include #include -#if MACH_KDB -#include -#include -#include -#include -#include -#include -#include -#include + +static boolean_t cpuid_dbg +#if DEBUG + = TRUE; +#else + = FALSE; #endif +#define DBG(x...) \ + do { \ + if (cpuid_dbg) \ + kprintf(x); \ + } while (0) \ #define min(a,b) ((a) < (b) ? (a) : (b)) #define quad(hi,lo) (((uint64_t)(hi)) << 32 | (lo)) @@ -161,6 +162,7 @@ static cpuid_cache_descriptor_t intel_cpuid_leaf2_descriptor_table[] = { { 0x70, CACHE, TRACE, 8, 12*K, NA }, { 0x71, CACHE, TRACE, 8, 16*K, NA }, { 0x72, CACHE, TRACE, 8, 32*K, NA }, + { 0x76, TLB, INST, NA, BOTH, 8 }, { 0x78, CACHE, L2, 4, 1*M, 64 }, { 0x79, CACHE, L2_2LINESECTOR, 8, 128*K, 64 }, { 0x7A, CACHE, L2_2LINESECTOR, 8, 256*K, 64 }, @@ -180,8 +182,11 @@ static cpuid_cache_descriptor_t intel_cpuid_leaf2_descriptor_table[] = { { 0xB2, TLB, INST, 4, SMALL, 64 }, { 0xB3, TLB, DATA, 4, SMALL, 128 }, { 0xB4, TLB, DATA1, 4, SMALL, 256 }, + { 0xB5, TLB, DATA1, 8, SMALL, 64 }, + { 0xB6, TLB, DATA1, 8, SMALL, 128 }, { 0xBA, TLB, DATA1, 4, BOTH, 64 }, - { 0xCA, STLB, DATA1, 4, BOTH, 512 }, + { 0xC1, STLB, DATA1, 8, SMALL, 1024}, + { 0xCA, STLB, DATA1, 4, SMALL, 512 }, { 0xD0, CACHE, L3, 4, 512*K, 64 }, { 0xD1, CACHE, L3, 4, 1*M, 64 }, { 0xD2, CACHE, L3, 4, 2*M, 64 }, @@ -203,7 +208,8 @@ static cpuid_cache_descriptor_t intel_cpuid_leaf2_descriptor_table[] = { { 0xE5, CACHE, L3, 16, 16*M, 64 }, { 0xE6, CACHE, L3, 16, 24*M, 64 }, { 0xF0, PREFETCH, NA, NA, 64, NA }, - { 0xF1, PREFETCH, NA, NA, 128, NA } + { 0xF1, PREFETCH, NA, NA, 128, NA }, + { 0xFF, CACHE, NA, NA, 0, NA } }; #define INTEL_LEAF2_DESC_NUM (sizeof(intel_cpuid_leaf2_descriptor_table) / \ sizeof(cpuid_cache_descriptor_t)) @@ -223,29 +229,19 @@ cpuid_leaf2_find(uint8_t value) * CPU identification routines. */ -static i386_cpu_info_t *cpuid_cpu_infop = NULL; static i386_cpu_info_t cpuid_cpu_info; +static i386_cpu_info_t *cpuid_cpu_infop = NULL; -#if defined(__x86_64__) static void cpuid_fn(uint32_t selector, uint32_t *result) { do_cpuid(selector, result); + DBG("cpuid_fn(0x%08x) eax:0x%08x ebx:0x%08x ecx:0x%08x edx:0x%08x\n", + selector, result[0], result[1], result[2], result[3]); } -#else -static void cpuid_fn(uint32_t selector, uint32_t *result) -{ - if (cpu_mode_is64bit()) { - asm("call _cpuid64" - : "=a" (result[0]), - "=b" (result[1]), - "=c" (result[2]), - "=d" (result[3]) - : "a"(selector)); - } else { - do_cpuid(selector, result); - } -} -#endif + +static const char *cache_type_str[LCACHE_MAX] = { + "Lnone", "L1I", "L1D", "L2U", "L3U" +}; /* this function is Intel-specific */ static void @@ -259,6 +255,8 @@ cpuid_set_cache_info( i386_cpu_info_t * info_p ) unsigned int j; boolean_t cpuid_deterministic_supported = FALSE; + DBG("cpuid_set_cache_info(%p)\n", info_p); + bzero( linesizes, sizeof(linesizes) ); /* Get processor cache descriptor info using leaf 2. We don't use @@ -307,7 +305,7 @@ cpuid_set_cache_info( i386_cpu_info_t * info_p ) reg[eax] = 4; /* cpuid request 4 */ reg[ecx] = index; /* index starting at 0 */ cpuid(reg); -//kprintf("cpuid(4) index=%d eax=%p\n", index, reg[eax]); + DBG("cpuid(4) index=%d eax=0x%x\n", index, reg[eax]); cache_type = bitfield32(reg[eax], 4, 0); if (cache_type == 0) break; /* no more caches */ @@ -349,7 +347,22 @@ cpuid_set_cache_info( i386_cpu_info_t * info_p ) info_p->cache_sharing[type] = cache_sharing; info_p->cache_partitions[type] = cache_partitions; linesizes[type] = cache_linesize; - + + DBG(" cache_size[%s] : %d\n", + cache_type_str[type], cache_size); + DBG(" cache_sharing[%s] : %d\n", + cache_type_str[type], cache_sharing); + DBG(" cache_partitions[%s]: %d\n", + cache_type_str[type], cache_partitions); + + /* + * Overwrite associativity determined via + * CPUID.0x80000006 -- this leaf is more + * accurate + */ + if (type == L2U) + info_p->cpuid_cache_L2_associativity = cache_associativity; + /* Compute the number of page colors for this cache, * which is: * ( linesize * sets ) / page_size @@ -377,6 +390,7 @@ cpuid_set_cache_info( i386_cpu_info_t * info_p ) vm_cache_geometry_colors = colors; } } + DBG(" vm_cache_geometry_colors: %d\n", vm_cache_geometry_colors); /* * If deterministic cache parameters are not available, use @@ -391,6 +405,13 @@ cpuid_set_cache_info( i386_cpu_info_t * info_p ) info_p->cache_partitions[L2U] = 1; linesizes[L2U] = info_p->cpuid_cache_linesize; + + DBG(" cache_size[L2U] : %d\n", + info_p->cache_size[L2U]); + DBG(" cache_sharing[L2U] : 1\n"); + DBG(" cache_partitions[L2U]: 1\n"); + DBG(" linesizes[L2U] : %d\n", + info_p->cpuid_cache_linesize); } /* @@ -402,16 +423,19 @@ cpuid_set_cache_info( i386_cpu_info_t * info_p ) else if (linesizes[L1D]) info_p->cache_linesize = linesizes[L1D]; else panic("no linesize"); + DBG(" cache_linesize : %d\n", info_p->cache_linesize); /* * Extract and publish TLB information from Leaf 2 descriptors. */ + DBG(" %ld leaf2 descriptors:\n", sizeof(info_p->cache_info)); for (i = 1; i < sizeof(info_p->cache_info); i++) { cpuid_cache_descriptor_t *descp; int id; int level; int page; + DBG(" 0x%02x", info_p->cache_info[i]); descp = cpuid_leaf2_find(info_p->cache_info[i]); if (descp == NULL) continue; @@ -446,6 +470,7 @@ cpuid_set_cache_info( i386_cpu_info_t * info_p ) info_p->cpuid_stlb = descp->entries; } } + DBG("\n"); } static void @@ -454,6 +479,8 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) uint32_t reg[4]; char str[128], *p; + DBG("cpuid_set_generic_info(%p)\n", info_p); + /* do cpuid 0 to get vendor */ cpuid_fn(0, reg); info_p->cpuid_max_basic = reg[eax]; @@ -497,10 +524,24 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) /* Get cache and addressing info. */ if (info_p->cpuid_max_ext >= 0x80000006) { + uint32_t assoc; cpuid_fn(0x80000006, reg); info_p->cpuid_cache_linesize = bitfield32(reg[ecx], 7, 0); - info_p->cpuid_cache_L2_associativity = - bitfield32(reg[ecx],15,12); + assoc = bitfield32(reg[ecx],15,12); + /* + * L2 associativity is encoded, though in an insufficiently + * descriptive fashion, e.g. 24-way is mapped to 16-way. + * Represent a fully associative cache as 0xFFFF. + * Overwritten by associativity as determined via CPUID.4 + * if available. + */ + if (assoc == 6) + assoc = 8; + else if (assoc == 8) + assoc = 16; + else if (assoc == 0xF) + assoc = 0xFFFF; + info_p->cpuid_cache_L2_associativity = assoc; info_p->cpuid_cache_size = bitfield32(reg[ecx],31,16); cpuid_fn(0x80000008, reg); info_p->cpuid_address_bits_physical = @@ -509,8 +550,15 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) bitfield32(reg[eax],15, 8); } - /* get processor signature and decode */ + /* + * Get processor signature and decode + * and bracket this with the approved procedure for reading the + * the microcode version number a.k.a. signature a.k.a. BIOS ID + */ + wrmsr64(MSR_IA32_BIOS_SIGN_ID, 0); cpuid_fn(1, reg); + info_p->cpuid_microcode_version = + (uint32_t) (rdmsr64(MSR_IA32_BIOS_SIGN_ID) >> 32); info_p->cpuid_signature = reg[eax]; info_p->cpuid_stepping = bitfield32(reg[eax], 3, 0); info_p->cpuid_model = bitfield32(reg[eax], 7, 4); @@ -521,6 +569,9 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) info_p->cpuid_brand = bitfield32(reg[ebx], 7, 0); info_p->cpuid_features = quad(reg[ecx], reg[edx]); + /* Get "processor flag"; necessary for microcode update matching */ + info_p->cpuid_processor_flag = (rdmsr64(MSR_IA32_PLATFORM_ID)>> 50) & 0x7; + /* Fold extensions into family/model */ if (info_p->cpuid_family == 0x0f) info_p->cpuid_family += info_p->cpuid_extfamily; @@ -539,17 +590,32 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) quad(reg[ecx], reg[edx]); } + DBG(" max_basic : %d\n", info_p->cpuid_max_basic); + DBG(" max_ext : 0x%08x\n", info_p->cpuid_max_ext); + DBG(" vendor : %s\n", info_p->cpuid_vendor); + DBG(" brand_string : %s\n", info_p->cpuid_brand_string); + DBG(" signature : 0x%08x\n", info_p->cpuid_signature); + DBG(" stepping : %d\n", info_p->cpuid_stepping); + DBG(" model : %d\n", info_p->cpuid_model); + DBG(" family : %d\n", info_p->cpuid_family); + DBG(" type : %d\n", info_p->cpuid_type); + DBG(" extmodel : %d\n", info_p->cpuid_extmodel); + DBG(" extfamily : %d\n", info_p->cpuid_extfamily); + DBG(" brand : %d\n", info_p->cpuid_brand); + DBG(" features : 0x%016llx\n", info_p->cpuid_features); + DBG(" extfeatures : 0x%016llx\n", info_p->cpuid_extfeatures); + DBG(" logical_per_package : %d\n", info_p->cpuid_logical_per_package); + DBG(" microcode_version : 0x%08x\n", info_p->cpuid_microcode_version); + /* Fold in the Invariant TSC feature bit, if present */ if (info_p->cpuid_max_ext >= 0x80000007) { cpuid_fn(0x80000007, reg); info_p->cpuid_extfeatures |= reg[edx] & (uint32_t)CPUID_EXTFEATURE_TSCI; + DBG(" extfeatures : 0x%016llx\n", + info_p->cpuid_extfeatures); } - /* Find the microcode version number a.k.a. signature a.k.a. BIOS ID */ - info_p->cpuid_microcode_version = - (uint32_t) (rdmsr64(MSR_IA32_BIOS_SIGN_ID) >> 32); - if (info_p->cpuid_max_basic >= 0x5) { cpuid_mwait_leaf_t *cmp = &info_p->cpuid_mwait_leaf; @@ -562,6 +628,12 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) cmp->extensions = reg[ecx]; cmp->sub_Cstates = reg[edx]; info_p->cpuid_mwait_leafp = cmp; + + DBG(" Monitor/Mwait Leaf:\n"); + DBG(" linesize_min : %d\n", cmp->linesize_min); + DBG(" linesize_max : %d\n", cmp->linesize_max); + DBG(" extensions : %d\n", cmp->extensions); + DBG(" sub_Cstates : 0x%08x\n", cmp->sub_Cstates); } if (info_p->cpuid_max_basic >= 0x6) { @@ -574,9 +646,26 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) ctp->sensor = bitfield32(reg[eax], 0, 0); ctp->dynamic_acceleration = bitfield32(reg[eax], 1, 1); ctp->invariant_APIC_timer = bitfield32(reg[eax], 2, 2); + ctp->core_power_limits = bitfield32(reg[eax], 4, 4); + ctp->fine_grain_clock_mod = bitfield32(reg[eax], 5, 5); + ctp->package_thermal_intr = bitfield32(reg[eax], 6, 6); ctp->thresholds = bitfield32(reg[ebx], 3, 0); ctp->ACNT_MCNT = bitfield32(reg[ecx], 0, 0); + ctp->hardware_feedback = bitfield32(reg[ecx], 1, 1); + ctp->energy_policy = bitfield32(reg[ecx], 3, 3); info_p->cpuid_thermal_leafp = ctp; + + DBG(" Thermal/Power Leaf:\n"); + DBG(" sensor : %d\n", ctp->sensor); + DBG(" dynamic_acceleration : %d\n", ctp->dynamic_acceleration); + DBG(" invariant_APIC_timer : %d\n", ctp->invariant_APIC_timer); + DBG(" core_power_limits : %d\n", ctp->core_power_limits); + DBG(" fine_grain_clock_mod : %d\n", ctp->fine_grain_clock_mod); + DBG(" package_thermal_intr : %d\n", ctp->package_thermal_intr); + DBG(" thresholds : %d\n", ctp->thresholds); + DBG(" ACNT_MCNT : %d\n", ctp->ACNT_MCNT); + DBG(" ACNT2 : %d\n", ctp->hardware_feedback); + DBG(" energy_policy : %d\n", ctp->energy_policy); } if (info_p->cpuid_max_basic >= 0xa) { @@ -594,6 +683,41 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) capp->fixed_number = bitfield32(reg[edx], 4, 0); capp->fixed_width = bitfield32(reg[edx], 12, 5); info_p->cpuid_arch_perf_leafp = capp; + + DBG(" Architectural Performance Monitoring Leaf:\n"); + DBG(" version : %d\n", capp->version); + DBG(" number : %d\n", capp->number); + DBG(" width : %d\n", capp->width); + DBG(" events_number : %d\n", capp->events_number); + DBG(" events : %d\n", capp->events); + DBG(" fixed_number : %d\n", capp->fixed_number); + DBG(" fixed_width : %d\n", capp->fixed_width); + } + + if (info_p->cpuid_max_basic >= 0xd) { + cpuid_xsave_leaf_t *xsp = &info_p->cpuid_xsave_leaf; + /* + * XSAVE Features: + */ + cpuid_fn(0xd, info_p->cpuid_xsave_leaf.extended_state); + info_p->cpuid_xsave_leafp = xsp; + + DBG(" XSAVE Leaf:\n"); + DBG(" EAX : 0x%x\n", xsp->extended_state[eax]); + DBG(" EBX : 0x%x\n", xsp->extended_state[ebx]); + DBG(" ECX : 0x%x\n", xsp->extended_state[ecx]); + DBG(" EDX : 0x%x\n", xsp->extended_state[edx]); + } + + if (info_p->cpuid_model >= CPUID_MODEL_IVYBRIDGE) { + /* + * Leaf7 Features: + */ + cpuid_fn(0x7, reg); + info_p->cpuid_leaf7_features = reg[ebx]; + + DBG(" Feature Leaf7:\n"); + DBG(" EBX : 0x%x\n", reg[ebx]); } return; @@ -607,12 +731,6 @@ cpuid_set_cpufamily(i386_cpu_info_t *info_p) switch (info_p->cpuid_family) { case 6: switch (info_p->cpuid_model) { - case 13: - cpufamily = CPUFAMILY_INTEL_6_13; - break; - case 14: - cpufamily = CPUFAMILY_INTEL_YONAH; - break; case 15: cpufamily = CPUFAMILY_INTEL_MEROM; break; @@ -625,20 +743,40 @@ cpuid_set_cpufamily(i386_cpu_info_t *info_p) case CPUID_MODEL_NEHALEM_EX: cpufamily = CPUFAMILY_INTEL_NEHALEM; break; + case CPUID_MODEL_DALES_32NM: + case CPUID_MODEL_WESTMERE: + case CPUID_MODEL_WESTMERE_EX: + cpufamily = CPUFAMILY_INTEL_WESTMERE; + break; + case CPUID_MODEL_SANDYBRIDGE: + case CPUID_MODEL_JAKETOWN: + cpufamily = CPUFAMILY_INTEL_SANDYBRIDGE; + break; + case CPUID_MODEL_IVYBRIDGE: + case CPUID_MODEL_IVYBRIDGE_EP: + cpufamily = CPUFAMILY_INTEL_IVYBRIDGE; + break; + case CPUID_MODEL_HASWELL: + case CPUID_MODEL_HASWELL_ULT: + case CPUID_MODEL_CRYSTALWELL: + cpufamily = CPUFAMILY_INTEL_HASWELL; + break; } break; } info_p->cpuid_cpufamily = cpufamily; + DBG("cpuid_set_cpufamily(%p) returning 0x%x\n", info_p, cpufamily); return cpufamily; } - +/* + * Must be invoked either when executing single threaded, or with + * independent synchronization. + */ void cpuid_set_info(void) { i386_cpu_info_t *info_p = &cpuid_cpu_info; - - bzero((void *)info_p, sizeof(cpuid_cpu_info)); cpuid_set_generic_info(info_p); @@ -651,14 +789,23 @@ cpuid_set_info(void) info_p->cpuid_cpu_type = CPU_TYPE_X86; info_p->cpuid_cpu_subtype = CPU_SUBTYPE_X86_ARCH1; - - cpuid_set_cache_info(&cpuid_cpu_info); + /* Must be invoked after set_generic_info */ + cpuid_set_cache_info(info_p); /* * Find the number of enabled cores and threads * (which determines whether SMT/Hyperthreading is active). */ switch (info_p->cpuid_cpufamily) { + case CPUFAMILY_INTEL_WESTMERE: { + uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT); + info_p->core_count = bitfield32((uint32_t)msr, 19, 16); + info_p->thread_count = bitfield32((uint32_t)msr, 15, 0); + break; + } + case CPUFAMILY_INTEL_HASWELL: + case CPUFAMILY_INTEL_IVYBRIDGE: + case CPUFAMILY_INTEL_SANDYBRIDGE: case CPUFAMILY_INTEL_NEHALEM: { uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT); info_p->core_count = bitfield32((uint32_t)msr, 31, 16); @@ -670,76 +817,131 @@ cpuid_set_info(void) info_p->core_count = info_p->cpuid_cores_per_package; info_p->thread_count = info_p->cpuid_logical_per_package; } + DBG("cpuid_set_info():\n"); + DBG(" core_count : %d\n", info_p->core_count); + DBG(" thread_count : %d\n", info_p->thread_count); - cpuid_cpu_info.cpuid_model_string = ""; /* deprecated */ + info_p->cpuid_model_string = ""; /* deprecated */ } -static struct { +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_SSE3, "SSE3"}, - {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_CX16, "CX16"}, - {CPUID_FEATURE_xTPR, "TPR"}, - {CPUID_FEATURE_PDCM, "PDCM"}, - {CPUID_FEATURE_SSE4_1, "SSE4.1"}, - {CPUID_FEATURE_SSE4_2, "SSE4.2"}, - {CPUID_FEATURE_xAPIC, "xAPIC"}, - {CPUID_FEATURE_POPCNT, "POPCNT"}, - {CPUID_FEATURE_VMM, "VMM"}, + {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_RDTSCP, "RDTSCP"}, + {CPUID_EXTFEATURE_1GBPAGE, "1GBPAGE"}, {CPUID_EXTFEATURE_EM64T, "EM64T"}, {CPUID_EXTFEATURE_LAHF, "LAHF"}, + {CPUID_EXTFEATURE_RDTSCP, "RDTSCP"}, {CPUID_EXTFEATURE_TSCI, "TSCI"}, {0, 0} + +}, +leaf7_feature_map[] = { + {CPUID_LEAF7_FEATURE_SMEP, "SMEP"}, + {CPUID_LEAF7_FEATURE_ENFSTRG, "ENFSTRG"}, + {CPUID_LEAF7_FEATURE_RDWRFSGS, "RDWRFSGS"}, + {CPUID_LEAF7_FEATURE_TSCOFF, "TSC_THREAD_OFFSET"}, + {CPUID_LEAF7_FEATURE_BMI1, "BMI1"}, + {CPUID_LEAF7_FEATURE_HLE, "HLE"}, + {CPUID_LEAF7_FEATURE_AVX2, "AVX2"}, + {CPUID_LEAF7_FEATURE_BMI2, "BMI2"}, + {CPUID_LEAF7_FEATURE_INVPCID, "INVPCID"}, + {CPUID_LEAF7_FEATURE_RTM, "RTM"}, + {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; } @@ -749,47 +951,20 @@ cpuid_info(void) char * cpuid_get_feature_names(uint64_t features, char *buf, unsigned buf_len) { - size_t len = -1; - char *p = buf; - int i; - - for (i = 0; feature_map[i].mask != 0; i++) { - if ((features & feature_map[i].mask) == 0) - continue; - if (len > 0) - *p++ = ' '; - len = min(strlen(feature_map[i].name), (size_t) ((buf_len-1) - (p-buf))); - if (len == 0) - break; - bcopy(feature_map[i].name, p, len); - p += len; - } - *p = '\0'; - return buf; + return cpuid_get_names(feature_map, features, buf, buf_len); } char * cpuid_get_extfeature_names(uint64_t extfeatures, char *buf, unsigned buf_len) { - size_t len = -1; - char *p = buf; - int i; - - for (i = 0; extfeature_map[i].mask != 0; i++) { - if ((extfeatures & extfeature_map[i].mask) == 0) - continue; - if (len > 0) - *p++ = ' '; - len = min(strlen(extfeature_map[i].name), (size_t) ((buf_len-1)-(p-buf))); - if (len == 0) - break; - bcopy(extfeature_map[i].name, p, len); - p += len; - } - *p = '\0'; - return buf; + 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); +} void cpuid_feature_display( @@ -797,17 +972,20 @@ cpuid_feature_display( { char buf[256]; - kprintf("%s: %s\n", header, - cpuid_get_feature_names(cpuid_features(), - buf, sizeof(buf))); + 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))); + 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_info.cpuid_cores_per_package, - s_if_plural(cpuid_cpu_info.cpuid_cores_per_package), - cpuid_cpu_info.cpuid_logical_per_package, - s_if_plural(cpuid_cpu_info.cpuid_logical_per_package)); + 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)); } } @@ -826,8 +1004,8 @@ void cpuid_cpu_display( const char *header) { - if (cpuid_cpu_info.cpuid_brand_string[0] != '\0') { - kprintf("%s: %s\n", header, cpuid_cpu_info.cpuid_brand_string); + if (cpuid_cpu_infop->cpuid_brand_string[0] != '\0') { + kprintf("%s: %s\n", header, cpuid_cpu_infop->cpuid_brand_string); } } @@ -868,15 +1046,15 @@ cpuid_features(void) 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_info.cpuid_features &= ~(CPUID_FEATURE_SSE | CPUID_FEATURE_SSE2 | CPUID_FEATURE_FXSR); + 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_info.cpuid_features &= ~(CPUID_FEATURE_SSE2); + cpuid_cpu_infop->cpuid_features &= ~(CPUID_FEATURE_SSE2); } } checked = 1; } - return cpuid_cpu_info.cpuid_features; + return cpuid_cpu_infop->cpuid_features; } uint64_t @@ -885,48 +1063,76 @@ cpuid_extfeatures(void) return cpuid_info()->cpuid_extfeatures; } +uint64_t +cpuid_leaf7_features(void) +{ + return cpuid_info()->cpuid_leaf7_features; +} -#if MACH_KDB +static i386_vmm_info_t *_cpuid_vmm_infop = NULL; +static i386_vmm_info_t _cpuid_vmm_info; -/* - * Display the cpuid - * * - * cp - */ -void -db_cpuid(__unused db_expr_t addr, - __unused int have_addr, - __unused db_expr_t count, - __unused char *modif) +static void +cpuid_init_vmm_info(i386_vmm_info_t *info_p) { + uint32_t reg[4]; + uint32_t max_vmm_leaf; + + bzero(info_p, sizeof(*info_p)); - uint32_t i, mid; - uint32_t cpid[4]; + if (!cpuid_vmm_present()) + return; - do_cpuid(0, cpid); /* Get the first cpuid which is the number of - * basic ids */ - db_printf("%08X - %08X %08X %08X %08X\n", - 0, cpid[eax], cpid[ebx], cpid[ecx], cpid[edx]); + DBG("cpuid_init_vmm_info(%p)\n", info_p); - mid = cpid[eax]; /* Set the number */ - for (i = 1; i <= mid; i++) { /* Dump 'em out */ - do_cpuid(i, cpid); /* Get the next */ - db_printf("%08X - %08X %08X %08X %08X\n", - i, cpid[eax], cpid[ebx], cpid[ecx], cpid[edx]); + /* do cpuid 0x40000000 to get VMM vendor */ + cpuid_fn(0x40000000, reg); + 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 { + info_p->cpuid_vmm_family = CPUID_VMM_FAMILY_UNKNOWN; } - db_printf("\n"); - - do_cpuid(0x80000000, cpid); /* Get the first extended cpuid which - * is the number of extended ids */ - db_printf("%08X - %08X %08X %08X %08X\n", - 0x80000000, cpid[eax], cpid[ebx], cpid[ecx], cpid[edx]); - - mid = cpid[eax]; /* Set the number */ - for (i = 0x80000001; i <= mid; i++) { /* Dump 'em out */ - do_cpuid(i, cpid); /* Get the next */ - db_printf("%08X - %08X %08X %08X %08X\n", - i, cpid[eax], cpid[ebx], cpid[ecx], cpid[edx]); + + /* 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; } -#endif