ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / um / kernel / skas / process.c
1 /* 
2  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <signal.h>
9 #include <setjmp.h>
10 #include <sched.h>
11 #include <sys/wait.h>
12 #include <sys/ptrace.h>
13 #include <sys/mman.h>
14 #include <sys/user.h>
15 #include <asm/unistd.h>
16 #include "user.h"
17 #include "ptrace_user.h"
18 #include "time_user.h"
19 #include "sysdep/ptrace.h"
20 #include "user_util.h"
21 #include "kern_util.h"
22 #include "skas.h"
23 #include "sysdep/sigcontext.h"
24 #include "os.h"
25 #include "proc_mm.h"
26 #include "skas_ptrace.h"
27
28 unsigned long exec_regs[FRAME_SIZE];
29 unsigned long exec_fp_regs[HOST_FP_SIZE];
30 unsigned long exec_fpx_regs[HOST_XFP_SIZE];
31 int have_fpx_regs = 1;
32
33 static void handle_segv(int pid)
34 {
35         struct ptrace_faultinfo fault;
36         int err;
37
38         err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
39         if(err)
40                 panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
41                       errno);
42
43         segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
44 }
45
46 static void handle_trap(int pid, union uml_pt_regs *regs)
47 {
48         int err, syscall_nr, status;
49
50         syscall_nr = PT_SYSCALL_NR(regs->skas.regs);
51         if(syscall_nr < 1){
52                 relay_signal(SIGTRAP, regs);
53                 return;
54         }
55         UPT_SYSCALL_NR(regs) = syscall_nr;
56
57         err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
58         if(err < 0)
59                 panic("handle_trap - nullifying syscall failed errno = %d\n", 
60                       errno);
61
62         err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
63         if(err < 0)
64                 panic("handle_trap - continuing to end of syscall failed, "
65                       "errno = %d\n", errno);
66
67         err = waitpid(pid, &status, WUNTRACED);
68         if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
69                 panic("handle_trap - failed to wait at end of syscall, "
70                       "errno = %d, status = %d\n", errno, status);
71
72         handle_syscall(regs);
73 }
74
75 int userspace_pid;
76
77 static int userspace_tramp(void *arg)
78 {
79         init_new_thread_signals(0);
80         enable_timer();
81         ptrace(PTRACE_TRACEME, 0, 0, 0);
82         os_stop_process(os_getpid());
83         return(0);
84 }
85
86 void start_userspace(void)
87 {
88         void *stack;
89         unsigned long sp;
90         int pid, status, n;
91
92         stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
93                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
94         if(stack == MAP_FAILED)
95                 panic("start_userspace : mmap failed, errno = %d", errno);
96         sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
97
98         pid = clone(userspace_tramp, (void *) sp, 
99                     CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
100         if(pid < 0)
101                 panic("start_userspace : clone failed, errno = %d", errno);
102
103         do {
104                 n = waitpid(pid, &status, WUNTRACED);
105                 if(n < 0)
106                         panic("start_userspace : wait failed, errno = %d", 
107                               errno);
108         } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
109
110         if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
111                 panic("start_userspace : expected SIGSTOP, got status = %d",
112                       status);
113
114         if(munmap(stack, PAGE_SIZE) < 0)
115                 panic("start_userspace : munmap failed, errno = %d\n", errno);
116
117         userspace_pid = pid;
118 }
119
120 void userspace(union uml_pt_regs *regs)
121 {
122         int err, status, op;
123
124         restore_registers(regs);
125                 
126         err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0);
127         if(err)
128                 panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", 
129                        errno);
130         while(1){
131                 err = waitpid(userspace_pid, &status, WUNTRACED);
132                 if(err < 0)
133                         panic("userspace - waitpid failed, errno = %d\n", 
134                               errno);
135
136                 regs->skas.is_user = 1;
137                 save_registers(regs);
138
139                 if(WIFSTOPPED(status)){
140                         switch(WSTOPSIG(status)){
141                         case SIGSEGV:
142                                 handle_segv(userspace_pid);
143                                 break;
144                         case SIGTRAP:
145                                 handle_trap(userspace_pid, regs);
146                                 break;
147                         case SIGIO:
148                         case SIGVTALRM:
149                         case SIGILL:
150                         case SIGBUS:
151                         case SIGFPE:
152                                 user_signal(WSTOPSIG(status), regs);
153                                 break;
154                         default:
155                                 printk("userspace - child stopped with signal "
156                                        "%d\n", WSTOPSIG(status));
157                         }
158                         interrupt_end();
159                 }
160
161                 restore_registers(regs);
162
163                 op = singlestepping_skas() ? PTRACE_SINGLESTEP : 
164                         PTRACE_SYSCALL;
165                 err = ptrace(op, userspace_pid, 0, 0);
166                 if(err)
167                         panic("userspace - PTRACE_SYSCALL failed, "
168                               "errno = %d\n", errno);
169         }
170 }
171
172 void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
173                 void (*handler)(int))
174 {
175         jmp_buf switch_buf, fork_buf;
176
177         *switch_buf_ptr = &switch_buf;
178         *fork_buf_ptr = &fork_buf;
179
180         if(setjmp(fork_buf) == 0)
181                 new_thread_proc(stack, handler);
182
183         remove_sigstack();
184 }
185
186 void thread_wait(void *sw, void *fb)
187 {
188         jmp_buf buf, **switch_buf = sw, *fork_buf;
189
190         *switch_buf = &buf;
191         fork_buf = fb;
192         if(setjmp(buf) == 0)
193                 longjmp(*fork_buf, 1);
194 }
195
196 static int move_registers(int int_op, int fp_op, union uml_pt_regs *regs,
197                           unsigned long *fp_regs)
198 {
199         if(ptrace(int_op, userspace_pid, 0, regs->skas.regs) < 0)
200                 return(-errno);
201         if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0)
202                 return(-errno);
203         return(0);
204 }
205
206 void save_registers(union uml_pt_regs *regs)
207 {
208         unsigned long *fp_regs;
209         int err, fp_op;
210
211         if(have_fpx_regs){
212                 fp_op = PTRACE_GETFPXREGS;
213                 fp_regs = regs->skas.xfp;
214         }
215         else {
216                 fp_op = PTRACE_GETFPREGS;
217                 fp_regs = regs->skas.fp;
218         }
219
220         err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs);
221         if(err)
222                 panic("save_registers - saving registers failed, errno = %d\n",
223                       err);
224 }
225
226 void restore_registers(union uml_pt_regs *regs)
227 {
228         unsigned long *fp_regs;
229         int err, fp_op;
230
231         if(have_fpx_regs){
232                 fp_op = PTRACE_SETFPXREGS;
233                 fp_regs = regs->skas.xfp;
234         }
235         else {
236                 fp_op = PTRACE_SETFPREGS;
237                 fp_regs = regs->skas.fp;
238         }
239
240         err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs);
241         if(err)
242                 panic("restore_registers - saving registers failed, "
243                       "errno = %d\n", err);
244 }
245
246 void switch_threads(void *me, void *next)
247 {
248         jmp_buf my_buf, **me_ptr = me, *next_buf = next;
249         
250         *me_ptr = &my_buf;
251         if(setjmp(my_buf) == 0)
252                 longjmp(*next_buf, 1);
253 }
254
255 static jmp_buf initial_jmpbuf;
256
257 /* XXX Make these percpu */
258 static void (*cb_proc)(void *arg);
259 static void *cb_arg;
260 static jmp_buf *cb_back;
261
262 int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
263 {
264         jmp_buf **switch_buf = switch_buf_ptr;
265         int n;
266
267         *fork_buf_ptr = &initial_jmpbuf;
268         n = setjmp(initial_jmpbuf);
269         if(n == 0)
270                 new_thread_proc((void *) stack, new_thread_handler);
271         else if(n == 1)
272                 remove_sigstack();
273         else if(n == 2){
274                 (*cb_proc)(cb_arg);
275                 longjmp(*cb_back, 1);
276         }
277         else if(n == 3){
278                 kmalloc_ok = 0;
279                 return(0);
280         }
281         else if(n == 4){
282                 kmalloc_ok = 0;
283                 return(1);
284         }
285         longjmp(**switch_buf, 1);
286 }
287
288 void remove_sigstack(void)
289 {
290         stack_t stack = ((stack_t) { .ss_flags  = SS_DISABLE,
291                                      .ss_sp     = NULL,
292                                      .ss_size   = 0 });
293
294         if(sigaltstack(&stack, NULL) != 0)
295                 panic("disabling signal stack failed, errno = %d\n", errno);
296 }
297
298 void initial_thread_cb_skas(void (*proc)(void *), void *arg)
299 {
300         jmp_buf here;
301
302         cb_proc = proc;
303         cb_arg = arg;
304         cb_back = &here;
305
306         block_signals();
307         if(setjmp(here) == 0)
308                 longjmp(initial_jmpbuf, 2);
309         unblock_signals();
310
311         cb_proc = NULL;
312         cb_arg = NULL;
313         cb_back = NULL;
314 }
315
316 void halt_skas(void)
317 {
318         block_signals();
319         longjmp(initial_jmpbuf, 3);
320 }
321
322 void reboot_skas(void)
323 {
324         block_signals();
325         longjmp(initial_jmpbuf, 4);
326 }
327
328 int new_mm(int from)
329 {
330         struct proc_mm_op copy;
331         int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0);
332
333         if(fd < 0)
334                 return(-errno);
335
336         if(from != -1){
337                 copy = ((struct proc_mm_op) { .op       = MM_COPY_SEGMENTS,
338                                               .u        = 
339                                               { .copy_segments  = from } } );
340                 n = os_write_file(fd, &copy, sizeof(copy));
341                 if(n != sizeof(copy)) 
342                         printk("new_mm : /proc/mm copy_segments failed, "
343                                "errno = %d\n", errno);
344         }
345         return(fd);
346 }
347
348 void switch_mm_skas(int mm_fd)
349 {
350         int err;
351
352         err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd);
353         if(err)
354                 panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
355                       errno);
356 }
357
358 void kill_off_processes_skas(void)
359 {
360         os_kill_process(userspace_pid, 1);
361 }
362
363 void init_registers(int pid)
364 {
365         int err;
366
367         if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0)
368                 panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", 
369                       errno);
370
371         err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
372         if(!err)
373                 return;
374
375         have_fpx_regs = 0;
376         if(errno != EIO)
377                 panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", 
378                       errno);
379
380         err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
381         if(err)
382                 panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", 
383                       errno);
384 }
385
386 /*
387  * Overrides for Emacs so that we follow Linus's tabbing style.
388  * Emacs will notice this stuff at the end of the file and automatically
389  * adjust the settings for this buffer only.  This must remain at the end
390  * of the file.
391  * ---------------------------------------------------------------------------
392  * Local variables:
393  * c-file-style: "linux"
394  * End:
395  */