From 13abd0e50433092c41551bc13c32268028b6d663 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 30 Jan 2008 13:30:45 +0100 Subject: x86: tls32 moved This renames arch/x86/ia32/tls32.c to arch/x86/kernel/tls.c, which does nothing now but paves the way to consolidate this code for 32-bit too. Signed-off-by: Roland McGrath Cc: Andrew Morton Cc: Zachary Amsden Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/tls.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 arch/x86/kernel/tls.c (limited to 'arch/x86/kernel/tls.c') diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c new file mode 100644 index 000000000000..5291596f19b0 --- /dev/null +++ b/arch/x86/kernel/tls.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * sys_alloc_thread_area: get a yet unused TLS descriptor index. + */ +static int get_free_idx(void) +{ + struct thread_struct *t = ¤t->thread; + int idx; + + for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) + if (desc_empty((struct n_desc_struct *)(t->tls_array) + idx)) + return idx + GDT_ENTRY_TLS_MIN; + return -ESRCH; +} + +/* + * Set a given TLS descriptor: + * When you want addresses > 32bit use arch_prctl() + */ +int do_set_thread_area(struct thread_struct *t, struct user_desc __user *u_info) +{ + struct user_desc info; + struct n_desc_struct *desc; + int cpu, idx; + + if (copy_from_user(&info, u_info, sizeof(info))) + return -EFAULT; + + idx = info.entry_number; + + /* + * index -1 means the kernel should try to find and + * allocate an empty descriptor: + */ + if (idx == -1) { + idx = get_free_idx(); + if (idx < 0) + return idx; + if (put_user(idx, &u_info->entry_number)) + return -EFAULT; + } + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN; + + /* + * We must not get preempted while modifying the TLS. + */ + cpu = get_cpu(); + + if (LDT_empty(&info)) { + desc->a = 0; + desc->b = 0; + } else { + desc->a = LDT_entry_a(&info); + desc->b = LDT_entry_b(&info); + } + if (t == ¤t->thread) + load_TLS(t, cpu); + + put_cpu(); + return 0; +} + +asmlinkage long sys32_set_thread_area(struct user_desc __user *u_info) +{ + return do_set_thread_area(¤t->thread, u_info); +} + + +/* + * Get the current Thread-Local Storage area: + */ + +#define GET_LIMIT(desc) ( \ + ((desc)->a & 0x0ffff) | \ + ((desc)->b & 0xf0000) ) + +#define GET_32BIT(desc) (((desc)->b >> 22) & 1) +#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) +#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) +#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) +#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) +#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) +#define GET_LONGMODE(desc) (((desc)->b >> 21) & 1) + +int do_get_thread_area(struct thread_struct *t, struct user_desc __user *u_info) +{ + struct user_desc info; + struct n_desc_struct *desc; + int idx; + + if (get_user(idx, &u_info->entry_number)) + return -EFAULT; + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN; + + memset(&info, 0, sizeof(struct user_desc)); + info.entry_number = idx; + info.base_addr = get_desc_base(desc); + info.limit = GET_LIMIT(desc); + info.seg_32bit = GET_32BIT(desc); + info.contents = GET_CONTENTS(desc); + info.read_exec_only = !GET_WRITABLE(desc); + info.limit_in_pages = GET_LIMIT_PAGES(desc); + info.seg_not_present = !GET_PRESENT(desc); + info.useable = GET_USEABLE(desc); + info.lm = GET_LONGMODE(desc); + + if (copy_to_user(u_info, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +asmlinkage long sys32_get_thread_area(struct user_desc __user *u_info) +{ + return do_get_thread_area(¤t->thread, u_info); +} + + +int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs) +{ + struct n_desc_struct *desc; + struct user_desc info; + struct user_desc __user *cp; + int idx; + + cp = (void __user *)childregs->rsi; + if (copy_from_user(&info, cp, sizeof(info))) + return -EFAULT; + if (LDT_empty(&info)) + return -EINVAL; + + idx = info.entry_number; + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = (struct n_desc_struct *)(p->thread.tls_array) + idx - GDT_ENTRY_TLS_MIN; + desc->a = LDT_entry_a(&info); + desc->b = LDT_entry_b(&info); + + return 0; +} -- cgit v1.2.3 From efd1ca52d04d2f6df337a3332cee56cd60e6d4c4 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 30 Jan 2008 13:30:46 +0100 Subject: 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 Cc: Andrew Morton Cc: Zachary Amsden Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/ia32/ia32entry.S | 4 +- arch/x86/kernel/Makefile_32 | 1 + arch/x86/kernel/process_32.c | 141 ++----------------------------------------- arch/x86/kernel/process_64.c | 3 +- arch/x86/kernel/ptrace_32.c | 91 +++------------------------- arch/x86/kernel/ptrace_64.c | 26 ++++---- arch/x86/kernel/tls.c | 96 ++++++++++++----------------- include/asm-x86/ia32.h | 6 -- include/asm-x86/ptrace.h | 11 ++++ 9 files changed, 77 insertions(+), 302 deletions(-) (limited to 'arch/x86/kernel/tls.c') diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 2499a324feaa..0db0a6291bbd 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -643,8 +643,8 @@ ia32_sys_call_table: .quad compat_sys_futex /* 240 */ .quad compat_sys_sched_setaffinity .quad compat_sys_sched_getaffinity - .quad sys32_set_thread_area - .quad sys32_get_thread_area + .quad sys_set_thread_area + .quad sys_get_thread_area .quad compat_sys_io_setup /* 245 */ .quad sys_io_destroy .quad compat_sys_io_getevents diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32 index 2c9596b9349c..9a6577a746ba 100644 --- a/arch/x86/kernel/Makefile_32 +++ b/arch/x86/kernel/Makefile_32 @@ -10,6 +10,7 @@ obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o rtc.o +obj-y += tls.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ obj-y += acpi/ diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 631af167bc51..4d66a56280d3 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -501,32 +501,15 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, set_tsk_thread_flag(p, TIF_IO_BITMAP); } + err = 0; + /* * Set a new TLS for the child thread? */ - if (clone_flags & CLONE_SETTLS) { - struct desc_struct *desc; - struct user_desc info; - int idx; - - err = -EFAULT; - if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info))) - goto out; - err = -EINVAL; - if (LDT_empty(&info)) - goto out; - - idx = info.entry_number; - if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) - goto out; - - desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; - desc->a = LDT_entry_a(&info); - desc->b = LDT_entry_b(&info); - } + if (clone_flags & CLONE_SETTLS) + err = do_set_thread_area(p, -1, + (struct user_desc __user *)childregs->esi, 0); - err = 0; - out: if (err && p->thread.io_bitmap_ptr) { kfree(p->thread.io_bitmap_ptr); p->thread.io_bitmap_max = 0; @@ -872,120 +855,6 @@ unsigned long get_wchan(struct task_struct *p) return 0; } -/* - * sys_alloc_thread_area: get a yet unused TLS descriptor index. - */ -static int get_free_idx(void) -{ - struct thread_struct *t = ¤t->thread; - int idx; - - for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) - if (desc_empty(t->tls_array + idx)) - return idx + GDT_ENTRY_TLS_MIN; - return -ESRCH; -} - -/* - * Set a given TLS descriptor: - */ -asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) -{ - struct thread_struct *t = ¤t->thread; - struct user_desc info; - struct desc_struct *desc; - int cpu, idx; - - if (copy_from_user(&info, u_info, sizeof(info))) - return -EFAULT; - idx = info.entry_number; - - /* - * index -1 means the kernel should try to find and - * allocate an empty descriptor: - */ - if (idx == -1) { - idx = get_free_idx(); - if (idx < 0) - return idx; - if (put_user(idx, &u_info->entry_number)) - return -EFAULT; - } - - if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) - return -EINVAL; - - desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN; - - /* - * We must not get preempted while modifying the TLS. - */ - cpu = get_cpu(); - - if (LDT_empty(&info)) { - desc->a = 0; - desc->b = 0; - } else { - desc->a = LDT_entry_a(&info); - desc->b = LDT_entry_b(&info); - } - load_TLS(t, cpu); - - put_cpu(); - - return 0; -} - -/* - * Get the current Thread-Local Storage area: - */ - -#define GET_BASE(desc) ( \ - (((desc)->a >> 16) & 0x0000ffff) | \ - (((desc)->b << 16) & 0x00ff0000) | \ - ( (desc)->b & 0xff000000) ) - -#define GET_LIMIT(desc) ( \ - ((desc)->a & 0x0ffff) | \ - ((desc)->b & 0xf0000) ) - -#define GET_32BIT(desc) (((desc)->b >> 22) & 1) -#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) -#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) -#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) -#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) -#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) - -asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) -{ - struct user_desc info; - struct desc_struct *desc; - int idx; - - if (get_user(idx, &u_info->entry_number)) - return -EFAULT; - if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) - return -EINVAL; - - memset(&info, 0, sizeof(info)); - - desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; - - info.entry_number = idx; - info.base_addr = GET_BASE(desc); - info.limit = GET_LIMIT(desc); - info.seg_32bit = GET_32BIT(desc); - info.contents = GET_CONTENTS(desc); - info.read_exec_only = !GET_WRITABLE(desc); - info.limit_in_pages = GET_LIMIT_PAGES(desc); - info.seg_not_present = !GET_PRESENT(desc); - info.useable = GET_USEABLE(desc); - - if (copy_to_user(u_info, &info, sizeof(info))) - return -EFAULT; - return 0; -} - unsigned long arch_align_stack(unsigned long sp) { if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 9ea1d7546f80..ccc9d68d5a58 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -524,7 +524,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, if (clone_flags & CLONE_SETTLS) { #ifdef CONFIG_IA32_EMULATION if (test_thread_flag(TIF_IA32)) - err = ia32_child_tls(p, childregs); + err = do_set_thread_area(p, -1, + (struct user_desc __user *)childregs->rsi, 0); else #endif err = do_arch_prctl(p, ARCH_SET_FS, childregs->r8); 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) clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); } -/* - * Perform get_thread_area on behalf of the traced child. - */ -static int -ptrace_get_thread_area(struct task_struct *child, - int idx, struct user_desc __user *user_desc) -{ - struct user_desc info; - struct desc_struct *desc; - -/* - * Get the current Thread-Local Storage area: - */ - -#define GET_BASE(desc) ( \ - (((desc)->a >> 16) & 0x0000ffff) | \ - (((desc)->b << 16) & 0x00ff0000) | \ - ( (desc)->b & 0xff000000) ) - -#define GET_LIMIT(desc) ( \ - ((desc)->a & 0x0ffff) | \ - ((desc)->b & 0xf0000) ) - -#define GET_32BIT(desc) (((desc)->b >> 22) & 1) -#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) -#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) -#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) -#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) -#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) - - if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) - return -EINVAL; - - desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; - - info.entry_number = idx; - info.base_addr = GET_BASE(desc); - info.limit = GET_LIMIT(desc); - info.seg_32bit = GET_32BIT(desc); - info.contents = GET_CONTENTS(desc); - info.read_exec_only = !GET_WRITABLE(desc); - info.limit_in_pages = GET_LIMIT_PAGES(desc); - info.seg_not_present = !GET_PRESENT(desc); - info.useable = GET_USEABLE(desc); - - if (copy_to_user(user_desc, &info, sizeof(info))) - return -EFAULT; - - return 0; -} - -/* - * Perform set_thread_area on behalf of the traced child. - */ -static int -ptrace_set_thread_area(struct task_struct *child, - int idx, struct user_desc __user *user_desc) -{ - struct user_desc info; - struct desc_struct *desc; - - if (copy_from_user(&info, user_desc, sizeof(info))) - return -EFAULT; - - if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) - return -EINVAL; - - desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; - if (LDT_empty(&info)) { - desc->a = 0; - desc->b = 0; - } else { - desc->a = LDT_entry_a(&info); - desc->b = LDT_entry_b(&info); - } - - return 0; -} - long arch_ptrace(struct task_struct *child, long request, long addr, long data) { struct user * dummy = NULL; @@ -601,13 +522,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } case PTRACE_GET_THREAD_AREA: - ret = ptrace_get_thread_area(child, addr, - (struct user_desc __user *) data); + if (addr < 0) + return -EIO; + ret = do_get_thread_area(child, addr, + (struct user_desc __user *) data); break; case PTRACE_SET_THREAD_AREA: - ret = ptrace_set_thread_area(child, addr, - (struct user_desc __user *) data); + if (addr < 0) + return -EIO; + ret = do_set_thread_area(child, addr, + (struct user_desc __user *) data, 0); break; default: diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c index 1edece36044c..375fadc23a25 100644 --- a/arch/x86/kernel/ptrace_64.c +++ b/arch/x86/kernel/ptrace_64.c @@ -474,23 +474,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) 64bit debugger to fully examine them too. Better don't use it against 64bit processes, use PTRACE_ARCH_PRCTL instead. */ - case PTRACE_SET_THREAD_AREA: { - struct user_desc __user *p; - int old; - p = (struct user_desc __user *)data; - get_user(old, &p->entry_number); - put_user(addr, &p->entry_number); - ret = do_set_thread_area(&child->thread, p); - put_user(old, &p->entry_number); - break; case PTRACE_GET_THREAD_AREA: - p = (struct user_desc __user *)data; - get_user(old, &p->entry_number); - put_user(addr, &p->entry_number); - ret = do_get_thread_area(&child->thread, p); - put_user(old, &p->entry_number); + if (addr < 0) + return -EIO; + ret = do_get_thread_area(child, addr, + (struct user_desc __user *) data); + + break; + case PTRACE_SET_THREAD_AREA: + if (addr < 0) + return -EIO; + ret = do_set_thread_area(child, addr, + (struct user_desc __user *) data, 0); break; - } #endif /* normal 64bit interface to access TLS data. Works just like arch_prctl, except that the arguments diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 5291596f19b0..67a377621b12 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -19,31 +19,34 @@ static int get_free_idx(void) int idx; for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) - if (desc_empty((struct n_desc_struct *)(t->tls_array) + idx)) + if (desc_empty(&t->tls_array[idx])) return idx + GDT_ENTRY_TLS_MIN; return -ESRCH; } /* * Set a given TLS descriptor: - * When you want addresses > 32bit use arch_prctl() */ -int do_set_thread_area(struct thread_struct *t, struct user_desc __user *u_info) +int do_set_thread_area(struct task_struct *p, int idx, + struct user_desc __user *u_info, + int can_allocate) { + struct thread_struct *t = &p->thread; struct user_desc info; - struct n_desc_struct *desc; - int cpu, idx; + u32 *desc; + int cpu; if (copy_from_user(&info, u_info, sizeof(info))) return -EFAULT; - idx = info.entry_number; + if (idx == -1) + idx = info.entry_number; /* * index -1 means the kernel should try to find and * allocate an empty descriptor: */ - if (idx == -1) { + if (idx == -1 && can_allocate) { idx = get_free_idx(); if (idx < 0) return idx; @@ -54,7 +57,7 @@ int do_set_thread_area(struct thread_struct *t, struct user_desc __user *u_info) if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; - desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN; + desc = (u32 *) &t->tls_array[idx - GDT_ENTRY_TLS_MIN]; /* * We must not get preempted while modifying the TLS. @@ -62,11 +65,11 @@ int do_set_thread_area(struct thread_struct *t, struct user_desc __user *u_info) cpu = get_cpu(); if (LDT_empty(&info)) { - desc->a = 0; - desc->b = 0; + desc[0] = 0; + desc[1] = 0; } else { - desc->a = LDT_entry_a(&info); - desc->b = LDT_entry_b(&info); + desc[0] = LDT_entry_a(&info); + desc[1] = LDT_entry_b(&info); } if (t == ¤t->thread) load_TLS(t, cpu); @@ -75,9 +78,9 @@ int do_set_thread_area(struct thread_struct *t, struct user_desc __user *u_info) return 0; } -asmlinkage long sys32_set_thread_area(struct user_desc __user *u_info) +asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) { - return do_set_thread_area(¤t->thread, u_info); + return do_set_thread_area(current, -1, u_info, 1); } @@ -85,34 +88,32 @@ asmlinkage long sys32_set_thread_area(struct user_desc __user *u_info) * Get the current Thread-Local Storage area: */ -#define GET_LIMIT(desc) ( \ - ((desc)->a & 0x0ffff) | \ - ((desc)->b & 0xf0000) ) - -#define GET_32BIT(desc) (((desc)->b >> 22) & 1) -#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) -#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) -#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) -#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) -#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) -#define GET_LONGMODE(desc) (((desc)->b >> 21) & 1) - -int do_get_thread_area(struct thread_struct *t, struct user_desc __user *u_info) +#define GET_LIMIT(desc) (((desc)[0] & 0x0ffff) | ((desc)[1] & 0xf0000)) +#define GET_32BIT(desc) (((desc)[1] >> 22) & 1) +#define GET_CONTENTS(desc) (((desc)[1] >> 10) & 3) +#define GET_WRITABLE(desc) (((desc)[1] >> 9) & 1) +#define GET_LIMIT_PAGES(desc) (((desc)[1] >> 23) & 1) +#define GET_PRESENT(desc) (((desc)[1] >> 15) & 1) +#define GET_USEABLE(desc) (((desc)[1] >> 20) & 1) +#define GET_LONGMODE(desc) (((desc)[1] >> 21) & 1) + +int do_get_thread_area(struct task_struct *p, int idx, + struct user_desc __user *u_info) { + struct thread_struct *t = &p->thread; struct user_desc info; - struct n_desc_struct *desc; - int idx; + u32 *desc; - if (get_user(idx, &u_info->entry_number)) + if (idx == -1 && get_user(idx, &u_info->entry_number)) return -EFAULT; if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; - desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN; + desc = (u32 *) &t->tls_array[idx - GDT_ENTRY_TLS_MIN]; memset(&info, 0, sizeof(struct user_desc)); info.entry_number = idx; - info.base_addr = get_desc_base(desc); + info.base_addr = get_desc_base((void *)desc); info.limit = GET_LIMIT(desc); info.seg_32bit = GET_32BIT(desc); info.contents = GET_CONTENTS(desc); @@ -120,39 +121,16 @@ int do_get_thread_area(struct thread_struct *t, struct user_desc __user *u_info) info.limit_in_pages = GET_LIMIT_PAGES(desc); info.seg_not_present = !GET_PRESENT(desc); info.useable = GET_USEABLE(desc); +#ifdef CONFIG_X86_64 info.lm = GET_LONGMODE(desc); +#endif if (copy_to_user(u_info, &info, sizeof(info))) return -EFAULT; return 0; } -asmlinkage long sys32_get_thread_area(struct user_desc __user *u_info) +asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) { - return do_get_thread_area(¤t->thread, u_info); -} - - -int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs) -{ - struct n_desc_struct *desc; - struct user_desc info; - struct user_desc __user *cp; - int idx; - - cp = (void __user *)childregs->rsi; - if (copy_from_user(&info, cp, sizeof(info))) - return -EFAULT; - if (LDT_empty(&info)) - return -EINVAL; - - idx = info.entry_number; - if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) - return -EINVAL; - - desc = (struct n_desc_struct *)(p->thread.tls_array) + idx - GDT_ENTRY_TLS_MIN; - desc->a = LDT_entry_a(&info); - desc->b = LDT_entry_b(&info); - - return 0; + return do_get_thread_area(current, -1, u_info); } diff --git a/include/asm-x86/ia32.h b/include/asm-x86/ia32.h index 0190b7c4e319..aa9733206e29 100644 --- a/include/asm-x86/ia32.h +++ b/include/asm-x86/ia32.h @@ -159,12 +159,6 @@ struct ustat32 { #define IA32_STACK_TOP IA32_PAGE_OFFSET #ifdef __KERNEL__ -struct user_desc; -struct siginfo_t; -int do_get_thread_area(struct thread_struct *t, struct user_desc __user *info); -int do_set_thread_area(struct thread_struct *t, struct user_desc __user *info); -int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs); - struct linux_binprm; extern int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int exec_stack); diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h index 51ddb2590870..105d1534eaf4 100644 --- a/include/asm-x86/ptrace.h +++ b/include/asm-x86/ptrace.h @@ -137,6 +137,17 @@ enum { }; #endif /* __KERNEL__ */ #endif /* !__i386__ */ + +#ifdef __KERNEL__ + +struct user_desc; +extern int do_get_thread_area(struct task_struct *p, int idx, + struct user_desc __user *info); +extern int do_set_thread_area(struct task_struct *p, int idx, + struct user_desc __user *info, int can_allocate); + +#endif /* __KERNEL__ */ + #endif /* !__ASSEMBLY__ */ #endif -- cgit v1.2.3 From 80fbb69a8d1268ef48dfe21da80e68cb01922f31 Mon Sep 17 00:00:00 2001 From: Glauber de Oliveira Costa Date: Wed, 30 Jan 2008 13:31:13 +0100 Subject: x86: introduce fill_ldt This patch introduces fill_ldt(), which populates a ldt descriptor from a user_desc in once, instead of relying in the LDT_entry_a and LDT_entry_b macros Signed-off-by: Glauber de Oliveira Costa Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/ldt.c | 3 +-- arch/x86/kernel/process_64.c | 3 +-- arch/x86/kernel/tls.c | 7 +++---- include/asm-x86/desc.h | 29 +++++++++++++++++++++++++++++ include/asm-x86/desc_32.h | 15 --------------- include/asm-x86/desc_64.h | 17 ----------------- 6 files changed, 34 insertions(+), 40 deletions(-) (limited to 'arch/x86/kernel/tls.c') diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index 7eb0c8a45734..3e872b468533 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -223,8 +223,7 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) } } - ldt.a = LDT_entry_a(&ldt_info); - ldt.b = LDT_entry_b(&ldt_info); + fill_ldt(&ldt, &ldt_info); if (oldmode) ldt.avl = 0; diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 86c310acc989..f91521e26335 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -457,8 +457,7 @@ static inline void set_32bit_tls(struct task_struct *t, int tls, u32 addr) }; struct desc_struct *desc = (void *)t->thread.tls_array; desc += tls; - desc->a = LDT_entry_a(&ud); - desc->b = LDT_entry_b(&ud); + fill_ldt(desc, &ud); } static inline u32 read_32bit_tls(struct task_struct *t, int tls) diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 67a377621b12..74d2b65a82eb 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -67,10 +67,9 @@ int do_set_thread_area(struct task_struct *p, int idx, if (LDT_empty(&info)) { desc[0] = 0; desc[1] = 0; - } else { - desc[0] = LDT_entry_a(&info); - desc[1] = LDT_entry_b(&info); - } + } else + fill_ldt((struct desc_struct *)desc, &info); + if (t == ¤t->thread) load_TLS(t, cpu); diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index 6065c5092265..47086d2d9298 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h @@ -1,5 +1,34 @@ +#ifndef _ASM_DESC_H_ +#define _ASM_DESC_H_ + +#ifndef __ASSEMBLY__ +#include +#include + +static inline void fill_ldt(struct desc_struct *desc, struct user_desc *info) +{ + desc->limit0 = info->limit & 0x0ffff; + desc->base0 = info->base_addr & 0x0000ffff; + + desc->base1 = (info->base_addr & 0x00ff0000) >> 16; + desc->type = (info->read_exec_only ^ 1) << 1; + desc->type |= info->contents << 2; + desc->s = 1; + desc->dpl = 0x3; + desc->p = info->seg_not_present ^ 1; + desc->limit = (info->limit & 0xf0000) >> 16; + desc->avl = info->useable; + desc->d = info->seg_32bit; + desc->g = info->limit_in_pages; + desc->base2 = (info->base_addr & 0xff000000) >> 24; +} + +#endif + #ifdef CONFIG_X86_32 # include "desc_32.h" #else # include "desc_64.h" #endif + +#endif diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 54b2314f2ddf..03700991c5db 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -163,21 +163,6 @@ static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const vo #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) -#define LDT_entry_a(info) \ - ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff)) - -#define LDT_entry_b(info) \ - (((info)->base_addr & 0xff000000) | \ - (((info)->base_addr & 0x00ff0000) >> 16) | \ - ((info)->limit & 0xf0000) | \ - (((info)->read_exec_only ^ 1) << 9) | \ - ((info)->contents << 10) | \ - (((info)->seg_not_present ^ 1) << 15) | \ - ((info)->seg_32bit << 22) | \ - ((info)->limit_in_pages << 23) | \ - ((info)->useable << 20) | \ - 0x7000) - #define LDT_empty(info) (\ (info)->base_addr == 0 && \ (info)->limit == 0 && \ diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index c49f928ed8b6..ba7fb87d10f3 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -147,23 +147,6 @@ static inline void set_ldt_desc(unsigned cpu, void *addr, int size) (unsigned long)addr, DESC_LDT, size * 8 - 1); } -#define LDT_entry_a(info) \ - ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff)) -/* Don't allow setting of the lm bit. It is useless anyways because - 64bit system calls require __USER_CS. */ -#define LDT_entry_b(info) \ - (((info)->base_addr & 0xff000000) | \ - (((info)->base_addr & 0x00ff0000) >> 16) | \ - ((info)->limit & 0xf0000) | \ - (((info)->read_exec_only ^ 1) << 9) | \ - ((info)->contents << 10) | \ - (((info)->seg_not_present ^ 1) << 15) | \ - ((info)->seg_32bit << 22) | \ - ((info)->limit_in_pages << 23) | \ - ((info)->useable << 20) | \ - /* ((info)->lm << 21) | */ \ - 0x7000) - #define LDT_empty(info) (\ (info)->base_addr == 0 && \ (info)->limit == 0 && \ -- cgit v1.2.3 From cc6978528cbd475d952e0eb5073375839dfb600e Mon Sep 17 00:00:00 2001 From: Glauber de Oliveira Costa Date: Wed, 30 Jan 2008 13:31:14 +0100 Subject: x86: modify get_desc_base This patch makes get_desc_base() receive a struct desc_struct, and then uses its internal fields to compute the base address. This is done at both i386 and x86_64, and then it is moved to common header Signed-off-by: Glauber de Oliveira Costa Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/tls.c | 2 +- arch/x86/mm/fault_32.c | 2 +- include/asm-x86/desc.h | 5 +++++ include/asm-x86/desc_32.h | 8 -------- include/asm-x86/desc_64.h | 9 --------- 5 files changed, 7 insertions(+), 19 deletions(-) (limited to 'arch/x86/kernel/tls.c') diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 74d2b65a82eb..98f428be8e8c 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -112,7 +112,7 @@ int do_get_thread_area(struct task_struct *p, int idx, memset(&info, 0, sizeof(struct user_desc)); info.entry_number = idx; - info.base_addr = get_desc_base((void *)desc); + info.base_addr = get_desc_base((struct desc_struct *)desc); info.limit = GET_LIMIT(desc); info.seg_32bit = GET_32BIT(desc); info.contents = GET_CONTENTS(desc); diff --git a/arch/x86/mm/fault_32.c b/arch/x86/mm/fault_32.c index 6056c6d71835..ef5ab2b925c4 100644 --- a/arch/x86/mm/fault_32.c +++ b/arch/x86/mm/fault_32.c @@ -115,7 +115,7 @@ static inline unsigned long get_segment_eip(struct pt_regs *regs, } /* Decode the code segment base from the descriptor */ - base = get_desc_base((unsigned long *)desc); + base = get_desc_base((struct desc_struct *)desc); if (seg & (1<<2)) { mutex_unlock(¤t->mm->context.lock); diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index 99c4adc851e2..a6fdd7c7b6b2 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h @@ -69,6 +69,11 @@ static inline void load_LDT(mm_context_t *pc) preempt_enable(); } +static inline unsigned long get_desc_base(struct desc_struct *desc) +{ + return desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24); +} + #else /* * GET_DESC_BASE reads the descriptor base of the specified segment. diff --git a/include/asm-x86/desc_32.h b/include/asm-x86/desc_32.h index 01415ad35fdf..8450c2a99c3a 100644 --- a/include/asm-x86/desc_32.h +++ b/include/asm-x86/desc_32.h @@ -168,14 +168,6 @@ static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const vo #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) -static inline unsigned long get_desc_base(unsigned long *desc) -{ - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} #endif /* !__ASSEMBLY__ */ #endif diff --git a/include/asm-x86/desc_64.h b/include/asm-x86/desc_64.h index 448f96ed973f..a7a6c301c6bc 100644 --- a/include/asm-x86/desc_64.h +++ b/include/asm-x86/desc_64.h @@ -156,15 +156,6 @@ static inline void load_TLS(struct thread_struct *t, unsigned int cpu) gdt[i] = t->tls_array[i]; } -static inline unsigned long get_desc_base(const void *ptr) -{ - const u32 *desc = ptr; - unsigned long base; - base = ((desc[0] >> 16) & 0x0000ffff) | - ((desc[1] << 16) & 0x00ff0000) | - (desc[1] & 0xff000000); - return base; -} #endif /* !__ASSEMBLY__ */ #endif -- cgit v1.2.3 From 1bd5718ce58fb49ac158653380fa200f4759daad Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 30 Jan 2008 13:31:51 +0100 Subject: x86: x86 TLS desc_struct cleanup This cleans up the TLS code to use struct desc_struct and to separate the encoding and installation magic from the interface wrappers. Signed-off-by: Roland McGrath Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/tls.c | 89 +++++++++++++++++++++++++------------------------- include/asm-x86/desc.h | 11 +++++-- 2 files changed, 54 insertions(+), 46 deletions(-) (limited to 'arch/x86/kernel/tls.c') diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 98f428be8e8c..f11c92a3faac 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -24,6 +24,29 @@ static int get_free_idx(void) return -ESRCH; } +static void set_tls_desc(struct task_struct *p, int idx, + const struct user_desc *info) +{ + struct thread_struct *t = &p->thread; + struct desc_struct *desc = &t->tls_array[idx - GDT_ENTRY_TLS_MIN]; + int cpu; + + /* + * We must not get preempted while modifying the TLS. + */ + cpu = get_cpu(); + + if (LDT_empty(info)) + desc->a = desc->b = 0; + else + fill_ldt(desc, info); + + if (t == ¤t->thread) + load_TLS(t, cpu); + + put_cpu(); +} + /* * Set a given TLS descriptor: */ @@ -31,10 +54,7 @@ int do_set_thread_area(struct task_struct *p, int idx, struct user_desc __user *u_info, int can_allocate) { - struct thread_struct *t = &p->thread; struct user_desc info; - u32 *desc; - int cpu; if (copy_from_user(&info, u_info, sizeof(info))) return -EFAULT; @@ -57,23 +77,8 @@ int do_set_thread_area(struct task_struct *p, int idx, if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; - desc = (u32 *) &t->tls_array[idx - GDT_ENTRY_TLS_MIN]; + set_tls_desc(p, idx, &info); - /* - * We must not get preempted while modifying the TLS. - */ - cpu = get_cpu(); - - if (LDT_empty(&info)) { - desc[0] = 0; - desc[1] = 0; - } else - fill_ldt((struct desc_struct *)desc, &info); - - if (t == ¤t->thread) - load_TLS(t, cpu); - - put_cpu(); return 0; } @@ -87,42 +92,38 @@ asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) * Get the current Thread-Local Storage area: */ -#define GET_LIMIT(desc) (((desc)[0] & 0x0ffff) | ((desc)[1] & 0xf0000)) -#define GET_32BIT(desc) (((desc)[1] >> 22) & 1) -#define GET_CONTENTS(desc) (((desc)[1] >> 10) & 3) -#define GET_WRITABLE(desc) (((desc)[1] >> 9) & 1) -#define GET_LIMIT_PAGES(desc) (((desc)[1] >> 23) & 1) -#define GET_PRESENT(desc) (((desc)[1] >> 15) & 1) -#define GET_USEABLE(desc) (((desc)[1] >> 20) & 1) -#define GET_LONGMODE(desc) (((desc)[1] >> 21) & 1) +static void fill_user_desc(struct user_desc *info, int idx, + const struct desc_struct *desc) + +{ + memset(info, 0, sizeof(*info)); + info->entry_number = idx; + info->base_addr = get_desc_base(desc); + info->limit = get_desc_limit(desc); + info->seg_32bit = desc->d; + info->contents = desc->type >> 2; + info->read_exec_only = !(desc->type & 2); + info->limit_in_pages = desc->g; + info->seg_not_present = !desc->p; + info->useable = desc->avl; +#ifdef CONFIG_X86_64 + info->lm = desc->l; +#endif +} int do_get_thread_area(struct task_struct *p, int idx, struct user_desc __user *u_info) { - struct thread_struct *t = &p->thread; struct user_desc info; - u32 *desc; if (idx == -1 && get_user(idx, &u_info->entry_number)) return -EFAULT; + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; - desc = (u32 *) &t->tls_array[idx - GDT_ENTRY_TLS_MIN]; - - memset(&info, 0, sizeof(struct user_desc)); - info.entry_number = idx; - info.base_addr = get_desc_base((struct desc_struct *)desc); - info.limit = GET_LIMIT(desc); - info.seg_32bit = GET_32BIT(desc); - info.contents = GET_CONTENTS(desc); - info.read_exec_only = !GET_WRITABLE(desc); - info.limit_in_pages = GET_LIMIT_PAGES(desc); - info.seg_not_present = !GET_PRESENT(desc); - info.useable = GET_USEABLE(desc); -#ifdef CONFIG_X86_64 - info.lm = GET_LONGMODE(desc); -#endif + fill_user_desc(&info, idx, + &p->thread.tls_array[idx - GDT_ENTRY_TLS_MIN]); if (copy_to_user(u_info, &info, sizeof(info))) return -EFAULT; diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index e17581ad8824..5b6a05d3a771 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h @@ -7,7 +7,8 @@ #include #include -static inline void fill_ldt(struct desc_struct *desc, struct user_desc *info) +static inline void fill_ldt(struct desc_struct *desc, + const struct user_desc *info) { desc->limit0 = info->limit & 0x0ffff; desc->base0 = info->base_addr & 0x0000ffff; @@ -275,10 +276,16 @@ static inline void load_LDT(mm_context_t *pc) preempt_enable(); } -static inline unsigned long get_desc_base(struct desc_struct *desc) +static inline unsigned long get_desc_base(const struct desc_struct *desc) { return desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24); } + +static inline unsigned long get_desc_limit(const struct desc_struct *desc) +{ + return desc->limit0 | (desc->limit << 16); +} + static inline void _set_gate(int gate, unsigned type, void *addr, unsigned dpl, unsigned ist, unsigned seg) { -- cgit v1.2.3 From 4c79a2d8e5b7e0a2f987ace9b6af9e7a1655447b Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 30 Jan 2008 13:31:52 +0100 Subject: x86: x86 user_regset TLS This adds accessor functions in the user_regset style for the TLS data. Signed-off-by: Roland McGrath Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/tls.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++---- arch/x86/kernel/tls.h | 21 ++++++++++++ 2 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 arch/x86/kernel/tls.h (limited to 'arch/x86/kernel/tls.c') diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index f11c92a3faac..6dfd4e76661a 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -10,6 +11,8 @@ #include #include +#include "tls.h" + /* * sys_alloc_thread_area: get a yet unused TLS descriptor index. */ @@ -25,7 +28,7 @@ static int get_free_idx(void) } static void set_tls_desc(struct task_struct *p, int idx, - const struct user_desc *info) + const struct user_desc *info, int n) { struct thread_struct *t = &p->thread; struct desc_struct *desc = &t->tls_array[idx - GDT_ENTRY_TLS_MIN]; @@ -36,10 +39,14 @@ static void set_tls_desc(struct task_struct *p, int idx, */ cpu = get_cpu(); - if (LDT_empty(info)) - desc->a = desc->b = 0; - else - fill_ldt(desc, info); + while (n-- > 0) { + if (LDT_empty(info)) + desc->a = desc->b = 0; + else + fill_ldt(desc, info); + ++info; + ++desc; + } if (t == ¤t->thread) load_TLS(t, cpu); @@ -77,7 +84,7 @@ int do_set_thread_area(struct task_struct *p, int idx, if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; - set_tls_desc(p, idx, &info); + set_tls_desc(p, idx, &info, 1); return 0; } @@ -134,3 +141,73 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) { return do_get_thread_area(current, -1, u_info); } + +int regset_tls_active(struct task_struct *target, + const struct user_regset *regset) +{ + struct thread_struct *t = &target->thread; + int n = GDT_ENTRY_TLS_ENTRIES; + while (n > 0 && desc_empty(&t->tls_array[n - 1])) + --n; + return n; +} + +int regset_tls_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const struct desc_struct *tls; + + if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || + (pos % sizeof(struct user_desc)) != 0 || + (count % sizeof(struct user_desc)) != 0) + return -EINVAL; + + pos /= sizeof(struct user_desc); + count /= sizeof(struct user_desc); + + tls = &target->thread.tls_array[pos]; + + if (kbuf) { + struct user_desc *info = kbuf; + while (count-- > 0) + fill_user_desc(info++, GDT_ENTRY_TLS_MIN + pos++, + tls++); + } else { + struct user_desc __user *u_info = ubuf; + while (count-- > 0) { + struct user_desc info; + fill_user_desc(&info, GDT_ENTRY_TLS_MIN + pos++, tls++); + if (__copy_to_user(u_info++, &info, sizeof(info))) + return -EFAULT; + } + } + + return 0; +} + +int regset_tls_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES]; + const struct user_desc *info; + + if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || + (pos % sizeof(struct user_desc)) != 0 || + (count % sizeof(struct user_desc)) != 0) + return -EINVAL; + + if (kbuf) + info = kbuf; + else if (__copy_from_user(infobuf, ubuf, count)) + return -EFAULT; + else + info = infobuf; + + set_tls_desc(target, + GDT_ENTRY_TLS_MIN + (pos / sizeof(struct user_desc)), + info, count / sizeof(struct user_desc)); + + return 0; +} diff --git a/arch/x86/kernel/tls.h b/arch/x86/kernel/tls.h new file mode 100644 index 000000000000..2f083a2fe216 --- /dev/null +++ b/arch/x86/kernel/tls.h @@ -0,0 +1,21 @@ +/* + * Internal declarations for x86 TLS implementation functions. + * + * Copyright (C) 2007 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * Red Hat Author: Roland McGrath. + */ + +#ifndef _ARCH_X86_KERNEL_TLS_H + +#include + +extern user_regset_active_fn regset_tls_active; +extern user_regset_get_fn regset_tls_get; +extern user_regset_set_fn regset_tls_set; + +#endif /* _ARCH_X86_KERNEL_TLS_H */ -- cgit v1.2.3