aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/cpu
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2007-05-02 13:27:10 -0400
committerAndi Kleen <andi@basil.nowhere.org>2007-05-02 13:27:10 -0400
commitbf50467204b435421d8de33ad080fa46c6f3d50b (patch)
tree87a27c6f23f28d0e7dacee4ac45986e897d244a8 /arch/i386/kernel/cpu
parentae1ee11be77f51cedb6c569887dddc70c163ab6d (diff)
[PATCH] i386: Use per-cpu GDT immediately upon boot
Now we are no longer dynamically allocating the GDT, we don't need the "cpu_gdt_table" at all: we can switch straight from "boot_gdt_table" to the per-cpu GDT. This means initializing the cpu_gdt array in C. The boot CPU uses the per-cpu var directly, then in smp_prepare_cpus() it switches to the per-cpu copy just allocated. For secondary CPUs, the early_gdt_descr is set to point directly to their per-cpu copy. For UP the code is very simple: it keeps using the "per-cpu" GDT as per SMP, but we never have to move. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'arch/i386/kernel/cpu')
-rw-r--r--arch/i386/kernel/cpu/common.c72
1 files changed, 27 insertions, 45 deletions
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 2335f4464ead..fd6b079f7609 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -25,7 +25,33 @@
25DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); 25DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
26EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); 26EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
27 27
28DEFINE_PER_CPU(struct desc_struct, cpu_gdt[GDT_ENTRIES]); 28DEFINE_PER_CPU(struct desc_struct, cpu_gdt[GDT_ENTRIES]) = {
29 [GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 },
30 [GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 },
31 [GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 },
32 [GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 },
33 /*
34 * Segments used for calling PnP BIOS have byte granularity.
35 * They code segments and data segments have fixed 64k limits,
36 * the transfer segment sizes are set at run time.
37 */
38 [GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */
39 [GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */
40 [GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */
41 [GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */
42 [GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */
43 /*
44 * The APM segments have byte granularity and their bases
45 * are set at run time. All have 64k limits.
46 */
47 [GDT_ENTRY_APMBIOS_BASE] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */
48 /* 16-bit code */
49 [GDT_ENTRY_APMBIOS_BASE+1] = { 0x0000ffff, 0x00009a00 },
50 [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */
51
52 [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 },
53 [GDT_ENTRY_PDA] = { 0x00000000, 0x00c09200 }, /* set in setup_pda */
54};
29 55
30DEFINE_PER_CPU(struct i386_pda, _cpu_pda); 56DEFINE_PER_CPU(struct i386_pda, _cpu_pda);
31EXPORT_PER_CPU_SYMBOL(_cpu_pda); 57EXPORT_PER_CPU_SYMBOL(_cpu_pda);
@@ -618,46 +644,6 @@ struct i386_pda boot_pda = {
618 .pcurrent = &init_task, 644 .pcurrent = &init_task,
619}; 645};
620 646
621static inline void set_kernel_fs(void)
622{
623 /* Set %fs for this CPU's PDA. Memory clobber is to create a
624 barrier with respect to any PDA operations, so the compiler
625 doesn't move any before here. */
626 asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory");
627}
628
629/* Initialize the CPU's GDT and PDA. This is either the boot CPU doing itself
630 (still using cpu_gdt_table), or a CPU doing it for a secondary which
631 will soon come up. */
632__cpuinit void init_gdt(int cpu, struct task_struct *idle)
633{
634 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
635 struct desc_struct *gdt = per_cpu(cpu_gdt, cpu);
636 struct i386_pda *pda = &per_cpu(_cpu_pda, cpu);
637
638 memcpy(gdt, cpu_gdt_table, GDT_SIZE);
639 cpu_gdt_descr->address = (unsigned long)gdt;
640 cpu_gdt_descr->size = GDT_SIZE - 1;
641
642 pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a,
643 (u32 *)&gdt[GDT_ENTRY_PDA].b,
644 (unsigned long)pda, sizeof(*pda) - 1,
645 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */
646
647 memset(pda, 0, sizeof(*pda));
648 pda->_pda = pda;
649 pda->cpu_number = cpu;
650 pda->pcurrent = idle;
651}
652
653void __cpuinit cpu_set_gdt(int cpu)
654{
655 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
656
657 load_gdt(cpu_gdt_descr);
658 set_kernel_fs();
659}
660
661/* Common CPU init for both boot and secondary CPUs */ 647/* Common CPU init for both boot and secondary CPUs */
662static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) 648static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
663{ 649{
@@ -740,10 +726,6 @@ void __cpuinit cpu_init(void)
740 int cpu = smp_processor_id(); 726 int cpu = smp_processor_id();
741 struct task_struct *curr = current; 727 struct task_struct *curr = current;
742 728
743 /* Set up the real GDT and PDA, so we can transition from the
744 boot_gdt_table & boot_pda. */
745 init_gdt(cpu, curr);
746 cpu_set_gdt(cpu);
747 _cpu_init(cpu, curr); 729 _cpu_init(cpu, curr);
748} 730}
749 731