aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/include/os.h10
-rw-r--r--arch/um/include/skas/skas.h3
-rw-r--r--arch/um/include/sysdep-i386/archsetjmp.h3
-rw-r--r--arch/um/include/sysdep-x86_64/archsetjmp.h3
-rw-r--r--arch/um/kernel/skas/process_kern.c36
-rw-r--r--arch/um/os-Linux/skas/process.c68
-rw-r--r--include/asm-um/processor-generic.h6
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);
308extern void userspace(union uml_pt_regs *regs); 309extern void userspace(union uml_pt_regs *regs);
309extern void map_stub_pages(int fd, unsigned long code, 310extern void map_stub_pages(int fd, unsigned long code,
310 unsigned long data, unsigned long stack); 311 unsigned long data, unsigned long stack);
311extern void new_thread(void *stack, void **switch_buf_ptr, 312extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void));
312 void **fork_buf_ptr, void (*handler)(int)); 313extern void switch_threads(jmp_buf *me, jmp_buf *you);
313extern void thread_wait(void *sw, void *fb); 314extern int start_idle_thread(void *stack, jmp_buf *switch_buf);
314extern void switch_threads(void *me, void *next);
315extern int start_idle_thread(void *stack, void *switch_buf_ptr,
316 void **fork_buf_ptr);
317extern void initial_thread_cb_skas(void (*proc)(void *), 315extern void initial_thread_cb_skas(void (*proc)(void *),
318 void *arg); 316 void *arg);
319extern void halt_skas(void); 317extern 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;
14extern int skas_needs_stub; 14extern int skas_needs_stub;
15 15
16extern int user_thread(unsigned long stack, int flags); 16extern int user_thread(unsigned long stack, int flags);
17extern void new_thread_proc(void *stack, void (*handler)(int sig)); 17extern void new_thread_handler(void);
18extern void new_thread_handler(int sig);
19extern void handle_syscall(union uml_pt_regs *regs); 18extern void handle_syscall(union uml_pt_regs *regs);
20extern int new_mm(unsigned long stack); 19extern int new_mm(unsigned long stack);
21extern void get_skas_faultinfo(int pid, struct faultinfo * fi); 20extern 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
17typedef struct __jmp_buf jmp_buf[1]; 17typedef 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
19typedef struct __jmp_buf jmp_buf[1]; 19typedef 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
44extern void schedule_tail(struct task_struct *prev); 44extern void schedule_tail(struct task_struct *prev);
45 45
46void 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 */
49void 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(&current->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
73void 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
79void release_thread_skas(struct task_struct *task) 73void release_thread_skas(struct task_struct *task)
80{ 74{
81} 75}
82 76
83void fork_handler(int sig) 77/* Called magically, see new_thread_handler above */
78void fork_handler(void)
84{ 79{
85 os_usr1_signal(1);
86 thread_wait(&current->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, &regs->regs.skas, 106 memcpy(&p->thread.regs.regs.skas, &regs->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
189int external_pid_skas(struct task_struct *task) 179int 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
447void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, 447void 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
480void 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
490void switch_threads(void *me, void *next) 459void 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
499static jmp_buf initial_jmpbuf; 465static jmp_buf initial_jmpbuf;
@@ -503,23 +469,21 @@ static void (*cb_proc)(void *arg);
503static void *cb_arg; 469static void *cb_arg;
504static jmp_buf *cb_back; 470static jmp_buf *cb_back;
505 471
506int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) 472int 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
540void initial_thread_cb_skas(void (*proc)(void *), void *arg) 504void 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
17struct mm_struct; 18struct 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