/*
* @OSF_COPYRIGHT@
*/
-
+#include <platforms.h>
+#include <mach_kdb.h>
#include <pexpert/pexpert.h>
#include "cpuid.h"
+#if MACH_KDB
+#include <i386/db_machdep.h>
+#include <ddb/db_aout.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_command.h>
+#include <ddb/db_output.h>
+#include <ddb/db_expr.h>
+#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.
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 */
/* 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 */
"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, \
(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. */
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";
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:
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:
case CPUID_BRAND_MOBILE_17:
return "Mobile Intel";
}
-
return "Unknown Intel";
}
/* 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:
/* (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);
/* (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 )
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
/* 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) {
/* 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;
}
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",},
{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';
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])) {
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