aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/include/os.h4
-rw-r--r--arch/um/kernel/exec_kern.c12
-rw-r--r--arch/um/kernel/process_kern.c20
-rw-r--r--arch/um/kernel/ptrace.c10
-rw-r--r--arch/um/kernel/skas/process_kern.c2
-rw-r--r--arch/um/os-Linux/Makefile4
-rw-r--r--arch/um/os-Linux/tls.c77
-rw-r--r--arch/um/sys-i386/Makefile3
-rw-r--r--arch/um/sys-i386/ptrace.c2
-rw-r--r--arch/um/sys-i386/sys_call_table.S2
-rw-r--r--arch/um/sys-i386/syscalls.c14
-rw-r--r--arch/um/sys-i386/tls.c326
-rw-r--r--arch/um/sys-x86_64/Makefile3
-rw-r--r--arch/um/sys-x86_64/tls.c14
-rw-r--r--include/asm-um/desc.h12
-rw-r--r--include/asm-um/processor-i386.h35
-rw-r--r--include/asm-um/processor-x86_64.h9
-rw-r--r--include/asm-um/ptrace-generic.h14
-rw-r--r--include/asm-um/ptrace-i386.h41
-rw-r--r--include/asm-um/ptrace-x86_64.h35
-rw-r--r--include/asm-um/segment.h2
21 files changed, 580 insertions, 61 deletions
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 5fb84e889b2..e9e1db1e08d 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -236,6 +236,10 @@ extern int run_helper_thread(int (*proc)(void *), void *arg,
236 int stack_order); 236 int stack_order);
237extern int helper_wait(int pid); 237extern int helper_wait(int pid);
238 238
239
240/* tls.c */
241extern int os_set_thread_area(void *data, int pid);
242extern int os_get_thread_area(void *data, int pid);
239/* umid.c */ 243/* umid.c */
240 244
241extern int umid_file_name(char *name, char *buf, int len); 245extern int umid_file_name(char *name, char *buf, int len);
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
index f9b346e05b0..c0cb627bf59 100644
--- a/arch/um/kernel/exec_kern.c
+++ b/arch/um/kernel/exec_kern.c
@@ -22,6 +22,7 @@
22 22
23void flush_thread(void) 23void flush_thread(void)
24{ 24{
25 arch_flush_thread(&current->thread.arch);
25 CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); 26 CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
26} 27}
27 28
@@ -74,14 +75,3 @@ long sys_execve(char __user *file, char __user *__user *argv,
74 unlock_kernel(); 75 unlock_kernel();
75 return(error); 76 return(error);
76} 77}
77
78/*
79 * Overrides for Emacs so that we follow Linus's tabbing style.
80 * Emacs will notice this stuff at the end of the file and automatically
81 * adjust the settings for this buffer only. This must remain at the end
82 * of the file.
83 * ---------------------------------------------------------------------------
84 * Local variables:
85 * c-file-style: "linux"
86 * End:
87 */
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index ba8a52c1f7a..f6a5a502120 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -156,9 +156,25 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
156 unsigned long stack_top, struct task_struct * p, 156 unsigned long stack_top, struct task_struct * p,
157 struct pt_regs *regs) 157 struct pt_regs *regs)
158{ 158{
159 int ret;
160
159 p->thread = (struct thread_struct) INIT_THREAD; 161 p->thread = (struct thread_struct) INIT_THREAD;
160 return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, 162 ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
161 clone_flags, sp, stack_top, p, regs)); 163 clone_flags, sp, stack_top, p, regs);
164
165 if (ret || !current->thread.forking)
166 goto out;
167
168 clear_flushed_tls(p);
169
170 /*
171 * Set a new TLS for the child thread?
172 */
173 if (clone_flags & CLONE_SETTLS)
174 ret = arch_copy_tls(p);
175
176out:
177 return ret;
162} 178}
163 179
164void initial_thread_cb(void (*proc)(void *), void *arg) 180void initial_thread_cb(void (*proc)(void *), void *arg)
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index 394582202ce..60d2eda995c 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -185,6 +185,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
185 ret = set_fpxregs(data, child); 185 ret = set_fpxregs(data, child);
186 break; 186 break;
187#endif 187#endif
188 case PTRACE_GET_THREAD_AREA:
189 ret = ptrace_get_thread_area(child, addr,
190 (struct user_desc __user *) data);
191 break;
192
193 case PTRACE_SET_THREAD_AREA:
194 ret = ptrace_set_thread_area(child, addr,
195 (struct user_desc __user *) data);
196 break;
197
188 case PTRACE_FAULTINFO: { 198 case PTRACE_FAULTINFO: {
189 /* Take the info from thread->arch->faultinfo, 199 /* Take the info from thread->arch->faultinfo,
190 * but transfer max. sizeof(struct ptrace_faultinfo). 200 * but transfer max. sizeof(struct ptrace_faultinfo).
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index 14360ac17f0..38b185370c4 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -111,6 +111,8 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
111 if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; 111 if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
112 112
113 handler = fork_handler; 113 handler = fork_handler;
114
115 arch_copy_thread(&current->thread.arch, &p->thread.arch);
114 } 116 }
115 else { 117 else {
116 init_thread_registers(&p->thread.regs.regs); 118 init_thread_registers(&p->thread.regs.regs);
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index 9e0788cf3ae..f4bfc4c7cca 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -4,7 +4,7 @@
4# 4#
5 5
6obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ 6obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \
7 signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \ 7 signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o tls.o \
8 user_syms.o util.o drivers/ sys-$(SUBARCH)/ 8 user_syms.o util.o drivers/ sys-$(SUBARCH)/
9 9
10obj-$(CONFIG_MODE_SKAS) += skas/ 10obj-$(CONFIG_MODE_SKAS) += skas/
@@ -12,7 +12,7 @@ obj-$(CONFIG_TTY_LOG) += tty_log.o
12user-objs-$(CONFIG_TTY_LOG) += tty_log.o 12user-objs-$(CONFIG_TTY_LOG) += tty_log.o
13 13
14USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ 14USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \
15 process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o \ 15 process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o tls.o \
16 uaccess.o umid.o util.o 16 uaccess.o umid.o util.o
17 17
18CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) 18CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c
new file mode 100644
index 00000000000..63dfcf70937
--- /dev/null
+++ b/arch/um/os-Linux/tls.c
@@ -0,0 +1,77 @@
1#include <errno.h>
2#include <sys/ptrace.h>
3#include <asm/ldt.h>
4#include "uml-config.h"
5
6/* TLS support - we basically rely on the host's one.*/
7
8/* In TT mode, this should be called only by the tracing thread, and makes sense
9 * only for PTRACE_SET_THREAD_AREA. In SKAS mode, it's used normally.
10 *
11 */
12
13#ifndef PTRACE_GET_THREAD_AREA
14#define PTRACE_GET_THREAD_AREA 25
15#endif
16
17#ifndef PTRACE_SET_THREAD_AREA
18#define PTRACE_SET_THREAD_AREA 26
19#endif
20
21int os_set_thread_area(void *data, int pid)
22{
23 struct user_desc *info = data;
24 int ret;
25
26 ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number,
27 (unsigned long) info);
28 if (ret < 0)
29 ret = -errno;
30 return ret;
31}
32
33#ifdef UML_CONFIG_MODE_SKAS
34
35int os_get_thread_area(void *data, int pid)
36{
37 struct user_desc *info = data;
38 int ret;
39
40 ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number,
41 (unsigned long) info);
42 if (ret < 0)
43 ret = -errno;
44 return ret;
45}
46
47#endif
48
49#ifdef UML_CONFIG_MODE_TT
50#include "linux/unistd.h"
51
52_syscall1(int, get_thread_area, struct user_desc *, u_info);
53_syscall1(int, set_thread_area, struct user_desc *, u_info);
54
55int do_set_thread_area_tt(struct user_desc *info)
56{
57 int ret;
58
59 ret = set_thread_area(info);
60 if (ret < 0) {
61 ret = -errno;
62 }
63 return ret;
64}
65
66int do_get_thread_area_tt(struct user_desc *info)
67{
68 int ret;
69
70 ret = get_thread_area(info);
71 if (ret < 0) {
72 ret = -errno;
73 }
74 return ret;
75}
76
77#endif /* UML_CONFIG_MODE_TT */
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 2c06a07a1bd..98b20b7bba4 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,5 +1,6 @@
1obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ 1obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
2 ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o sys_call_table.o 2 ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o \
3 sys_call_table.o tls.o
3 4
4obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o 5obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
5 6
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index 927fcd95565..6a23cc6947c 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -18,10 +18,12 @@
18void arch_switch_to_tt(struct task_struct *from, struct task_struct *to) 18void arch_switch_to_tt(struct task_struct *from, struct task_struct *to)
19{ 19{
20 update_debugregs(to->thread.arch.debugregs_seq); 20 update_debugregs(to->thread.arch.debugregs_seq);
21 arch_switch_tls_tt(from, to);
21} 22}
22 23
23void arch_switch_to_skas(struct task_struct *from, struct task_struct *to) 24void arch_switch_to_skas(struct task_struct *from, struct task_struct *to)
24{ 25{
26 arch_switch_tls_skas(from, to);
25} 27}
26 28
27int is_syscall(unsigned long addr) 29int is_syscall(unsigned long addr)
diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S
index ad75c27afe3..1ff61474b25 100644
--- a/arch/um/sys-i386/sys_call_table.S
+++ b/arch/um/sys-i386/sys_call_table.S
@@ -6,8 +6,6 @@
6 6
7#define sys_vm86old sys_ni_syscall 7#define sys_vm86old sys_ni_syscall
8#define sys_vm86 sys_ni_syscall 8#define sys_vm86 sys_ni_syscall
9#define sys_set_thread_area sys_ni_syscall
10#define sys_get_thread_area sys_ni_syscall
11 9
12#define sys_stime um_stime 10#define sys_stime um_stime
13#define sys_time um_time 11#define sys_time um_time
diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c
index 1845123ed12..749dd1bfe60 100644
--- a/arch/um/sys-i386/syscalls.c
+++ b/arch/um/sys-i386/syscalls.c
@@ -61,21 +61,27 @@ long old_select(struct sel_arg_struct __user *arg)
61 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); 61 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
62} 62}
63 63
64/* The i386 version skips reading from %esi, the fourth argument. So we must do 64/*
65 * this, too. 65 * The prototype on i386 is:
66 *
67 * int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr)
68 *
69 * and the "newtls" arg. on i386 is read by copy_thread directly from the
70 * register saved on the stack.
66 */ 71 */
67long sys_clone(unsigned long clone_flags, unsigned long newsp, 72long sys_clone(unsigned long clone_flags, unsigned long newsp,
68 int __user *parent_tid, int unused, int __user *child_tid) 73 int __user *parent_tid, void *newtls, int __user *child_tid)
69{ 74{
70 long ret; 75 long ret;
71 76
72 if (!newsp) 77 if (!newsp)
73 newsp = UPT_SP(&current->thread.regs.regs); 78 newsp = UPT_SP(&current->thread.regs.regs);
79
74 current->thread.forking = 1; 80 current->thread.forking = 1;
75 ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid, 81 ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
76 child_tid); 82 child_tid);
77 current->thread.forking = 0; 83 current->thread.forking = 0;
78 return(ret); 84 return ret;
79} 85}
80 86
81/* 87/*
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
new file mode 100644
index 00000000000..e3c5bc593fa
--- /dev/null
+++ b/arch/um/sys-i386/tls.c
@@ -0,0 +1,326 @@
1/*
2 * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/kernel.h"
8#include "linux/sched.h"
9#include "linux/slab.h"
10#include "linux/types.h"
11#include "asm/uaccess.h"
12#include "asm/ptrace.h"
13#include "asm/segment.h"
14#include "asm/smp.h"
15#include "asm/desc.h"
16#include "choose-mode.h"
17#include "kern.h"
18#include "kern_util.h"
19#include "mode_kern.h"
20#include "os.h"
21#include "mode.h"
22
23#ifdef CONFIG_MODE_SKAS
24#include "skas.h"
25#endif
26
27#ifdef CONFIG_MODE_SKAS
28int do_set_thread_area_skas(struct user_desc *info)
29{
30 int ret;
31 u32 cpu;
32
33 cpu = get_cpu();
34 ret = os_set_thread_area(info, userspace_pid[cpu]);
35 put_cpu();
36 return ret;
37}
38
39int do_get_thread_area_skas(struct user_desc *info)
40{
41 int ret;
42 u32 cpu;
43
44 cpu = get_cpu();
45 ret = os_get_thread_area(info, userspace_pid[cpu]);
46 put_cpu();
47 return ret;
48}
49#endif
50
51/*
52 * sys_get_thread_area: get a yet unused TLS descriptor index.
53 * XXX: Consider leaving one free slot for glibc usage at first place. This must
54 * be done here (and by changing GDT_ENTRY_TLS_* macros) and nowhere else.
55 *
56 * Also, this must be tested when compiling in SKAS mode with dinamic linking
57 * and running against NPTL.
58 */
59static int get_free_idx(struct task_struct* task)
60{
61 struct thread_struct *t = &task->thread;
62 int idx;
63
64 if (!t->arch.tls_array)
65 return GDT_ENTRY_TLS_MIN;
66
67 for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
68 if (!t->arch.tls_array[idx].present)
69 return idx + GDT_ENTRY_TLS_MIN;
70 return -ESRCH;
71}
72
73#define O_FORCE 1
74
75static inline void clear_user_desc(struct user_desc* info)
76{
77 /* Postcondition: LDT_empty(info) returns true. */
78 memset(info, 0, sizeof(*info));
79
80 /* Check the LDT_empty or the i386 sys_get_thread_area code - we obtain
81 * indeed an empty user_desc.
82 */
83 info->read_exec_only = 1;
84 info->seg_not_present = 1;
85}
86
87static int load_TLS(int flags, struct task_struct *to)
88{
89 int ret = 0;
90 int idx;
91
92 for (idx = GDT_ENTRY_TLS_MIN; idx < GDT_ENTRY_TLS_MAX; idx++) {
93 struct uml_tls_struct* curr = &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN];
94
95 /* Actually, now if it wasn't flushed it gets cleared and
96 * flushed to the host, which will clear it.*/
97 if (!curr->present) {
98 if (!curr->flushed) {
99 clear_user_desc(&curr->tls);
100 curr->tls.entry_number = idx;
101 } else {
102 WARN_ON(!LDT_empty(&curr->tls));
103 continue;
104 }
105 }
106
107 if (!(flags & O_FORCE) && curr->flushed)
108 continue;
109
110 ret = do_set_thread_area(&curr->tls);
111 if (ret)
112 goto out;
113
114 curr->flushed = 1;
115 }
116out:
117 return ret;
118}
119
120/* Verify if we need to do a flush for the new process, i.e. if there are any
121 * present desc's, only if they haven't been flushed.
122 */
123static inline int needs_TLS_update(struct task_struct *task)
124{
125 int i;
126 int ret = 0;
127
128 for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) {
129 struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN];
130
131 /* Can't test curr->present, we may need to clear a descriptor
132 * which had a value. */
133 if (curr->flushed)
134 continue;
135 ret = 1;
136 break;
137 }
138 return ret;
139}
140
141/* On a newly forked process, the TLS descriptors haven't yet been flushed. So
142 * we mark them as such and the first switch_to will do the job.
143 */
144void clear_flushed_tls(struct task_struct *task)
145{
146 int i;
147
148 for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) {
149 struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN];
150
151 /* Still correct to do this, if it wasn't present on the host it
152 * will remain as flushed as it was. */
153 if (!curr->present)
154 continue;
155
156 curr->flushed = 0;
157 }
158}
159
160/* This in SKAS0 does not need to be used, since we have different host
161 * processes. Nor will this need to be used when we'll add support to the host
162 * SKAS patch. */
163int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to)
164{
165 return load_TLS(O_FORCE, to);
166}
167
168int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to)
169{
170 if (needs_TLS_update(to))
171 return load_TLS(0, to);
172
173 return 0;
174}
175
176static int set_tls_entry(struct task_struct* task, struct user_desc *info,
177 int idx, int flushed)
178{
179 struct thread_struct *t = &task->thread;
180
181 if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
182 return -EINVAL;
183
184 t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls = *info;
185 t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present = 1;
186 t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed = flushed;
187
188 return 0;
189}
190
191int arch_copy_tls(struct task_struct *new)
192{
193 struct user_desc info;
194 int idx, ret = -EFAULT;
195
196 if (copy_from_user(&info,
197 (void __user *) UPT_ESI(&new->thread.regs.regs),
198 sizeof(info)))
199 goto out;
200
201 ret = -EINVAL;
202 if (LDT_empty(&info))
203 goto out;
204
205 idx = info.entry_number;
206
207 ret = set_tls_entry(new, &info, idx, 0);
208out:
209 return ret;
210}
211
212/* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */
213static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx)
214{
215 struct thread_struct *t = &task->thread;
216
217 if (!t->arch.tls_array)
218 goto clear;
219
220 if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
221 return -EINVAL;
222
223 if (!t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present)
224 goto clear;
225
226 *info = t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls;
227
228out:
229 /* Temporary debugging check, to make sure that things have been
230 * flushed. This could be triggered if load_TLS() failed.
231 */
232 if (unlikely(task == current && !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) {
233 printk(KERN_ERR "get_tls_entry: task with pid %d got here "
234 "without flushed TLS.", current->pid);
235 }
236
237 return 0;
238clear:
239 /* When the TLS entry has not been set, the values read to user in the
240 * tls_array are 0 (because it's cleared at boot, see
241 * arch/i386/kernel/head.S:cpu_gdt_table). Emulate that.
242 */
243 clear_user_desc(info);
244 info->entry_number = idx;
245 goto out;
246}
247
248asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc)
249{
250 struct user_desc info;
251 int idx, ret;
252
253 if (copy_from_user(&info, user_desc, sizeof(info)))
254 return -EFAULT;
255
256 idx = info.entry_number;
257
258 if (idx == -1) {
259 idx = get_free_idx(current);
260 if (idx < 0)
261 return idx;
262 info.entry_number = idx;
263 /* Tell the user which slot we chose for him.*/
264 if (put_user(idx, &user_desc->entry_number))
265 return -EFAULT;
266 }
267
268 ret = CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, &info);
269 if (ret)
270 return ret;
271 return set_tls_entry(current, &info, idx, 1);
272}
273
274/*
275 * Perform set_thread_area on behalf of the traced child.
276 * Note: error handling is not done on the deferred load, and this differ from
277 * i386. However the only possible error are caused by bugs.
278 */
279int ptrace_set_thread_area(struct task_struct *child, int idx,
280 struct user_desc __user *user_desc)
281{
282 struct user_desc info;
283
284 if (copy_from_user(&info, user_desc, sizeof(info)))
285 return -EFAULT;
286
287 return set_tls_entry(child, &info, idx, 0);
288}
289
290asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc)
291{
292 struct user_desc info;
293 int idx, ret;
294
295 if (get_user(idx, &user_desc->entry_number))
296 return -EFAULT;
297
298 ret = get_tls_entry(current, &info, idx);
299 if (ret < 0)
300 goto out;
301
302 if (copy_to_user(user_desc, &info, sizeof(info)))
303 ret = -EFAULT;
304
305out:
306 return ret;
307}
308
309/*
310 * Perform get_thread_area on behalf of the traced child.
311 */
312int ptrace_get_thread_area(struct task_struct *child, int idx,
313 struct user_desc __user *user_desc)
314{
315 struct user_desc info;
316 int ret;
317
318 ret = get_tls_entry(child, &info, idx);
319 if (ret < 0)
320 goto out;
321
322 if (copy_to_user(user_desc, &info, sizeof(info)))
323 ret = -EFAULT;
324out:
325 return ret;
326}
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 1ee2ed1599b..b5fc22babdd 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -5,7 +5,8 @@
5# 5#
6 6
7obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ 7obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
8 sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o ksyms.o 8 sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o ksyms.o \
9 tls.o
9 10
10obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o 11obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
11obj-$(CONFIG_MODULES) += um_module.o 12obj-$(CONFIG_MODULES) += um_module.o
diff --git a/arch/um/sys-x86_64/tls.c b/arch/um/sys-x86_64/tls.c
new file mode 100644
index 00000000000..ce1bf1b81c4
--- /dev/null
+++ b/arch/um/sys-x86_64/tls.c
@@ -0,0 +1,14 @@
1#include "linux/sched.h"
2
3void debug_arch_force_load_TLS(void)
4{
5}
6
7void clear_flushed_tls(struct task_struct *task)
8{
9}
10
11int arch_copy_tls(struct task_struct *t)
12{
13 return 0;
14}
diff --git a/include/asm-um/desc.h b/include/asm-um/desc.h
index ac1d2a20d17..4ec34a51b62 100644
--- a/include/asm-um/desc.h
+++ b/include/asm-um/desc.h
@@ -1,6 +1,16 @@
1#ifndef __UM_DESC_H 1#ifndef __UM_DESC_H
2#define __UM_DESC_H 2#define __UM_DESC_H
3 3
4#include "asm/arch/desc.h" 4/* Taken from asm-i386/desc.h, it's the only thing we need. The rest wouldn't
5 * compile, and has never been used. */
6#define LDT_empty(info) (\
7 (info)->base_addr == 0 && \
8 (info)->limit == 0 && \
9 (info)->contents == 0 && \
10 (info)->read_exec_only == 1 && \
11 (info)->seg_32bit == 0 && \
12 (info)->limit_in_pages == 0 && \
13 (info)->seg_not_present == 1 && \
14 (info)->useable == 0 )
5 15
6#endif 16#endif
diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h
index 4108a579eb9..595f1c3e1e4 100644
--- a/include/asm-um/processor-i386.h
+++ b/include/asm-um/processor-i386.h
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) 2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
@@ -6,21 +6,48 @@
6#ifndef __UM_PROCESSOR_I386_H 6#ifndef __UM_PROCESSOR_I386_H
7#define __UM_PROCESSOR_I386_H 7#define __UM_PROCESSOR_I386_H
8 8
9#include "linux/string.h"
10#include "asm/host_ldt.h"
11#include "asm/segment.h"
12
9extern int host_has_xmm; 13extern int host_has_xmm;
10extern int host_has_cmov; 14extern int host_has_cmov;
11 15
12/* include faultinfo structure */ 16/* include faultinfo structure */
13#include "sysdep/faultinfo.h" 17#include "sysdep/faultinfo.h"
14 18
19struct uml_tls_struct {
20 struct user_desc tls;
21 unsigned flushed:1;
22 unsigned present:1;
23};
24
15struct arch_thread { 25struct arch_thread {
26 struct uml_tls_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
16 unsigned long debugregs[8]; 27 unsigned long debugregs[8];
17 int debugregs_seq; 28 int debugregs_seq;
18 struct faultinfo faultinfo; 29 struct faultinfo faultinfo;
19}; 30};
20 31
21#define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \ 32#define INIT_ARCH_THREAD { \
22 .debugregs_seq = 0, \ 33 .tls_array = { [ 0 ... GDT_ENTRY_TLS_ENTRIES - 1 ] = \
23 .faultinfo = { 0, 0, 0 } } 34 { .present = 0, .flushed = 0 } }, \
35 .debugregs = { [ 0 ... 7 ] = 0 }, \
36 .debugregs_seq = 0, \
37 .faultinfo = { 0, 0, 0 } \
38}
39
40static inline void arch_flush_thread(struct arch_thread *thread)
41{
42 /* Clear any TLS still hanging */
43 memset(&thread->tls_array, 0, sizeof(thread->tls_array));
44}
45
46static inline void arch_copy_thread(struct arch_thread *from,
47 struct arch_thread *to)
48{
49 memcpy(&to->tls_array, &from->tls_array, sizeof(from->tls_array));
50}
24 51
25#include "asm/arch/user.h" 52#include "asm/arch/user.h"
26 53
diff --git a/include/asm-um/processor-x86_64.h b/include/asm-um/processor-x86_64.h
index e1e1255a1d3..10609af376c 100644
--- a/include/asm-um/processor-x86_64.h
+++ b/include/asm-um/processor-x86_64.h
@@ -28,6 +28,15 @@ extern inline void rep_nop(void)
28 .debugregs_seq = 0, \ 28 .debugregs_seq = 0, \
29 .faultinfo = { 0, 0, 0 } } 29 .faultinfo = { 0, 0, 0 } }
30 30
31static inline void arch_flush_thread(struct arch_thread *thread)
32{
33}
34
35static inline void arch_copy_thread(struct arch_thread *from,
36 struct arch_thread *to)
37{
38}
39
31#include "asm/arch/user.h" 40#include "asm/arch/user.h"
32 41
33#define current_text_addr() \ 42#define current_text_addr() \
diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h
index 8c57e384cb8..503484305e6 100644
--- a/include/asm-um/ptrace-generic.h
+++ b/include/asm-um/ptrace-generic.h
@@ -60,17 +60,9 @@ extern void show_regs(struct pt_regs *regs);
60extern void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs, 60extern void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
61 int error_code); 61 int error_code);
62 62
63#endif 63extern int arch_copy_tls(struct task_struct *new);
64extern void clear_flushed_tls(struct task_struct *task);
64 65
65#endif 66#endif
66 67
67/* 68#endif
68 * Overrides for Emacs so that we follow Linus's tabbing style.
69 * Emacs will notice this stuff at the end of the file and automatically
70 * adjust the settings for this buffer only. This must remain at the end
71 * of the file.
72 * ---------------------------------------------------------------------------
73 * Local variables:
74 * c-file-style: "linux"
75 * End:
76 */
diff --git a/include/asm-um/ptrace-i386.h b/include/asm-um/ptrace-i386.h
index fe882b9d917..30656c962d7 100644
--- a/include/asm-um/ptrace-i386.h
+++ b/include/asm-um/ptrace-i386.h
@@ -8,8 +8,11 @@
8 8
9#define HOST_AUDIT_ARCH AUDIT_ARCH_I386 9#define HOST_AUDIT_ARCH AUDIT_ARCH_I386
10 10
11#include "linux/compiler.h"
11#include "sysdep/ptrace.h" 12#include "sysdep/ptrace.h"
12#include "asm/ptrace-generic.h" 13#include "asm/ptrace-generic.h"
14#include "asm/host_ldt.h"
15#include "choose-mode.h"
13 16
14#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs) 17#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
15#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs) 18#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs)
@@ -38,15 +41,31 @@
38 41
39#define user_mode(r) UPT_IS_USER(&(r)->regs) 42#define user_mode(r) UPT_IS_USER(&(r)->regs)
40 43
41#endif 44extern int ptrace_get_thread_area(struct task_struct *child, int idx,
45 struct user_desc __user *user_desc);
42 46
43/* 47extern int ptrace_set_thread_area(struct task_struct *child, int idx,
44 * Overrides for Emacs so that we follow Linus's tabbing style. 48 struct user_desc __user *user_desc);
45 * Emacs will notice this stuff at the end of the file and automatically 49
46 * adjust the settings for this buffer only. This must remain at the end 50extern int do_set_thread_area_skas(struct user_desc *info);
47 * of the file. 51extern int do_get_thread_area_skas(struct user_desc *info);
48 * --------------------------------------------------------------------------- 52
49 * Local variables: 53extern int do_set_thread_area_tt(struct user_desc *info);
50 * c-file-style: "linux" 54extern int do_get_thread_area_tt(struct user_desc *info);
51 * End: 55
52 */ 56extern int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to);
57extern int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to);
58
59static inline int do_get_thread_area(struct user_desc *info)
60{
61 return CHOOSE_MODE_PROC(do_get_thread_area_tt, do_get_thread_area_skas, info);
62}
63
64static inline int do_set_thread_area(struct user_desc *info)
65{
66 return CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, info);
67}
68
69struct task_struct;
70
71#endif
diff --git a/include/asm-um/ptrace-x86_64.h b/include/asm-um/ptrace-x86_64.h
index be51219a8ff..c894e68b1f9 100644
--- a/include/asm-um/ptrace-x86_64.h
+++ b/include/asm-um/ptrace-x86_64.h
@@ -8,6 +8,8 @@
8#define __UM_PTRACE_X86_64_H 8#define __UM_PTRACE_X86_64_H
9 9
10#include "linux/compiler.h" 10#include "linux/compiler.h"
11#include "asm/errno.h"
12#include "asm/host_ldt.h"
11 13
12#define signal_fault signal_fault_x86_64 14#define signal_fault signal_fault_x86_64
13#define __FRAME_OFFSETS /* Needed to get the R* macros */ 15#define __FRAME_OFFSETS /* Needed to get the R* macros */
@@ -63,15 +65,26 @@ void signal_fault(struct pt_regs_subarch *regs, void *frame, char *where);
63 65
64#define profile_pc(regs) PT_REGS_IP(regs) 66#define profile_pc(regs) PT_REGS_IP(regs)
65 67
66#endif 68static inline int ptrace_get_thread_area(struct task_struct *child, int idx,
69 struct user_desc __user *user_desc)
70{
71 return -ENOSYS;
72}
67 73
68/* 74static inline int ptrace_set_thread_area(struct task_struct *child, int idx,
69 * Overrides for Emacs so that we follow Linus's tabbing style. 75 struct user_desc __user *user_desc)
70 * Emacs will notice this stuff at the end of the file and automatically 76{
71 * adjust the settings for this buffer only. This must remain at the end 77 return -ENOSYS;
72 * of the file. 78}
73 * --------------------------------------------------------------------------- 79
74 * Local variables: 80static inline void arch_switch_to_tt(struct task_struct *from,
75 * c-file-style: "linux" 81 struct task_struct *to)
76 * End: 82{
77 */ 83}
84
85static inline void arch_switch_to_skas(struct task_struct *from,
86 struct task_struct *to)
87{
88}
89
90#endif
diff --git a/include/asm-um/segment.h b/include/asm-um/segment.h
index 55e40301f62..48775452e2c 100644
--- a/include/asm-um/segment.h
+++ b/include/asm-um/segment.h
@@ -1,4 +1,6 @@
1#ifndef __UM_SEGMENT_H 1#ifndef __UM_SEGMENT_H
2#define __UM_SEGMENT_H 2#define __UM_SEGMENT_H
3 3
4#include "asm/arch/segment.h"
5
4#endif 6#endif