diff options
author | Tejun Heo <tj@kernel.org> | 2009-02-09 08:17:40 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-09 18:42:00 -0500 |
commit | ccbeed3a05908d201b47b6c3dd1a373138bba566 (patch) | |
tree | e834d548c70426aa3885dd2169be1a79be4a617b /arch/x86/include/asm | |
parent | d9a89a26e02ef9ed03f74a755a8b4d8f3a066622 (diff) |
x86: make lazy %gs optional on x86_32
Impact: pt_regs changed, lazy gs handling made optional, add slight
overhead to SAVE_ALL, simplifies error_code path a bit
On x86_32, %gs hasn't been used by kernel and handled lazily. pt_regs
doesn't have place for it and gs is saved/loaded only when necessary.
In preparation for stack protector support, this patch makes lazy %gs
handling optional by doing the followings.
* Add CONFIG_X86_32_LAZY_GS and place for gs in pt_regs.
* Save and restore %gs along with other registers in entry_32.S unless
LAZY_GS. Note that this unfortunately adds "pushl $0" on SAVE_ALL
even when LAZY_GS. However, it adds no overhead to common exit path
and simplifies entry path with error code.
* Define different user_gs accessors depending on LAZY_GS and add
lazy_save_gs() and lazy_load_gs() which are noop if !LAZY_GS. The
lazy_*_gs() ops are used to save, load and clear %gs lazily.
* Define ELF_CORE_COPY_KERNEL_REGS() which always read %gs directly.
xen and lguest changes need to be verified.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Jeremy Fitzhardinge <jeremy@xensource.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/include/asm')
-rw-r--r-- | arch/x86/include/asm/elf.h | 15 | ||||
-rw-r--r-- | arch/x86/include/asm/mmu_context.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/ptrace.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/system.h | 12 |
4 files changed, 27 insertions, 6 deletions
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 39b0aac1675c..83c1bc8d2e8a 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h | |||
@@ -112,7 +112,7 @@ extern unsigned int vdso_enabled; | |||
112 | * now struct_user_regs, they are different) | 112 | * now struct_user_regs, they are different) |
113 | */ | 113 | */ |
114 | 114 | ||
115 | #define ELF_CORE_COPY_REGS(pr_reg, regs) \ | 115 | #define ELF_CORE_COPY_REGS_COMMON(pr_reg, regs) \ |
116 | do { \ | 116 | do { \ |
117 | pr_reg[0] = regs->bx; \ | 117 | pr_reg[0] = regs->bx; \ |
118 | pr_reg[1] = regs->cx; \ | 118 | pr_reg[1] = regs->cx; \ |
@@ -124,7 +124,6 @@ do { \ | |||
124 | pr_reg[7] = regs->ds & 0xffff; \ | 124 | pr_reg[7] = regs->ds & 0xffff; \ |
125 | pr_reg[8] = regs->es & 0xffff; \ | 125 | pr_reg[8] = regs->es & 0xffff; \ |
126 | pr_reg[9] = regs->fs & 0xffff; \ | 126 | pr_reg[9] = regs->fs & 0xffff; \ |
127 | pr_reg[10] = get_user_gs(regs); \ | ||
128 | pr_reg[11] = regs->orig_ax; \ | 127 | pr_reg[11] = regs->orig_ax; \ |
129 | pr_reg[12] = regs->ip; \ | 128 | pr_reg[12] = regs->ip; \ |
130 | pr_reg[13] = regs->cs & 0xffff; \ | 129 | pr_reg[13] = regs->cs & 0xffff; \ |
@@ -133,6 +132,18 @@ do { \ | |||
133 | pr_reg[16] = regs->ss & 0xffff; \ | 132 | pr_reg[16] = regs->ss & 0xffff; \ |
134 | } while (0); | 133 | } while (0); |
135 | 134 | ||
135 | #define ELF_CORE_COPY_REGS(pr_reg, regs) \ | ||
136 | do { \ | ||
137 | ELF_CORE_COPY_REGS_COMMON(pr_reg, regs);\ | ||
138 | pr_reg[10] = get_user_gs(regs); \ | ||
139 | } while (0); | ||
140 | |||
141 | #define ELF_CORE_COPY_KERNEL_REGS(pr_reg, regs) \ | ||
142 | do { \ | ||
143 | ELF_CORE_COPY_REGS_COMMON(pr_reg, regs);\ | ||
144 | savesegment(gs, pr_reg[10]); \ | ||
145 | } while (0); | ||
146 | |||
136 | #define ELF_PLATFORM (utsname()->machine) | 147 | #define ELF_PLATFORM (utsname()->machine) |
137 | #define set_personality_64bit() do { } while (0) | 148 | #define set_personality_64bit() do { } while (0) |
138 | 149 | ||
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index 4955165682c5..f923203dc39a 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h | |||
@@ -79,7 +79,7 @@ do { \ | |||
79 | #ifdef CONFIG_X86_32 | 79 | #ifdef CONFIG_X86_32 |
80 | #define deactivate_mm(tsk, mm) \ | 80 | #define deactivate_mm(tsk, mm) \ |
81 | do { \ | 81 | do { \ |
82 | set_user_gs(task_pt_regs(tsk), 0); \ | 82 | lazy_load_gs(0); \ |
83 | } while (0) | 83 | } while (0) |
84 | #else | 84 | #else |
85 | #define deactivate_mm(tsk, mm) \ | 85 | #define deactivate_mm(tsk, mm) \ |
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 6d34d954c228..e304b66abeea 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h | |||
@@ -28,7 +28,7 @@ struct pt_regs { | |||
28 | int xds; | 28 | int xds; |
29 | int xes; | 29 | int xes; |
30 | int xfs; | 30 | int xfs; |
31 | /* int gs; */ | 31 | int xgs; |
32 | long orig_eax; | 32 | long orig_eax; |
33 | long eip; | 33 | long eip; |
34 | int xcs; | 34 | int xcs; |
@@ -50,7 +50,7 @@ struct pt_regs { | |||
50 | unsigned long ds; | 50 | unsigned long ds; |
51 | unsigned long es; | 51 | unsigned long es; |
52 | unsigned long fs; | 52 | unsigned long fs; |
53 | /* int gs; */ | 53 | unsigned long gs; |
54 | unsigned long orig_ax; | 54 | unsigned long orig_ax; |
55 | unsigned long ip; | 55 | unsigned long ip; |
56 | unsigned long cs; | 56 | unsigned long cs; |
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index 70c74b8db875..79b98e5b96f4 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h | |||
@@ -186,10 +186,20 @@ extern void native_load_gs_index(unsigned); | |||
186 | * x86_32 user gs accessors. | 186 | * x86_32 user gs accessors. |
187 | */ | 187 | */ |
188 | #ifdef CONFIG_X86_32 | 188 | #ifdef CONFIG_X86_32 |
189 | #ifdef CONFIG_X86_32_LAZY_GS | ||
189 | #define get_user_gs(regs) (u16)({unsigned long v; savesegment(gs, v); v;}) | 190 | #define get_user_gs(regs) (u16)({unsigned long v; savesegment(gs, v); v;}) |
190 | #define set_user_gs(regs, v) loadsegment(gs, (unsigned long)(v)) | 191 | #define set_user_gs(regs, v) loadsegment(gs, (unsigned long)(v)) |
191 | #define task_user_gs(tsk) ((tsk)->thread.gs) | 192 | #define task_user_gs(tsk) ((tsk)->thread.gs) |
192 | #endif | 193 | #define lazy_save_gs(v) savesegment(gs, (v)) |
194 | #define lazy_load_gs(v) loadsegment(gs, (v)) | ||
195 | #else /* X86_32_LAZY_GS */ | ||
196 | #define get_user_gs(regs) (u16)((regs)->gs) | ||
197 | #define set_user_gs(regs, v) do { (regs)->gs = (v); } while (0) | ||
198 | #define task_user_gs(tsk) (task_pt_regs(tsk)->gs) | ||
199 | #define lazy_save_gs(v) do { } while (0) | ||
200 | #define lazy_load_gs(v) do { } while (0) | ||
201 | #endif /* X86_32_LAZY_GS */ | ||
202 | #endif /* X86_32 */ | ||
193 | 203 | ||
194 | static inline unsigned long get_limit(unsigned long segment) | 204 | static inline unsigned long get_limit(unsigned long segment) |
195 | { | 205 | { |