diff options
Diffstat (limited to 'arch/um/os-Linux/skas/process.c')
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 122 |
1 files changed, 74 insertions, 48 deletions
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 1f39f2bf7ce9..5c088a55396c 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "process.h" | 34 | #include "process.h" |
35 | #include "longjmp.h" | 35 | #include "longjmp.h" |
36 | #include "kern_constants.h" | 36 | #include "kern_constants.h" |
37 | #include "as-layout.h" | ||
37 | 38 | ||
38 | int is_skas_winch(int pid, int fd, void *data) | 39 | int is_skas_winch(int pid, int fd, void *data) |
39 | { | 40 | { |
@@ -60,37 +61,42 @@ static int ptrace_dump_regs(int pid) | |||
60 | return 0; | 61 | return 0; |
61 | } | 62 | } |
62 | 63 | ||
63 | void wait_stub_done(int pid, int sig, char * fname) | 64 | /* |
65 | * Signals that are OK to receive in the stub - we'll just continue it. | ||
66 | * SIGWINCH will happen when UML is inside a detached screen. | ||
67 | */ | ||
68 | #define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) | ||
69 | |||
70 | /* Signals that the stub will finish with - anything else is an error */ | ||
71 | #define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP)) | ||
72 | |||
73 | void wait_stub_done(int pid) | ||
64 | { | 74 | { |
65 | int n, status, err; | 75 | int n, status, err; |
66 | 76 | ||
67 | do { | 77 | while(1){ |
68 | if ( sig != -1 ) { | ||
69 | err = ptrace(PTRACE_CONT, pid, 0, sig); | ||
70 | if(err) | ||
71 | panic("%s : continue failed, errno = %d\n", | ||
72 | fname, errno); | ||
73 | } | ||
74 | sig = 0; | ||
75 | |||
76 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 78 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
77 | } while((n >= 0) && WIFSTOPPED(status) && | 79 | if((n < 0) || !WIFSTOPPED(status)) |
78 | ((WSTOPSIG(status) == SIGVTALRM) || | 80 | goto bad_wait; |
79 | /* running UML inside a detached screen can cause | 81 | |
80 | * SIGWINCHes | 82 | if(((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0) |
81 | */ | 83 | break; |
82 | (WSTOPSIG(status) == SIGWINCH))); | 84 | |
83 | 85 | err = ptrace(PTRACE_CONT, pid, 0, 0); | |
84 | if((n < 0) || !WIFSTOPPED(status) || | ||
85 | (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){ | ||
86 | err = ptrace_dump_regs(pid); | ||
87 | if(err) | 86 | if(err) |
88 | printk("Failed to get registers from stub, " | 87 | panic("wait_stub_done : continue failed, errno = %d\n", |
89 | "errno = %d\n", -err); | 88 | errno); |
90 | panic("%s : failed to wait for SIGUSR1/SIGTRAP, " | ||
91 | "pid = %d, n = %d, errno = %d, status = 0x%x\n", | ||
92 | fname, pid, n, errno, status); | ||
93 | } | 89 | } |
90 | |||
91 | if(((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0) | ||
92 | return; | ||
93 | |||
94 | bad_wait: | ||
95 | err = ptrace_dump_regs(pid); | ||
96 | if(err) | ||
97 | printk("Failed to get registers from stub, errno = %d\n", -err); | ||
98 | panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, " | ||
99 | "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status); | ||
94 | } | 100 | } |
95 | 101 | ||
96 | extern unsigned long current_stub_stack(void); | 102 | extern unsigned long current_stub_stack(void); |
@@ -112,7 +118,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi) | |||
112 | sizeof(struct ptrace_faultinfo)); | 118 | sizeof(struct ptrace_faultinfo)); |
113 | } | 119 | } |
114 | else { | 120 | else { |
115 | wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo"); | 121 | err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); |
122 | if(err) | ||
123 | panic("Failed to continue stub, pid = %d, errno = %d\n", | ||
124 | pid, errno); | ||
125 | wait_stub_done(pid); | ||
116 | 126 | ||
117 | /* faultinfo is prepared by the stub-segv-handler at start of | 127 | /* faultinfo is prepared by the stub-segv-handler at start of |
118 | * the stub stack page. We just have to copy it. | 128 | * the stub stack page. We just have to copy it. |
@@ -304,10 +314,13 @@ void userspace(union uml_pt_regs *regs) | |||
304 | UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ | 314 | UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ |
305 | 315 | ||
306 | if(WIFSTOPPED(status)){ | 316 | if(WIFSTOPPED(status)){ |
307 | switch(WSTOPSIG(status)){ | 317 | int sig = WSTOPSIG(status); |
318 | switch(sig){ | ||
308 | case SIGSEGV: | 319 | case SIGSEGV: |
309 | if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) | 320 | if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo){ |
310 | user_signal(SIGSEGV, regs, pid); | 321 | get_skas_faultinfo(pid, ®s->skas.faultinfo); |
322 | (*sig_info[SIGSEGV])(SIGSEGV, regs); | ||
323 | } | ||
311 | else handle_segv(pid, regs); | 324 | else handle_segv(pid, regs); |
312 | break; | 325 | break; |
313 | case SIGTRAP + 0x80: | 326 | case SIGTRAP + 0x80: |
@@ -322,11 +335,13 @@ void userspace(union uml_pt_regs *regs) | |||
322 | case SIGBUS: | 335 | case SIGBUS: |
323 | case SIGFPE: | 336 | case SIGFPE: |
324 | case SIGWINCH: | 337 | case SIGWINCH: |
325 | user_signal(WSTOPSIG(status), regs, pid); | 338 | block_signals(); |
339 | (*sig_info[sig])(sig, regs); | ||
340 | unblock_signals(); | ||
326 | break; | 341 | break; |
327 | default: | 342 | default: |
328 | printk("userspace - child stopped with signal " | 343 | printk("userspace - child stopped with signal " |
329 | "%d\n", WSTOPSIG(status)); | 344 | "%d\n", sig); |
330 | } | 345 | } |
331 | pid = userspace_pid[0]; | 346 | pid = userspace_pid[0]; |
332 | interrupt_end(); | 347 | interrupt_end(); |
@@ -338,11 +353,29 @@ void userspace(union uml_pt_regs *regs) | |||
338 | } | 353 | } |
339 | } | 354 | } |
340 | 355 | ||
356 | static unsigned long thread_regs[MAX_REG_NR]; | ||
357 | static unsigned long thread_fp_regs[HOST_FP_SIZE]; | ||
358 | |||
359 | static int __init init_thread_regs(void) | ||
360 | { | ||
361 | get_safe_registers(thread_regs, thread_fp_regs); | ||
362 | /* Set parent's instruction pointer to start of clone-stub */ | ||
363 | thread_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + | ||
364 | (unsigned long) stub_clone_handler - | ||
365 | (unsigned long) &__syscall_stub_start; | ||
366 | thread_regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE - | ||
367 | sizeof(void *); | ||
368 | #ifdef __SIGNAL_FRAMESIZE | ||
369 | thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; | ||
370 | #endif | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | __initcall(init_thread_regs); | ||
375 | |||
341 | int copy_context_skas0(unsigned long new_stack, int pid) | 376 | int copy_context_skas0(unsigned long new_stack, int pid) |
342 | { | 377 | { |
343 | int err; | 378 | int err; |
344 | unsigned long regs[MAX_REG_NR]; | ||
345 | unsigned long fp_regs[HOST_FP_SIZE]; | ||
346 | unsigned long current_stack = current_stub_stack(); | 379 | unsigned long current_stack = current_stub_stack(); |
347 | struct stub_data *data = (struct stub_data *) current_stack; | 380 | struct stub_data *data = (struct stub_data *) current_stack; |
348 | struct stub_data *child_data = (struct stub_data *) new_stack; | 381 | struct stub_data *child_data = (struct stub_data *) new_stack; |
@@ -357,23 +390,12 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
357 | .timer = ((struct itimerval) | 390 | .timer = ((struct itimerval) |
358 | { { 0, 1000000 / hz() }, | 391 | { { 0, 1000000 / hz() }, |
359 | { 0, 1000000 / hz() }})}); | 392 | { 0, 1000000 / hz() }})}); |
360 | get_safe_registers(regs, fp_regs); | 393 | err = ptrace_setregs(pid, thread_regs); |
361 | |||
362 | /* Set parent's instruction pointer to start of clone-stub */ | ||
363 | regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + | ||
364 | (unsigned long) stub_clone_handler - | ||
365 | (unsigned long) &__syscall_stub_start; | ||
366 | regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE - | ||
367 | sizeof(void *); | ||
368 | #ifdef __SIGNAL_FRAMESIZE | ||
369 | regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; | ||
370 | #endif | ||
371 | err = ptrace_setregs(pid, regs); | ||
372 | if(err < 0) | 394 | if(err < 0) |
373 | panic("copy_context_skas0 : PTRACE_SETREGS failed, " | 395 | panic("copy_context_skas0 : PTRACE_SETREGS failed, " |
374 | "pid = %d, errno = %d\n", pid, -err); | 396 | "pid = %d, errno = %d\n", pid, -err); |
375 | 397 | ||
376 | err = ptrace_setfpregs(pid, fp_regs); | 398 | err = ptrace_setfpregs(pid, thread_fp_regs); |
377 | if(err < 0) | 399 | if(err < 0) |
378 | panic("copy_context_skas0 : PTRACE_SETFPREGS failed, " | 400 | panic("copy_context_skas0 : PTRACE_SETFPREGS failed, " |
379 | "pid = %d, errno = %d\n", pid, -err); | 401 | "pid = %d, errno = %d\n", pid, -err); |
@@ -384,7 +406,11 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
384 | /* Wait, until parent has finished its work: read child's pid from | 406 | /* Wait, until parent has finished its work: read child's pid from |
385 | * parent's stack, and check, if bad result. | 407 | * parent's stack, and check, if bad result. |
386 | */ | 408 | */ |
387 | wait_stub_done(pid, 0, "copy_context_skas0"); | 409 | err = ptrace(PTRACE_CONT, pid, 0, 0); |
410 | if(err) | ||
411 | panic("Failed to continue new process, pid = %d, " | ||
412 | "errno = %d\n", pid, errno); | ||
413 | wait_stub_done(pid); | ||
388 | 414 | ||
389 | pid = data->err; | 415 | pid = data->err; |
390 | if(pid < 0) | 416 | if(pid < 0) |
@@ -394,7 +420,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
394 | /* Wait, until child has finished too: read child's result from | 420 | /* Wait, until child has finished too: read child's result from |
395 | * child's stack and check it. | 421 | * child's stack and check it. |
396 | */ | 422 | */ |
397 | wait_stub_done(pid, -1, "copy_context_skas0"); | 423 | wait_stub_done(pid); |
398 | if (child_data->err != UML_CONFIG_STUB_DATA) | 424 | if (child_data->err != UML_CONFIG_STUB_DATA) |
399 | panic("copy_context_skas0 - stub-child reports error %ld\n", | 425 | panic("copy_context_skas0 - stub-child reports error %ld\n", |
400 | child_data->err); | 426 | child_data->err); |