X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..22ba694c5857e62b5a553b1505dcf2e509177f28:/osfmk/i386/cpuid.c?ds=sidebyside diff --git a/osfmk/i386/cpuid.c b/osfmk/i386/cpuid.c index c6891aefb..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 }, @@ -224,32 +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 (get_is64bit()) { - asm("call _cpuid64" - : "=a" (result[0]), - "=b" (result[1]), - "=c" (result[2]), - "=d" (result[3]) - : "a"(selector), - "b" (0), - "c" (0), - "d" (0)); - } 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 @@ -263,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 @@ -311,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 */ @@ -354,6 +348,13 @@ cpuid_set_cache_info( i386_cpu_info_t * info_p ) 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 @@ -389,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 @@ -403,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); } /* @@ -414,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; @@ -458,6 +470,7 @@ cpuid_set_cache_info( i386_cpu_info_t * info_p ) info_p->cpuid_stlb = descp->entries; } } + DBG("\n"); } static void @@ -466,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]; @@ -555,7 +570,7 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) 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) & 3; + info_p->cpuid_processor_flag = (rdmsr64(MSR_IA32_PLATFORM_ID)>> 50) & 0x7; /* Fold extensions into family/model */ if (info_p->cpuid_family == 0x0f) @@ -575,11 +590,30 @@ 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); } if (info_p->cpuid_max_basic >= 0x5) { @@ -594,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) { @@ -606,14 +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], 3, 3); - ctp->fine_grain_clock_mod = bitfield32(reg[eax], 4, 4); - ctp->package_thermal_intr = bitfield32(reg[eax], 5, 5); + 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], 2, 2); + 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) { @@ -631,6 +683,15 @@ 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) { @@ -640,6 +701,23 @@ cpuid_set_generic_info(i386_cpu_info_t *info_p) */ 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; @@ -653,11 +731,6 @@ cpuid_set_cpufamily(i386_cpu_info_t *info_p) switch (info_p->cpuid_family) { case 6: switch (info_p->cpuid_model) { -#if CONFIG_YONAH - case 14: - cpufamily = CPUFAMILY_INTEL_YONAH; - break; -#endif case 15: cpufamily = CPUFAMILY_INTEL_MEROM; break; @@ -679,11 +752,21 @@ cpuid_set_cpufamily(i386_cpu_info_t *info_p) 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; } /* @@ -694,8 +777,6 @@ 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); @@ -709,7 +790,7 @@ cpuid_set_info(void) info_p->cpuid_cpu_type = CPU_TYPE_X86; info_p->cpuid_cpu_subtype = CPU_SUBTYPE_X86_ARCH1; /* Must be invoked after set_generic_info */ - cpuid_set_cache_info(&cpuid_cpu_info); + cpuid_set_cache_info(info_p); /* * Find the number of enabled cores and threads @@ -722,6 +803,8 @@ cpuid_set_info(void) 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); @@ -734,11 +817,14 @@ 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[] = { @@ -782,12 +868,13 @@ static struct { {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_xAPIC, "xAPIC"}, + {CPUID_FEATURE_x2APIC, "x2APIC"}, {CPUID_FEATURE_MOVBE, "MOVBE"}, {CPUID_FEATURE_POPCNT, "POPCNT"}, {CPUID_FEATURE_AES, "AES"}, @@ -798,6 +885,8 @@ static struct { {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[] = { @@ -809,13 +898,50 @@ extfeature_map[] = { {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; } @@ -825,48 +951,20 @@ cpuid_info(void) char * cpuid_get_feature_names(uint64_t features, char *buf, unsigned buf_len) { - size_t len = 0; - char *p = buf; - int i; - - for (i = 0; feature_map[i].mask != 0; i++) { - if ((features & feature_map[i].mask) == 0) - continue; - if (len && ((size_t)(p - buf) < (buf_len - 1))) - *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 = 0; - char *p = buf; - int i; - - for (i = 0; extfeature_map[i].mask != 0; i++) { - if ((extfeatures & extfeature_map[i].mask) == 0) - continue; - if (len && ((size_t) (p - buf) < (buf_len - 1))) - *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( @@ -874,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)); } } @@ -903,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); } } @@ -945,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 @@ -962,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)); + + if (!cpuid_vmm_present()) + return; - uint32_t i, mid; - uint32_t cpid[4]; + DBG("cpuid_init_vmm_info(%p)\n", info_p); - 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]); + /* 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; + } - 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]); + /* 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]; } - 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]); + + 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