aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/cpu/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/cpu/common.c')
-rw-r--r--arch/i386/kernel/cpu/common.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 7eb9213734a3..e6bd095ae108 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
22DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
23EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
24
21DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]); 25DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
22EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack); 26EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
23 27
@@ -274,10 +278,10 @@ void __devinit generic_identify(struct cpuinfo_x86 * c)
274 c->x86_capability[4] = excap; 278 c->x86_capability[4] = excap;
275 c->x86 = (tfms >> 8) & 15; 279 c->x86 = (tfms >> 8) & 15;
276 c->x86_model = (tfms >> 4) & 15; 280 c->x86_model = (tfms >> 4) & 15;
277 if (c->x86 == 0xf) { 281 if (c->x86 == 0xf)
278 c->x86 += (tfms >> 20) & 0xff; 282 c->x86 += (tfms >> 20) & 0xff;
283 if (c->x86 >= 0x6)
279 c->x86_model += ((tfms >> 16) & 0xF) << 4; 284 c->x86_model += ((tfms >> 16) & 0xF) << 4;
280 }
281 c->x86_mask = tfms & 15; 285 c->x86_mask = tfms & 15;
282 } else { 286 } else {
283 /* Have CPUID level 0 only - unheard of */ 287 /* Have CPUID level 0 only - unheard of */
@@ -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 = &current->thread; 577 struct thread_struct *thread = &current->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 /*