diff options
author | Roland McGrath <roland@redhat.com> | 2008-01-30 07:30:46 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:30:46 -0500 |
commit | efd1ca52d04d2f6df337a3332cee56cd60e6d4c4 (patch) | |
tree | cf1e630d25cc45f399388f5fc996d86cf3bcf9ff /arch/x86/kernel/ptrace_32.c | |
parent | 13abd0e50433092c41551bc13c32268028b6d663 (diff) |
x86: TLS cleanup
This consolidates the four different places that implemented the same
encoding magic for the GDT-slot 32-bit TLS support. The old tls32.c was
renamed and is now only slightly modified to be the shared implementation.
Signed-off-by: Roland McGrath <roland@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Zachary Amsden <zach@vmware.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/ptrace_32.c')
-rw-r--r-- | arch/x86/kernel/ptrace_32.c | 91 |
1 files changed, 8 insertions, 83 deletions
diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c index ff5431cc03ee..09227cfb7c4c 100644 --- a/arch/x86/kernel/ptrace_32.c +++ b/arch/x86/kernel/ptrace_32.c | |||
@@ -276,85 +276,6 @@ void ptrace_disable(struct task_struct *child) | |||
276 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | 276 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); |
277 | } | 277 | } |
278 | 278 | ||
279 | /* | ||
280 | * Perform get_thread_area on behalf of the traced child. | ||
281 | */ | ||
282 | static int | ||
283 | ptrace_get_thread_area(struct task_struct *child, | ||
284 | int idx, struct user_desc __user *user_desc) | ||
285 | { | ||
286 | struct user_desc info; | ||
287 | struct desc_struct *desc; | ||
288 | |||
289 | /* | ||
290 | * Get the current Thread-Local Storage area: | ||
291 | */ | ||
292 | |||
293 | #define GET_BASE(desc) ( \ | ||
294 | (((desc)->a >> 16) & 0x0000ffff) | \ | ||
295 | (((desc)->b << 16) & 0x00ff0000) | \ | ||
296 | ( (desc)->b & 0xff000000) ) | ||
297 | |||
298 | #define GET_LIMIT(desc) ( \ | ||
299 | ((desc)->a & 0x0ffff) | \ | ||
300 | ((desc)->b & 0xf0000) ) | ||
301 | |||
302 | #define GET_32BIT(desc) (((desc)->b >> 22) & 1) | ||
303 | #define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) | ||
304 | #define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) | ||
305 | #define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) | ||
306 | #define GET_PRESENT(desc) (((desc)->b >> 15) & 1) | ||
307 | #define GET_USEABLE(desc) (((desc)->b >> 20) & 1) | ||
308 | |||
309 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | ||
310 | return -EINVAL; | ||
311 | |||
312 | desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; | ||
313 | |||
314 | info.entry_number = idx; | ||
315 | info.base_addr = GET_BASE(desc); | ||
316 | info.limit = GET_LIMIT(desc); | ||
317 | info.seg_32bit = GET_32BIT(desc); | ||
318 | info.contents = GET_CONTENTS(desc); | ||
319 | info.read_exec_only = !GET_WRITABLE(desc); | ||
320 | info.limit_in_pages = GET_LIMIT_PAGES(desc); | ||
321 | info.seg_not_present = !GET_PRESENT(desc); | ||
322 | info.useable = GET_USEABLE(desc); | ||
323 | |||
324 | if (copy_to_user(user_desc, &info, sizeof(info))) | ||
325 | return -EFAULT; | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * Perform set_thread_area on behalf of the traced child. | ||
332 | */ | ||
333 | static int | ||
334 | ptrace_set_thread_area(struct task_struct *child, | ||
335 | int idx, struct user_desc __user *user_desc) | ||
336 | { | ||
337 | struct user_desc info; | ||
338 | struct desc_struct *desc; | ||
339 | |||
340 | if (copy_from_user(&info, user_desc, sizeof(info))) | ||
341 | return -EFAULT; | ||
342 | |||
343 | if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) | ||
344 | return -EINVAL; | ||
345 | |||
346 | desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; | ||
347 | if (LDT_empty(&info)) { | ||
348 | desc->a = 0; | ||
349 | desc->b = 0; | ||
350 | } else { | ||
351 | desc->a = LDT_entry_a(&info); | ||
352 | desc->b = LDT_entry_b(&info); | ||
353 | } | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 279 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
359 | { | 280 | { |
360 | struct user * dummy = NULL; | 281 | struct user * dummy = NULL; |
@@ -601,13 +522,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
601 | } | 522 | } |
602 | 523 | ||
603 | case PTRACE_GET_THREAD_AREA: | 524 | case PTRACE_GET_THREAD_AREA: |
604 | ret = ptrace_get_thread_area(child, addr, | 525 | if (addr < 0) |
605 | (struct user_desc __user *) data); | 526 | return -EIO; |
527 | ret = do_get_thread_area(child, addr, | ||
528 | (struct user_desc __user *) data); | ||
606 | break; | 529 | break; |
607 | 530 | ||
608 | case PTRACE_SET_THREAD_AREA: | 531 | case PTRACE_SET_THREAD_AREA: |
609 | ret = ptrace_set_thread_area(child, addr, | 532 | if (addr < 0) |
610 | (struct user_desc __user *) data); | 533 | return -EIO; |
534 | ret = do_set_thread_area(child, addr, | ||
535 | (struct user_desc __user *) data, 0); | ||
611 | break; | 536 | break; |
612 | 537 | ||
613 | default: | 538 | default: |