diff options
-rw-r--r-- | arch/um/include/kern_util.h | 3 | ||||
-rw-r--r-- | arch/um/kernel/dyn.lds.S | 2 | ||||
-rw-r--r-- | arch/um/kernel/init_task.c | 16 | ||||
-rw-r--r-- | arch/um/kernel/irq.c | 111 | ||||
-rw-r--r-- | arch/um/kernel/skas/process.c | 4 | ||||
-rw-r--r-- | arch/um/kernel/uml.lds.S | 2 | ||||
-rw-r--r-- | arch/um/os-Linux/signal.c | 40 | ||||
-rw-r--r-- | arch/um/os-Linux/sys-i386/signal.c | 8 | ||||
-rw-r--r-- | arch/um/os-Linux/sys-x86_64/signal.c | 6 | ||||
-rw-r--r-- | include/asm-um/thread_info.h | 2 |
10 files changed, 180 insertions, 14 deletions
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 50a49691e0e6..8d7f7c1cb9c6 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h | |||
@@ -117,4 +117,7 @@ extern void sigio_handler(int sig, union uml_pt_regs *regs); | |||
117 | 117 | ||
118 | extern void copy_sc(union uml_pt_regs *regs, void *from); | 118 | extern void copy_sc(union uml_pt_regs *regs, void *from); |
119 | 119 | ||
120 | unsigned long to_irq_stack(int sig, unsigned long *mask_out); | ||
121 | unsigned long from_irq_stack(int nested); | ||
122 | |||
120 | #endif | 123 | #endif |
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index e36f92b463ce..87a4e4427d8d 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S | |||
@@ -97,6 +97,8 @@ SECTIONS | |||
97 | .data : { | 97 | .data : { |
98 | . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ | 98 | . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ |
99 | *(.data.init_task) | 99 | *(.data.init_task) |
100 | . = ALIGN(KERNEL_STACK_SIZE); | ||
101 | *(.data.init_irqstack) | ||
100 | *(.data .data.* .gnu.linkonce.d.*) | 102 | *(.data .data.* .gnu.linkonce.d.*) |
101 | SORT(CONSTRUCTORS) | 103 | SORT(CONSTRUCTORS) |
102 | } | 104 | } |
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index f5385a3799bb..d4f1d1ab252b 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,intel.linux}.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
@@ -33,14 +33,18 @@ EXPORT_SYMBOL(init_task); | |||
33 | /* | 33 | /* |
34 | * Initial thread structure. | 34 | * Initial thread structure. |
35 | * | 35 | * |
36 | * We need to make sure that this is 16384-byte aligned due to the | 36 | * We need to make sure that this is aligned due to the |
37 | * way process stacks are handled. This is done by having a special | 37 | * way process stacks are handled. This is done by having a special |
38 | * "init_task" linker map entry.. | 38 | * "init_task" linker map entry.. |
39 | */ | 39 | */ |
40 | 40 | ||
41 | union thread_union init_thread_union | 41 | union thread_union init_thread_union |
42 | __attribute__((__section__(".data.init_task"))) = | 42 | __attribute__((__section__(".data.init_task"))) = |
43 | { INIT_THREAD_INFO(init_task) }; | 43 | { INIT_THREAD_INFO(init_task) }; |
44 | |||
45 | union thread_union cpu0_irqstack | ||
46 | __attribute__((__section__(".data.init_irqstack"))) = | ||
47 | { INIT_THREAD_INFO(init_task) }; | ||
44 | 48 | ||
45 | void unprotect_stack(unsigned long stack) | 49 | void unprotect_stack(unsigned long stack) |
46 | { | 50 | { |
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index a9651a175eb5..dba04d88b432 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "sigio.h" | 32 | #include "sigio.h" |
33 | #include "um_malloc.h" | 33 | #include "um_malloc.h" |
34 | #include "misc_constants.h" | 34 | #include "misc_constants.h" |
35 | #include "as-layout.h" | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * Generic, controller-independent functions: | 38 | * Generic, controller-independent functions: |
@@ -468,3 +469,113 @@ int init_aio_irq(int irq, char *name, irq_handler_t handler) | |||
468 | out: | 469 | out: |
469 | return err; | 470 | return err; |
470 | } | 471 | } |
472 | |||
473 | /* | ||
474 | * IRQ stack entry and exit: | ||
475 | * | ||
476 | * Unlike i386, UML doesn't receive IRQs on the normal kernel stack | ||
477 | * and switch over to the IRQ stack after some preparation. We use | ||
478 | * sigaltstack to receive signals on a separate stack from the start. | ||
479 | * These two functions make sure the rest of the kernel won't be too | ||
480 | * upset by being on a different stack. The IRQ stack has a | ||
481 | * thread_info structure at the bottom so that current et al continue | ||
482 | * to work. | ||
483 | * | ||
484 | * to_irq_stack copies the current task's thread_info to the IRQ stack | ||
485 | * thread_info and sets the tasks's stack to point to the IRQ stack. | ||
486 | * | ||
487 | * from_irq_stack copies the thread_info struct back (flags may have | ||
488 | * been modified) and resets the task's stack pointer. | ||
489 | * | ||
490 | * Tricky bits - | ||
491 | * | ||
492 | * What happens when two signals race each other? UML doesn't block | ||
493 | * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal | ||
494 | * could arrive while a previous one is still setting up the | ||
495 | * thread_info. | ||
496 | * | ||
497 | * There are three cases - | ||
498 | * The first interrupt on the stack - sets up the thread_info and | ||
499 | * handles the interrupt | ||
500 | * A nested interrupt interrupting the copying of the thread_info - | ||
501 | * can't handle the interrupt, as the stack is in an unknown state | ||
502 | * A nested interrupt not interrupting the copying of the | ||
503 | * thread_info - doesn't do any setup, just handles the interrupt | ||
504 | * | ||
505 | * The first job is to figure out whether we interrupted stack setup. | ||
506 | * This is done by xchging the signal mask with thread_info->pending. | ||
507 | * If the value that comes back is zero, then there is no setup in | ||
508 | * progress, and the interrupt can be handled. If the value is | ||
509 | * non-zero, then there is stack setup in progress. In order to have | ||
510 | * the interrupt handled, we leave our signal in the mask, and it will | ||
511 | * be handled by the upper handler after it has set up the stack. | ||
512 | * | ||
513 | * Next is to figure out whether we are the outer handler or a nested | ||
514 | * one. As part of setting up the stack, thread_info->real_thread is | ||
515 | * set to non-NULL (and is reset to NULL on exit). This is the | ||
516 | * nesting indicator. If it is non-NULL, then the stack is already | ||
517 | * set up and the handler can run. | ||
518 | */ | ||
519 | |||
520 | static unsigned long pending_mask; | ||
521 | |||
522 | unsigned long to_irq_stack(int sig, unsigned long *mask_out) | ||
523 | { | ||
524 | struct thread_info *ti; | ||
525 | unsigned long mask, old; | ||
526 | int nested; | ||
527 | |||
528 | mask = xchg(&pending_mask, 1 << sig); | ||
529 | if(mask != 0){ | ||
530 | /* If any interrupts come in at this point, we want to | ||
531 | * make sure that their bits aren't lost by our | ||
532 | * putting our bit in. So, this loop accumulates bits | ||
533 | * until xchg returns the same value that we put in. | ||
534 | * When that happens, there were no new interrupts, | ||
535 | * and pending_mask contains a bit for each interrupt | ||
536 | * that came in. | ||
537 | */ | ||
538 | old = 1 << sig; | ||
539 | do { | ||
540 | old |= mask; | ||
541 | mask = xchg(&pending_mask, old); | ||
542 | } while(mask != old); | ||
543 | return 1; | ||
544 | } | ||
545 | |||
546 | ti = current_thread_info(); | ||
547 | nested = (ti->real_thread != NULL); | ||
548 | if(!nested){ | ||
549 | struct task_struct *task; | ||
550 | struct thread_info *tti; | ||
551 | |||
552 | task = cpu_tasks[ti->cpu].task; | ||
553 | tti = task_thread_info(task); | ||
554 | *ti = *tti; | ||
555 | ti->real_thread = tti; | ||
556 | task->stack = ti; | ||
557 | } | ||
558 | |||
559 | mask = xchg(&pending_mask, 0); | ||
560 | *mask_out |= mask | nested; | ||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | unsigned long from_irq_stack(int nested) | ||
565 | { | ||
566 | struct thread_info *ti, *to; | ||
567 | unsigned long mask; | ||
568 | |||
569 | ti = current_thread_info(); | ||
570 | |||
571 | pending_mask = 1; | ||
572 | |||
573 | to = ti->real_thread; | ||
574 | current->stack = to; | ||
575 | ti->real_thread = NULL; | ||
576 | *to = *ti; | ||
577 | |||
578 | mask = xchg(&pending_mask, 0); | ||
579 | return mask & ~1; | ||
580 | } | ||
581 | |||
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index a96ae1a0610e..2a69a7ce5792 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c | |||
@@ -163,8 +163,12 @@ static int start_kernel_proc(void *unused) | |||
163 | 163 | ||
164 | extern int userspace_pid[]; | 164 | extern int userspace_pid[]; |
165 | 165 | ||
166 | extern char cpu0_irqstack[]; | ||
167 | |||
166 | int start_uml_skas(void) | 168 | int start_uml_skas(void) |
167 | { | 169 | { |
170 | stack_protections((unsigned long) &cpu0_irqstack); | ||
171 | set_sigstack(cpu0_irqstack, THREAD_SIZE); | ||
168 | if(proc_mm) | 172 | if(proc_mm) |
169 | userspace_pid[0] = start_userspace(0); | 173 | userspace_pid[0] = start_userspace(0); |
170 | 174 | ||
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index f6301274cf3c..bc59f97e34d0 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S | |||
@@ -59,6 +59,8 @@ SECTIONS | |||
59 | { | 59 | { |
60 | . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ | 60 | . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ |
61 | *(.data.init_task) | 61 | *(.data.init_task) |
62 | . = ALIGN(KERNEL_STACK_SIZE); | ||
63 | *(.data.init_irqstack) | ||
62 | *(.data) | 64 | *(.data) |
63 | *(.gnu.linkonce.d*) | 65 | *(.gnu.linkonce.d*) |
64 | CONSTRUCTORS | 66 | CONSTRUCTORS |
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 420ee86d0d1a..18e5c8b67eb8 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c | |||
@@ -117,6 +117,46 @@ void remove_sigstack(void) | |||
117 | 117 | ||
118 | void (*handlers[_NSIG])(int sig, struct sigcontext *sc); | 118 | void (*handlers[_NSIG])(int sig, struct sigcontext *sc); |
119 | 119 | ||
120 | void handle_signal(int sig, struct sigcontext *sc) | ||
121 | { | ||
122 | unsigned long pending = 0; | ||
123 | |||
124 | do { | ||
125 | int nested, bail; | ||
126 | |||
127 | /* | ||
128 | * pending comes back with one bit set for each | ||
129 | * interrupt that arrived while setting up the stack, | ||
130 | * plus a bit for this interrupt, plus the zero bit is | ||
131 | * set if this is a nested interrupt. | ||
132 | * If bail is true, then we interrupted another | ||
133 | * handler setting up the stack. In this case, we | ||
134 | * have to return, and the upper handler will deal | ||
135 | * with this interrupt. | ||
136 | */ | ||
137 | bail = to_irq_stack(sig, &pending); | ||
138 | if(bail) | ||
139 | return; | ||
140 | |||
141 | nested = pending & 1; | ||
142 | pending &= ~1; | ||
143 | |||
144 | while((sig = ffs(pending)) != 0){ | ||
145 | sig--; | ||
146 | pending &= ~(1 << sig); | ||
147 | (*handlers[sig])(sig, sc); | ||
148 | } | ||
149 | |||
150 | /* Again, pending comes back with a mask of signals | ||
151 | * that arrived while tearing down the stack. If this | ||
152 | * is non-zero, we just go back, set up the stack | ||
153 | * again, and handle the new interrupts. | ||
154 | */ | ||
155 | if(!nested) | ||
156 | pending = from_irq_stack(nested); | ||
157 | } while(pending); | ||
158 | } | ||
159 | |||
120 | extern void hard_handler(int sig); | 160 | extern void hard_handler(int sig); |
121 | 161 | ||
122 | void set_handler(int sig, void (*handler)(int), int flags, ...) | 162 | void set_handler(int sig, void (*handler)(int), int flags, ...) |
diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c index 0d3eae518352..f311609f93da 100644 --- a/arch/um/os-Linux/sys-i386/signal.c +++ b/arch/um/os-Linux/sys-i386/signal.c | |||
@@ -1,15 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) | 2 | * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <signal.h> | 6 | #include <signal.h> |
7 | 7 | ||
8 | extern void (*handlers[])(int sig, struct sigcontext *sc); | 8 | extern void handle_signal(int sig, struct sigcontext *sc); |
9 | 9 | ||
10 | void hard_handler(int sig) | 10 | void hard_handler(int sig) |
11 | { | 11 | { |
12 | struct sigcontext *sc = (struct sigcontext *) (&sig + 1); | 12 | handle_signal(sig, (struct sigcontext *) (&sig + 1)); |
13 | |||
14 | (*handlers[sig])(sig, sc); | ||
15 | } | 13 | } |
diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c index 3f369e5f976b..82a388822cd3 100644 --- a/arch/um/os-Linux/sys-x86_64/signal.c +++ b/arch/um/os-Linux/sys-x86_64/signal.c | |||
@@ -1,16 +1,16 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) | 2 | * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <signal.h> | 6 | #include <signal.h> |
7 | 7 | ||
8 | extern void (*handlers[])(int sig, struct sigcontext *sc); | 8 | extern void handle_signal(int sig, struct sigcontext *sc); |
9 | 9 | ||
10 | void hard_handler(int sig) | 10 | void hard_handler(int sig) |
11 | { | 11 | { |
12 | struct ucontext *uc; | 12 | struct ucontext *uc; |
13 | asm("movq %%rdx, %0" : "=r" (uc)); | 13 | asm("movq %%rdx, %0" : "=r" (uc)); |
14 | 14 | ||
15 | (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext); | 15 | handle_signal(sig, (struct sigcontext *) &uc->uc_mcontext); |
16 | } | 16 | } |
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index 261e2f4528f6..18a13ba74605 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h | |||
@@ -22,6 +22,7 @@ struct thread_info { | |||
22 | 0-0xBFFFFFFF for user | 22 | 0-0xBFFFFFFF for user |
23 | 0-0xFFFFFFFF for kernel */ | 23 | 0-0xFFFFFFFF for kernel */ |
24 | struct restart_block restart_block; | 24 | struct restart_block restart_block; |
25 | struct thread_info *real_thread; /* Points to non-IRQ stack */ | ||
25 | }; | 26 | }; |
26 | 27 | ||
27 | #define INIT_THREAD_INFO(tsk) \ | 28 | #define INIT_THREAD_INFO(tsk) \ |
@@ -35,6 +36,7 @@ struct thread_info { | |||
35 | .restart_block = { \ | 36 | .restart_block = { \ |
36 | .fn = do_no_restart_syscall, \ | 37 | .fn = do_no_restart_syscall, \ |
37 | }, \ | 38 | }, \ |
39 | .real_thread = NULL, \ | ||
38 | } | 40 | } |
39 | 41 | ||
40 | #define init_thread_info (init_thread_union.thread_info) | 42 | #define init_thread_info (init_thread_union.thread_info) |