X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/21362eb3e66fd2c787aee132bce100a44d71a99c..4452a7af2eac33dbad800bcc91f2399d62c18f53:/osfmk/i386/cpuid.c?ds=sidebyside diff --git a/osfmk/i386/cpuid.c b/osfmk/i386/cpuid.c index d4879d3a3..3fe712adb 100644 --- a/osfmk/i386/cpuid.c +++ b/osfmk/i386/cpuid.c @@ -28,12 +28,28 @@ /* * @OSF_COPYRIGHT@ */ - +#include +#include #include #include "cpuid.h" +#if MACH_KDB +#include +#include +#include +#include +#include +#include +#include +#include +#endif #define min(a,b) ((a) < (b) ? (a) : (b)) +#define quad(hi,lo) (((uint64_t)(hi)) << 32 | (lo)) + +#define bit(n) (1UL << (n)) +#define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1)) +#define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l) /* * CPU identification routines. @@ -44,6 +60,7 @@ static unsigned int cpuid_maxcpuid; +static i386_cpu_info_t *cpuid_cpu_infop = NULL; static i386_cpu_info_t cpuid_cpu_info; uint32_t cpuid_feature; /* XXX obsolescent for compat */ @@ -78,10 +95,10 @@ cpuid_get_info(i386_cpu_info_t *info_p) /* do cpuid 0 to get vendor */ do_cpuid(0, cpuid_result); - cpuid_maxcpuid = cpuid_result[0]; - bcopy((char *)&cpuid_result[1], &info_p->cpuid_vendor[0], 4); /* ugh */ - bcopy((char *)&cpuid_result[2], &info_p->cpuid_vendor[8], 4); - bcopy((char *)&cpuid_result[3], &info_p->cpuid_vendor[4], 4); + cpuid_maxcpuid = cpuid_result[eax]; + bcopy((char *)&cpuid_result[ebx], &info_p->cpuid_vendor[0], 4); /* ug */ + bcopy((char *)&cpuid_result[ecx], &info_p->cpuid_vendor[8], 4); + bcopy((char *)&cpuid_result[edx], &info_p->cpuid_vendor[4], 4); info_p->cpuid_vendor[12] = 0; /* look up vendor */ @@ -161,6 +178,8 @@ CACHE_DESC(CPUID_CACHE_UCACHE_1M, L2U, 1*1024*1024, 32, \ "Unified L2 cache, 1M, 4-way set associative, 32byte line size"), CACHE_DESC(CPUID_CACHE_UCACHE_2M, L2U, 2*1024*1024, 32, \ "Unified L2 cache, 2M, 4-way set associative, 32byte line size"), +CACHE_DESC(CPUID_CACHE_UCACHE_4M, L2U, 4*1024*1024, 64, \ + "Unified L2 cache, 4M, 16-way set associative, 64byte line size"), CACHE_DESC(CPUID_CACHE_UCACHE_128K_64, L2U, 128*1024, 64, \ "Unified L2 cache, 128K, 8-way set associative, 64byte line size"), CACHE_DESC(CPUID_CACHE_UCACHE_256K_64, L2U, 256*1024, 64, \ @@ -211,9 +230,12 @@ CACHE_DESC(CPUID_CACHE_NULL, Lnone, 0, 0, \ (char *)0), }; -static const char * get_intel_model_string( i386_cpu_info_t * info_p ) +static const char * get_intel_model_string( i386_cpu_info_t * info_p, cpu_type_t* type, cpu_subtype_t* subtype) { - /* check for brand id */ + *type = CPU_TYPE_X86; + *subtype = CPU_SUBTYPE_X86_ARCH1; + + /* check for brand id string */ switch(info_p->cpuid_brand) { case CPUID_BRAND_UNSUPPORTED: /* brand ID not supported; use alternate method. */ @@ -242,14 +264,13 @@ static const char * get_intel_model_string( i386_cpu_info_t * info_p ) default: return "Unknown Intel P6 Family"; } - case CPUID_FAMILY_ITANIUM: - return "Intel Itanium"; case CPUID_FAMILY_EXTENDED: switch (info_p->cpuid_extfamily) { case CPUID_EXTFAMILY_PENTIUM4: + *subtype = CPU_SUBTYPE_PENTIUM_4; return "Intel Pentium 4"; - case CPUID_EXTFAMILY_ITANIUM2: - return "Intel Itanium 2"; + default: + return "Unknown Intel Extended Family"; } default: return "Unknown Intel Family"; @@ -263,10 +284,11 @@ static const char * get_intel_model_string( i386_cpu_info_t * info_p ) case CPUID_BRAND_PENTIUM_III_4: return "Pentium III"; case CPUID_BRAND_PIII_XEON: - if (info_p->cpuid_signature == 0x6B1) - return "Intel Celeron"; - else - return "Intel Pentium III Xeon"; + if (info_p->cpuid_signature == 0x6B1) { + return "Intel Celeron"; + } else { + return "Intel Pentium III Xeon"; + } case CPUID_BRAND_PENTIUM_III_M: return "Mobile Intel Pentium III-M"; case CPUID_BRAND_M_CELERON_7: @@ -276,16 +298,19 @@ static const char * get_intel_model_string( i386_cpu_info_t * info_p ) return "Mobile Intel Celeron"; case CPUID_BRAND_PENTIUM4_8: case CPUID_BRAND_PENTIUM4_9: + *subtype = CPU_SUBTYPE_PENTIUM_4; return "Intel Pentium 4"; case CPUID_BRAND_XEON: return "Intel Xeon"; case CPUID_BRAND_XEON_MP: return "Intel Xeon MP"; case CPUID_BRAND_PENTIUM4_M: - if (info_p->cpuid_signature == 0xF13) - return "Intel Xeon"; - else - return "Mobile Intel Pentium 4"; + if (info_p->cpuid_signature == 0xF13) { + return "Intel Xeon"; + } else { + *subtype = CPU_SUBTYPE_PENTIUM_4; + return "Mobile Intel Pentium 4"; + } case CPUID_BRAND_CELERON_M: return "Intel Celeron M"; case CPUID_BRAND_PENTIUM_M: @@ -294,7 +319,6 @@ static const char * get_intel_model_string( i386_cpu_info_t * info_p ) case CPUID_BRAND_MOBILE_17: return "Mobile Intel"; } - return "Unknown Intel"; } @@ -353,17 +377,69 @@ static void set_intel_cache_info( i386_cpu_info_t * info_p ) /* If we have no L2 cache, use the L1 data cache line size */ if (info_p->cache_size[L2U] == 0) info_p->cache_linesize = l1d_cache_linesize; + + /* + * Get cache sharing info if available. + */ + do_cpuid(0, cpuid_result); + if (cpuid_result[eax] >= 4) { + uint32_t reg[4]; + uint32_t index; + for (index = 0;; index++) { + /* + * Scan making calls for cpuid with %eax = 4 + * to get info about successive cache levels + * until a null type is returned. + */ + cache_type_t type = Lnone; + uint32_t cache_type; + uint32_t cache_level; + uint32_t cache_sharing; + + 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]); + cache_type = bitfield(reg[eax], 4, 0); + if (cache_type == 0) + break; /* done with cache info */ + cache_level = bitfield(reg[eax], 7, 5); + cache_sharing = bitfield(reg[eax], 25, 14); + info_p->cpuid_cores_per_package = + bitfield(reg[eax], 31, 26) + 1; + switch (cache_level) { + case 1: + type = cache_type == 1 ? L1D : + cache_type == 2 ? L1I : + Lnone; + break; + case 2: + type = cache_type == 3 ? L2U : + Lnone; + break; + case 3: + type = cache_type == 3 ? L3U : + Lnone; + } + if (type != Lnone) + info_p->cache_sharing[type] = cache_sharing + 1; + } + } } static void set_cpu_intel( i386_cpu_info_t * info_p ) { set_cpu_generic(info_p); set_intel_cache_info(info_p); - info_p->cpuid_model_string = get_intel_model_string(info_p); + info_p->cpuid_model_string = get_intel_model_string(info_p, &info_p->cpuid_cpu_type, &info_p->cpuid_cpu_subtype); } -static const char * get_amd_model_string( i386_cpu_info_t * info_p ) +static const char * get_amd_model_string( i386_cpu_info_t * info_p, cpu_type_t* type, cpu_subtype_t* subtype ) { + *type = CPU_TYPE_X86; + *subtype = CPU_SUBTYPE_X86_ARCH1; + + /* check for brand id string */ switch (info_p->cpuid_family) { case CPUID_FAMILY_486: @@ -444,11 +520,11 @@ static void set_amd_cache_info( i386_cpu_info_t * info_p ) /* (ignore) */ /* ECX: L1 Data Cache Information */ - info_p->cache_size[L1D] = ((cpuid_result[2] >> 24) & 0xFF) * 1024; - info_p->cache_linesize = (cpuid_result[2] & 0xFF); + info_p->cache_size[L1D] = ((cpuid_result[ecx] >> 24) & 0xFF) * 1024; + info_p->cache_linesize = (cpuid_result[ecx] & 0xFF); /* EDX: L1 Instruction Cache Information */ - info_p->cache_size[L1I] = ((cpuid_result[3] >> 24) & 0xFF) * 1024; + info_p->cache_size[L1I] = ((cpuid_result[edx] >> 24) & 0xFF) * 1024; /* L2 Cache Information */ do_cpuid(0x80000006, cpuid_result); @@ -460,16 +536,16 @@ static void set_amd_cache_info( i386_cpu_info_t * info_p ) /* (ignore) */ /* ECX: L2 Cache Information */ - info_p->cache_size[L2U] = ((cpuid_result[2] >> 16) & 0xFFFF) * 1024; + info_p->cache_size[L2U] = ((cpuid_result[ecx] >> 16) & 0xFFFF) * 1024; if (info_p->cache_size[L2U] > 0) - info_p->cache_linesize = cpuid_result[2] & 0xFF; + info_p->cache_linesize = cpuid_result[ecx] & 0xFF; } static void set_cpu_amd( i386_cpu_info_t * info_p ) { set_cpu_generic(info_p); set_amd_cache_info(info_p); - info_p->cpuid_model_string = get_amd_model_string(info_p); + info_p->cpuid_model_string = get_amd_model_string(info_p, &info_p->cpuid_cpu_type, &info_p->cpuid_cpu_subtype); } static void set_cpu_nsc( i386_cpu_info_t * info_p ) @@ -477,12 +553,16 @@ static void set_cpu_nsc( i386_cpu_info_t * info_p ) set_cpu_generic(info_p); set_amd_cache_info(info_p); - if (info_p->cpuid_family == CPUID_FAMILY_586 && info_p->cpuid_model == CPUID_MODEL_GX1) + /* check for brand id string */ + if (info_p->cpuid_family == CPUID_FAMILY_586 && info_p->cpuid_model == CPUID_MODEL_GX1) { info_p->cpuid_model_string = "AMD Geode GX1"; - else if (info_p->cpuid_family == CPUID_FAMILY_586 && info_p->cpuid_model == CPUID_MODEL_GX2) + } else if (info_p->cpuid_family == CPUID_FAMILY_586 && info_p->cpuid_model == CPUID_MODEL_GX2) { info_p->cpuid_model_string = "AMD Geode GX"; - else + } else { info_p->cpuid_model_string = "Unknown National Semiconductor"; + } + info_p->cpuid_cpu_type = CPU_TYPE_X86; + info_p->cpuid_cpu_subtype = CPU_SUBTYPE_X86_ARCH1; } static void @@ -494,7 +574,7 @@ set_cpu_generic(i386_cpu_info_t *info_p) /* get extended cpuid results */ do_cpuid(0x80000000, cpuid_result); - max_extid = cpuid_result[0]; + max_extid = cpuid_result[eax]; /* check to see if we can get brand string */ if (max_extid >= 0x80000004) { @@ -526,15 +606,23 @@ set_cpu_generic(i386_cpu_info_t *info_p) /* get processor signature and decode */ do_cpuid(1, cpuid_result); - info_p->cpuid_signature = cpuid_result[0]; - info_p->cpuid_stepping = cpuid_result[0] & 0x0f; - info_p->cpuid_model = (cpuid_result[0] >> 4) & 0x0f; - info_p->cpuid_family = (cpuid_result[0] >> 8) & 0x0f; - info_p->cpuid_type = (cpuid_result[0] >> 12) & 0x03; - info_p->cpuid_extmodel = (cpuid_result[0] >> 16) & 0x0f; - info_p->cpuid_extfamily = (cpuid_result[0] >> 20) & 0xff; - info_p->cpuid_brand = cpuid_result[1] & 0xff; - info_p->cpuid_features = cpuid_result[3]; + info_p->cpuid_signature = cpuid_result[eax]; + info_p->cpuid_stepping = bitfield(cpuid_result[eax], 3, 0); + info_p->cpuid_model = bitfield(cpuid_result[eax], 7, 4); + info_p->cpuid_family = bitfield(cpuid_result[eax], 11, 8); + info_p->cpuid_type = bitfield(cpuid_result[eax], 13, 12); + info_p->cpuid_extmodel = bitfield(cpuid_result[eax], 19, 16); + info_p->cpuid_extfamily = bitfield(cpuid_result[eax], 27, 20); + info_p->cpuid_brand = bitfield(cpuid_result[ebx], 7, 0); + info_p->cpuid_logical_per_package = + bitfield(cpuid_result[ebx], 23, 16); + info_p->cpuid_features = quad(cpuid_result[ecx], cpuid_result[edx]); + + if (max_extid >= 0x80000001) { + do_cpuid(0x80000001, cpuid_result); + info_p->cpuid_extfeatures = + quad(cpuid_result[ecx], cpuid_result[edx]); + } return; } @@ -547,9 +635,9 @@ set_cpu_unknown(__unused i386_cpu_info_t *info_p) static struct { - uint32_t mask; + uint64_t mask; const char *name; -} feature_names[] = { +} feature_map[] = { {CPUID_FEATURE_FPU, "FPU",}, {CPUID_FEATURE_VME, "VME",}, {CPUID_FEATURE_DE, "DE",}, @@ -578,25 +666,76 @@ static struct { {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_MNI, "MNI"}, + {CPUID_FEATURE_CID, "CID"}, + {CPUID_FEATURE_CX16, "CX16"}, + {CPUID_FEATURE_xTPR, "TPR"}, + {0, 0} +}, +extfeature_map[] = { + {CPUID_EXTFEATURE_SYSCALL, "SYSCALL"}, + {CPUID_EXTFEATURE_XD, "XD"}, + {CPUID_EXTFEATURE_EM64T, "EM64T"}, + {CPUID_EXTFEATURE_LAHF, "LAHF"}, {0, 0} }; +i386_cpu_info_t * +cpuid_info(void) +{ + /* Set-up the cpuid_indo stucture lazily */ + if (cpuid_cpu_infop == NULL) { + cpuid_get_info(&cpuid_cpu_info); + cpuid_cpu_infop = &cpuid_cpu_info; + } + return cpuid_cpu_infop; +} + char * -cpuid_get_feature_names(uint32_t feature, char *buf, unsigned buf_len) +cpuid_get_feature_names(uint64_t features, char *buf, unsigned buf_len) { + int len = -1; + char *p = buf; int i; - int len; + + 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), (buf_len-1) - (p-buf)); + if (len == 0) + break; + bcopy(feature_map[i].name, p, len); + p += len; + } + *p = '\0'; + return buf; +} + +char * +cpuid_get_extfeature_names(uint64_t extfeatures, char *buf, unsigned buf_len) +{ + int len = -1; char *p = buf; + int i; - for (i = 0; feature_names[i].mask != 0; i++) { - if ((feature & feature_names[i].mask) == 0) + for (i = 0; extfeature_map[i].mask != 0; i++) { + if ((extfeatures & extfeature_map[i].mask) == 0) continue; - if (i > 0) + if (len > 0) *p++ = ' '; - len = min(strlen(feature_names[i].name), (buf_len-1) - (p-buf)); + len = min(strlen(extfeature_map[i].name), (buf_len-1)-(p-buf)); if (len == 0) break; - bcopy(feature_names[i].name, p, len); + bcopy(extfeature_map[i].name, p, len); p += len; } *p = '\0'; @@ -605,37 +744,69 @@ cpuid_get_feature_names(uint32_t feature, char *buf, unsigned buf_len) void cpuid_feature_display( - const char *header, - __unused int my_cpu) + const char *header) +{ + char buf[256]; + + kprintf("%s: %s\n", header, + cpuid_get_feature_names(cpuid_features(), + buf, sizeof(buf))); + 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)); + } +} + +void +cpuid_extfeature_display( + const char *header) { char buf[256]; - printf("%s: %s\n", header, - cpuid_get_feature_names(cpuid_features(), buf, sizeof(buf))); + kprintf("%s: %s\n", header, + cpuid_get_extfeature_names(cpuid_extfeatures(), + buf, sizeof(buf))); } void cpuid_cpu_display( - const char *header, - __unused int my_cpu) + const char *header) { - if (cpuid_cpu_info.cpuid_brand_string[0] != '\0') { - printf("%s: %s\n", header, - cpuid_cpu_info.cpuid_brand_string); + if (cpuid_info()->cpuid_brand_string[0] != '\0') { + kprintf("%s: %s\n", header, cpuid_cpu_info.cpuid_brand_string); } } unsigned int cpuid_family(void) { - return cpuid_cpu_info.cpuid_family; + return cpuid_info()->cpuid_family; } -unsigned int +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[16] = { 0 }; + + (void) cpuid_info(); if (!checked) { /* check for boot-time fpu limitations */ if (PE_parse_boot_arg("_fpu", &fpu_arg[0])) { @@ -653,17 +824,59 @@ cpuid_features(void) return cpuid_cpu_info.cpuid_features; } -i386_cpu_info_t * -cpuid_info(void) +uint64_t +cpuid_extfeatures(void) { - return &cpuid_cpu_info; + return cpuid_info()->cpuid_extfeatures; } - -/* XXX for temporary compatibility */ + void -set_cpu_model(void) +cpuid_set_info(void) { cpuid_get_info(&cpuid_cpu_info); - cpuid_feature = cpuid_cpu_info.cpuid_features; /* XXX compat */ } +#if MACH_KDB + +/* + * Display the cpuid + * * + * cp + */ +void +db_cpuid(__unused db_expr_t addr, + __unused int have_addr, + __unused db_expr_t count, + __unused char *modif) +{ + + uint32_t i, mid; + uint32_t cpid[4]; + + 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]); + + 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]); + } + 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]); + } +} + +#endif