📄 setup.c
字号:
NULL, "Pentium II (Deschutes)", "Mobile Pentium II", "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, "Pentium III (Cascades)", NULL, NULL, NULL, NULL }}, { X86_VENDOR_AMD, 4, { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }}, { X86_VENDOR_AMD, 5, /* Is this this really necessary?? */ { "K5/SSA5", "K5", "K5", "K5", NULL, NULL, "K6", "K6", "K6-2", "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_AMD, 6, /* Is this this really necessary?? */ { "Athlon", "Athlon", "Athlon", NULL, "Athlon", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_UMC, 4, { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_NEXGEN, 5, { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_RISE, 5, { "mP6", "mP6", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},};/* Look up CPU names by table lookup. */static char __init *table_lookup_model(struct cpuinfo_x86 *c){ struct cpu_model_info *info = cpu_models; int i; if ( c->x86_model >= 16 ) return NULL; /* Range check */ for ( i = 0 ; i < sizeof(cpu_models)/sizeof(struct cpu_model_info) ; i++ ) { if ( info->vendor == c->x86_vendor && info->family == c->x86 ) { return info->model_names[c->x86_model]; } info++; } return NULL; /* Not found */}/* * Detect a NexGen CPU running without BIOS hypercode new enough * to have CPUID. (Thanks to Herbert Oppmann) */ static int __init deep_magic_nexgen_probe(void){ int ret; __asm__ __volatile__ ( " movw $0x5555, %%ax\n" " xorw %%dx,%%dx\n" " movw $2, %%cx\n" " divw %%cx\n" " movl $0, %%eax\n" " jnz 1f\n" " movl $1, %%eax\n" "1:\n" : "=a" (ret) : : "cx", "dx" ); return ret;}static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c){ if( test_bit(X86_FEATURE_PN, &c->x86_capability) && disable_x86_serial_nr ) { /* Disable processor serial number */ unsigned long lo,hi; rdmsr(0x119,lo,hi); lo |= 0x200000; wrmsr(0x119,lo,hi); printk(KERN_INFO "CPU serial number disabled.\n"); clear_bit(X86_FEATURE_PN, &c->x86_capability); }}int __init x86_serial_nr_setup(char *s){ disable_x86_serial_nr = 0; return 1;}__setup("serialnumber", x86_serial_nr_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 __init have_cpuid_p(void){ return flag_is_changeable_p(X86_EFLAGS_ID);}/* * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected * by the fact that they preserve the flags across the division of 5/2. * PII and PPro exhibit this behavior too, but they have cpuid available. */ /* * Perform the Cyrix 5/2 test. A Cyrix won't change * the flags, while other 486 chips will. */static inline int test_cyrix_52div(void){ unsigned int test; __asm__ __volatile__( "sahf\n\t" /* clear flags (%eax = 0x0005) */ "div %b2\n\t" /* divide 5 by 2 */ "lahf" /* store flags into %ah */ : "=a" (test) : "0" (5), "q" (2) : "cc"); /* AH is 0x02 on Cyrix after the divide.. */ return (unsigned char) (test >> 8) == 0x02;}/* Try to detect a CPU with disabled CPUID, and if so, enable. This routine may also be used to detect non-CPUID processors and fill in some of the information manually. */static int __init id_and_try_enable_cpuid(struct cpuinfo_x86 *c){ /* First of all, decide if this is a 486 or higher */ /* It's a 486 if we can modify the AC flag */ if ( flag_is_changeable_p(X86_EFLAGS_AC) ) c->x86 = 4; else c->x86 = 3; /* Detect Cyrix with disabled CPUID */ if ( c->x86 == 4 && test_cyrix_52div() ) { strcpy(c->x86_vendor_id, "CyrixInstead"); } /* Detect NexGen with old hypercode */ if ( deep_magic_nexgen_probe() ) { strcpy(c->x86_vendor_id, "NexGenDriven"); } return have_cpuid_p(); /* Check to see if CPUID now enabled? */}/* * This does the hard work of actually picking apart the CPU stuff... */void __init identify_cpu(struct cpuinfo_x86 *c){ int junk, i; u32 xlvl, tfms; c->loops_per_jiffy = loops_per_jiffy; c->x86_cache_size = -1; c->x86_vendor = X86_VENDOR_UNKNOWN; c->cpuid_level = -1; /* CPUID not detected */ c->x86_model = c->x86_mask = 0; /* So far unknown... */ c->x86_vendor_id[0] = '\0'; /* Unset */ c->x86_model_id[0] = '\0'; /* Unset */ memset(&c->x86_capability, 0, sizeof c->x86_capability); if ( !have_cpuid_p() && !id_and_try_enable_cpuid(c) ) { /* CPU doesn't have CPUID */ /* If there are any capabilities, they're vendor-specific */ /* enable_cpuid() would have set c->x86 for us. */ } else { /* CPU does have CPUID */ /* 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); /* 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 ) { cpuid(0x00000001, &tfms, &junk, &junk, &c->x86_capability[0]); c->x86 = (tfms >> 8) & 15; c->x86_model = (tfms >> 4) & 15; c->x86_mask = tfms & 15; } 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); if ( xlvl >= 0x80000004 ) get_model_name(c); /* Default name */ } /* Transmeta-defined flags: level 0x80860001 */ xlvl = cpuid_eax(0x80860000); if ( (xlvl & 0xffff0000) == 0x80860000 ) { if ( xlvl >= 0x80860001 ) c->x86_capability[2] = cpuid_edx(0x80860001); } } printk("CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n", c->x86_capability[0], c->x86_capability[1], c->x86_capability[2], c->x86_vendor); /* * 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 ( c->x86_vendor ) { case X86_VENDOR_UNKNOWN: default: /* Not much we can do here... */ break; case X86_VENDOR_CYRIX: init_cyrix(c); break; case X86_VENDOR_AMD: init_amd(c); break; case X86_VENDOR_CENTAUR: init_centaur(c); break; case X86_VENDOR_INTEL: init_intel(c); break; case X86_VENDOR_NEXGEN: c->x86_cache_size = 256; /* A few had 1 MB... */ break; case X86_VENDOR_TRANSMETA: init_transmeta(c); break; } printk("CPU: After vendor init, caps: %08x %08x %08x %08x\n", c->x86_capability[0], c->x86_capability[1], c->x86_capability[2], c->x86_capability[3]); /* * The vendor-specific functions might have changed features. Now * we do "generic changes." */ /* TSC disabled? */#ifdef CONFIG_TSC if ( tsc_disable ) clear_bit(X86_FEATURE_TSC, &c->x86_capability);#endif /* Disable the PN if appropriate */ squash_the_stupid_serial_number(c); /* If the model name is still unset, do table lookup. */ if ( !c->x86_model_id[0] ) { char *p; p = table_lookup_model(c); if ( p ) strcpy(c->x86_model_id, p); else /* Last resort... */ sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model); } /* Now the feature flags better reflect actual CPU features! */ printk("CPU: After generic, caps: %08x %08x %08x %08x\n", c->x86_capability[0], c->x86_capability[1], c->x86_capability[2], c->x86_capability[3]); /* * On SMP, 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.x86_capability[i] &= c->x86_capability[i]; } printk("CPU: Common caps: %08x %08x %08x %08x\n", boot_cpu_data.x86_capability[0], boot_cpu_data.x86_capability[1], boot_cpu_data.x86_capability[2], boot_cpu_data.x86_capability[3]);}/* * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c */ void __init dodgy_tsc(void){ get_cpu_vendor(&boot_cpu_data); if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) init_cyrix(&boot_cpu_data);}/* These need to match <asm/processor.h> */static char *cpu_vendor_names[] __initdata = { "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };void __init print_cpu_info(struct cpuinfo_x86 *c){ char *vendor = NULL; if (c->x86_vendor < sizeof(cpu_vendor_names)/sizeof(char *)) vendor = cpu_vendor_names[c->x86_vendor]; else if (c->cpuid_level >= 0) vendor = c->x86_vendor_id; if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor))) printk("%s ", vendor); if (!c->x86_model_id[0]) printk("%d86", c->x86); else printk("%s", c->x86_model_id); if (c->x86_mask || c->cpuid_level >= 0) printk(" stepping %02x\n", c->x86_mask); else printk("\n");}/* * Get CPU information for use by the procfs. */int get_cpuinfo(char * buffer){ char *p = buffer; /* * These flag bits must match the definitions in <asm/cpufeature.h>. * NULL means this bit is undefined or reserved; either way it doesn't * have meaning as far as Linux is concerned. Note that it's important * to realize there is a difference between this table and CPUID -- if * applications want to get the raw CPUID data, they should access * /dev/cpu/<cpu_nr>/cpuid instead. */ 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", NULL, "tm", "ia64", NULL, /* AMD-defined */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "mmxext", NULL, NULL, NULL, NULL, NULL, 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, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; struct cpuinfo_x86 *c = cpu_data; int i, n; for (n = 0; n < NR_CPUS; n++, c++) { int fpu_exception;#ifdef CONFIG_SMP if (!(cpu_online_map & (1<<n))) continue;#endif p += sprintf(p,"processor\t: %d\n" "vendor_id\t: %s\n" "cpu family\t: %d\n" "model\t\t: %d\n" "model name\t: %s\n", n, c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown", c->x86, c->x86_model, c->x86_model_id[0] ? c->x86_model_id : "unknown"); if (c->x86_mask || c->cpuid_level >= 0) p += sprintf(p, "stepping\t: %d\n", c->x86_mask); else p += sprintf(p, "stepping\t: unknown\n"); if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) { p += sprintf(p, "cpu MHz\t\t: %lu.%03lu\n", cpu_khz / 1000, (cpu_khz % 1000)); } /* Cache size */ if (c->x86_cache_size >= 0) p += sprintf(p, "cache size\t: %d KB\n", c->x86_cache_size); /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu); p += sprintf(p, "fdiv_bug\t: %s\n" "hlt_bug\t\t: %s\n" "f00f_bug\t: %s\n" "coma_bug\t: %s\n" "fpu\t\t: %s\n" "fpu_exception\t: %s\n" "cpuid level\t: %d\n" "wp\t\t: %s\n" "flags\t\t:", c->fdiv_bug ? "yes" : "no", c->hlt_works_ok ? "no" : "yes", c->f00f_bug ? "yes" : "no", c->coma_bug ? "yes" : "no", c->hard_math ? "yes" : "no", fpu_exception ? "yes" : "no", c->cpuid_level, c->wp_works_ok ? "yes" : "no"); for ( i = 0 ; i < 32*NCAPINTS ; i++ ) if ( test_bit(i, &c->x86_capability) && x86_cap_flags[i] != NULL ) p += sprintf(p, " %s", x86_cap_flags[i]); p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n", c->loops_per_jiffy/(500000/HZ), (c->loops_per_jiffy/(5000/HZ)) % 100); } return p - buffer;}static unsigned long cpu_initialized __initdata = 0;/* * cpu_init() initializes state that is per-CPU. Some data is already * initialized (naturally) in the bootstrap process, such as the GDT * and IDT. We reload them nevertheless, this function acts as a * 'CPU state barrier', nothing should get across. */void __init cpu_init (void){ int nr = smp_processor_id(); struct tss_struct * t = &init_tss[nr]; if (test_and_set_bit(nr, &cpu_initialized)) { printk("CPU#%d already initialized!\n", nr); for (;;) __sti(); } printk("Initializing CPU#%d\n", nr); if (cpu_has_vme || cpu_has_tsc || cpu_has_de) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);#ifndef CONFIG_X86_TSC if (tsc_disable && cpu_has_tsc) { printk("Disabling TSC...\n"); /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/ clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); set_in_cr4(X86_CR4_TSD); }#endif __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); __asm__ __volatile__("lidt %0": "=m" (idt_descr)); /* * Delete NT */ __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); /* * set up and load the per-CPU TSS and LDT */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; if(current->mm) BUG(); enter_lazy_tlb(&init_mm, current, nr); t->esp0 = current->thread.esp0; set_tss_desc(nr,t); gdt_table[__TSS(nr)].b &= 0xfffffdff; load_TR(nr); load_LDT(&init_mm); /* * Clear all 6 debug registers: */#define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) ); CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);#undef CD /* * Force FPU initialization: */ current->flags &= ~PF_USEDFPU; current->used_math = 0; stts();}/* * Local Variables: * mode:c * c-file-style:"k&r" * c-basic-offset:8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -