summaryrefslogtreecommitdiffstats
path: root/cpuid.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpuid.c')
-rw-r--r--cpuid.c321
1 files changed, 75 insertions, 246 deletions
diff --git a/cpuid.c b/cpuid.c
index 9a0843b..4c25ede 100644
--- a/cpuid.c
+++ b/cpuid.c
@@ -4,255 +4,84 @@
* Implements CPUID querying functions
*
*/
+#include "stdin.h"
#include "cpuid.h"
-cpuid_t cpuid_data0;
-cpuid_t cpuid_data80;
+struct cpu_ident cpu_id;
-unsigned num_logical_cpus = 1; // number of logical cpus per physical package
-unsigned num_cores_per_package = 1; // number of cores in each physical cpu package
-unsigned num_hyper_threads_per_core = 1; // number of hyper-threads per core
-
-void
-cpuid_get(unsigned n, cpuid_t *data)
-{
- data->eax = n;
- GET_CPUID(data->eax, data->ebx, data->ecx, data->edx);
-}
-
-
-/* cpuid_get_vendor_string ---
- *
- * This function gets the vendor string from the processor's cpuid instruction
- * and passes it back to the caller in an easy to use structure.
- */
-cpuid_vendor_string_t
-cpuid_get_vendor_string(void)
-{
- static cpuid_vendor_string_t v;
-
- /* Note: the string gets passed in EBX-EDX-ECX, not the intuitive order. */
- v.uint32_array[0] = cpuid_data0.ebx;
- v.uint32_array[1] = cpuid_data0.edx;
- v.uint32_array[2] = cpuid_data0.ecx;
- v.char_array[CPUID_VENDOR_STR_LENGTH-1] = '\0';
- return v;
-}
-
-
-/* cpuid_get_version ---
- *
- * This function reads the processors version information using CPUID and puts
- * it into a union for easy use by the caller.
- */
-cpuid_version_t
-cpuid_get_version(void)
-{
- cpuid_version_t v;
- uint32_t junkEBX = 0, junkECX = 0, junkEDX = 0;
- v.flat = 0x1;
- GET_CPUID(v.flat, junkEBX, junkECX, junkEDX);
- return v;
-}
-
-
-cpuid_feature_flags_t
-cpuid_get_feature_flags(void)
-{
- cpuid_feature_flags_t f;
- uint32_t junkEAX = 0x1, junkEBX = 0;
- GET_CPUID(junkEAX, junkEBX, f.uint32_array[1], f.uint32_array[0]);
- return f;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * cpuid_get_ext_feature_flags --
- *
- * Passes back the caller the extended feature flags supported by
- * this CPU. This can be used, among other things, to determine if the
- * processor supports long mode.
- *
- * Results:
- * Returns TRUE if the processor supports the extended feature flags
- * CPUID node, and FALSE otherwise.
- *
- * Side effects:
- * Calls CPUID a couple of times.
- *
- *-----------------------------------------------------------------------------
- */
-
-bool
-cpuid_get_ext_feature_flags(cpuid_ext_feature_flags_t *f) // OUT: Flags for this CPU
-{
- uint32_t eax, ebx, ecx;
-
- if (cpuid_data80.eax < 0x80000001) {
- // Extended feature flags not supported on this CPU
- return FALSE;
- }
- eax = CPUID_EXTENDED_FEATURE;
- GET_CPUID(eax, ebx, ecx, f->flat);
- return TRUE;
-}
-
-#define CHAR_TO_INT(a,b,c,d) ((a) + (b) * 0x100 + (c) * 0x10000 + (d) * 0x1000000)
-
-bool
-cpuid_is_vendor_amd(void)
-{
- return cpuid_data0.ebx == CHAR_TO_INT('A', 'u', 't', 'h')
- && cpuid_data0.edx == CHAR_TO_INT('e', 'n', 't', 'i')
- && cpuid_data0.ecx == CHAR_TO_INT('c', 'A', 'M', 'D');
-}
-
-
-bool
-cpuid_is_vendor_intel(void)
-{
- return cpuid_data0.ebx == CHAR_TO_INT('G', 'e', 'n', 'u')
- && cpuid_data0.edx == CHAR_TO_INT('i', 'n', 'e', 'I')
- && cpuid_data0.ecx == CHAR_TO_INT('n', 't', 'e', 'l');
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * cpuid_is_family_p4 --
- *
- * Returns TRUE if the processor we're running on is an Intel processor
- * of the P4 family.
- *
- * Results:
- * The obvious.
- *
- *-----------------------------------------------------------------------------
- */
-
-bool
-cpuid_is_family_p4(void)
-{
- cpuid_version_t v = cpuid_get_version();
-
- return cpuid_is_vendor_intel() && v.bits.family == CPUID_FAMILY_EXTENDED &&
- v.bits.extendedFamily == CPUID_EXTENDED_FAMILY_PENTIUM4;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * cpuid_is_family_p6 --
- *
- * Returns TRUE if the processor we're running on belongs to the P6 family.
- *
- * Results:
- * The obvious.
- *
- *-----------------------------------------------------------------------------
- */
-
-bool
-cpuid_is_family_p6(void)
-{
- cpuid_version_t v = cpuid_get_version();
-
- return cpuid_is_vendor_intel() && v.bits.family == CPUID_FAMILY_P6;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * cpuid_is_family_opteron --
- *
- * Returns TRUE if the processor we're running on belongs to the
- * Opteron family.
- *
- *-----------------------------------------------------------------------------
- */
-
-bool
-cpuid_is_family_opteron(void)
+void get_cpuid()
{
- cpuid_version_t v = cpuid_get_version();
- return cpuid_is_vendor_amd() && CPUID_FAMILY_IS_OPTERON(v.flat);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * cpuid_init --
- *
- * Executes CPUID and caches values in cpuid_data0 abd cpuid_data80.
- *
- *-----------------------------------------------------------------------------
- */
-void
-cpuid_init(void)
-{
- //bool htt = FALSE;
- cpuid_t id1;
-
- /* First get the basic cpuid information on what the
- * type of the processor is , i.e intel or amd etc
- * and how much of extra cpuid information is available
- * with the processor
- */
- cpuid_data0.eax = 0;
- GET_CPUID(cpuid_data0.eax, cpuid_data0.ebx,
- cpuid_data0.ecx, cpuid_data0.edx);
-
-
- /* Find out if hyper-threading is available and there is more than one
- * logical processor. See section 7.6.3 in Intel IA-32 volume III.
- */
- cpuid_get(1, &id1);
+ unsigned int *v, dummy[3];
+ char *p, *q;
+
+ /* Get max std cpuid & vendor ID */
+ cpuid(0x0, &cpu_id.max_cpuid, &cpu_id.vend_id.uint32_array[0],
+ &cpu_id.vend_id.uint32_array[2], &cpu_id.vend_id.uint32_array[1]);
+ cpu_id.vend_id.char_array[11] = 0;
+
+ /* Get processor family information & feature flags */
+ if (cpu_id.max_cpuid >= 1) {
+ cpuid(0x00000001, &cpu_id.vers.flat, &cpu_id.info.flat,
+ &cpu_id.fid.uint32_array[1], &cpu_id.fid.uint32_array[0]);
+ }
+
+ /* Get the digital thermal sensor & power management status bits */
+ if(cpu_id.max_cpuid >= 6) {
+ cpuid(0x00000006, &cpu_id.dts_pmp, &dummy[0], &dummy[1], &dummy[2]);
+ }
+
+ /* Get the max extended cpuid */
+ cpuid(0x80000000, &cpu_id.max_xcpuid, &dummy[0], &dummy[1], &dummy[2]);
+
+ /* Get extended feature flags, only save EDX */
+ if (cpu_id.max_xcpuid >= 0x80000001) {
+ cpuid(0x80000001, &dummy[0], &dummy[1],
+ &dummy[2], &cpu_id.fid.uint32_array[2]);
+ }
+
+ /* Get the brand ID */
+ if (cpu_id.max_xcpuid >= 0x80000004) {
+ v = (unsigned int *)&cpu_id.brand_id;
+ cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+ cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+ cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+ cpu_id.brand_id.char_array[47] = 0;
+ }
+ /*
+ * Intel chips right-justify this string for some dumb reason;
+ * undo that brain damage:
+ */
+ p = q = &cpu_id.brand_id.char_array[0];
+ while (*p == ' ')
+ p++;
+ if (p != q) {
+ while (*p)
+ *q++ = *p++;
+ while (q <= &cpu_id.brand_id.char_array[48])
+ *q++ = '\0'; /* Zero-pad the rest */
+ }
+
+ /* Get cache information */
+ switch(cpu_id.vend_id.char_array[0]) {
+ case 'A':
+ /* AMD Processors */
+ /* The cache information is only in ecx and edx so only save
+ * those registers */
+ if (cpu_id.max_xcpuid >= 0x80000005) {
+ cpuid(0x80000005, &dummy[0], &dummy[1],
+ &cpu_id.cache_info.uint[0], &cpu_id.cache_info.uint[1]);
+ }
+ if (cpu_id.max_xcpuid >= 0x80000006) {
+ cpuid(0x80000006, &dummy[0], &dummy[1],
+ &cpu_id.cache_info.uint[2], &cpu_id.cache_info.uint[3]);
+ }
+ break;
+ case 'G':
+ /* Intel Processors, Need to do this in init.c */
+ break;
+ }
+
+ /* Turn off mon bit since monitor based spin wait may not be reliable */
+ cpu_id.fid.bits.mon = 0;
- if (cpuid_is_vendor_intel()) {
- if (cpuid_is_family_p6()) {
- // Extended CPUID features not supported on PIII
- return;
- }
- if (cpuid_is_family_p4()) {
- /*
- * Multi-core processors have the HT feature bit set (even if they
- * don't support HT).
- * The number of HT is the total number, not per-core number.
- * The number of cores is off by 1, i.e. single-core reports 0.
- */
- //htt = id1.edx & CPUID_FEATURE_COMMON_ID1EDX_HT;
- if (id1.edx & CPUID_FEATURE_COMMON_ID1EDX_HT) {
- num_hyper_threads_per_core = (id1.ebx >> 16) & 0xff;
- if (cpuid_max_func() >= 4) {
- cpuid_t id4;
- cpuid_get(4, &id4);
- num_cores_per_package = ((id4.eax >> 26) & 0x3f) + 1;
- num_hyper_threads_per_core /= num_cores_per_package;
- }
- }
- }
- } else if (cpuid_is_vendor_amd()) {
- cpuid_data80.eax = 0x80000000;
- GET_CPUID(cpuid_data80.eax, cpuid_data80.ebx,
- cpuid_data80.ecx, cpuid_data80.edx);
- if (cpuid_max_ext_func() >= 0x80000008) {
- /* Number of cores is reported in extended function 0x80000008
- * For legacy multi-core support, AMD CPUs report the number of
- * cores as hyper-threads. Adjust the numbers to reflect that there
- * are no threads.
- */
- cpuid_t id88;
- cpuid_get(0x80000008, &id88);
- num_cores_per_package = id88.ecx & 0xff;
- num_hyper_threads_per_core = 1;
- }
- } else {
- /* Unknown cpu type. we use the defaults */
- }
}