diff options
Diffstat (limited to 'arch/i386/kernel/cpu/common.c')
-rw-r--r-- | arch/i386/kernel/cpu/common.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 7eb9213734a3..4ecd4b326ded 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/smp.h> | 4 | #include <linux/smp.h> |
5 | #include <linux/module.h> | 5 | #include <linux/module.h> |
6 | #include <linux/percpu.h> | 6 | #include <linux/percpu.h> |
7 | #include <linux/bootmem.h> | ||
7 | #include <asm/semaphore.h> | 8 | #include <asm/semaphore.h> |
8 | #include <asm/processor.h> | 9 | #include <asm/processor.h> |
9 | #include <asm/i387.h> | 10 | #include <asm/i387.h> |
@@ -18,6 +19,9 @@ | |||
18 | 19 | ||
19 | #include "cpu.h" | 20 | #include "cpu.h" |
20 | 21 | ||
22 | DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); | ||
23 | EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); | ||
24 | |||
21 | DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]); | 25 | DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]); |
22 | EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack); | 26 | EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack); |
23 | 27 | ||
@@ -571,8 +575,9 @@ void __devinit cpu_init(void) | |||
571 | int cpu = smp_processor_id(); | 575 | int cpu = smp_processor_id(); |
572 | struct tss_struct * t = &per_cpu(init_tss, cpu); | 576 | struct tss_struct * t = &per_cpu(init_tss, cpu); |
573 | struct thread_struct *thread = ¤t->thread; | 577 | struct thread_struct *thread = ¤t->thread; |
574 | struct desc_struct *gdt = get_cpu_gdt_table(cpu); | 578 | struct desc_struct *gdt; |
575 | __u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu); | 579 | __u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu); |
580 | struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); | ||
576 | 581 | ||
577 | if (cpu_test_and_set(cpu, cpu_initialized)) { | 582 | if (cpu_test_and_set(cpu, cpu_initialized)) { |
578 | printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); | 583 | printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); |
@@ -590,6 +595,25 @@ void __devinit cpu_init(void) | |||
590 | } | 595 | } |
591 | 596 | ||
592 | /* | 597 | /* |
598 | * This is a horrible hack to allocate the GDT. The problem | ||
599 | * is that cpu_init() is called really early for the boot CPU | ||
600 | * (and hence needs bootmem) but much later for the secondary | ||
601 | * CPUs, when bootmem will have gone away | ||
602 | */ | ||
603 | if (NODE_DATA(0)->bdata->node_bootmem_map) { | ||
604 | gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE); | ||
605 | /* alloc_bootmem_pages panics on failure, so no check */ | ||
606 | memset(gdt, 0, PAGE_SIZE); | ||
607 | } else { | ||
608 | gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL); | ||
609 | if (unlikely(!gdt)) { | ||
610 | printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu); | ||
611 | for (;;) | ||
612 | local_irq_enable(); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | /* | ||
593 | * Initialize the per-CPU GDT with the boot GDT, | 617 | * Initialize the per-CPU GDT with the boot GDT, |
594 | * and set up the GDT descriptor: | 618 | * and set up the GDT descriptor: |
595 | */ | 619 | */ |
@@ -601,10 +625,10 @@ void __devinit cpu_init(void) | |||
601 | ((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) | | 625 | ((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) | |
602 | (CPU_16BIT_STACK_SIZE - 1); | 626 | (CPU_16BIT_STACK_SIZE - 1); |
603 | 627 | ||
604 | cpu_gdt_descr[cpu].size = GDT_SIZE - 1; | 628 | cpu_gdt_descr->size = GDT_SIZE - 1; |
605 | cpu_gdt_descr[cpu].address = (unsigned long)gdt; | 629 | cpu_gdt_descr->address = (unsigned long)gdt; |
606 | 630 | ||
607 | load_gdt(&cpu_gdt_descr[cpu]); | 631 | load_gdt(cpu_gdt_descr); |
608 | load_idt(&idt_descr); | 632 | load_idt(&idt_descr); |
609 | 633 | ||
610 | /* | 634 | /* |