diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2007-05-02 13:27:10 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2007-05-02 13:27:10 -0400 |
commit | bf50467204b435421d8de33ad080fa46c6f3d50b (patch) | |
tree | 87a27c6f23f28d0e7dacee4ac45986e897d244a8 /arch/i386/kernel/cpu | |
parent | ae1ee11be77f51cedb6c569887dddc70c163ab6d (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.c | 72 |
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 @@ | |||
25 | DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); | 25 | DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); |
26 | EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); | 26 | EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); |
27 | 27 | ||
28 | DEFINE_PER_CPU(struct desc_struct, cpu_gdt[GDT_ENTRIES]); | 28 | DEFINE_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 | ||
30 | DEFINE_PER_CPU(struct i386_pda, _cpu_pda); | 56 | DEFINE_PER_CPU(struct i386_pda, _cpu_pda); |
31 | EXPORT_PER_CPU_SYMBOL(_cpu_pda); | 57 | EXPORT_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 | ||
621 | static 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 | |||
653 | void __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 */ |
662 | static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) | 648 | static 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 | ||