diff options
Diffstat (limited to 'cpuid.c')
-rw-r--r-- | cpuid.c | 321 |
1 files changed, 75 insertions, 246 deletions
@@ -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 */ - } } |