uml: redo host capability detection and disabling
[safe/jmp/linux-2.6] / arch / um / os-Linux / signal.c
index 62a66f3..3f1694b 100644 (file)
@@ -9,6 +9,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <strings.h>
+#include "as-layout.h"
 #include "kern_util.h"
 #include "os.h"
 #include "sysdep/barrier.h"
 /* Copied from linux/compiler-gcc.h since we can't include it directly */
 #define barrier() __asm__ __volatile__("": : :"memory")
 
+void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {
+       [SIGTRAP]       = relay_signal,
+       [SIGFPE]        = relay_signal,
+       [SIGILL]        = relay_signal,
+       [SIGWINCH]      = winch,
+       [SIGBUS]        = bus_handler,
+       [SIGSEGV]       = segv_handler,
+       [SIGIO]         = sigio_handler,
+       [SIGVTALRM]     = timer_handler };
+
+static void sig_handler_common(int sig, struct sigcontext *sc)
+{
+       struct uml_pt_regs r;
+       int save_errno = errno;
+
+       r.is_user = 0;
+       if (sig == SIGSEGV) {
+               /* For segfaults, we want the data from the sigcontext. */
+               copy_sc(&r, sc);
+               GET_FAULTINFO_FROM_SC(r.faultinfo, sc);
+       }
+
+       /* enable signals if sig isn't IRQ signal */
+       if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
+               unblock_signals();
+
+       (*sig_info[sig])(sig, &r);
+
+       errno = save_errno;
+}
+
 /*
  * These are the asynchronous signals.  SIGPROF is excluded because we want to
  * be able to profile all of UML, not just the non-critical sections.  If
@@ -31,7 +63,7 @@
 #define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
 
 static int signals_enabled;
-static unsigned int pending;
+static unsigned int signals_pending;
 
 void sig_handler(int sig, struct sigcontext *sc)
 {
@@ -39,13 +71,13 @@ void sig_handler(int sig, struct sigcontext *sc)
 
        enabled = signals_enabled;
        if (!enabled && (sig == SIGIO)) {
-               pending |= SIGIO_MASK;
+               signals_pending |= SIGIO_MASK;
                return;
        }
 
        block_signals();
 
-       sig_handler_common_skas(sig, sc);
+       sig_handler_common(sig, sc);
 
        set_signals(enabled);
 }
@@ -67,7 +99,7 @@ void alarm_handler(int sig, struct sigcontext *sc)
 
        enabled = signals_enabled;
        if (!signals_enabled) {
-               pending |= SIGVTALRM_MASK;
+               signals_pending |= SIGVTALRM_MASK;
                return;
        }
 
@@ -93,16 +125,6 @@ void set_sigstack(void *sig_stack, int size)
                panic("enabling signal stack failed, errno = %d\n", errno);
 }
 
-void remove_sigstack(void)
-{
-       stack_t stack = ((stack_t) { .ss_flags  = SS_DISABLE,
-                                    .ss_sp     = NULL,
-                                    .ss_size   = 0 });
-
-       if (sigaltstack(&stack, NULL) != 0)
-               panic("disabling signal stack failed, errno = %d\n", errno);
-}
-
 void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
 
 void handle_signal(int sig, struct sigcontext *sc)
@@ -165,6 +187,9 @@ void set_handler(int sig, void (*handler)(int), int flags, ...)
                sigaddset(&action.sa_mask, mask);
        va_end(ap);
 
+       if (sig == SIGSEGV)
+               flags |= SA_NODEFER;
+
        action.sa_flags = flags;
        action.sa_restorer = NULL;
        if (sigaction(sig, &action, NULL) < 0)
@@ -178,13 +203,14 @@ void set_handler(int sig, void (*handler)(int), int flags, ...)
 
 int change_sig(int signal, int on)
 {
-       sigset_t sigset, old;
+       sigset_t sigset;
 
        sigemptyset(&sigset);
        sigaddset(&sigset, signal);
-       if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old) < 0)
+       if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0)
                return -errno;
-       return !sigismember(&old, signal);
+
+       return 0;
 }
 
 void block_signals(void)
@@ -209,26 +235,26 @@ void unblock_signals(void)
        /*
         * We loop because the IRQ handler returns with interrupts off.  So,
         * interrupts may have arrived and we need to re-enable them and
-        * recheck pending.
+        * recheck signals_pending.
         */
-       while(1) {
+       while (1) {
                /*
                 * Save and reset save_pending after enabling signals.  This
-                * way, pending won't be changed while we're reading it.
+                * way, signals_pending won't be changed while we're reading it.
                 */
                signals_enabled = 1;
 
                /*
-                * Setting signals_enabled and reading pending must
+                * Setting signals_enabled and reading signals_pending must
                 * happen in this order.
                 */
                barrier();
 
-               save_pending = pending;
+               save_pending = signals_pending;
                if (save_pending == 0)
                        return;
 
-               pending = 0;
+               signals_pending = 0;
 
                /*
                 * We have pending interrupts, so disable signals, as the
@@ -244,7 +270,7 @@ void unblock_signals(void)
                 * back here.
                 */
                if (save_pending & SIGIO_MASK)
-                       sig_handler_common_skas(SIGIO, NULL);
+                       sig_handler_common(SIGIO, NULL);
 
                if (save_pending & SIGVTALRM_MASK)
                        real_alarm_handler(NULL);