diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2006-12-06 20:14:02 -0500 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-12-06 20:14:02 -0500 |
commit | f95d47caae5302a63d92be9a0292abc90e2a14e1 (patch) | |
tree | cfa963975d104c56aba28df6c941759175ed4b98 /arch/i386/kernel/cpu/common.c | |
parent | 62111195800d80c66cdc69063ea3145878c99fbf (diff) |
[PATCH] i386: Use %gs as the PDA base-segment in the kernel
This patch is the meat of the PDA change. This patch makes several related
changes:
1: Most significantly, %gs is now used in the kernel. This means that on
entry, the old value of %gs is saved away, and it is reloaded with
__KERNEL_PDA.
2: entry.S constructs the stack in the shape of struct pt_regs, and this
is passed around the kernel so that the process's saved register
state can be accessed.
Unfortunately struct pt_regs doesn't currently have space for %gs
(or %fs). This patch extends pt_regs to add space for gs (no space
is allocated for %fs, since it won't be used, and it would just
complicate the code in entry.S to work around the space).
3: Because %gs is now saved on the stack like %ds, %es and the integer
registers, there are a number of places where it no longer needs to
be handled specially; namely context switch, and saving/restoring the
register state in a signal context.
4: And since kernel threads run in kernel space and call normal kernel
code, they need to be created with their %gs == __KERNEL_PDA.
Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Cc: Chuck Ebbert <76306.1226@compuserve.com>
Cc: Zachary Amsden <zach@vmware.com>
Cc: Jan Beulich <jbeulich@novell.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Diffstat (limited to 'arch/i386/kernel/cpu/common.c')
-rw-r--r-- | arch/i386/kernel/cpu/common.c | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 2534e25ed745..4e63d8ce602b 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c | |||
@@ -593,6 +593,14 @@ void __init early_cpu_init(void) | |||
593 | #endif | 593 | #endif |
594 | } | 594 | } |
595 | 595 | ||
596 | /* Make sure %gs is initialized properly in idle threads */ | ||
597 | struct pt_regs * __devinit idle_regs(struct pt_regs *regs) | ||
598 | { | ||
599 | memset(regs, 0, sizeof(struct pt_regs)); | ||
600 | regs->xgs = __KERNEL_PDA; | ||
601 | return regs; | ||
602 | } | ||
603 | |||
596 | __cpuinit int alloc_gdt(int cpu) | 604 | __cpuinit int alloc_gdt(int cpu) |
597 | { | 605 | { |
598 | struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); | 606 | struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); |
@@ -644,6 +652,14 @@ struct i386_pda boot_pda = { | |||
644 | ._pda = &boot_pda, | 652 | ._pda = &boot_pda, |
645 | }; | 653 | }; |
646 | 654 | ||
655 | static inline void set_kernel_gs(void) | ||
656 | { | ||
657 | /* Set %gs for this CPU's PDA. Memory clobber is to create a | ||
658 | barrier with respect to any PDA operations, so the compiler | ||
659 | doesn't move any before here. */ | ||
660 | asm volatile ("mov %0, %%gs" : : "r" (__KERNEL_PDA) : "memory"); | ||
661 | } | ||
662 | |||
647 | /* Initialize the CPU's GDT and PDA. The boot CPU does this for | 663 | /* Initialize the CPU's GDT and PDA. The boot CPU does this for |
648 | itself, but secondaries find this done for them. */ | 664 | itself, but secondaries find this done for them. */ |
649 | __cpuinit int init_gdt(int cpu, struct task_struct *idle) | 665 | __cpuinit int init_gdt(int cpu, struct task_struct *idle) |
@@ -693,6 +709,7 @@ static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) | |||
693 | the boot CPU, this will transition from the boot gdt+pda to | 709 | the boot CPU, this will transition from the boot gdt+pda to |
694 | the real ones). */ | 710 | the real ones). */ |
695 | load_gdt(cpu_gdt_descr); | 711 | load_gdt(cpu_gdt_descr); |
712 | set_kernel_gs(); | ||
696 | 713 | ||
697 | if (cpu_test_and_set(cpu, cpu_initialized)) { | 714 | if (cpu_test_and_set(cpu, cpu_initialized)) { |
698 | printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); | 715 | printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); |
@@ -731,8 +748,8 @@ static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) | |||
731 | __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); | 748 | __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); |
732 | #endif | 749 | #endif |
733 | 750 | ||
734 | /* Clear %fs and %gs. */ | 751 | /* Clear %fs. */ |
735 | asm volatile ("movl %0, %%fs; movl %0, %%gs" : : "r" (0)); | 752 | asm volatile ("mov %0, %%fs" : : "r" (0)); |
736 | 753 | ||
737 | /* Clear all 6 debug registers: */ | 754 | /* Clear all 6 debug registers: */ |
738 | set_debugreg(0, 0); | 755 | set_debugreg(0, 0); |