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:41:58 -0500 |
commit | d9a89a26e02ef9ed03f74a755a8b4d8f3a066622 (patch) | |
tree | 35f3713bca4e6b815f6b9db92dc9d812ec7213ff /arch/x86/kernel | |
parent | f0d96110f9fd98a1a22e03b8adba69508843d910 (diff) |
x86: add %gs accessors for x86_32
Impact: cleanup
On x86_32, %gs is handled lazily. It's not saved and restored on
kernel entry/exit but only when necessary which usually is during task
switch but there are few other places. Currently, it's done by
calling savesegment() and loadsegment() explicitly. Define
get_user_gs(), set_user_gs() and task_user_gs() and use them instead.
While at it, clean up register access macros in signal.c.
This cleans up code a bit and will help future changes.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/process_32.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 14 | ||||
-rw-r--r-- | arch/x86/kernel/signal.c | 41 | ||||
-rw-r--r-- | arch/x86/kernel/vm86_32.c | 4 |
4 files changed, 27 insertions, 38 deletions
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 1a1ae8edc40c..d58a340e1be3 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -131,7 +131,7 @@ void __show_regs(struct pt_regs *regs, int all) | |||
131 | if (user_mode_vm(regs)) { | 131 | if (user_mode_vm(regs)) { |
132 | sp = regs->sp; | 132 | sp = regs->sp; |
133 | ss = regs->ss & 0xffff; | 133 | ss = regs->ss & 0xffff; |
134 | savesegment(gs, gs); | 134 | gs = get_user_gs(regs); |
135 | } else { | 135 | } else { |
136 | sp = (unsigned long) (®s->sp); | 136 | sp = (unsigned long) (®s->sp); |
137 | savesegment(ss, ss); | 137 | savesegment(ss, ss); |
@@ -304,7 +304,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
304 | 304 | ||
305 | p->thread.ip = (unsigned long) ret_from_fork; | 305 | p->thread.ip = (unsigned long) ret_from_fork; |
306 | 306 | ||
307 | savesegment(gs, p->thread.gs); | 307 | task_user_gs(p) = get_user_gs(regs); |
308 | 308 | ||
309 | tsk = current; | 309 | tsk = current; |
310 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { | 310 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { |
@@ -342,7 +342,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
342 | void | 342 | void |
343 | start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) | 343 | start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) |
344 | { | 344 | { |
345 | __asm__("movl %0, %%gs" : : "r"(0)); | 345 | set_user_gs(regs, 0); |
346 | regs->fs = 0; | 346 | regs->fs = 0; |
347 | set_fs(USER_DS); | 347 | set_fs(USER_DS); |
348 | regs->ds = __USER_DS; | 348 | regs->ds = __USER_DS; |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 0a5df5f82fb9..508b6b57d0c3 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -90,9 +90,10 @@ static u16 get_segment_reg(struct task_struct *task, unsigned long offset) | |||
90 | if (offset != offsetof(struct user_regs_struct, gs)) | 90 | if (offset != offsetof(struct user_regs_struct, gs)) |
91 | retval = *pt_regs_access(task_pt_regs(task), offset); | 91 | retval = *pt_regs_access(task_pt_regs(task), offset); |
92 | else { | 92 | else { |
93 | retval = task->thread.gs; | ||
94 | if (task == current) | 93 | if (task == current) |
95 | savesegment(gs, retval); | 94 | retval = get_user_gs(task_pt_regs(task)); |
95 | else | ||
96 | retval = task_user_gs(task); | ||
96 | } | 97 | } |
97 | return retval; | 98 | return retval; |
98 | } | 99 | } |
@@ -126,13 +127,10 @@ static int set_segment_reg(struct task_struct *task, | |||
126 | break; | 127 | break; |
127 | 128 | ||
128 | case offsetof(struct user_regs_struct, gs): | 129 | case offsetof(struct user_regs_struct, gs): |
129 | task->thread.gs = value; | ||
130 | if (task == current) | 130 | if (task == current) |
131 | /* | 131 | set_user_gs(task_pt_regs(task), value); |
132 | * The user-mode %gs is not affected by | 132 | else |
133 | * kernel entry, so we must update the CPU. | 133 | task_user_gs(task) = value; |
134 | */ | ||
135 | loadsegment(gs, value); | ||
136 | } | 134 | } |
137 | 135 | ||
138 | return 0; | 136 | return 0; |
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 7fc78b019815..8562387c75a7 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -50,27 +50,23 @@ | |||
50 | # define FIX_EFLAGS __FIX_EFLAGS | 50 | # define FIX_EFLAGS __FIX_EFLAGS |
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | #define COPY(x) { \ | 53 | #define COPY(x) do { \ |
54 | get_user_ex(regs->x, &sc->x); \ | 54 | get_user_ex(regs->x, &sc->x); \ |
55 | } | 55 | } while (0) |
56 | 56 | ||
57 | #define COPY_SEG(seg) { \ | 57 | #define GET_SEG(seg) ({ \ |
58 | unsigned short tmp; \ | 58 | unsigned short tmp; \ |
59 | get_user_ex(tmp, &sc->seg); \ | 59 | get_user_ex(tmp, &sc->seg); \ |
60 | regs->seg = tmp; \ | 60 | tmp; \ |
61 | } | 61 | }) |
62 | 62 | ||
63 | #define COPY_SEG_CPL3(seg) { \ | 63 | #define COPY_SEG(seg) do { \ |
64 | unsigned short tmp; \ | 64 | regs->seg = GET_SEG(seg); \ |
65 | get_user_ex(tmp, &sc->seg); \ | 65 | } while (0) |
66 | regs->seg = tmp | 3; \ | ||
67 | } | ||
68 | 66 | ||
69 | #define GET_SEG(seg) { \ | 67 | #define COPY_SEG_CPL3(seg) do { \ |
70 | unsigned short tmp; \ | 68 | regs->seg = GET_SEG(seg) | 3; \ |
71 | get_user_ex(tmp, &sc->seg); \ | 69 | } while (0) |
72 | loadsegment(seg, tmp); \ | ||
73 | } | ||
74 | 70 | ||
75 | static int | 71 | static int |
76 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | 72 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, |
@@ -86,7 +82,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
86 | get_user_try { | 82 | get_user_try { |
87 | 83 | ||
88 | #ifdef CONFIG_X86_32 | 84 | #ifdef CONFIG_X86_32 |
89 | GET_SEG(gs); | 85 | set_user_gs(regs, GET_SEG(gs)); |
90 | COPY_SEG(fs); | 86 | COPY_SEG(fs); |
91 | COPY_SEG(es); | 87 | COPY_SEG(es); |
92 | COPY_SEG(ds); | 88 | COPY_SEG(ds); |
@@ -138,12 +134,7 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
138 | put_user_try { | 134 | put_user_try { |
139 | 135 | ||
140 | #ifdef CONFIG_X86_32 | 136 | #ifdef CONFIG_X86_32 |
141 | { | 137 | put_user_ex(get_user_gs(regs), (unsigned int __user *)&sc->gs); |
142 | unsigned int tmp; | ||
143 | |||
144 | savesegment(gs, tmp); | ||
145 | put_user_ex(tmp, (unsigned int __user *)&sc->gs); | ||
146 | } | ||
147 | put_user_ex(regs->fs, (unsigned int __user *)&sc->fs); | 138 | put_user_ex(regs->fs, (unsigned int __user *)&sc->fs); |
148 | put_user_ex(regs->es, (unsigned int __user *)&sc->es); | 139 | put_user_ex(regs->es, (unsigned int __user *)&sc->es); |
149 | put_user_ex(regs->ds, (unsigned int __user *)&sc->ds); | 140 | put_user_ex(regs->ds, (unsigned int __user *)&sc->ds); |
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 4eeb5cf9720d..55ea30d2a3d6 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c | |||
@@ -158,7 +158,7 @@ struct pt_regs *save_v86_state(struct kernel_vm86_regs *regs) | |||
158 | ret = KVM86->regs32; | 158 | ret = KVM86->regs32; |
159 | 159 | ||
160 | ret->fs = current->thread.saved_fs; | 160 | ret->fs = current->thread.saved_fs; |
161 | loadsegment(gs, current->thread.saved_gs); | 161 | set_user_gs(ret, current->thread.saved_gs); |
162 | 162 | ||
163 | return ret; | 163 | return ret; |
164 | } | 164 | } |
@@ -323,7 +323,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk | |||
323 | info->regs32->ax = 0; | 323 | info->regs32->ax = 0; |
324 | tsk->thread.saved_sp0 = tsk->thread.sp0; | 324 | tsk->thread.saved_sp0 = tsk->thread.sp0; |
325 | tsk->thread.saved_fs = info->regs32->fs; | 325 | tsk->thread.saved_fs = info->regs32->fs; |
326 | savesegment(gs, tsk->thread.saved_gs); | 326 | tsk->thread.saved_gs = get_user_gs(info->regs32); |
327 | 327 | ||
328 | tss = &per_cpu(init_tss, get_cpu()); | 328 | tss = &per_cpu(init_tss, get_cpu()); |
329 | tsk->thread.sp0 = (unsigned long) &info->VM86_TSS_ESP0; | 329 | tsk->thread.sp0 = (unsigned long) &info->VM86_TSS_ESP0; |