diff options
Diffstat (limited to 'arch/um/os-Linux/skas/process.c')
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 190 |
1 files changed, 119 insertions, 71 deletions
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 0564422c155f..5c088a55396c 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <asm/types.h> | 18 | #include <asm/types.h> |
19 | #include "user.h" | 19 | #include "user.h" |
20 | #include "sysdep/ptrace.h" | 20 | #include "sysdep/ptrace.h" |
21 | #include "user_util.h" | ||
22 | #include "kern_util.h" | 21 | #include "kern_util.h" |
23 | #include "skas.h" | 22 | #include "skas.h" |
24 | #include "stub-data.h" | 23 | #include "stub-data.h" |
@@ -34,6 +33,8 @@ | |||
34 | #include "uml-config.h" | 33 | #include "uml-config.h" |
35 | #include "process.h" | 34 | #include "process.h" |
36 | #include "longjmp.h" | 35 | #include "longjmp.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 | { |
@@ -44,45 +45,58 @@ int is_skas_winch(int pid, int fd, void *data) | |||
44 | return(1); | 45 | return(1); |
45 | } | 46 | } |
46 | 47 | ||
47 | void wait_stub_done(int pid, int sig, char * fname) | 48 | static int ptrace_dump_regs(int pid) |
48 | { | 49 | { |
49 | int n, status, err; | 50 | unsigned long regs[MAX_REG_NR]; |
51 | int i; | ||
52 | |||
53 | if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) | ||
54 | return -errno; | ||
55 | else { | ||
56 | printk("Stub registers -\n"); | ||
57 | for(i = 0; i < ARRAY_SIZE(regs); i++) | ||
58 | printk("\t%d - %lx\n", i, regs[i]); | ||
59 | } | ||
60 | |||
61 | return 0; | ||
62 | } | ||
50 | 63 | ||
51 | do { | 64 | /* |
52 | if ( sig != -1 ) { | 65 | * Signals that are OK to receive in the stub - we'll just continue it. |
53 | err = ptrace(PTRACE_CONT, pid, 0, sig); | 66 | * SIGWINCH will happen when UML is inside a detached screen. |
54 | if(err) | 67 | */ |
55 | panic("%s : continue failed, errno = %d\n", | 68 | #define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) |
56 | fname, errno); | 69 | |
57 | } | 70 | /* Signals that the stub will finish with - anything else is an error */ |
58 | sig = 0; | 71 | #define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP)) |
72 | |||
73 | void wait_stub_done(int pid) | ||
74 | { | ||
75 | int n, status, err; | ||
59 | 76 | ||
77 | while(1){ | ||
60 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 78 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
61 | } while((n >= 0) && WIFSTOPPED(status) && | 79 | if((n < 0) || !WIFSTOPPED(status)) |
62 | ((WSTOPSIG(status) == SIGVTALRM) || | 80 | goto bad_wait; |
63 | /* running UML inside a detached screen can cause | 81 | |
64 | * SIGWINCHes | 82 | if(((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0) |
65 | */ | 83 | break; |
66 | (WSTOPSIG(status) == SIGWINCH))); | 84 | |
67 | 85 | err = ptrace(PTRACE_CONT, pid, 0, 0); | |
68 | if((n < 0) || !WIFSTOPPED(status) || | 86 | if(err) |
69 | (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){ | 87 | panic("wait_stub_done : continue failed, errno = %d\n", |
70 | unsigned long regs[MAX_REG_NR]; | 88 | errno); |
71 | |||
72 | if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) | ||
73 | printk("Failed to get registers from stub, " | ||
74 | "errno = %d\n", errno); | ||
75 | else { | ||
76 | int i; | ||
77 | |||
78 | printk("Stub registers -\n"); | ||
79 | for(i = 0; i < ARRAY_SIZE(regs); i++) | ||
80 | printk("\t%d - %lx\n", i, regs[i]); | ||
81 | } | ||
82 | panic("%s : failed to wait for SIGUSR1/SIGTRAP, " | ||
83 | "pid = %d, n = %d, errno = %d, status = 0x%x\n", | ||
84 | fname, pid, n, errno, status); | ||
85 | } | 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); | ||
86 | } | 100 | } |
87 | 101 | ||
88 | extern unsigned long current_stub_stack(void); | 102 | extern unsigned long current_stub_stack(void); |
@@ -104,7 +118,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi) | |||
104 | sizeof(struct ptrace_faultinfo)); | 118 | sizeof(struct ptrace_faultinfo)); |
105 | } | 119 | } |
106 | else { | 120 | else { |
107 | 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); | ||
108 | 126 | ||
109 | /* faultinfo is prepared by the stub-segv-handler at start of | 127 | /* faultinfo is prepared by the stub-segv-handler at start of |
110 | * the stub stack page. We just have to copy it. | 128 | * the stub stack page. We just have to copy it. |
@@ -142,9 +160,14 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu | |||
142 | 160 | ||
143 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); | 161 | CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); |
144 | if((err < 0) || !WIFSTOPPED(status) || | 162 | if((err < 0) || !WIFSTOPPED(status) || |
145 | (WSTOPSIG(status) != SIGTRAP + 0x80)) | 163 | (WSTOPSIG(status) != SIGTRAP + 0x80)){ |
164 | err = ptrace_dump_regs(pid); | ||
165 | if(err) | ||
166 | printk("Failed to get registers from process, " | ||
167 | "errno = %d\n", -err); | ||
146 | panic("handle_trap - failed to wait at end of syscall, " | 168 | panic("handle_trap - failed to wait at end of syscall, " |
147 | "errno = %d, status = %d\n", errno, status); | 169 | "errno = %d, status = %d\n", errno, status); |
170 | } | ||
148 | } | 171 | } |
149 | 172 | ||
150 | handle_syscall(regs); | 173 | handle_syscall(regs); |
@@ -172,7 +195,7 @@ static int userspace_tramp(void *stack) | |||
172 | int fd; | 195 | int fd; |
173 | __u64 offset; | 196 | __u64 offset; |
174 | fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); | 197 | fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); |
175 | addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(), | 198 | addr = mmap64((void *) UML_CONFIG_STUB_CODE, UM_KERN_PAGE_SIZE, |
176 | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); | 199 | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); |
177 | if(addr == MAP_FAILED){ | 200 | if(addr == MAP_FAILED){ |
178 | printk("mapping mmap stub failed, errno = %d\n", | 201 | printk("mapping mmap stub failed, errno = %d\n", |
@@ -182,8 +205,8 @@ static int userspace_tramp(void *stack) | |||
182 | 205 | ||
183 | if(stack != NULL){ | 206 | if(stack != NULL){ |
184 | fd = phys_mapping(to_phys(stack), &offset); | 207 | fd = phys_mapping(to_phys(stack), &offset); |
185 | addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(), | 208 | addr = mmap((void *) UML_CONFIG_STUB_DATA, |
186 | PROT_READ | PROT_WRITE, | 209 | UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, |
187 | MAP_FIXED | MAP_SHARED, fd, offset); | 210 | MAP_FIXED | MAP_SHARED, fd, offset); |
188 | if(addr == MAP_FAILED){ | 211 | if(addr == MAP_FAILED){ |
189 | printk("mapping segfault stack failed, " | 212 | printk("mapping segfault stack failed, " |
@@ -199,7 +222,7 @@ static int userspace_tramp(void *stack) | |||
199 | (unsigned long) stub_segv_handler - | 222 | (unsigned long) stub_segv_handler - |
200 | (unsigned long) &__syscall_stub_start; | 223 | (unsigned long) &__syscall_stub_start; |
201 | 224 | ||
202 | set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size()); | 225 | set_sigstack((void *) UML_CONFIG_STUB_DATA, UM_KERN_PAGE_SIZE); |
203 | sigemptyset(&sa.sa_mask); | 226 | sigemptyset(&sa.sa_mask); |
204 | sigaddset(&sa.sa_mask, SIGIO); | 227 | sigaddset(&sa.sa_mask, SIGIO); |
205 | sigaddset(&sa.sa_mask, SIGWINCH); | 228 | sigaddset(&sa.sa_mask, SIGWINCH); |
@@ -291,10 +314,13 @@ void userspace(union uml_pt_regs *regs) | |||
291 | UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ | 314 | UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ |
292 | 315 | ||
293 | if(WIFSTOPPED(status)){ | 316 | if(WIFSTOPPED(status)){ |
294 | switch(WSTOPSIG(status)){ | 317 | int sig = WSTOPSIG(status); |
318 | switch(sig){ | ||
295 | case SIGSEGV: | 319 | case SIGSEGV: |
296 | if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) | 320 | if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo){ |
297 | user_signal(SIGSEGV, regs, pid); | 321 | get_skas_faultinfo(pid, ®s->skas.faultinfo); |
322 | (*sig_info[SIGSEGV])(SIGSEGV, regs); | ||
323 | } | ||
298 | else handle_segv(pid, regs); | 324 | else handle_segv(pid, regs); |
299 | break; | 325 | break; |
300 | case SIGTRAP + 0x80: | 326 | case SIGTRAP + 0x80: |
@@ -309,11 +335,13 @@ void userspace(union uml_pt_regs *regs) | |||
309 | case SIGBUS: | 335 | case SIGBUS: |
310 | case SIGFPE: | 336 | case SIGFPE: |
311 | case SIGWINCH: | 337 | case SIGWINCH: |
312 | user_signal(WSTOPSIG(status), regs, pid); | 338 | block_signals(); |
339 | (*sig_info[sig])(sig, regs); | ||
340 | unblock_signals(); | ||
313 | break; | 341 | break; |
314 | default: | 342 | default: |
315 | printk("userspace - child stopped with signal " | 343 | printk("userspace - child stopped with signal " |
316 | "%d\n", WSTOPSIG(status)); | 344 | "%d\n", sig); |
317 | } | 345 | } |
318 | pid = userspace_pid[0]; | 346 | pid = userspace_pid[0]; |
319 | interrupt_end(); | 347 | interrupt_end(); |
@@ -325,11 +353,29 @@ void userspace(union uml_pt_regs *regs) | |||
325 | } | 353 | } |
326 | } | 354 | } |
327 | 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 | |||
328 | int copy_context_skas0(unsigned long new_stack, int pid) | 376 | int copy_context_skas0(unsigned long new_stack, int pid) |
329 | { | 377 | { |
330 | int err; | 378 | int err; |
331 | unsigned long regs[MAX_REG_NR]; | ||
332 | unsigned long fp_regs[HOST_FP_SIZE]; | ||
333 | unsigned long current_stack = current_stub_stack(); | 379 | unsigned long current_stack = current_stub_stack(); |
334 | struct stub_data *data = (struct stub_data *) current_stack; | 380 | struct stub_data *data = (struct stub_data *) current_stack; |
335 | struct stub_data *child_data = (struct stub_data *) new_stack; | 381 | struct stub_data *child_data = (struct stub_data *) new_stack; |
@@ -344,23 +390,12 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
344 | .timer = ((struct itimerval) | 390 | .timer = ((struct itimerval) |
345 | { { 0, 1000000 / hz() }, | 391 | { { 0, 1000000 / hz() }, |
346 | { 0, 1000000 / hz() }})}); | 392 | { 0, 1000000 / hz() }})}); |
347 | get_safe_registers(regs, fp_regs); | 393 | err = ptrace_setregs(pid, thread_regs); |
348 | |||
349 | /* Set parent's instruction pointer to start of clone-stub */ | ||
350 | regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + | ||
351 | (unsigned long) stub_clone_handler - | ||
352 | (unsigned long) &__syscall_stub_start; | ||
353 | regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE - | ||
354 | sizeof(void *); | ||
355 | #ifdef __SIGNAL_FRAMESIZE | ||
356 | regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; | ||
357 | #endif | ||
358 | err = ptrace_setregs(pid, regs); | ||
359 | if(err < 0) | 394 | if(err < 0) |
360 | panic("copy_context_skas0 : PTRACE_SETREGS failed, " | 395 | panic("copy_context_skas0 : PTRACE_SETREGS failed, " |
361 | "pid = %d, errno = %d\n", pid, -err); | 396 | "pid = %d, errno = %d\n", pid, -err); |
362 | 397 | ||
363 | err = ptrace_setfpregs(pid, fp_regs); | 398 | err = ptrace_setfpregs(pid, thread_fp_regs); |
364 | if(err < 0) | 399 | if(err < 0) |
365 | panic("copy_context_skas0 : PTRACE_SETFPREGS failed, " | 400 | panic("copy_context_skas0 : PTRACE_SETFPREGS failed, " |
366 | "pid = %d, errno = %d\n", pid, -err); | 401 | "pid = %d, errno = %d\n", pid, -err); |
@@ -371,7 +406,11 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
371 | /* 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 |
372 | * parent's stack, and check, if bad result. | 407 | * parent's stack, and check, if bad result. |
373 | */ | 408 | */ |
374 | 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); | ||
375 | 414 | ||
376 | pid = data->err; | 415 | pid = data->err; |
377 | if(pid < 0) | 416 | if(pid < 0) |
@@ -381,7 +420,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
381 | /* Wait, until child has finished too: read child's result from | 420 | /* Wait, until child has finished too: read child's result from |
382 | * child's stack and check it. | 421 | * child's stack and check it. |
383 | */ | 422 | */ |
384 | wait_stub_done(pid, -1, "copy_context_skas0"); | 423 | wait_stub_done(pid); |
385 | if (child_data->err != UML_CONFIG_STUB_DATA) | 424 | if (child_data->err != UML_CONFIG_STUB_DATA) |
386 | panic("copy_context_skas0 - stub-child reports error %ld\n", | 425 | panic("copy_context_skas0 - stub-child reports error %ld\n", |
387 | child_data->err); | 426 | child_data->err); |
@@ -396,7 +435,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
396 | 435 | ||
397 | /* | 436 | /* |
398 | * This is used only, if stub pages are needed, while proc_mm is | 437 | * This is used only, if stub pages are needed, while proc_mm is |
399 | * availabl. Opening /proc/mm creates a new mm_context, which lacks | 438 | * available. Opening /proc/mm creates a new mm_context, which lacks |
400 | * the stub-pages. Thus, we map them using /proc/mm-fd | 439 | * the stub-pages. Thus, we map them using /proc/mm-fd |
401 | */ | 440 | */ |
402 | void map_stub_pages(int fd, unsigned long code, | 441 | void map_stub_pages(int fd, unsigned long code, |
@@ -418,12 +457,13 @@ void map_stub_pages(int fd, unsigned long code, | |||
418 | .fd = code_fd, | 457 | .fd = code_fd, |
419 | .offset = code_offset | 458 | .offset = code_offset |
420 | } } }); | 459 | } } }); |
421 | n = os_write_file(fd, &mmop, sizeof(mmop)); | 460 | CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); |
422 | if(n != sizeof(mmop)){ | 461 | if(n != sizeof(mmop)){ |
462 | n = errno; | ||
423 | printk("mmap args - addr = 0x%lx, fd = %d, offset = %llx\n", | 463 | printk("mmap args - addr = 0x%lx, fd = %d, offset = %llx\n", |
424 | code, code_fd, (unsigned long long) code_offset); | 464 | code, code_fd, (unsigned long long) code_offset); |
425 | panic("map_stub_pages : /proc/mm map for code failed, " | 465 | panic("map_stub_pages : /proc/mm map for code failed, " |
426 | "err = %d\n", -n); | 466 | "err = %d\n", n); |
427 | } | 467 | } |
428 | 468 | ||
429 | if ( stack ) { | 469 | if ( stack ) { |
@@ -440,10 +480,10 @@ void map_stub_pages(int fd, unsigned long code, | |||
440 | .fd = map_fd, | 480 | .fd = map_fd, |
441 | .offset = map_offset | 481 | .offset = map_offset |
442 | } } }); | 482 | } } }); |
443 | n = os_write_file(fd, &mmop, sizeof(mmop)); | 483 | CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); |
444 | if(n != sizeof(mmop)) | 484 | if(n != sizeof(mmop)) |
445 | panic("map_stub_pages : /proc/mm map for data failed, " | 485 | panic("map_stub_pages : /proc/mm map for data failed, " |
446 | "err = %d\n", -n); | 486 | "err = %d\n", errno); |
447 | } | 487 | } |
448 | } | 488 | } |
449 | 489 | ||
@@ -480,7 +520,15 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) | |||
480 | SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, | 520 | SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, |
481 | SIGVTALRM, -1); | 521 | SIGVTALRM, -1); |
482 | 522 | ||
483 | n = UML_SETJMP(&initial_jmpbuf); | 523 | /* |
524 | * Can't use UML_SETJMP or UML_LONGJMP here because they save | ||
525 | * and restore signals, with the possible side-effect of | ||
526 | * trying to handle any signals which came when they were | ||
527 | * blocked, which can't be done on this stack. | ||
528 | * Signals must be blocked when jumping back here and restored | ||
529 | * after returning to the jumper. | ||
530 | */ | ||
531 | n = setjmp(initial_jmpbuf); | ||
484 | switch(n){ | 532 | switch(n){ |
485 | case INIT_JMP_NEW_THREAD: | 533 | case INIT_JMP_NEW_THREAD: |
486 | (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; | 534 | (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; |
@@ -490,7 +538,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) | |||
490 | break; | 538 | break; |
491 | case INIT_JMP_CALLBACK: | 539 | case INIT_JMP_CALLBACK: |
492 | (*cb_proc)(cb_arg); | 540 | (*cb_proc)(cb_arg); |
493 | UML_LONGJMP(cb_back, 1); | 541 | longjmp(*cb_back, 1); |
494 | break; | 542 | break; |
495 | case INIT_JMP_HALT: | 543 | case INIT_JMP_HALT: |
496 | kmalloc_ok = 0; | 544 | kmalloc_ok = 0; |
@@ -501,7 +549,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) | |||
501 | default: | 549 | default: |
502 | panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); | 550 | panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); |
503 | } | 551 | } |
504 | UML_LONGJMP(switch_buf, 1); | 552 | longjmp(*switch_buf, 1); |
505 | } | 553 | } |
506 | 554 | ||
507 | void initial_thread_cb_skas(void (*proc)(void *), void *arg) | 555 | void initial_thread_cb_skas(void (*proc)(void *), void *arg) |