📄 common.c
字号:
#include <linux/init.h>#include <linux/string.h>#include <linux/delay.h>#include <linux/smp.h>#include <linux/module.h>#include <linux/percpu.h>#include <linux/bootmem.h>#include <asm/semaphore.h>#include <asm/processor.h>#include <asm/i387.h>#include <asm/msr.h>#include <asm/io.h>#include <asm/mmu_context.h>#include <asm/mtrr.h>#include <asm/mce.h>#ifdef CONFIG_X86_LOCAL_APIC#include <asm/mpspec.h>#include <asm/apic.h>#include <mach_apic.h>#endif#include "cpu.h"DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { [GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 }, [GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 }, [GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 }, [GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 }, /* * Segments used for calling PnP BIOS have byte granularity. * They code segments and data segments have fixed 64k limits, * the transfer segment sizes are set at run time. */ [GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ [GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */ [GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */ [GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */ [GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */ /* * The APM segments have byte granularity and their bases * are set at run time. All have 64k limits. */ [GDT_ENTRY_APMBIOS_BASE] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ /* 16-bit code */ [GDT_ENTRY_APMBIOS_BASE+1] = { 0x0000ffff, 0x00009a00 }, [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */ [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 }, [GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 },} };EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);static int cachesize_override __cpuinitdata = -1;static int disable_x86_fxsr __cpuinitdata;static int disable_x86_serial_nr __cpuinitdata = 1;static int disable_x86_sep __cpuinitdata;struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};extern int disable_pse;static void __cpuinit default_init(struct cpuinfo_x86 * c){ /* Not much we can do here... */ /* Check if at least it has cpuid */ if (c->cpuid_level == -1) { /* No cpuid. It must be an ancient CPU */ if (c->x86 == 4) strcpy(c->x86_model_id, "486"); else if (c->x86 == 3) strcpy(c->x86_model_id, "386"); }}static struct cpu_dev __cpuinitdata default_cpu = { .c_init = default_init, .c_vendor = "Unknown",};static struct cpu_dev * this_cpu __cpuinitdata = &default_cpu;static int __init cachesize_setup(char *str){ get_option (&str, &cachesize_override); return 1;}__setup("cachesize=", cachesize_setup);int __cpuinit get_model_name(struct cpuinfo_x86 *c){ unsigned int *v; char *p, *q; if (cpuid_eax(0x80000000) < 0x80000004) return 0; v = (unsigned int *) c->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]); c->x86_model_id[48] = 0; /* Intel chips right-justify this string for some dumb reason; undo that brain damage */ p = q = &c->x86_model_id[0]; while ( *p == ' ' ) p++; if ( p != q ) { while ( *p ) *q++ = *p++; while ( q <= &c->x86_model_id[48] ) *q++ = '\0'; /* Zero-pad the rest */ } return 1;}void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c){ unsigned int n, dummy, ecx, edx, l2size; n = cpuid_eax(0x80000000); if (n >= 0x80000005) { cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n", edx>>24, edx&0xFF, ecx>>24, ecx&0xFF); c->x86_cache_size=(ecx>>24)+(edx>>24); } if (n < 0x80000006) /* Some chips just has a large L1. */ return; ecx = cpuid_ecx(0x80000006); l2size = ecx >> 16; /* do processor-specific cache resizing */ if (this_cpu->c_size_cache) l2size = this_cpu->c_size_cache(c,l2size); /* Allow user to override all this if necessary. */ if (cachesize_override != -1) l2size = cachesize_override; if ( l2size == 0 ) return; /* Again, no L2 cache is possible */ c->x86_cache_size = l2size; printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n", l2size, ecx & 0xFF);}/* Naming convention should be: <Name> [(<Codename>)] *//* This table only is used unless init_<vendor>() below doesn't set it; *//* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used *//* Look up CPU names by table lookup. */static char __cpuinit *table_lookup_model(struct cpuinfo_x86 *c){ struct cpu_model_info *info; if ( c->x86_model >= 16 ) return NULL; /* Range check */ if (!this_cpu) return NULL; info = this_cpu->c_models; while (info && info->family) { if (info->family == c->x86) return info->model_names[c->x86_model]; info++; } return NULL; /* Not found */}static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c, int early){ char *v = c->x86_vendor_id; int i; static int printed; for (i = 0; i < X86_VENDOR_NUM; i++) { if (cpu_devs[i]) { if (!strcmp(v,cpu_devs[i]->c_ident[0]) || (cpu_devs[i]->c_ident[1] && !strcmp(v,cpu_devs[i]->c_ident[1]))) { c->x86_vendor = i; if (!early) this_cpu = cpu_devs[i]; return; } } } if (!printed) { printed++; printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n"); printk(KERN_ERR "CPU: Your system may be unstable.\n"); } c->x86_vendor = X86_VENDOR_UNKNOWN; this_cpu = &default_cpu;}static int __init x86_fxsr_setup(char * s){ /* Tell all the other CPUs to not use it... */ disable_x86_fxsr = 1; /* * ... and clear the bits early in the boot_cpu_data * so that the bootup process doesn't try to do this * either. */ clear_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability); clear_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability); return 1;}__setup("nofxsr", x86_fxsr_setup);static int __init x86_sep_setup(char * s){ disable_x86_sep = 1; return 1;}__setup("nosep", x86_sep_setup);/* Standard macro to see if a specific flag is changeable */static inline int flag_is_changeable_p(u32 flag){ u32 f1, f2; asm("pushfl\n\t" "pushfl\n\t" "popl %0\n\t" "movl %0,%1\n\t" "xorl %2,%0\n\t" "pushl %0\n\t" "popfl\n\t" "pushfl\n\t" "popl %0\n\t" "popfl\n\t" : "=&r" (f1), "=&r" (f2) : "ir" (flag)); return ((f1^f2) & flag) != 0;}/* Probe for the CPUID instruction */static int __cpuinit have_cpuid_p(void){ return flag_is_changeable_p(X86_EFLAGS_ID);}void __init cpu_detect(struct cpuinfo_x86 *c){ /* Get vendor name */ cpuid(0x00000000, &c->cpuid_level, (int *)&c->x86_vendor_id[0], (int *)&c->x86_vendor_id[8], (int *)&c->x86_vendor_id[4]); c->x86 = 4; if (c->cpuid_level >= 0x00000001) { u32 junk, tfms, cap0, misc; cpuid(0x00000001, &tfms, &misc, &junk, &cap0); c->x86 = (tfms >> 8) & 15; c->x86_model = (tfms >> 4) & 15; if (c->x86 == 0xf) c->x86 += (tfms >> 20) & 0xff; if (c->x86 >= 0x6) c->x86_model += ((tfms >> 16) & 0xF) << 4; c->x86_mask = tfms & 15; if (cap0 & (1<<19)) c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8; }}/* Do minimum CPU detection early. Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment. The others are not touched to avoid unwanted side effects. WARNING: this function is only called on the BP. Don't add code here that is supposed to run on all CPUs. */static void __init early_cpu_detect(void){ struct cpuinfo_x86 *c = &boot_cpu_data; c->x86_cache_alignment = 32; if (!have_cpuid_p()) return; cpu_detect(c); get_cpu_vendor(c, 1);}static void __cpuinit generic_identify(struct cpuinfo_x86 * c){ u32 tfms, xlvl; int ebx; if (have_cpuid_p()) { /* Get vendor name */ cpuid(0x00000000, &c->cpuid_level, (int *)&c->x86_vendor_id[0], (int *)&c->x86_vendor_id[8], (int *)&c->x86_vendor_id[4]); get_cpu_vendor(c, 0); /* Initialize the standard set of capabilities */ /* Note that the vendor-specific code below might override */ /* Intel-defined flags: level 0x00000001 */ if ( c->cpuid_level >= 0x00000001 ) { u32 capability, excap; cpuid(0x00000001, &tfms, &ebx, &excap, &capability); c->x86_capability[0] = capability; c->x86_capability[4] = excap; c->x86 = (tfms >> 8) & 15; c->x86_model = (tfms >> 4) & 15; if (c->x86 == 0xf) c->x86 += (tfms >> 20) & 0xff; if (c->x86 >= 0x6) c->x86_model += ((tfms >> 16) & 0xF) << 4; c->x86_mask = tfms & 15;#ifdef CONFIG_X86_HT c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0);#else c->apicid = (ebx >> 24) & 0xFF;#endif if (c->x86_capability[0] & (1<<19)) c->x86_clflush_size = ((ebx >> 8) & 0xff) * 8; } else { /* Have CPUID level 0 only - unheard of */ c->x86 = 4; } /* AMD-defined flags: level 0x80000001 */ xlvl = cpuid_eax(0x80000000); if ( (xlvl & 0xffff0000) == 0x80000000 ) { if ( xlvl >= 0x80000001 ) { c->x86_capability[1] = cpuid_edx(0x80000001); c->x86_capability[6] = cpuid_ecx(0x80000001); } if ( xlvl >= 0x80000004 ) get_model_name(c); /* Default name */ } init_scattered_cpuid_features(c); } early_intel_workaround(c);#ifdef CONFIG_X86_HT c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;#endif}static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -