diff options
Diffstat (limited to 'arch/x86/kernel/cpu/common.c')
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 179 |
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 | ||
24 | DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { | 24 | DEFINE_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 | } }; |
51 | EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); | 58 | EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); |
52 | 59 | ||
60 | __u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata; | ||
61 | |||
53 | static int cachesize_override __cpuinitdata = -1; | 62 | static int cachesize_override __cpuinitdata = -1; |
54 | static int disable_x86_fxsr __cpuinitdata; | ||
55 | static int disable_x86_serial_nr __cpuinitdata = 1; | 63 | static int disable_x86_serial_nr __cpuinitdata = 1; |
56 | static int disable_x86_sep __cpuinitdata; | ||
57 | 64 | ||
58 | struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {}; | 65 | struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {}; |
59 | 66 | ||
60 | extern int disable_pse; | ||
61 | |||
62 | static void __cpuinit default_init(struct cpuinfo_x86 * c) | 67 | static 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 | ||
208 | static int __init x86_fxsr_setup(char * s) | 213 | static 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 | ||
225 | static int __init x86_sep_setup(char * s) | 222 | static 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 | } |
281 | static 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 | ||
305 | static void __cpuinit generic_identify(struct cpuinfo_x86 * c) | 340 | static 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 | */ |
395 | static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) | 428 | void __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 | ||
508 | void __init identify_boot_cpu(void) | 512 | void __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 | ||
516 | void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) | 519 | void __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 | ||
573 | static __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 | |||
570 | void __cpuinit print_cpu_info(struct cpuinfo_x86 *c) | 580 | void __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 | ||
603 | static __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 | |||
593 | cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; | 614 | cpumask_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 */ |
634 | struct pt_regs * __devinit idle_regs(struct pt_regs *regs) | 647 | struct 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. */ |
643 | void switch_to_new_gdt(void) | 656 | void 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); |