#include #include #include #include #include #include #include /** * Information about the boot CPU. * The CPU capabilities stored in this structure are the lowest common * denominator for all CPUs in the system... in this sense, boot_cpu_data * is special compared to the corresponding entry in the cpu_info[] array. */ struct cpuinfo boot_cpu_data; /** * On AMD multi-core CPUs, the lower bits of the local APIC ID distinquish the * cores. This function assumes the number of cores is a power of two. */ static void __init amd_detect_cmp(struct cpuinfo *c) { struct arch_cpuinfo *a = &c->arch; unsigned bits; unsigned ecx = cpuid_ecx(0x80000008); a->x86_pkg_cores = (ecx & 0xff) + 1; /* CPU telling us the core id bits shift? */ bits = (ecx >> 12) & 0xF; /* Otherwise recompute */ if (bits == 0) { while ((1 << bits) < a->x86_pkg_cores) bits++; } /* Determine the physical socket ID */ c->phys_socket_id = c->physical_id >> bits; /* Determine the physical core ID (index of core in socket) */ c->phys_core_id = c->physical_id & ((1 << bits)-1); } static void __init amd_cpu(struct cpuinfo *c) { unsigned level; unsigned long value; unsigned int eax, ebx, ecx, edx; struct arch_cpuinfo *a = &c->arch; /* * Disable TLB flush filter by setting HWCR.FFDIS on K8 * bit 6 of msr C001_0015 * * Errata 63 for SH-B3 steppings * Errata 122 for all steppings (F+ have it disabled by default) */ if (a->x86_family == 15) { rdmsrl(MSR_K8_HWCR, value); value |= 1 << 6; wrmsrl(MSR_K8_HWCR, value); } /* * Bit 31 in normal CPUID used for nonstandard 3DNow ID; * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ clear_bit(0*32+31, &a->x86_capability); /* On C+ stepping K8 rep microcode works well for copy/memset */ level = cpuid_eax(1); if (a->x86_family == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)) set_bit(X86_FEATURE_REP_GOOD, &a->x86_capability); if (a->x86_family == 0x10) set_bit(X86_FEATURE_REP_GOOD, &a->x86_capability); /* Enable workaround for FXSAVE leak */ if (a->x86_family >= 6) set_bit(X86_FEATURE_FXSAVE_LEAK, &a->x86_capability); /* Determine L1 Cache and TLB Information */ if (a->extended_cpuid_level >= 0x80000005) { cpuid(0x80000005, &eax, &ebx, &ecx, &edx); /* 2-MB L1 TLB (inclusive with L2 TLB) */ a->x86_tlb_size[INST][L1][PAGE_2MB] = (eax & 0xff); a->x86_tlb_size[DATA][L1][PAGE_2MB] = ((eax >> 16) & 0xff); /* 4-KB L1 TLB (inclusive with L2 TLB) */ a->x86_tlb_size[INST][L1][PAGE_4KB] = (ebx & 0xff); a->x86_tlb_size[DATA][L1][PAGE_4KB] = ((ebx >> 16) & 0xff); /* L1 Instruction Cache */ a->x86_cache_size[INST][L1] = (edx >> 24); a->x86_cache_line[INST][L1] = (edx & 0xff); /* L1 Data Cache */ a->x86_cache_size[DATA][L1] = (ecx >> 24); a->x86_cache_line[DATA][L1] = (ecx & 0xff); } /* Determine L2 Cache and TLB Information */ if (a->extended_cpuid_level >= 0x80000006) { cpuid(0x80000006, &eax, &ebx, &ecx, &edx); /* 2-MB L2 TLB */ if ((eax & 0xffff0000) == 0) { /* Unified I+D 2-MB L2 TLB */ a->x86_tlb_size[UNIF][L2][PAGE_2MB] = eax & 0xfff; } else { a->x86_tlb_size[INST][L2][PAGE_2MB] = eax & 0xfff; a->x86_tlb_size[DATA][L2][PAGE_2MB] = (eax>>16) & 0xfff; } /* 4-KB L2 TLB */ if ((ebx & 0xffff0000) == 0) { /* Unified I+D 4-KB L2 TLB */ a->x86_tlb_size[UNIF][L2][PAGE_4KB] = ebx & 0xfff; } else { a->x86_tlb_size[INST][L2][PAGE_4KB] = ebx & 0xfff; a->x86_tlb_size[DATA][L2][PAGE_4KB] = (ebx>>16) & 0xfff; } /* Unified L2 Cache */ a->x86_cache_size[UNIF][L2] = ecx >> 16; a->x86_cache_line[UNIF][L2] = ecx & 0xff; } /* Determine Advanced Power Management Features */ if (a->extended_cpuid_level >= 0x80000007) { a->x86_power = cpuid_edx(0x80000007); } /* Determine Maximum Address Sizes */ if (a->extended_cpuid_level >= 0x80000008) { cpuid(0x80000008, &eax, &ebx, &ecx, &edx); a->x86_virt_bits = (eax >> 8) & 0xff; a->x86_phys_bits = eax & 0xff; } /* a->x86_power is 8000_0007 edx. Bit 8 is constant TSC */ if (a->x86_power & (1<<8)) set_bit(X86_FEATURE_CONSTANT_TSC, &a->x86_capability); /* Multi core CPU? */ if (a->extended_cpuid_level >= 0x80000008) amd_detect_cmp(c); if (a->x86_family == 0xf || a->x86_family == 0x10 || a->x86_family == 0x11) set_bit(X86_FEATURE_K8, &a->x86_capability); /* RDTSC can be speculated around */ clear_bit(X86_FEATURE_SYNC_RDTSC, &a->x86_capability); /* Family 10 doesn't support C states in MWAIT so don't use it */ if (a->x86_family == 0x10) clear_bit(X86_FEATURE_MWAIT, &a->x86_capability); } static void __init intel_cpu(struct cpuinfo *c) { /* TODO */ } /* * Do some early cpuid on the boot CPU to get some parameter that are * needed before check_bugs. Everything advanced is in identify_cpu * below. */ void __init early_identify_cpu(struct cpuinfo *c) { struct arch_cpuinfo *a = &c->arch; uint32_t tfms; uint32_t misc; /* * Zero structure, except apic_id should have already been filled in. */ uint8_t apic_id = a->apic_id; memset(a, 0, sizeof(*a)); a->apic_id = apic_id; /* * Set some defaults to begin with. */ a->x86_vendor_id[0] = '\0'; /* Unset */ a->x86_model_id[0] = '\0'; /* Unset */ a->x86_clflush_size = 64; a->x86_pkg_cores = 1; a->max_cpu_khz = 1000000; /* start out with 1 GHz */ a->min_cpu_khz = a->max_cpu_khz; a->cur_cpu_khz = a->max_cpu_khz; a->tsc_khz = a->max_cpu_khz; memset(&a->x86_capability, 0, sizeof(a->x86_capability)); /* Determine the CPU vendor */ cpuid(0x00000000, &a->cpuid_level, (unsigned int *)&a->x86_vendor_id[0], (unsigned int *)&a->x86_vendor_id[8], (unsigned int *)&a->x86_vendor_id[4]); /* Derive the vendor ID from the vendor string */ if (!strcmp(a->x86_vendor_id, "AuthenticAMD")) a->x86_vendor = X86_VENDOR_AMD; else if (!strcmp(a->x86_vendor_id, "GenuineIntel")) a->x86_vendor = X86_VENDOR_INTEL; else a->x86_vendor = X86_VENDOR_UNKNOWN; if (a->cpuid_level == 0) panic("CPU only has CPUID level 0... is your CPU ancient?"); /* * Determine Intel-defined CPU features and other standard info. * NOTE: Vendor-specific code may override these later. */ cpuid(0x00000001, &tfms, /* type, family, model, stepping */ &misc, /* brand, cflush sz, logical cpus, apic id */ &a->x86_capability[4], /* extended cpu features */ &a->x86_capability[0] /* cpu features */ ); /* Determine the CPU family */ a->x86_family = (tfms >> 8) & 0xf; if (a->x86_family == 0xf) a->x86_family += ((tfms >> 20) & 0xff); /* Determine the CPU model */ a->x86_model = (tfms >> 4) & 0xf; if (a->x86_family >= 0x6) a->x86_model += (((tfms >> 16) & 0xf) << 4); /* Determine the CPU stepping */ a->x86_stepping = tfms & 0xf; /* Determine the CLFLUSH size, if the CPU supports CLFLUSH */ if (a->x86_capability[0] & (1 << X86_FEATURE_CLFLSH)) a->x86_clflush_size = ((misc >> 8) & 0xff) * 8; /* * Determine the CPU's initial local APIC ID. * NOTE: The BIOS may change the CPU's Local APIC ID before * passing control to the OS kernel, however the value * reported by CPUID will never change. The initial APIC * ID can sometimes be used to discover CPU topology. */ a->initial_lapic_id = (misc >> 24) & 0xff; /* TODO: determine page sizes supported via CPUID */ c->pagesz_mask = (VM_PAGE_4KB | VM_PAGE_2MB); } /* * This does the hard work of actually picking apart the CPU stuff... */ void __init identify_cpu(void) { int i; struct cpuinfo *c = &cpu_info[this_cpu]; struct arch_cpuinfo *a = &c->arch; early_identify_cpu(c); /* Determine the extended CPUID level */ a->extended_cpuid_level = cpuid_eax(0x80000000); /* Parse extended CPUID information */ if ((a->extended_cpuid_level & 0xffff0000) == 0x80000000) { /* Determine AMD-defined CPU features: level 0x80000001 */ if (a->extended_cpuid_level >= 0x80000001) { a->x86_capability[1] = cpuid_edx(0x80000001); a->x86_capability[6] = cpuid_ecx(0x80000001); } /* Determine processor brand/model string */ if (a->extended_cpuid_level >= 0x80000004) { unsigned int *v = (unsigned int *) a->x86_model_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]); a->x86_model_id[48] = '\0'; } else { strcpy(a->x86_model_id, "Unknown x86-64 Model"); } } /* * Vendor-specific initialization. In this section we * canonicalize the feature flags, meaning if there are * features a certain CPU supports which CPUID doesn't * tell us, CPUID claiming incorrect flags, or other bugs, * we handle them here. * * At the end of this section, c->x86_capability better * indicate the features this CPU genuinely supports! */ switch (a->x86_vendor) { case X86_VENDOR_AMD: amd_cpu(c); break; case X86_VENDOR_INTEL: intel_cpu(c); break; case X86_VENDOR_UNKNOWN: default: panic("Unknown x86 CPU Vendor."); } /* * boot_cpu_data holds the common feature set between * all CPUs; so make sure that we indicate which features are * common between the CPUs. The first time this routine gets * executed, c == &boot_cpu_data. */ if (c != &boot_cpu_data) { /* AND the already accumulated flags with these */ for (i = 0 ; i < NCAPINTS ; i++) boot_cpu_data.arch.x86_capability[i] &= c->arch.x86_capability[i]; } } /** * Prints architecture specific CPU information to the console. */ void print_arch_cpuinfo(struct cpuinfo *c) { int i; struct arch_cpuinfo *a = &c->arch; char buf[1024]; /* * These flag bits must match the definitions in . * NULL means this bit is undefined or reserved; either way it doesn't * have meaning as far as the kernel is concerned. */ static char *x86_cap_flags[] = { /* Intel-defined */ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe", /* AMD-defined */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL, NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm", "3dnowext", "3dnow", /* Transmeta-defined */ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Other (Linux-defined) */ "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL, "constant_tsc", "up", NULL, "arch_perfmon", "pebs", "bts", NULL, "sync_rdtsc", "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Intel-defined (#2) */ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est", "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* VIA/Cyrix/Centaur-defined */ NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en", "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* AMD-defined (#2) */ "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy", "altmovcr8", "abm", "sse4a", "misalignsse", "3dnowprefetch", "osvw", "ibs", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Auxiliary (Linux-defined) */ "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; static char *x86_power_flags[] = { "ts", /* temperature sensor */ "fid", /* frequency id control */ "vid", /* voltage id control */ "ttp", /* thermal trip */ "tm", "stc", "100mhzsteps", "hwpstate", "", /* tsc invariant mapped to constant_tsc */ /* nothing */ }; printk(KERN_DEBUG " Vendor: %s\n", a->x86_vendor_id); printk(KERN_DEBUG " Family: %u\n", a->x86_family); printk(KERN_DEBUG " Model: %u (%s)\n", a->x86_model, a->x86_model_id); printk(KERN_DEBUG " Stepping: %u\n", a->x86_stepping); printk(KERN_DEBUG " Frequency: %u.%03u MHz (max=%u.%03u, min=%u.%03u)\n", a->cur_cpu_khz / 1000, (a->cur_cpu_khz % 1000), a->max_cpu_khz / 1000, (a->max_cpu_khz % 1000), a->min_cpu_khz / 1000, (a->min_cpu_khz % 1000)); /* L1 Cache Info */ if (a->x86_cache_size[UNIF][L1] == 0) { printk(KERN_DEBUG " L1 Cache: I=%u KB, D=%u KB, line size=%u bytes\n", a->x86_cache_size[INST][L1], a->x86_cache_size[DATA][L1], a->x86_cache_line[DATA][L1]); } else { printk(KERN_DEBUG " L1 Cache: %u KB (unified I+D), line size=%u bytes\n", a->x86_cache_size[UNIF][L1], a->x86_cache_line[UNIF][L1]); } /* L2 Cache Info */ if (a->x86_cache_size[UNIF][L2] == 0) { printk(KERN_DEBUG " L2 Cache: I=%u KB, D=%u KB, line size=%u bytes\n", a->x86_cache_size[INST][L2], a->x86_cache_size[DATA][L2], a->x86_cache_line[DATA][L2]); } else { printk(KERN_DEBUG " L2 Cache: %u KB (unified I+D), line size=%u bytes\n", a->x86_cache_size[UNIF][L2], a->x86_cache_line[UNIF][L2]); } /* 4-KB Page TLB Info */ printk(KERN_DEBUG " 4-KB TLB: I=%u/%u entries D=%d/%d entries\n", a->x86_tlb_size[INST][L1][PAGE_4KB], a->x86_tlb_size[INST][L2][PAGE_4KB], a->x86_tlb_size[DATA][L1][PAGE_4KB], a->x86_tlb_size[DATA][L2][PAGE_4KB] ); /* 2-MB Page TLB Info */ printk(KERN_DEBUG " 2-MB TLB: I=%u/%u entries D=%d/%d entries\n", a->x86_tlb_size[INST][L1][PAGE_2MB], a->x86_tlb_size[INST][L2][PAGE_2MB], a->x86_tlb_size[DATA][L1][PAGE_2MB], a->x86_tlb_size[DATA][L2][PAGE_2MB] ); /* 1-GB Page TLB Info */ printk(KERN_DEBUG " 1-GB TLB: I=%u/%u entries D=%d/%d entries\n", a->x86_tlb_size[INST][L1][PAGE_1GB], a->x86_tlb_size[INST][L2][PAGE_1GB], a->x86_tlb_size[DATA][L1][PAGE_1GB], a->x86_tlb_size[DATA][L2][PAGE_1GB] ); /* Address bits */ printk(KERN_DEBUG " Address bits: %u bits physical, %u bits virtual\n", a->x86_phys_bits, a->x86_virt_bits); /* Bytes flushed by CLFLUSH instruction */ printk(KERN_DEBUG " CLFLUSH size: %u bytes\n", a->x86_clflush_size); /* CPU Features */ buf[0] = '\0'; for (i = 0; i < 32*NCAPINTS; i++) { if (cpu_has(c, i) && x86_cap_flags[i] != NULL) { strcat(buf, x86_cap_flags[i]); strcat(buf, " "); } } printk(KERN_DEBUG " CPU Features: %s\n", buf); /* Power Management Features */ if (a->x86_power == 0) { strcpy(buf, "none"); } else { buf[0] = '\0'; for (i = 0; i < 32; i++) { if ((i < ARRAY_SIZE(x86_power_flags)) && x86_power_flags[i]) { strcat(buf, x86_power_flags[i]); strcat(buf, " "); } else { char bit_str[7]; bit_str[0] = '\0'; sprintf(bit_str, "[%d] ", i); strcat(buf, bit_str); } } } printk(KERN_DEBUG " Power Features: %s\n", buf); }