aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/os-Linux
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/os-Linux')
-rw-r--r--arch/um/os-Linux/Makefile14
-rw-r--r--arch/um/os-Linux/aio.c414
-rw-r--r--arch/um/os-Linux/elf_aux.c3
-rw-r--r--arch/um/os-Linux/process.c58
-rw-r--r--arch/um/os-Linux/start_up.c359
-rw-r--r--arch/um/os-Linux/tt.c113
6 files changed, 954 insertions, 7 deletions
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index 4ddf540284ce..7a1662419c0c 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -3,11 +3,19 @@
3# Licensed under the GPL 3# Licensed under the GPL
4# 4#
5 5
6obj-y = elf_aux.o file.o process.o signal.o time.o tty.o user_syms.o drivers/ \ 6obj-y = aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \
7 sys-$(SUBARCH)/ 7 tty.o user_syms.o drivers/ sys-$(SUBARCH)/
8 8
9USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o 9USER_OBJS := aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \
10 tty.o
11
12elf_aux.o: $(ARCH_DIR)/kernel-offsets.h
13CFLAGS_elf_aux.o += -I$(objtree)/arch/um
10 14
11CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) 15CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
12 16
17HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \
18 echo -DHAVE_AIO_ABI )
19CFLAGS_aio.o += $(HAVE_AIO_ABI)
20
13include arch/um/scripts/Makefile.rules 21include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
new file mode 100644
index 000000000000..b04897cd995d
--- /dev/null
+++ b/arch/um/os-Linux/aio.c
@@ -0,0 +1,414 @@
1/*
2 * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <unistd.h>
8#include <signal.h>
9#include <string.h>
10#include <errno.h>
11#include <sched.h>
12#include <sys/syscall.h>
13#include "os.h"
14#include "helper.h"
15#include "aio.h"
16#include "init.h"
17#include "user.h"
18#include "mode.h"
19
20static int aio_req_fd_r = -1;
21static int aio_req_fd_w = -1;
22
23static int update_aio(struct aio_context *aio, int res)
24{
25 if(res < 0)
26 aio->len = res;
27 else if((res == 0) && (aio->type == AIO_READ)){
28 /* This is the EOF case - we have hit the end of the file
29 * and it ends in a partial block, so we fill the end of
30 * the block with zeros and claim success.
31 */
32 memset(aio->data, 0, aio->len);
33 aio->len = 0;
34 }
35 else if(res > 0){
36 aio->len -= res;
37 aio->data += res;
38 aio->offset += res;
39 return aio->len;
40 }
41
42 return 0;
43}
44
45#if defined(HAVE_AIO_ABI)
46#include <linux/aio_abi.h>
47
48/* If we have the headers, we are going to build with AIO enabled.
49 * If we don't have aio in libc, we define the necessary stubs here.
50 */
51
52#if !defined(HAVE_AIO_LIBC)
53
54static long io_setup(int n, aio_context_t *ctxp)
55{
56 return syscall(__NR_io_setup, n, ctxp);
57}
58
59static long io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
60{
61 return syscall(__NR_io_submit, ctx, nr, iocbpp);
62}
63
64static long io_getevents(aio_context_t ctx_id, long min_nr, long nr,
65 struct io_event *events, struct timespec *timeout)
66{
67 return syscall(__NR_io_getevents, ctx_id, min_nr, nr, events, timeout);
68}
69
70#endif
71
72/* The AIO_MMAP cases force the mmapped page into memory here
73 * rather than in whatever place first touches the data. I used
74 * to do this by touching the page, but that's delicate because
75 * gcc is prone to optimizing that away. So, what's done here
76 * is we read from the descriptor from which the page was
77 * mapped. The caller is required to pass an offset which is
78 * inside the page that was mapped. Thus, when the read
79 * returns, we know that the page is in the page cache, and
80 * that it now backs the mmapped area.
81 */
82
83static int do_aio(aio_context_t ctx, struct aio_context *aio)
84{
85 struct iocb iocb, *iocbp = &iocb;
86 char c;
87 int err;
88
89 iocb = ((struct iocb) { .aio_data = (unsigned long) aio,
90 .aio_reqprio = 0,
91 .aio_fildes = aio->fd,
92 .aio_buf = (unsigned long) aio->data,
93 .aio_nbytes = aio->len,
94 .aio_offset = aio->offset,
95 .aio_reserved1 = 0,
96 .aio_reserved2 = 0,
97 .aio_reserved3 = 0 });
98
99 switch(aio->type){
100 case AIO_READ:
101 iocb.aio_lio_opcode = IOCB_CMD_PREAD;
102 break;
103 case AIO_WRITE:
104 iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
105 break;
106 case AIO_MMAP:
107 iocb.aio_lio_opcode = IOCB_CMD_PREAD;
108 iocb.aio_buf = (unsigned long) &c;
109 iocb.aio_nbytes = sizeof(c);
110 break;
111 default:
112 printk("Bogus op in do_aio - %d\n", aio->type);
113 err = -EINVAL;
114 goto out;
115 }
116
117 err = io_submit(ctx, 1, &iocbp);
118 if(err > 0)
119 err = 0;
120
121 out:
122 return err;
123}
124
125static aio_context_t ctx = 0;
126
127static int aio_thread(void *arg)
128{
129 struct aio_thread_reply reply;
130 struct aio_context *aio;
131 struct io_event event;
132 int err, n;
133
134 signal(SIGWINCH, SIG_IGN);
135
136 while(1){
137 n = io_getevents(ctx, 1, 1, &event, NULL);
138 if(n < 0){
139 if(errno == EINTR)
140 continue;
141 printk("aio_thread - io_getevents failed, "
142 "errno = %d\n", errno);
143 }
144 else {
145 aio = (struct aio_context *) event.data;
146 if(update_aio(aio, event.res)){
147 do_aio(ctx, aio);
148 continue;
149 }
150
151 reply = ((struct aio_thread_reply)
152 { .data = aio,
153 .err = aio->len });
154 err = os_write_file(aio->reply_fd, &reply,
155 sizeof(reply));
156 if(err != sizeof(reply))
157 printk("aio_thread - write failed, "
158 "fd = %d, err = %d\n", aio->reply_fd,
159 -err);
160 }
161 }
162 return 0;
163}
164
165#endif
166
167static int do_not_aio(struct aio_context *aio)
168{
169 char c;
170 int err;
171
172 switch(aio->type){
173 case AIO_READ:
174 err = os_seek_file(aio->fd, aio->offset);
175 if(err)
176 goto out;
177
178 err = os_read_file(aio->fd, aio->data, aio->len);
179 break;
180 case AIO_WRITE:
181 err = os_seek_file(aio->fd, aio->offset);
182 if(err)
183 goto out;
184
185 err = os_write_file(aio->fd, aio->data, aio->len);
186 break;
187 case AIO_MMAP:
188 err = os_seek_file(aio->fd, aio->offset);
189 if(err)
190 goto out;
191
192 err = os_read_file(aio->fd, &c, sizeof(c));
193 break;
194 default:
195 printk("do_not_aio - bad request type : %d\n", aio->type);
196 err = -EINVAL;
197 break;
198 }
199
200 out:
201 return err;
202}
203
204static int not_aio_thread(void *arg)
205{
206 struct aio_context *aio;
207 struct aio_thread_reply reply;
208 int err;
209
210 signal(SIGWINCH, SIG_IGN);
211 while(1){
212 err = os_read_file(aio_req_fd_r, &aio, sizeof(aio));
213 if(err != sizeof(aio)){
214 if(err < 0)
215 printk("not_aio_thread - read failed, "
216 "fd = %d, err = %d\n", aio_req_fd_r,
217 -err);
218 else {
219 printk("not_aio_thread - short read, fd = %d, "
220 "length = %d\n", aio_req_fd_r, err);
221 }
222 continue;
223 }
224 again:
225 err = do_not_aio(aio);
226
227 if(update_aio(aio, err))
228 goto again;
229
230 reply = ((struct aio_thread_reply) { .data = aio,
231 .err = aio->len });
232 err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
233 if(err != sizeof(reply))
234 printk("not_aio_thread - write failed, fd = %d, "
235 "err = %d\n", aio_req_fd_r, -err);
236 }
237}
238
239static int submit_aio_24(struct aio_context *aio)
240{
241 int err;
242
243 err = os_write_file(aio_req_fd_w, &aio, sizeof(aio));
244 if(err == sizeof(aio))
245 err = 0;
246
247 return err;
248}
249
250static int aio_pid = -1;
251static int (*submit_proc)(struct aio_context *aio);
252
253static int init_aio_24(void)
254{
255 unsigned long stack;
256 int fds[2], err;
257
258 err = os_pipe(fds, 1, 1);
259 if(err)
260 goto out;
261
262 aio_req_fd_w = fds[0];
263 aio_req_fd_r = fds[1];
264 err = run_helper_thread(not_aio_thread, NULL,
265 CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
266 if(err < 0)
267 goto out_close_pipe;
268
269 aio_pid = err;
270 goto out;
271
272 out_close_pipe:
273 os_close_file(fds[0]);
274 os_close_file(fds[1]);
275 aio_req_fd_w = -1;
276 aio_req_fd_r = -1;
277 out:
278#ifndef HAVE_AIO_ABI
279 printk("/usr/include/linux/aio_abi.h not present during build\n");
280#endif
281 printk("2.6 host AIO support not used - falling back to I/O "
282 "thread\n");
283
284 submit_proc = submit_aio_24;
285
286 return 0;
287}
288
289#ifdef HAVE_AIO_ABI
290#define DEFAULT_24_AIO 0
291static int submit_aio_26(struct aio_context *aio)
292{
293 struct aio_thread_reply reply;
294 int err;
295
296 err = do_aio(ctx, aio);
297 if(err){
298 reply = ((struct aio_thread_reply) { .data = aio,
299 .err = err });
300 err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
301 if(err != sizeof(reply))
302 printk("submit_aio_26 - write failed, "
303 "fd = %d, err = %d\n", aio->reply_fd, -err);
304 else err = 0;
305 }
306
307 return err;
308}
309
310static int init_aio_26(void)
311{
312 unsigned long stack;
313 int err;
314
315 if(io_setup(256, &ctx)){
316 printk("aio_thread failed to initialize context, err = %d\n",
317 errno);
318 return -errno;
319 }
320
321 err = run_helper_thread(aio_thread, NULL,
322 CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
323 if(err < 0)
324 return -errno;
325
326 aio_pid = err;
327
328 printk("Using 2.6 host AIO\n");
329
330 submit_proc = submit_aio_26;
331
332 return 0;
333}
334
335#else
336#define DEFAULT_24_AIO 1
337static int submit_aio_26(struct aio_context *aio)
338{
339 return -ENOSYS;
340}
341
342static int init_aio_26(void)
343{
344 submit_proc = submit_aio_26;
345 return -ENOSYS;
346}
347#endif
348
349static int aio_24 = DEFAULT_24_AIO;
350
351static int __init set_aio_24(char *name, int *add)
352{
353 aio_24 = 1;
354 return 0;
355}
356
357__uml_setup("aio=2.4", set_aio_24,
358"aio=2.4\n"
359" This is used to force UML to use 2.4-style AIO even when 2.6 AIO is\n"
360" available. 2.4 AIO is a single thread that handles one request at a\n"
361" time, synchronously. 2.6 AIO is a thread which uses the 2.6 AIO \n"
362" interface to handle an arbitrary number of pending requests. 2.6 AIO \n"
363" is not available in tt mode, on 2.4 hosts, or when UML is built with\n"
364" /usr/include/linux/aio_abi.h not available. Many distributions don't\n"
365" include aio_abi.h, so you will need to copy it from a kernel tree to\n"
366" your /usr/include/linux in order to build an AIO-capable UML\n\n"
367);
368
369static int init_aio(void)
370{
371 int err;
372
373 CHOOSE_MODE(({
374 if(!aio_24){
375 printk("Disabling 2.6 AIO in tt mode\n");
376 aio_24 = 1;
377 } }), (void) 0);
378
379 if(!aio_24){
380 err = init_aio_26();
381 if(err && (errno == ENOSYS)){
382 printk("2.6 AIO not supported on the host - "
383 "reverting to 2.4 AIO\n");
384 aio_24 = 1;
385 }
386 else return err;
387 }
388
389 if(aio_24)
390 return init_aio_24();
391
392 return 0;
393}
394
395/* The reason for the __initcall/__uml_exitcall asymmetry is that init_aio
396 * needs to be called when the kernel is running because it calls run_helper,
397 * which needs get_free_page. exit_aio is a __uml_exitcall because the generic
398 * kernel does not run __exitcalls on shutdown, and can't because many of them
399 * break when called outside of module unloading.
400 */
401__initcall(init_aio);
402
403static void exit_aio(void)
404{
405 if(aio_pid != -1)
406 os_kill_process(aio_pid, 1);
407}
408
409__uml_exitcall(exit_aio);
410
411int submit_aio(struct aio_context *aio)
412{
413 return (*submit_proc)(aio);
414}
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
index 4cca3e9c23fe..1399520a8588 100644
--- a/arch/um/os-Linux/elf_aux.c
+++ b/arch/um/os-Linux/elf_aux.c
@@ -12,8 +12,9 @@
12#include "init.h" 12#include "init.h"
13#include "elf_user.h" 13#include "elf_user.h"
14#include "mem_user.h" 14#include "mem_user.h"
15#include <kernel-offsets.h>
15 16
16#if ELF_CLASS == ELFCLASS32 17#if HOST_ELF_CLASS == ELFCLASS32
17typedef Elf32_auxv_t elf_auxv_t; 18typedef Elf32_auxv_t elf_auxv_t;
18#else 19#else
19typedef Elf64_auxv_t elf_auxv_t; 20typedef Elf64_auxv_t elf_auxv_t;
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index 1e126bfd31a7..d32413e4b4ce 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -3,10 +3,10 @@
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
5 5
6#include <unistd.h>
7#include <stdio.h> 6#include <stdio.h>
8#include <errno.h> 7#include <errno.h>
9#include <signal.h> 8#include <signal.h>
9#include <setjmp.h>
10#include <linux/unistd.h> 10#include <linux/unistd.h>
11#include <sys/mman.h> 11#include <sys/mman.h>
12#include <sys/wait.h> 12#include <sys/wait.h>
@@ -14,6 +14,10 @@
14#include "os.h" 14#include "os.h"
15#include "user.h" 15#include "user.h"
16#include "user_util.h" 16#include "user_util.h"
17#include "signal_user.h"
18#include "process.h"
19#include "irq_user.h"
20#include "kern_util.h"
17 21
18#define ARBITRARY_ADDR -1 22#define ARBITRARY_ADDR -1
19#define FAILURE_PID -1 23#define FAILURE_PID -1
@@ -114,8 +118,10 @@ void os_usr1_process(int pid)
114 kill(pid, SIGUSR1); 118 kill(pid, SIGUSR1);
115} 119}
116 120
117/*Don't use the glibc version, which caches the result in TLS. It misses some 121/* Don't use the glibc version, which caches the result in TLS. It misses some
118 * syscalls, and also breaks with clone(), which does not unshare the TLS.*/ 122 * syscalls, and also breaks with clone(), which does not unshare the TLS.
123 */
124
119inline _syscall0(pid_t, getpid) 125inline _syscall0(pid_t, getpid)
120 126
121int os_getpid(void) 127int os_getpid(void)
@@ -164,6 +170,52 @@ int os_unmap_memory(void *addr, int len)
164 return(0); 170 return(0);
165} 171}
166 172
173void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
174{
175 int flags = 0, pages;
176
177 if(sig_stack != NULL){
178 pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
179 set_sigstack(sig_stack, pages * page_size());
180 flags = SA_ONSTACK;
181 }
182 if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
183}
184
185void init_new_thread_signals(int altstack)
186{
187 int flags = altstack ? SA_ONSTACK : 0;
188
189 set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
190 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
191 set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
192 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
193 set_handler(SIGFPE, (__sighandler_t) sig_handler, flags,
194 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
195 set_handler(SIGILL, (__sighandler_t) sig_handler, flags,
196 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
197 set_handler(SIGBUS, (__sighandler_t) sig_handler, flags,
198 SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
199 set_handler(SIGUSR2, (__sighandler_t) sig_handler,
200 flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
201 signal(SIGHUP, SIG_IGN);
202
203 init_irq_signals(altstack);
204}
205
206int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
207{
208 sigjmp_buf buf;
209 int n;
210
211 *jmp_ptr = &buf;
212 n = sigsetjmp(buf, 1);
213 if(n != 0)
214 return(n);
215 (*fn)(arg);
216 return(0);
217}
218
167/* 219/*
168 * Overrides for Emacs so that we follow Linus's tabbing style. 220 * Overrides for Emacs so that we follow Linus's tabbing style.
169 * Emacs will notice this stuff at the end of the file and automatically 221 * Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
new file mode 100644
index 000000000000..040cc1472bc7
--- /dev/null
+++ b/arch/um/os-Linux/start_up.c
@@ -0,0 +1,359 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <signal.h>
9#include <sched.h>
10#include <errno.h>
11#include <stdarg.h>
12#include <stdlib.h>
13#include <setjmp.h>
14#include <sys/time.h>
15#include <sys/wait.h>
16#include <sys/mman.h>
17#include <asm/unistd.h>
18#include <asm/page.h>
19#include "user_util.h"
20#include "kern_util.h"
21#include "user.h"
22#include "signal_kern.h"
23#include "signal_user.h"
24#include "sysdep/ptrace.h"
25#include "sysdep/sigcontext.h"
26#include "irq_user.h"
27#include "ptrace_user.h"
28#include "time_user.h"
29#include "init.h"
30#include "os.h"
31#include "uml-config.h"
32#include "choose-mode.h"
33#include "mode.h"
34#include "tempfile.h"
35#ifdef UML_CONFIG_MODE_SKAS
36#include "skas.h"
37#include "skas_ptrace.h"
38#include "registers.h"
39#endif
40
41static int ptrace_child(void *arg)
42{
43 int ret;
44 int pid = os_getpid(), ppid = getppid();
45 int sc_result;
46
47 if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
48 perror("ptrace");
49 os_kill_process(pid, 0);
50 }
51 os_stop_process(pid);
52
53 /*This syscall will be intercepted by the parent. Don't call more than
54 * once, please.*/
55 sc_result = os_getpid();
56
57 if (sc_result == pid)
58 ret = 1; /*Nothing modified by the parent, we are running
59 normally.*/
60 else if (sc_result == ppid)
61 ret = 0; /*Expected in check_ptrace and check_sysemu when they
62 succeed in modifying the stack frame*/
63 else
64 ret = 2; /*Serious trouble! This could be caused by a bug in
65 host 2.6 SKAS3/2.6 patch before release -V6, together
66 with a bug in the UML code itself.*/
67 _exit(ret);
68}
69
70static int start_ptraced_child(void **stack_out)
71{
72 void *stack;
73 unsigned long sp;
74 int pid, n, status;
75
76 stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
77 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
78 if(stack == MAP_FAILED)
79 panic("check_ptrace : mmap failed, errno = %d", errno);
80 sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
81 pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
82 if(pid < 0)
83 panic("start_ptraced_child : clone failed, errno = %d", errno);
84 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
85 if(n < 0)
86 panic("check_ptrace : clone failed, errno = %d", errno);
87 if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
88 panic("check_ptrace : expected SIGSTOP, got status = %d",
89 status);
90
91 *stack_out = stack;
92 return(pid);
93}
94
95/* When testing for SYSEMU support, if it is one of the broken versions, we
96 * must just avoid using sysemu, not panic, but only if SYSEMU features are
97 * broken.
98 * So only for SYSEMU features we test mustpanic, while normal host features
99 * must work anyway!
100 */
101static int stop_ptraced_child(int pid, void *stack, int exitcode,
102 int mustpanic)
103{
104 int status, n, ret = 0;
105
106 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
107 panic("check_ptrace : ptrace failed, errno = %d", errno);
108 CATCH_EINTR(n = waitpid(pid, &status, 0));
109 if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
110 int exit_with = WEXITSTATUS(status);
111 if (exit_with == 2)
112 printk("check_ptrace : child exited with status 2. "
113 "Serious trouble happening! Try updating your "
114 "host skas patch!\nDisabling SYSEMU support.");
115 printk("check_ptrace : child exited with exitcode %d, while "
116 "expecting %d; status 0x%x", exit_with,
117 exitcode, status);
118 if (mustpanic)
119 panic("\n");
120 else
121 printk("\n");
122 ret = -1;
123 }
124
125 if(munmap(stack, PAGE_SIZE) < 0)
126 panic("check_ptrace : munmap failed, errno = %d", errno);
127 return ret;
128}
129
130int ptrace_faultinfo = 1;
131int proc_mm = 1;
132
133static int __init skas0_cmd_param(char *str, int* add)
134{
135 ptrace_faultinfo = proc_mm = 0;
136 return 0;
137}
138
139__uml_setup("skas0", skas0_cmd_param,
140 "skas0\n"
141 " Disables SKAS3 usage, so that SKAS0 is used, unless \n"
142 " you specify mode=tt.\n\n");
143
144static int force_sysemu_disabled = 0;
145
146static int __init nosysemu_cmd_param(char *str, int* add)
147{
148 force_sysemu_disabled = 1;
149 return 0;
150}
151
152__uml_setup("nosysemu", nosysemu_cmd_param,
153"nosysemu\n"
154" Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
155" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
156" behaviour of ptrace() and helps reducing host context switch rate.\n"
157" To make it working, you need a kernel patch for your host, too.\n"
158" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
159" information.\n\n");
160
161static void __init check_sysemu(void)
162{
163 void *stack;
164 int pid, n, status, count=0;
165
166 printk("Checking syscall emulation patch for ptrace...");
167 sysemu_supported = 0;
168 pid = start_ptraced_child(&stack);
169
170 if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
171 goto fail;
172
173 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
174 if (n < 0)
175 panic("check_sysemu : wait failed, errno = %d", errno);
176 if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
177 panic("check_sysemu : expected SIGTRAP, "
178 "got status = %d", status);
179
180 n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
181 os_getpid());
182 if(n < 0)
183 panic("check_sysemu : failed to modify system "
184 "call return, errno = %d", errno);
185
186 if (stop_ptraced_child(pid, stack, 0, 0) < 0)
187 goto fail_stopped;
188
189 sysemu_supported = 1;
190 printk("OK\n");
191 set_using_sysemu(!force_sysemu_disabled);
192
193 printk("Checking advanced syscall emulation patch for ptrace...");
194 pid = start_ptraced_child(&stack);
195
196 if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
197 (void *) PTRACE_O_TRACESYSGOOD) < 0)
198 panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d",
199 errno);
200
201 while(1){
202 count++;
203 if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
204 goto fail;
205 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
206 if(n < 0)
207 panic("check_ptrace : wait failed, errno = %d", errno);
208 if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){
209 if (!count)
210 panic("check_ptrace : SYSEMU_SINGLESTEP "
211 "doesn't singlestep");
212 n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET,
213 os_getpid());
214 if(n < 0)
215 panic("check_sysemu : failed to modify system "
216 "call return, errno = %d", errno);
217 break;
218 }
219 else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
220 count++;
221 else
222 panic("check_ptrace : expected SIGTRAP or "
223 "(SIGTRAP|0x80), got status = %d", status);
224 }
225 if (stop_ptraced_child(pid, stack, 0, 0) < 0)
226 goto fail_stopped;
227
228 sysemu_supported = 2;
229 printk("OK\n");
230
231 if ( !force_sysemu_disabled )
232 set_using_sysemu(sysemu_supported);
233 return;
234
235fail:
236 stop_ptraced_child(pid, stack, 1, 0);
237fail_stopped:
238 printk("missing\n");
239}
240
241static void __init check_ptrace(void)
242{
243 void *stack;
244 int pid, syscall, n, status;
245
246 printk("Checking that ptrace can change system call numbers...");
247 pid = start_ptraced_child(&stack);
248
249 if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
250 panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno);
251
252 while(1){
253 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
254 panic("check_ptrace : ptrace failed, errno = %d",
255 errno);
256 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
257 if(n < 0)
258 panic("check_ptrace : wait failed, errno = %d", errno);
259 if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|0x80)))
260 panic("check_ptrace : expected (SIGTRAP|0x80), "
261 "got status = %d", status);
262
263 syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET,
264 0);
265 if(syscall == __NR_getpid){
266 n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
267 __NR_getppid);
268 if(n < 0)
269 panic("check_ptrace : failed to modify system "
270 "call, errno = %d", errno);
271 break;
272 }
273 }
274 stop_ptraced_child(pid, stack, 0, 1);
275 printk("OK\n");
276 check_sysemu();
277}
278
279void os_early_checks(void)
280{
281 check_ptrace();
282}
283
284static int __init noprocmm_cmd_param(char *str, int* add)
285{
286 proc_mm = 0;
287 return 0;
288}
289
290__uml_setup("noprocmm", noprocmm_cmd_param,
291"noprocmm\n"
292" Turns off usage of /proc/mm, even if host supports it.\n"
293" To support /proc/mm, the host needs to be patched using\n"
294" the current skas3 patch.\n\n");
295
296static int __init noptracefaultinfo_cmd_param(char *str, int* add)
297{
298 ptrace_faultinfo = 0;
299 return 0;
300}
301
302__uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param,
303"noptracefaultinfo\n"
304" Turns off usage of PTRACE_FAULTINFO, even if host supports\n"
305" it. To support PTRACE_FAULTINFO, the host needs to be patched\n"
306" using the current skas3 patch.\n\n");
307
308#ifdef UML_CONFIG_MODE_SKAS
309static inline void check_skas3_ptrace_support(void)
310{
311 struct ptrace_faultinfo fi;
312 void *stack;
313 int pid, n;
314
315 printf("Checking for the skas3 patch in the host...");
316 pid = start_ptraced_child(&stack);
317
318 n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
319 if (n < 0) {
320 ptrace_faultinfo = 0;
321 if(errno == EIO)
322 printf("not found\n");
323 else
324 perror("not found");
325 }
326 else {
327 if (!ptrace_faultinfo)
328 printf("found but disabled on command line\n");
329 else
330 printf("found\n");
331 }
332
333 init_registers(pid);
334 stop_ptraced_child(pid, stack, 1, 1);
335}
336
337int can_do_skas(void)
338{
339 printf("Checking for /proc/mm...");
340 if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
341 proc_mm = 0;
342 printf("not found\n");
343 }
344 else {
345 if (!proc_mm)
346 printf("found but disabled on command line\n");
347 else
348 printf("found\n");
349 }
350
351 check_skas3_ptrace_support();
352 return 1;
353}
354#else
355int can_do_skas(void)
356{
357 return(0);
358}
359#endif
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c
new file mode 100644
index 000000000000..5b047ab8416a
--- /dev/null
+++ b/arch/um/os-Linux/tt.c
@@ -0,0 +1,113 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <signal.h>
9#include <sched.h>
10#include <errno.h>
11#include <stdarg.h>
12#include <stdlib.h>
13#include <setjmp.h>
14#include <sys/time.h>
15#include <sys/ptrace.h>
16#include <linux/ptrace.h>
17#include <sys/wait.h>
18#include <sys/mman.h>
19#include <asm/ptrace.h>
20#include <asm/unistd.h>
21#include <asm/page.h>
22#include "user_util.h"
23#include "kern_util.h"
24#include "user.h"
25#include "signal_kern.h"
26#include "signal_user.h"
27#include "sysdep/ptrace.h"
28#include "sysdep/sigcontext.h"
29#include "irq_user.h"
30#include "ptrace_user.h"
31#include "time_user.h"
32#include "init.h"
33#include "os.h"
34#include "uml-config.h"
35#include "choose-mode.h"
36#include "mode.h"
37#include "tempfile.h"
38
39/*
40 *-------------------------
41 * only for tt mode (will be deleted in future...)
42 *-------------------------
43 */
44
45struct tramp {
46 int (*tramp)(void *);
47 void *tramp_data;
48 unsigned long temp_stack;
49 int flags;
50 int pid;
51};
52
53/* See above for why sigkill is here */
54
55int sigkill = SIGKILL;
56
57int outer_tramp(void *arg)
58{
59 struct tramp *t;
60 int sig = sigkill;
61
62 t = arg;
63 t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
64 t->flags, t->tramp_data);
65 if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
66 kill(os_getpid(), sig);
67 _exit(0);
68}
69
70int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
71 int clone_flags, int (*tramp)(void *))
72{
73 struct tramp arg;
74 unsigned long sp;
75 int new_pid, status, err;
76
77 /* The trampoline will run on the temporary stack */
78 sp = stack_sp(temp_stack);
79
80 clone_flags |= CLONE_FILES | SIGCHLD;
81
82 arg.tramp = tramp;
83 arg.tramp_data = thread_arg;
84 arg.temp_stack = temp_stack;
85 arg.flags = clone_flags;
86
87 /* Start the process and wait for it to kill itself */
88 new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
89 if(new_pid < 0)
90 return(new_pid);
91
92 CATCH_EINTR(err = waitpid(new_pid, &status, 0));
93 if(err < 0)
94 panic("Waiting for outer trampoline failed - errno = %d",
95 errno);
96
97 if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
98 panic("outer trampoline didn't exit with SIGKILL, "
99 "status = %d", status);
100
101 return(arg.pid);
102}
103
104void forward_pending_sigio(int target)
105{
106 sigset_t sigs;
107
108 if(sigpending(&sigs))
109 panic("forward_pending_sigio : sigpending failed");
110 if(sigismember(&sigs, SIGIO))
111 kill(target, SIGIO);
112}
113