diff --git a/arch/um/include/os.h b/arch/um/include/os.h index be71b3d4c96109c97b12691f2bf0536b5528025b..120ca21a513a03853a38abf2004a35a1d0b4b173 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -14,6 +14,7 @@ #include "skas/mm_id.h" #include "irq_user.h" #include "sysdep/tls.h" +#include "sysdep/archsetjmp.h" #define OS_TYPE_FILE 1 #define OS_TYPE_DIR 2 @@ -308,12 +309,9 @@ extern int copy_context_skas0(unsigned long stack, int pid); extern void userspace(union uml_pt_regs *regs); extern void map_stub_pages(int fd, unsigned long code, unsigned long data, unsigned long stack); -extern void new_thread(void *stack, void **switch_buf_ptr, - void **fork_buf_ptr, void (*handler)(int)); -extern void thread_wait(void *sw, void *fb); -extern void switch_threads(void *me, void *next); -extern int start_idle_thread(void *stack, void *switch_buf_ptr, - void **fork_buf_ptr); +extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); +extern void switch_threads(jmp_buf *me, jmp_buf *you); +extern int start_idle_thread(void *stack, jmp_buf *switch_buf); extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); extern void halt_skas(void); diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h index 853b26f148c5bde6043a40dd74c288c7a8e6a4f7..e88926b16072e21d0b1c4af2f854397c24a8bfd0 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; extern int skas_needs_stub; extern int user_thread(unsigned long stack, int flags); -extern void new_thread_proc(void *stack, void (*handler)(int sig)); -extern void new_thread_handler(int sig); +extern void new_thread_handler(void); extern void handle_syscall(union uml_pt_regs *regs); extern int new_mm(unsigned long stack); 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 ea1ba3d42aee7b87fdf8734a4251534311ff97cd..11bafab669e942b517e403b13cb966eb2c9242b0 100644 --- a/arch/um/include/sysdep-i386/archsetjmp.h +++ b/arch/um/include/sysdep-i386/archsetjmp.h @@ -16,4 +16,7 @@ struct __jmp_buf { typedef struct __jmp_buf jmp_buf[1]; +#define JB_IP __eip +#define JB_SP __esp + #endif /* _SETJMP_H */ diff --git a/arch/um/include/sysdep-x86_64/archsetjmp.h b/arch/um/include/sysdep-x86_64/archsetjmp.h index 454fc60aff6d5a0ba12f403bf2b896f67e999aaa..9a5e1a6ec80042095b5f3562d2c2107e85431508 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 { typedef struct __jmp_buf jmp_buf[1]; +#define JB_IP __rip +#define JB_SP __rsp + #endif /* _SETJMP_H */ diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 55caeec8b25725d856db3af7a00d678277a520e5..c73d47c57abe3068de7b82e0ff0a26946701c044 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) switch_timers(0); switch_threads(&from->thread.mode.skas.switch_buf, - to->thread.mode.skas.switch_buf); + &to->thread.mode.skas.switch_buf); arch_switch_to_skas(current->thread.prev_sched, current); @@ -43,21 +43,21 @@ void switch_to_skas(void *prev, void *next) extern void schedule_tail(struct task_struct *prev); -void new_thread_handler(int sig) +/* This is called magically, by its address being stuffed in a jmp_buf + * and being longjmp-d to. + */ +void new_thread_handler(void) { int (*fn)(void *), n; void *arg; - fn = current->thread.request.u.thread.proc; - arg = current->thread.request.u.thread.arg; - os_usr1_signal(1); - thread_wait(¤t->thread.mode.skas.switch_buf, - current->thread.mode.skas.fork_buf); - if(current->thread.prev_sched != NULL) schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + /* The return value is 1 if the kernel thread execs a process, * 0 if it just exits */ @@ -70,22 +70,13 @@ void new_thread_handler(int sig) else do_exit(0); } -void new_thread_proc(void *stack, void (*handler)(int sig)) -{ - init_new_thread_stack(stack, handler); - os_usr1_process(os_getpid()); -} - void release_thread_skas(struct task_struct *task) { } -void fork_handler(int sig) +/* Called magically, see new_thread_handler above */ +void fork_handler(void) { - os_usr1_signal(1); - thread_wait(¤t->thread.mode.skas.switch_buf, - current->thread.mode.skas.fork_buf); - force_flush_all(); if(current->thread.prev_sched == NULL) panic("blech"); @@ -109,7 +100,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { - void (*handler)(int); + void (*handler)(void); if(current->thread.forking){ 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, } new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf, - &p->thread.mode.skas.fork_buf, handler); + handler); return(0); } @@ -182,8 +173,7 @@ int start_uml_skas(void) init_task.thread.request.u.thread.proc = start_kernel_proc; init_task.thread.request.u.thread.arg = NULL; return(start_idle_thread(task_stack_page(&init_task), - &init_task.thread.mode.skas.switch_buf, - &init_task.thread.mode.skas.fork_buf)); + &init_task.thread.mode.skas.switch_buf)); } 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 42e3d1ed802cadf01a6f06345daf8ecc327f05d5..cb9ab54146cc6126ac5a6344a520f4e0e8a8f25c 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, } } -void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, - void (*handler)(int)) +void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) { - unsigned long flags; - jmp_buf switch_buf, fork_buf; - - *switch_buf_ptr = &switch_buf; - *fork_buf_ptr = &fork_buf; - - /* Somewhat subtle - siglongjmp restores the signal mask before doing - * the longjmp. This means that when jumping from one stack to another - * when the target stack has interrupts enabled, an interrupt may occur - * on the source stack. This is bad when starting up a process because - * it's not supposed to get timer ticks until it has been scheduled. - * So, we disable interrupts around the sigsetjmp to ensure that - * they can't happen until we get back here where they are safe. - */ - flags = get_signals(); - block_signals(); - if(UML_SETJMP(&fork_buf) == 0) - new_thread_proc(stack, handler); - - remove_sigstack(); - - set_signals(flags); + (*buf)[0].JB_IP = (unsigned long) handler; + (*buf)[0].JB_SP = (unsigned long) stack + + (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *); } #define INIT_JMP_NEW_THREAD 0 -#define INIT_JMP_REMOVE_SIGSTACK 1 -#define INIT_JMP_CALLBACK 2 -#define INIT_JMP_HALT 3 -#define INIT_JMP_REBOOT 4 - -void thread_wait(void *sw, void *fb) -{ - jmp_buf buf, **switch_buf = sw, *fork_buf; - - *switch_buf = &buf; - fork_buf = fb; - if(UML_SETJMP(&buf) == 0) - UML_LONGJMP(fork_buf, INIT_JMP_REMOVE_SIGSTACK); -} +#define INIT_JMP_CALLBACK 1 +#define INIT_JMP_HALT 2 +#define INIT_JMP_REBOOT 3 -void switch_threads(void *me, void *next) +void switch_threads(jmp_buf *me, jmp_buf *you) { - jmp_buf my_buf, **me_ptr = me, *next_buf = next; - - *me_ptr = &my_buf; - if(UML_SETJMP(&my_buf) == 0) - UML_LONGJMP(next_buf, 1); + if(UML_SETJMP(me) == 0) + UML_LONGJMP(you, 1); } static jmp_buf initial_jmpbuf; @@ -503,23 +469,21 @@ static void (*cb_proc)(void *arg); static void *cb_arg; static jmp_buf *cb_back; -int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) +int start_idle_thread(void *stack, jmp_buf *switch_buf) { - jmp_buf **switch_buf = switch_buf_ptr; int n; set_handler(SIGWINCH, (__sighandler_t) sig_handler, SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, SIGVTALRM, -1); - *fork_buf_ptr = &initial_jmpbuf; n = UML_SETJMP(&initial_jmpbuf); switch(n){ case INIT_JMP_NEW_THREAD: - new_thread_proc((void *) stack, new_thread_handler); - break; - case INIT_JMP_REMOVE_SIGSTACK: - remove_sigstack(); + (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; + (*switch_buf)[0].JB_SP = (unsigned long) stack + + (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - + sizeof(void *); break; case INIT_JMP_CALLBACK: (*cb_proc)(cb_arg); @@ -534,7 +498,7 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) default: panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); } - UML_LONGJMP(*switch_buf, 1); + UML_LONGJMP(switch_buf, 1); } 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 afa4fe1ca9f13eaba82ebd9b33df0602e47ca022..d99bbddffdb99781730f50d66155abf80d80afc1 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -13,6 +13,7 @@ struct task_struct; #include "asm/ptrace.h" #include "choose-mode.h" #include "registers.h" +#include "sysdep/archsetjmp.h" struct mm_struct; @@ -43,8 +44,7 @@ struct thread_struct { #endif #ifdef CONFIG_MODE_SKAS struct { - void *switch_buf; - void *fork_buf; + jmp_buf switch_buf; int mm_count; } skas; #endif @@ -138,7 +138,7 @@ extern struct cpuinfo_um cpu_data[]; #ifdef CONFIG_MODE_SKAS #define KSTK_REG(tsk, reg) \ - get_thread_reg(reg, tsk->thread.mode.skas.switch_buf) + get_thread_reg(reg, &tsk->thread.mode.skas.switch_buf) #else #define KSTK_REG(tsk, reg) (0xbadbabe) #endif