diff options
-rw-r--r-- | arch/um/include/os.h | 10 | ||||
-rw-r--r-- | arch/um/include/skas/skas.h | 3 | ||||
-rw-r--r-- | arch/um/include/sysdep-i386/archsetjmp.h | 3 | ||||
-rw-r--r-- | arch/um/include/sysdep-x86_64/archsetjmp.h | 3 | ||||
-rw-r--r-- | arch/um/kernel/skas/process_kern.c | 36 | ||||
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 68 | ||||
-rw-r--r-- | include/asm-um/processor-generic.h | 6 |
7 files changed, 43 insertions, 86 deletions
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index be71b3d4c961..120ca21a513a 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "skas/mm_id.h" | 14 | #include "skas/mm_id.h" |
15 | #include "irq_user.h" | 15 | #include "irq_user.h" |
16 | #include "sysdep/tls.h" | 16 | #include "sysdep/tls.h" |
17 | #include "sysdep/archsetjmp.h" | ||
17 | 18 | ||
18 | #define OS_TYPE_FILE 1 | 19 | #define OS_TYPE_FILE 1 |
19 | #define OS_TYPE_DIR 2 | 20 | #define OS_TYPE_DIR 2 |
@@ -308,12 +309,9 @@ extern int copy_context_skas0(unsigned long stack, int pid); | |||
308 | extern void userspace(union uml_pt_regs *regs); | 309 | extern void userspace(union uml_pt_regs *regs); |
309 | extern void map_stub_pages(int fd, unsigned long code, | 310 | extern void map_stub_pages(int fd, unsigned long code, |
310 | unsigned long data, unsigned long stack); | 311 | unsigned long data, unsigned long stack); |
311 | extern void new_thread(void *stack, void **switch_buf_ptr, | 312 | extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); |
312 | void **fork_buf_ptr, void (*handler)(int)); | 313 | extern void switch_threads(jmp_buf *me, jmp_buf *you); |
313 | extern void thread_wait(void *sw, void *fb); | 314 | extern int start_idle_thread(void *stack, jmp_buf *switch_buf); |
314 | extern void switch_threads(void *me, void *next); | ||
315 | extern int start_idle_thread(void *stack, void *switch_buf_ptr, | ||
316 | void **fork_buf_ptr); | ||
317 | extern void initial_thread_cb_skas(void (*proc)(void *), | 315 | extern void initial_thread_cb_skas(void (*proc)(void *), |
318 | void *arg); | 316 | void *arg); |
319 | extern void halt_skas(void); | 317 | extern void halt_skas(void); |
diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h index 853b26f148c5..e88926b16072 100644 --- a/arch/um/include/skas/skas.h +++ b/arch/um/include/skas/skas.h | |||
@@ -14,8 +14,7 @@ extern int proc_mm, ptrace_faultinfo, ptrace_ldt; | |||
14 | extern int skas_needs_stub; | 14 | extern int skas_needs_stub; |
15 | 15 | ||
16 | extern int user_thread(unsigned long stack, int flags); | 16 | extern int user_thread(unsigned long stack, int flags); |
17 | extern void new_thread_proc(void *stack, void (*handler)(int sig)); | 17 | extern void new_thread_handler(void); |
18 | extern void new_thread_handler(int sig); | ||
19 | extern void handle_syscall(union uml_pt_regs *regs); | 18 | extern void handle_syscall(union uml_pt_regs *regs); |
20 | extern int new_mm(unsigned long stack); | 19 | extern int new_mm(unsigned long stack); |
21 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); | 20 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); |
diff --git a/arch/um/include/sysdep-i386/archsetjmp.h b/arch/um/include/sysdep-i386/archsetjmp.h index ea1ba3d42aee..11bafab669e9 100644 --- a/arch/um/include/sysdep-i386/archsetjmp.h +++ b/arch/um/include/sysdep-i386/archsetjmp.h | |||
@@ -16,4 +16,7 @@ struct __jmp_buf { | |||
16 | 16 | ||
17 | typedef struct __jmp_buf jmp_buf[1]; | 17 | typedef struct __jmp_buf jmp_buf[1]; |
18 | 18 | ||
19 | #define JB_IP __eip | ||
20 | #define JB_SP __esp | ||
21 | |||
19 | #endif /* _SETJMP_H */ | 22 | #endif /* _SETJMP_H */ |
diff --git a/arch/um/include/sysdep-x86_64/archsetjmp.h b/arch/um/include/sysdep-x86_64/archsetjmp.h index 454fc60aff6d..9a5e1a6ec800 100644 --- a/arch/um/include/sysdep-x86_64/archsetjmp.h +++ b/arch/um/include/sysdep-x86_64/archsetjmp.h | |||
@@ -18,4 +18,7 @@ struct __jmp_buf { | |||
18 | 18 | ||
19 | typedef struct __jmp_buf jmp_buf[1]; | 19 | typedef struct __jmp_buf jmp_buf[1]; |
20 | 20 | ||
21 | #define JB_IP __rip | ||
22 | #define JB_SP __rsp | ||
23 | |||
21 | #endif /* _SETJMP_H */ | 24 | #endif /* _SETJMP_H */ |
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 55caeec8b257..c73d47c57abe 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c | |||
@@ -33,7 +33,7 @@ void switch_to_skas(void *prev, void *next) | |||
33 | switch_timers(0); | 33 | switch_timers(0); |
34 | 34 | ||
35 | switch_threads(&from->thread.mode.skas.switch_buf, | 35 | switch_threads(&from->thread.mode.skas.switch_buf, |
36 | to->thread.mode.skas.switch_buf); | 36 | &to->thread.mode.skas.switch_buf); |
37 | 37 | ||
38 | arch_switch_to_skas(current->thread.prev_sched, current); | 38 | arch_switch_to_skas(current->thread.prev_sched, current); |
39 | 39 | ||
@@ -43,21 +43,21 @@ void switch_to_skas(void *prev, void *next) | |||
43 | 43 | ||
44 | extern void schedule_tail(struct task_struct *prev); | 44 | extern void schedule_tail(struct task_struct *prev); |
45 | 45 | ||
46 | void new_thread_handler(int sig) | 46 | /* This is called magically, by its address being stuffed in a jmp_buf |
47 | * and being longjmp-d to. | ||
48 | */ | ||
49 | void new_thread_handler(void) | ||
47 | { | 50 | { |
48 | int (*fn)(void *), n; | 51 | int (*fn)(void *), n; |
49 | void *arg; | 52 | void *arg; |
50 | 53 | ||
51 | fn = current->thread.request.u.thread.proc; | ||
52 | arg = current->thread.request.u.thread.arg; | ||
53 | os_usr1_signal(1); | ||
54 | thread_wait(¤t->thread.mode.skas.switch_buf, | ||
55 | current->thread.mode.skas.fork_buf); | ||
56 | |||
57 | if(current->thread.prev_sched != NULL) | 54 | if(current->thread.prev_sched != NULL) |
58 | schedule_tail(current->thread.prev_sched); | 55 | schedule_tail(current->thread.prev_sched); |
59 | current->thread.prev_sched = NULL; | 56 | current->thread.prev_sched = NULL; |
60 | 57 | ||
58 | fn = current->thread.request.u.thread.proc; | ||
59 | arg = current->thread.request.u.thread.arg; | ||
60 | |||
61 | /* The return value is 1 if the kernel thread execs a process, | 61 | /* The return value is 1 if the kernel thread execs a process, |
62 | * 0 if it just exits | 62 | * 0 if it just exits |
63 | */ | 63 | */ |
@@ -70,22 +70,13 @@ void new_thread_handler(int sig) | |||
70 | else do_exit(0); | 70 | else do_exit(0); |
71 | } | 71 | } |
72 | 72 | ||
73 | void new_thread_proc(void *stack, void (*handler)(int sig)) | ||
74 | { | ||
75 | init_new_thread_stack(stack, handler); | ||
76 | os_usr1_process(os_getpid()); | ||
77 | } | ||
78 | |||
79 | void release_thread_skas(struct task_struct *task) | 73 | void release_thread_skas(struct task_struct *task) |
80 | { | 74 | { |
81 | } | 75 | } |
82 | 76 | ||
83 | void fork_handler(int sig) | 77 | /* Called magically, see new_thread_handler above */ |
78 | void fork_handler(void) | ||
84 | { | 79 | { |
85 | os_usr1_signal(1); | ||
86 | thread_wait(¤t->thread.mode.skas.switch_buf, | ||
87 | current->thread.mode.skas.fork_buf); | ||
88 | |||
89 | force_flush_all(); | 80 | force_flush_all(); |
90 | if(current->thread.prev_sched == NULL) | 81 | if(current->thread.prev_sched == NULL) |
91 | panic("blech"); | 82 | panic("blech"); |
@@ -109,7 +100,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, | |||
109 | unsigned long stack_top, struct task_struct * p, | 100 | unsigned long stack_top, struct task_struct * p, |
110 | struct pt_regs *regs) | 101 | struct pt_regs *regs) |
111 | { | 102 | { |
112 | void (*handler)(int); | 103 | void (*handler)(void); |
113 | 104 | ||
114 | if(current->thread.forking){ | 105 | if(current->thread.forking){ |
115 | memcpy(&p->thread.regs.regs.skas, ®s->regs.skas, | 106 | memcpy(&p->thread.regs.regs.skas, ®s->regs.skas, |
@@ -128,7 +119,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, | |||
128 | } | 119 | } |
129 | 120 | ||
130 | new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf, | 121 | new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf, |
131 | &p->thread.mode.skas.fork_buf, handler); | 122 | handler); |
132 | return(0); | 123 | return(0); |
133 | } | 124 | } |
134 | 125 | ||
@@ -182,8 +173,7 @@ int start_uml_skas(void) | |||
182 | init_task.thread.request.u.thread.proc = start_kernel_proc; | 173 | init_task.thread.request.u.thread.proc = start_kernel_proc; |
183 | init_task.thread.request.u.thread.arg = NULL; | 174 | init_task.thread.request.u.thread.arg = NULL; |
184 | return(start_idle_thread(task_stack_page(&init_task), | 175 | return(start_idle_thread(task_stack_page(&init_task), |
185 | &init_task.thread.mode.skas.switch_buf, | 176 | &init_task.thread.mode.skas.switch_buf)); |
186 | &init_task.thread.mode.skas.fork_buf)); | ||
187 | } | 177 | } |
188 | 178 | ||
189 | int external_pid_skas(struct task_struct *task) | 179 | int external_pid_skas(struct task_struct *task) |
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 42e3d1ed802c..cb9ab54146cc 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -444,56 +444,22 @@ void map_stub_pages(int fd, unsigned long code, | |||
444 | } | 444 | } |
445 | } | 445 | } |
446 | 446 | ||
447 | void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, | 447 | void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) |
448 | void (*handler)(int)) | ||
449 | { | 448 | { |
450 | unsigned long flags; | 449 | (*buf)[0].JB_IP = (unsigned long) handler; |
451 | jmp_buf switch_buf, fork_buf; | 450 | (*buf)[0].JB_SP = (unsigned long) stack + |
452 | 451 | (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *); | |
453 | *switch_buf_ptr = &switch_buf; | ||
454 | *fork_buf_ptr = &fork_buf; | ||
455 | |||
456 | /* Somewhat subtle - siglongjmp restores the signal mask before doing | ||
457 | * the longjmp. This means that when jumping from one stack to another | ||
458 | * when the target stack has interrupts enabled, an interrupt may occur | ||
459 | * on the source stack. This is bad when starting up a process because | ||
460 | * it's not supposed to get timer ticks until it has been scheduled. | ||
461 | * So, we disable interrupts around the sigsetjmp to ensure that | ||
462 | * they can't happen until we get back here where they are safe. | ||
463 | */ | ||
464 | flags = get_signals(); | ||
465 | block_signals(); | ||
466 | if(UML_SETJMP(&fork_buf) == 0) | ||
467 | new_thread_proc(stack, handler); | ||
468 | |||
469 | remove_sigstack(); | ||
470 | |||
471 | set_signals(flags); | ||
472 | } | 452 | } |
473 | 453 | ||
474 | #define INIT_JMP_NEW_THREAD 0 | 454 | #define INIT_JMP_NEW_THREAD 0 |
475 | #define INIT_JMP_REMOVE_SIGSTACK 1 | 455 | #define INIT_JMP_CALLBACK 1 |
476 | #define INIT_JMP_CALLBACK 2 | 456 | #define INIT_JMP_HALT 2 |
477 | #define INIT_JMP_HALT 3 | 457 | #define INIT_JMP_REBOOT 3 |
478 | #define INIT_JMP_REBOOT 4 | ||
479 | |||
480 | void thread_wait(void *sw, void *fb) | ||
481 | { | ||
482 | jmp_buf buf, **switch_buf = sw, *fork_buf; | ||
483 | |||
484 | *switch_buf = &buf; | ||
485 | fork_buf = fb; | ||
486 | if(UML_SETJMP(&buf) == 0) | ||
487 | UML_LONGJMP(fork_buf, INIT_JMP_REMOVE_SIGSTACK); | ||
488 | } | ||
489 | 458 | ||
490 | void switch_threads(void *me, void *next) | 459 | void switch_threads(jmp_buf *me, jmp_buf *you) |
491 | { | 460 | { |
492 | jmp_buf my_buf, **me_ptr = me, *next_buf = next; | 461 | if(UML_SETJMP(me) == 0) |
493 | 462 | UML_LONGJMP(you, 1); | |
494 | *me_ptr = &my_buf; | ||
495 | if(UML_SETJMP(&my_buf) == 0) | ||
496 | UML_LONGJMP(next_buf, 1); | ||
497 | } | 463 | } |
498 | 464 | ||
499 | static jmp_buf initial_jmpbuf; | 465 | static jmp_buf initial_jmpbuf; |
@@ -503,23 +469,21 @@ static void (*cb_proc)(void *arg); | |||
503 | static void *cb_arg; | 469 | static void *cb_arg; |
504 | static jmp_buf *cb_back; | 470 | static jmp_buf *cb_back; |
505 | 471 | ||
506 | int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) | 472 | int start_idle_thread(void *stack, jmp_buf *switch_buf) |
507 | { | 473 | { |
508 | jmp_buf **switch_buf = switch_buf_ptr; | ||
509 | int n; | 474 | int n; |
510 | 475 | ||
511 | set_handler(SIGWINCH, (__sighandler_t) sig_handler, | 476 | set_handler(SIGWINCH, (__sighandler_t) sig_handler, |
512 | SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, | 477 | SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, |
513 | SIGVTALRM, -1); | 478 | SIGVTALRM, -1); |
514 | 479 | ||
515 | *fork_buf_ptr = &initial_jmpbuf; | ||
516 | n = UML_SETJMP(&initial_jmpbuf); | 480 | n = UML_SETJMP(&initial_jmpbuf); |
517 | switch(n){ | 481 | switch(n){ |
518 | case INIT_JMP_NEW_THREAD: | 482 | case INIT_JMP_NEW_THREAD: |
519 | new_thread_proc((void *) stack, new_thread_handler); | 483 | (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; |
520 | break; | 484 | (*switch_buf)[0].JB_SP = (unsigned long) stack + |
521 | case INIT_JMP_REMOVE_SIGSTACK: | 485 | (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - |
522 | remove_sigstack(); | 486 | sizeof(void *); |
523 | break; | 487 | break; |
524 | case INIT_JMP_CALLBACK: | 488 | case INIT_JMP_CALLBACK: |
525 | (*cb_proc)(cb_arg); | 489 | (*cb_proc)(cb_arg); |
@@ -534,7 +498,7 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) | |||
534 | default: | 498 | default: |
535 | panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); | 499 | panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); |
536 | } | 500 | } |
537 | UML_LONGJMP(*switch_buf, 1); | 501 | UML_LONGJMP(switch_buf, 1); |
538 | } | 502 | } |
539 | 503 | ||
540 | void initial_thread_cb_skas(void (*proc)(void *), void *arg) | 504 | void initial_thread_cb_skas(void (*proc)(void *), void *arg) |
diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index afa4fe1ca9f1..d99bbddffdb9 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h | |||
@@ -13,6 +13,7 @@ struct task_struct; | |||
13 | #include "asm/ptrace.h" | 13 | #include "asm/ptrace.h" |
14 | #include "choose-mode.h" | 14 | #include "choose-mode.h" |
15 | #include "registers.h" | 15 | #include "registers.h" |
16 | #include "sysdep/archsetjmp.h" | ||
16 | 17 | ||
17 | struct mm_struct; | 18 | struct mm_struct; |
18 | 19 | ||
@@ -43,8 +44,7 @@ struct thread_struct { | |||
43 | #endif | 44 | #endif |
44 | #ifdef CONFIG_MODE_SKAS | 45 | #ifdef CONFIG_MODE_SKAS |
45 | struct { | 46 | struct { |
46 | void *switch_buf; | 47 | jmp_buf switch_buf; |
47 | void *fork_buf; | ||
48 | int mm_count; | 48 | int mm_count; |
49 | } skas; | 49 | } skas; |
50 | #endif | 50 | #endif |
@@ -138,7 +138,7 @@ extern struct cpuinfo_um cpu_data[]; | |||
138 | 138 | ||
139 | #ifdef CONFIG_MODE_SKAS | 139 | #ifdef CONFIG_MODE_SKAS |
140 | #define KSTK_REG(tsk, reg) \ | 140 | #define KSTK_REG(tsk, reg) \ |
141 | get_thread_reg(reg, tsk->thread.mode.skas.switch_buf) | 141 | get_thread_reg(reg, &tsk->thread.mode.skas.switch_buf) |
142 | #else | 142 | #else |
143 | #define KSTK_REG(tsk, reg) (0xbadbabe) | 143 | #define KSTK_REG(tsk, reg) (0xbadbabe) |
144 | #endif | 144 | #endif |