X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=arch%2Fum%2Fos-Linux%2Fsignal.c;h=5aade6027e40e71f78ae1c49d5253a2a79bcc534;hb=fe2cc53e;hp=b98f7ea2d2f6562ce894e4a4fe6f57b003af7768;hpb=b981d8b3f5e008ff10d993be633ad00564fc22cd;p=mv-sheeva.git diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index b98f7ea2d2f..5aade6027e4 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -1,26 +1,58 @@ /* * Copyright (C) 2004 PathScale, Inc + * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include -#include -#include #include -#include #include -#include -#include -#include "user.h" -#include "signal_kern.h" -#include "sysdep/sigcontext.h" -#include "sysdep/barrier.h" -#include "sigcontext.h" -#include "mode.h" +#include +#include +#include +#include "as-layout.h" +#include "kern_util.h" #include "os.h" +#include "process.h" +#include "sysdep/barrier.h" +#include "sysdep/sigcontext.h" +#include "user.h" + +/* Copied from linux/compiler-gcc.h since we can't include it directly */ +#define barrier() __asm__ __volatile__("": : :"memory") -/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled - * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to +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 * profiling is not thread-safe, then that is not my problem. We can disable * profiling when SMP is enabled in that case. @@ -31,49 +63,35 @@ #define SIGVTALRM_BIT 1 #define SIGVTALRM_MASK (1 << SIGVTALRM_BIT) -#define SIGALRM_BIT 2 -#define SIGALRM_MASK (1 << SIGALRM_BIT) - -/* These are used by both the signal handlers and - * block/unblock_signals. I don't want modifications cached in a - * register - they must go straight to memory. - */ -static volatile int signals_enabled = 1; -static volatile int pending = 0; +static int signals_enabled; +static unsigned int signals_pending; void sig_handler(int sig, struct sigcontext *sc) { int enabled; enabled = signals_enabled; - if(!enabled && (sig == SIGIO)){ - pending |= SIGIO_MASK; + if (!enabled && (sig == SIGIO)) { + signals_pending |= SIGIO_MASK; return; } block_signals(); - CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, - sig, sc); + sig_handler_common(sig, sc); set_signals(enabled); } -static void real_alarm_handler(int sig, struct sigcontext *sc) +static void real_alarm_handler(struct sigcontext *sc) { - union uml_pt_regs regs; - - if(sig == SIGALRM) - switch_timers(0); + struct uml_pt_regs regs; - if(sc != NULL) + if (sc != NULL) copy_sc(®s, sc); - regs.skas.is_user = 0; + regs.is_user = 0; unblock_signals(); - timer_handler(sig, ®s); - - if(sig == SIGALRM) - switch_timers(1); + timer_handler(SIGVTALRM, ®s); } void alarm_handler(int sig, struct sigcontext *sc) @@ -81,40 +99,33 @@ void alarm_handler(int sig, struct sigcontext *sc) int enabled; enabled = signals_enabled; - if(!signals_enabled){ - if(sig == SIGVTALRM) - pending |= SIGVTALRM_MASK; - else pending |= SIGALRM_MASK; - + if (!signals_enabled) { + signals_pending |= SIGVTALRM_MASK; return; } block_signals(); - real_alarm_handler(sig, sc); + real_alarm_handler(sc); set_signals(enabled); } +void timer_init(void) +{ + set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, + SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1); +} + void set_sigstack(void *sig_stack, int size) { stack_t stack = ((stack_t) { .ss_flags = 0, .ss_sp = (__ptr_t) sig_stack, .ss_size = size - sizeof(void *) }); - if(sigaltstack(&stack, NULL) != 0) + if (sigaltstack(&stack, NULL) != 0) 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) @@ -135,26 +146,27 @@ void handle_signal(int sig, struct sigcontext *sc) * with this interrupt. */ bail = to_irq_stack(&pending); - if(bail) + if (bail) return; nested = pending & 1; pending &= ~1; - while((sig = ffs(pending)) != 0){ + while ((sig = ffs(pending)) != 0){ sig--; pending &= ~(1 << sig); (*handlers[sig])(sig, sc); } - /* Again, pending comes back with a mask of signals + /* + * Again, pending comes back with a mask of signals * that arrived while tearing down the stack. If this * is non-zero, we just go back, set up the stack * again, and handle the new interrupts. */ - if(!nested) + if (!nested) pending = from_irq_stack(nested); - } while(pending); + } while (pending); } extern void hard_handler(int sig); @@ -172,99 +184,97 @@ void set_handler(int sig, void (*handler)(int), int flags, ...) sigemptyset(&action.sa_mask); va_start(ap, flags); - while((mask = va_arg(ap, int)) != -1) + while ((mask = va_arg(ap, int)) != -1) 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) + if (sigaction(sig, &action, NULL) < 0) panic("sigaction failed - errno = %d\n", errno); sigemptyset(&sig_mask); sigaddset(&sig_mask, sig); - if(sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0) + if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0) panic("sigprocmask failed - errno = %d\n", errno); } int change_sig(int signal, int on) { - sigset_t sigset, old; + sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, signal); - sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old); - return(!sigismember(&old, signal)); + if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0) + return -errno; + + return 0; } void block_signals(void) { signals_enabled = 0; - /* This must return with signals disabled, so this barrier + /* + * This must return with signals disabled, so this barrier * ensures that writes are flushed out before the return. * This might matter if gcc figures out how to inline this and * decides to shuffle this code into the caller. */ - mb(); + barrier(); } void unblock_signals(void) { int save_pending; - if(signals_enabled == 1) + if (signals_enabled == 1) return; - /* We loop because the IRQ handler returns with interrupts off. So, + /* + * 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){ - /* Save and reset save_pending after enabling signals. This - * way, pending won't be changed while we're reading it. + while (1) { + /* + * Save and reset save_pending after enabling signals. This + * 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. */ - mb(); - - save_pending = pending; - if(save_pending == 0){ - /* This must return with signals enabled, so - * this barrier ensures that writes are - * flushed out before the return. This might - * matter if gcc figures out how to inline - * this (unlikely, given its size) and decides - * to shuffle this code into the caller. - */ - mb(); + barrier(); + + save_pending = signals_pending; + if (save_pending == 0) return; - } - pending = 0; + signals_pending = 0; - /* We have pending interrupts, so disable signals, as the + /* + * We have pending interrupts, so disable signals, as the * handlers expect them off when they are called. They will * be enabled again above. */ signals_enabled = 0; - /* Deal with SIGIO first because the alarm handler might + /* + * Deal with SIGIO first because the alarm handler might * schedule, leaving the pending SIGIO stranded until we come * back here. */ - if(save_pending & SIGIO_MASK) - CHOOSE_MODE_PROC(sig_handler_common_tt, - sig_handler_common_skas, SIGIO, NULL); - - if(save_pending & SIGALRM_MASK) - real_alarm_handler(SIGALRM, NULL); + if (save_pending & SIGIO_MASK) + sig_handler_common(SIGIO, NULL); - if(save_pending & SIGVTALRM_MASK) - real_alarm_handler(SIGVTALRM, NULL); + if (save_pending & SIGVTALRM_MASK) + real_alarm_handler(NULL); } } @@ -276,11 +286,11 @@ int get_signals(void) int set_signals(int enable) { int ret; - if(signals_enabled == enable) + if (signals_enabled == enable) return enable; ret = signals_enabled; - if(enable) + if (enable) unblock_signals(); else block_signals();