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/process.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/process.c')
-rw-r--r-- | arch/i386/kernel/process.c | 26 |
1 files changed, 12 insertions, 14 deletions
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index ae924c416b68..905364d42847 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c | |||
@@ -56,6 +56,7 @@ | |||
56 | 56 | ||
57 | #include <asm/tlbflush.h> | 57 | #include <asm/tlbflush.h> |
58 | #include <asm/cpu.h> | 58 | #include <asm/cpu.h> |
59 | #include <asm/pda.h> | ||
59 | 60 | ||
60 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 61 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
61 | 62 | ||
@@ -346,6 +347,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
346 | 347 | ||
347 | regs.xds = __USER_DS; | 348 | regs.xds = __USER_DS; |
348 | regs.xes = __USER_DS; | 349 | regs.xes = __USER_DS; |
350 | regs.xgs = __KERNEL_PDA; | ||
349 | regs.orig_eax = -1; | 351 | regs.orig_eax = -1; |
350 | regs.eip = (unsigned long) kernel_thread_helper; | 352 | regs.eip = (unsigned long) kernel_thread_helper; |
351 | regs.xcs = __KERNEL_CS | get_kernel_rpl(); | 353 | regs.xcs = __KERNEL_CS | get_kernel_rpl(); |
@@ -431,7 +433,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, | |||
431 | p->thread.eip = (unsigned long) ret_from_fork; | 433 | p->thread.eip = (unsigned long) ret_from_fork; |
432 | 434 | ||
433 | savesegment(fs,p->thread.fs); | 435 | savesegment(fs,p->thread.fs); |
434 | savesegment(gs,p->thread.gs); | ||
435 | 436 | ||
436 | tsk = current; | 437 | tsk = current; |
437 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { | 438 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { |
@@ -659,16 +660,16 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
659 | load_esp0(tss, next); | 660 | load_esp0(tss, next); |
660 | 661 | ||
661 | /* | 662 | /* |
662 | * Save away %fs and %gs. No need to save %es and %ds, as | 663 | * Save away %fs. No need to save %gs, as it was saved on the |
663 | * those are always kernel segments while inside the kernel. | 664 | * stack on entry. No need to save %es and %ds, as those are |
664 | * Doing this before setting the new TLS descriptors avoids | 665 | * always kernel segments while inside the kernel. Doing this |
665 | * the situation where we temporarily have non-reloadable | 666 | * before setting the new TLS descriptors avoids the situation |
666 | * segments in %fs and %gs. This could be an issue if the | 667 | * where we temporarily have non-reloadable segments in %fs |
667 | * NMI handler ever used %fs or %gs (it does not today), or | 668 | * and %gs. This could be an issue if the NMI handler ever |
668 | * if the kernel is running inside of a hypervisor layer. | 669 | * used %fs or %gs (it does not today), or if the kernel is |
670 | * running inside of a hypervisor layer. | ||
669 | */ | 671 | */ |
670 | savesegment(fs, prev->fs); | 672 | savesegment(fs, prev->fs); |
671 | savesegment(gs, prev->gs); | ||
672 | 673 | ||
673 | /* | 674 | /* |
674 | * Load the per-thread Thread-Local Storage descriptor. | 675 | * Load the per-thread Thread-Local Storage descriptor. |
@@ -676,16 +677,13 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
676 | load_TLS(next, cpu); | 677 | load_TLS(next, cpu); |
677 | 678 | ||
678 | /* | 679 | /* |
679 | * Restore %fs and %gs if needed. | 680 | * Restore %fs if needed. |
680 | * | 681 | * |
681 | * Glibc normally makes %fs be zero, and %gs is one of | 682 | * Glibc normally makes %fs be zero. |
682 | * the TLS segments. | ||
683 | */ | 683 | */ |
684 | if (unlikely(prev->fs | next->fs)) | 684 | if (unlikely(prev->fs | next->fs)) |
685 | loadsegment(fs, next->fs); | 685 | loadsegment(fs, next->fs); |
686 | 686 | ||
687 | if (prev->gs | next->gs) | ||
688 | loadsegment(gs, next->gs); | ||
689 | 687 | ||
690 | /* | 688 | /* |
691 | * Restore IOPL if needed. | 689 | * Restore IOPL if needed. |