aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/cpu/common.c')
-rw-r--r--arch/x86/kernel/cpu/common.c179
1 files changed, 93 insertions, 86 deletions
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index e2fcf2051bdb..db28aa9e2f69 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -22,43 +22,48 @@
22#include "cpu.h" 22#include "cpu.h"
23 23
24DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { 24DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
25 [GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 }, 25 [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } },
26 [GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 }, 26 [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } },
27 [GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 }, 27 [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } },
28 [GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 }, 28 [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff200 } } },
29 /* 29 /*
30 * Segments used for calling PnP BIOS have byte granularity. 30 * Segments used for calling PnP BIOS have byte granularity.
31 * They code segments and data segments have fixed 64k limits, 31 * They code segments and data segments have fixed 64k limits,
32 * the transfer segment sizes are set at run time. 32 * the transfer segment sizes are set at run time.
33 */ 33 */
34 [GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ 34 /* 32-bit code */
35 [GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */ 35 [GDT_ENTRY_PNPBIOS_CS32] = { { { 0x0000ffff, 0x00409a00 } } },
36 [GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */ 36 /* 16-bit code */
37 [GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */ 37 [GDT_ENTRY_PNPBIOS_CS16] = { { { 0x0000ffff, 0x00009a00 } } },
38 [GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */ 38 /* 16-bit data */
39 [GDT_ENTRY_PNPBIOS_DS] = { { { 0x0000ffff, 0x00009200 } } },
40 /* 16-bit data */
41 [GDT_ENTRY_PNPBIOS_TS1] = { { { 0x00000000, 0x00009200 } } },
42 /* 16-bit data */
43 [GDT_ENTRY_PNPBIOS_TS2] = { { { 0x00000000, 0x00009200 } } },
39 /* 44 /*
40 * The APM segments have byte granularity and their bases 45 * The APM segments have byte granularity and their bases
41 * are set at run time. All have 64k limits. 46 * are set at run time. All have 64k limits.
42 */ 47 */
43 [GDT_ENTRY_APMBIOS_BASE] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ 48 /* 32-bit code */
49 [GDT_ENTRY_APMBIOS_BASE] = { { { 0x0000ffff, 0x00409a00 } } },
44 /* 16-bit code */ 50 /* 16-bit code */
45 [GDT_ENTRY_APMBIOS_BASE+1] = { 0x0000ffff, 0x00009a00 }, 51 [GDT_ENTRY_APMBIOS_BASE+1] = { { { 0x0000ffff, 0x00009a00 } } },
46 [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */ 52 /* data */
53 [GDT_ENTRY_APMBIOS_BASE+2] = { { { 0x0000ffff, 0x00409200 } } },
47 54
48 [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 }, 55 [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } },
49 [GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 }, 56 [GDT_ENTRY_PERCPU] = { { { 0x00000000, 0x00000000 } } },
50} }; 57} };
51EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); 58EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
52 59
60__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
61
53static int cachesize_override __cpuinitdata = -1; 62static int cachesize_override __cpuinitdata = -1;
54static int disable_x86_fxsr __cpuinitdata;
55static int disable_x86_serial_nr __cpuinitdata = 1; 63static int disable_x86_serial_nr __cpuinitdata = 1;
56static int disable_x86_sep __cpuinitdata;
57 64
58struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {}; 65struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
59 66
60extern int disable_pse;
61
62static void __cpuinit default_init(struct cpuinfo_x86 * c) 67static void __cpuinit default_init(struct cpuinfo_x86 * c)
63{ 68{
64 /* Not much we can do here... */ 69 /* Not much we can do here... */
@@ -207,16 +212,8 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
207 212
208static int __init x86_fxsr_setup(char * s) 213static int __init x86_fxsr_setup(char * s)
209{ 214{
210 /* Tell all the other CPUs to not use it... */ 215 setup_clear_cpu_cap(X86_FEATURE_FXSR);
211 disable_x86_fxsr = 1; 216 setup_clear_cpu_cap(X86_FEATURE_XMM);
212
213 /*
214 * ... and clear the bits early in the boot_cpu_data
215 * so that the bootup process doesn't try to do this
216 * either.
217 */
218 clear_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability);
219 clear_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability);
220 return 1; 217 return 1;
221} 218}
222__setup("nofxsr", x86_fxsr_setup); 219__setup("nofxsr", x86_fxsr_setup);
@@ -224,7 +221,7 @@ __setup("nofxsr", x86_fxsr_setup);
224 221
225static int __init x86_sep_setup(char * s) 222static int __init x86_sep_setup(char * s)
226{ 223{
227 disable_x86_sep = 1; 224 setup_clear_cpu_cap(X86_FEATURE_SEP);
228 return 1; 225 return 1;
229} 226}
230__setup("nosep", x86_sep_setup); 227__setup("nosep", x86_sep_setup);
@@ -281,6 +278,33 @@ void __init cpu_detect(struct cpuinfo_x86 *c)
281 c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8; 278 c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
282 } 279 }
283} 280}
281static void __cpuinit early_get_cap(struct cpuinfo_x86 *c)
282{
283 u32 tfms, xlvl;
284 int ebx;
285
286 memset(&c->x86_capability, 0, sizeof c->x86_capability);
287 if (have_cpuid_p()) {
288 /* Intel-defined flags: level 0x00000001 */
289 if (c->cpuid_level >= 0x00000001) {
290 u32 capability, excap;
291 cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
292 c->x86_capability[0] = capability;
293 c->x86_capability[4] = excap;
294 }
295
296 /* AMD-defined flags: level 0x80000001 */
297 xlvl = cpuid_eax(0x80000000);
298 if ((xlvl & 0xffff0000) == 0x80000000) {
299 if (xlvl >= 0x80000001) {
300 c->x86_capability[1] = cpuid_edx(0x80000001);
301 c->x86_capability[6] = cpuid_ecx(0x80000001);
302 }
303 }
304
305 }
306
307}
284 308
285/* Do minimum CPU detection early. 309/* Do minimum CPU detection early.
286 Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment. 310 Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
@@ -300,6 +324,17 @@ static void __init early_cpu_detect(void)
300 cpu_detect(c); 324 cpu_detect(c);
301 325
302 get_cpu_vendor(c, 1); 326 get_cpu_vendor(c, 1);
327
328 switch (c->x86_vendor) {
329 case X86_VENDOR_AMD:
330 early_init_amd(c);
331 break;
332 case X86_VENDOR_INTEL:
333 early_init_intel(c);
334 break;
335 }
336
337 early_get_cap(c);
303} 338}
304 339
305static void __cpuinit generic_identify(struct cpuinfo_x86 * c) 340static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
@@ -357,8 +392,6 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
357 init_scattered_cpuid_features(c); 392 init_scattered_cpuid_features(c);
358 } 393 }
359 394
360 early_intel_workaround(c);
361
362#ifdef CONFIG_X86_HT 395#ifdef CONFIG_X86_HT
363 c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff; 396 c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
364#endif 397#endif
@@ -392,7 +425,7 @@ __setup("serialnumber", x86_serial_nr_setup);
392/* 425/*
393 * This does the hard work of actually picking apart the CPU stuff... 426 * This does the hard work of actually picking apart the CPU stuff...
394 */ 427 */
395static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) 428void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
396{ 429{
397 int i; 430 int i;
398 431
@@ -418,20 +451,9 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
418 451
419 generic_identify(c); 452 generic_identify(c);
420 453
421 printk(KERN_DEBUG "CPU: After generic identify, caps:"); 454 if (this_cpu->c_identify)
422 for (i = 0; i < NCAPINTS; i++)
423 printk(" %08lx", c->x86_capability[i]);
424 printk("\n");
425
426 if (this_cpu->c_identify) {
427 this_cpu->c_identify(c); 455 this_cpu->c_identify(c);
428 456
429 printk(KERN_DEBUG "CPU: After vendor identify, caps:");
430 for (i = 0; i < NCAPINTS; i++)
431 printk(" %08lx", c->x86_capability[i]);
432 printk("\n");
433 }
434
435 /* 457 /*
436 * Vendor-specific initialization. In this section we 458 * Vendor-specific initialization. In this section we
437 * canonicalize the feature flags, meaning if there are 459 * canonicalize the feature flags, meaning if there are
@@ -453,23 +475,6 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
453 * we do "generic changes." 475 * we do "generic changes."
454 */ 476 */
455 477
456 /* TSC disabled? */
457 if ( tsc_disable )
458 clear_bit(X86_FEATURE_TSC, c->x86_capability);
459
460 /* FXSR disabled? */
461 if (disable_x86_fxsr) {
462 clear_bit(X86_FEATURE_FXSR, c->x86_capability);
463 clear_bit(X86_FEATURE_XMM, c->x86_capability);
464 }
465
466 /* SEP disabled? */
467 if (disable_x86_sep)
468 clear_bit(X86_FEATURE_SEP, c->x86_capability);
469
470 if (disable_pse)
471 clear_bit(X86_FEATURE_PSE, c->x86_capability);
472
473 /* If the model name is still unset, do table lookup. */ 478 /* If the model name is still unset, do table lookup. */
474 if ( !c->x86_model_id[0] ) { 479 if ( !c->x86_model_id[0] ) {
475 char *p; 480 char *p;
@@ -482,13 +487,6 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
482 c->x86, c->x86_model); 487 c->x86, c->x86_model);
483 } 488 }
484 489
485 /* Now the feature flags better reflect actual CPU features! */
486
487 printk(KERN_DEBUG "CPU: After all inits, caps:");
488 for (i = 0; i < NCAPINTS; i++)
489 printk(" %08lx", c->x86_capability[i]);
490 printk("\n");
491
492 /* 490 /*
493 * On SMP, boot_cpu_data holds the common feature set between 491 * On SMP, boot_cpu_data holds the common feature set between
494 * all CPUs; so make sure that we indicate which features are 492 * all CPUs; so make sure that we indicate which features are
@@ -501,8 +499,14 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
501 boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; 499 boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
502 } 500 }
503 501
502 /* Clear all flags overriden by options */
503 for (i = 0; i < NCAPINTS; i++)
504 c->x86_capability[i] ^= cleared_cpu_caps[i];
505
504 /* Init Machine Check Exception if available. */ 506 /* Init Machine Check Exception if available. */
505 mcheck_init(c); 507 mcheck_init(c);
508
509 select_idle_routine(c);
506} 510}
507 511
508void __init identify_boot_cpu(void) 512void __init identify_boot_cpu(void)
@@ -510,7 +514,6 @@ void __init identify_boot_cpu(void)
510 identify_cpu(&boot_cpu_data); 514 identify_cpu(&boot_cpu_data);
511 sysenter_setup(); 515 sysenter_setup();
512 enable_sep_cpu(); 516 enable_sep_cpu();
513 mtrr_bp_init();
514} 517}
515 518
516void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) 519void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
@@ -567,6 +570,13 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
567} 570}
568#endif 571#endif
569 572
573static __init int setup_noclflush(char *arg)
574{
575 setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
576 return 1;
577}
578__setup("noclflush", setup_noclflush);
579
570void __cpuinit print_cpu_info(struct cpuinfo_x86 *c) 580void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
571{ 581{
572 char *vendor = NULL; 582 char *vendor = NULL;
@@ -590,6 +600,17 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
590 printk("\n"); 600 printk("\n");
591} 601}
592 602
603static __init int setup_disablecpuid(char *arg)
604{
605 int bit;
606 if (get_option(&arg, &bit) && bit < NCAPINTS*32)
607 setup_clear_cpu_cap(bit);
608 else
609 return 0;
610 return 1;
611}
612__setup("clearcpuid=", setup_disablecpuid);
613
593cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; 614cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
594 615
595/* This is hacky. :) 616/* This is hacky. :)
@@ -620,21 +641,13 @@ void __init early_cpu_init(void)
620 nexgen_init_cpu(); 641 nexgen_init_cpu();
621 umc_init_cpu(); 642 umc_init_cpu();
622 early_cpu_detect(); 643 early_cpu_detect();
623
624#ifdef CONFIG_DEBUG_PAGEALLOC
625 /* pse is not compatible with on-the-fly unmapping,
626 * disable it even if the cpus claim to support it.
627 */
628 clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability);
629 disable_pse = 1;
630#endif
631} 644}
632 645
633/* Make sure %fs is initialized properly in idle threads */ 646/* Make sure %fs is initialized properly in idle threads */
634struct pt_regs * __devinit idle_regs(struct pt_regs *regs) 647struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
635{ 648{
636 memset(regs, 0, sizeof(struct pt_regs)); 649 memset(regs, 0, sizeof(struct pt_regs));
637 regs->xfs = __KERNEL_PERCPU; 650 regs->fs = __KERNEL_PERCPU;
638 return regs; 651 return regs;
639} 652}
640 653
@@ -642,7 +655,7 @@ struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
642 * it's on the real one. */ 655 * it's on the real one. */
643void switch_to_new_gdt(void) 656void switch_to_new_gdt(void)
644{ 657{
645 struct Xgt_desc_struct gdt_descr; 658 struct desc_ptr gdt_descr;
646 659
647 gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id()); 660 gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
648 gdt_descr.size = GDT_SIZE - 1; 661 gdt_descr.size = GDT_SIZE - 1;
@@ -672,12 +685,6 @@ void __cpuinit cpu_init(void)
672 685
673 if (cpu_has_vme || cpu_has_tsc || cpu_has_de) 686 if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
674 clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); 687 clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
675 if (tsc_disable && cpu_has_tsc) {
676 printk(KERN_NOTICE "Disabling TSC...\n");
677 /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
678 clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
679 set_in_cr4(X86_CR4_TSD);
680 }
681 688
682 load_idt(&idt_descr); 689 load_idt(&idt_descr);
683 switch_to_new_gdt(); 690 switch_to_new_gdt();
@@ -691,7 +698,7 @@ void __cpuinit cpu_init(void)
691 BUG(); 698 BUG();
692 enter_lazy_tlb(&init_mm, curr); 699 enter_lazy_tlb(&init_mm, curr);
693 700
694 load_esp0(t, thread); 701 load_sp0(t, thread);
695 set_tss_desc(cpu,t); 702 set_tss_desc(cpu,t);
696 load_TR_desc(); 703 load_TR_desc();
697 load_LDT(&init_mm.context); 704 load_LDT(&init_mm.context);