|
@@ -4,6 +4,7 @@
|
|
#include <linux/smp.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
#include <linux/percpu.h>
|
|
#include <linux/percpu.h>
|
|
|
|
+#include <linux/bootmem.h>
|
|
#include <asm/semaphore.h>
|
|
#include <asm/semaphore.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/i387.h>
|
|
#include <asm/i387.h>
|
|
@@ -18,6 +19,9 @@
|
|
|
|
|
|
#include "cpu.h"
|
|
#include "cpu.h"
|
|
|
|
|
|
|
|
+DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
|
|
|
|
+EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
|
|
|
|
+
|
|
DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
|
|
DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
|
|
EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
|
|
EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
|
|
|
|
|
|
@@ -571,8 +575,9 @@ void __devinit cpu_init(void)
|
|
int cpu = smp_processor_id();
|
|
int cpu = smp_processor_id();
|
|
struct tss_struct * t = &per_cpu(init_tss, cpu);
|
|
struct tss_struct * t = &per_cpu(init_tss, cpu);
|
|
struct thread_struct *thread = ¤t->thread;
|
|
struct thread_struct *thread = ¤t->thread;
|
|
- struct desc_struct *gdt = get_cpu_gdt_table(cpu);
|
|
|
|
|
|
+ struct desc_struct *gdt;
|
|
__u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu);
|
|
__u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu);
|
|
|
|
+ struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
|
|
|
|
|
|
if (cpu_test_and_set(cpu, cpu_initialized)) {
|
|
if (cpu_test_and_set(cpu, cpu_initialized)) {
|
|
printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
|
|
printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
|
|
@@ -589,6 +594,25 @@ void __devinit cpu_init(void)
|
|
set_in_cr4(X86_CR4_TSD);
|
|
set_in_cr4(X86_CR4_TSD);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * This is a horrible hack to allocate the GDT. The problem
|
|
|
|
+ * is that cpu_init() is called really early for the boot CPU
|
|
|
|
+ * (and hence needs bootmem) but much later for the secondary
|
|
|
|
+ * CPUs, when bootmem will have gone away
|
|
|
|
+ */
|
|
|
|
+ if (NODE_DATA(0)->bdata->node_bootmem_map) {
|
|
|
|
+ gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE);
|
|
|
|
+ /* alloc_bootmem_pages panics on failure, so no check */
|
|
|
|
+ memset(gdt, 0, PAGE_SIZE);
|
|
|
|
+ } else {
|
|
|
|
+ gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL);
|
|
|
|
+ if (unlikely(!gdt)) {
|
|
|
|
+ printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
|
|
|
|
+ for (;;)
|
|
|
|
+ local_irq_enable();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Initialize the per-CPU GDT with the boot GDT,
|
|
* Initialize the per-CPU GDT with the boot GDT,
|
|
* and set up the GDT descriptor:
|
|
* and set up the GDT descriptor:
|
|
@@ -601,10 +625,10 @@ void __devinit cpu_init(void)
|
|
((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) |
|
|
((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) |
|
|
(CPU_16BIT_STACK_SIZE - 1);
|
|
(CPU_16BIT_STACK_SIZE - 1);
|
|
|
|
|
|
- cpu_gdt_descr[cpu].size = GDT_SIZE - 1;
|
|
|
|
- cpu_gdt_descr[cpu].address = (unsigned long)gdt;
|
|
|
|
|
|
+ cpu_gdt_descr->size = GDT_SIZE - 1;
|
|
|
|
+ cpu_gdt_descr->address = (unsigned long)gdt;
|
|
|
|
|
|
- load_gdt(&cpu_gdt_descr[cpu]);
|
|
|
|
|
|
+ load_gdt(cpu_gdt_descr);
|
|
load_idt(&idt_descr);
|
|
load_idt(&idt_descr);
|
|
|
|
|
|
/*
|
|
/*
|