aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/include/kern_util.h3
-rw-r--r--arch/um/kernel/dyn.lds.S2
-rw-r--r--arch/um/kernel/init_task.c16
-rw-r--r--arch/um/kernel/irq.c111
-rw-r--r--arch/um/kernel/skas/process.c4
-rw-r--r--arch/um/kernel/uml.lds.S2
-rw-r--r--arch/um/os-Linux/signal.c40
-rw-r--r--arch/um/os-Linux/sys-i386/signal.c8
-rw-r--r--arch/um/os-Linux/sys-x86_64/signal.c6
-rw-r--r--include/asm-um/thread_info.h2
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
118extern void copy_sc(union uml_pt_regs *regs, void *from); 118extern void copy_sc(union uml_pt_regs *regs, void *from);
119 119
120unsigned long to_irq_stack(int sig, unsigned long *mask_out);
121unsigned 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
41union thread_union init_thread_union 41union 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
45union thread_union cpu0_irqstack
46 __attribute__((__section__(".data.init_irqstack"))) =
47 { INIT_THREAD_INFO(init_task) };
44 48
45void unprotect_stack(unsigned long stack) 49void 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
520static unsigned long pending_mask;
521
522unsigned 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
564unsigned 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
164extern int userspace_pid[]; 164extern int userspace_pid[];
165 165
166extern char cpu0_irqstack[];
167
166int start_uml_skas(void) 168int 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
118void (*handlers[_NSIG])(int sig, struct sigcontext *sc); 118void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
119 119
120void 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
120extern void hard_handler(int sig); 160extern void hard_handler(int sig);
121 161
122void set_handler(int sig, void (*handler)(int), int flags, ...) 162void 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
8extern void (*handlers[])(int sig, struct sigcontext *sc); 8extern void handle_signal(int sig, struct sigcontext *sc);
9 9
10void hard_handler(int sig) 10void 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
8extern void (*handlers[])(int sig, struct sigcontext *sc); 8extern void handle_signal(int sig, struct sigcontext *sc);
9 9
10void hard_handler(int sig) 10void 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)