Commit 4c79a2d8e5b7e0a2f987ace9b6af9e7a1655447b

Authored by Roland McGrath
Committed by Ingo Molnar
1 parent 1bd5718ce5

x86: x86 user_regset TLS

This adds accessor functions in the user_regset style for the TLS data.

Signed-off-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Showing 2 changed files with 104 additions and 6 deletions Side-by-side Diff

arch/x86/kernel/tls.c
... ... @@ -2,6 +2,7 @@
2 2 #include <linux/errno.h>
3 3 #include <linux/sched.h>
4 4 #include <linux/user.h>
  5 +#include <linux/regset.h>
5 6  
6 7 #include <asm/uaccess.h>
7 8 #include <asm/desc.h>
... ... @@ -10,6 +11,8 @@
10 11 #include <asm/processor.h>
11 12 #include <asm/proto.h>
12 13  
  14 +#include "tls.h"
  15 +
13 16 /*
14 17 * sys_alloc_thread_area: get a yet unused TLS descriptor index.
15 18 */
... ... @@ -25,7 +28,7 @@
25 28 }
26 29  
27 30 static void set_tls_desc(struct task_struct *p, int idx,
28   - const struct user_desc *info)
  31 + const struct user_desc *info, int n)
29 32 {
30 33 struct thread_struct *t = &p->thread;
31 34 struct desc_struct *desc = &t->tls_array[idx - GDT_ENTRY_TLS_MIN];
... ... @@ -36,10 +39,14 @@
36 39 */
37 40 cpu = get_cpu();
38 41  
39   - if (LDT_empty(info))
40   - desc->a = desc->b = 0;
41   - else
42   - fill_ldt(desc, info);
  42 + while (n-- > 0) {
  43 + if (LDT_empty(info))
  44 + desc->a = desc->b = 0;
  45 + else
  46 + fill_ldt(desc, info);
  47 + ++info;
  48 + ++desc;
  49 + }
43 50  
44 51 if (t == &current->thread)
45 52 load_TLS(t, cpu);
... ... @@ -77,7 +84,7 @@
77 84 if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
78 85 return -EINVAL;
79 86  
80   - set_tls_desc(p, idx, &info);
  87 + set_tls_desc(p, idx, &info, 1);
81 88  
82 89 return 0;
83 90 }
... ... @@ -133,5 +140,75 @@
133 140 asmlinkage int sys_get_thread_area(struct user_desc __user *u_info)
134 141 {
135 142 return do_get_thread_area(current, -1, u_info);
  143 +}
  144 +
  145 +int regset_tls_active(struct task_struct *target,
  146 + const struct user_regset *regset)
  147 +{
  148 + struct thread_struct *t = &target->thread;
  149 + int n = GDT_ENTRY_TLS_ENTRIES;
  150 + while (n > 0 && desc_empty(&t->tls_array[n - 1]))
  151 + --n;
  152 + return n;
  153 +}
  154 +
  155 +int regset_tls_get(struct task_struct *target, const struct user_regset *regset,
  156 + unsigned int pos, unsigned int count,
  157 + void *kbuf, void __user *ubuf)
  158 +{
  159 + const struct desc_struct *tls;
  160 +
  161 + if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
  162 + (pos % sizeof(struct user_desc)) != 0 ||
  163 + (count % sizeof(struct user_desc)) != 0)
  164 + return -EINVAL;
  165 +
  166 + pos /= sizeof(struct user_desc);
  167 + count /= sizeof(struct user_desc);
  168 +
  169 + tls = &target->thread.tls_array[pos];
  170 +
  171 + if (kbuf) {
  172 + struct user_desc *info = kbuf;
  173 + while (count-- > 0)
  174 + fill_user_desc(info++, GDT_ENTRY_TLS_MIN + pos++,
  175 + tls++);
  176 + } else {
  177 + struct user_desc __user *u_info = ubuf;
  178 + while (count-- > 0) {
  179 + struct user_desc info;
  180 + fill_user_desc(&info, GDT_ENTRY_TLS_MIN + pos++, tls++);
  181 + if (__copy_to_user(u_info++, &info, sizeof(info)))
  182 + return -EFAULT;
  183 + }
  184 + }
  185 +
  186 + return 0;
  187 +}
  188 +
  189 +int regset_tls_set(struct task_struct *target, const struct user_regset *regset,
  190 + unsigned int pos, unsigned int count,
  191 + const void *kbuf, const void __user *ubuf)
  192 +{
  193 + struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES];
  194 + const struct user_desc *info;
  195 +
  196 + if (pos > GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
  197 + (pos % sizeof(struct user_desc)) != 0 ||
  198 + (count % sizeof(struct user_desc)) != 0)
  199 + return -EINVAL;
  200 +
  201 + if (kbuf)
  202 + info = kbuf;
  203 + else if (__copy_from_user(infobuf, ubuf, count))
  204 + return -EFAULT;
  205 + else
  206 + info = infobuf;
  207 +
  208 + set_tls_desc(target,
  209 + GDT_ENTRY_TLS_MIN + (pos / sizeof(struct user_desc)),
  210 + info, count / sizeof(struct user_desc));
  211 +
  212 + return 0;
136 213 }
arch/x86/kernel/tls.h
  1 +/*
  2 + * Internal declarations for x86 TLS implementation functions.
  3 + *
  4 + * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
  5 + *
  6 + * This copyrighted material is made available to anyone wishing to use,
  7 + * modify, copy, or redistribute it subject to the terms and conditions
  8 + * of the GNU General Public License v.2.
  9 + *
  10 + * Red Hat Author: Roland McGrath.
  11 + */
  12 +
  13 +#ifndef _ARCH_X86_KERNEL_TLS_H
  14 +
  15 +#include <linux/regset.h>
  16 +
  17 +extern user_regset_active_fn regset_tls_active;
  18 +extern user_regset_get_fn regset_tls_get;
  19 +extern user_regset_set_fn regset_tls_set;
  20 +
  21 +#endif /* _ARCH_X86_KERNEL_TLS_H */