X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=arch%2Fpowerpc%2Fkernel%2Fsignal.c;h=a9c148a09361d3442ff0294f8f6b81a96be72c08;hb=5f9f375a62d3fd3d7f0d5adc23039ade523e62ba;hp=f92856b98b703117bba18ee941ad9ac70322b2c5;hpb=db277e9a67b9d81b9d6cd74edf0c3e1a0ef2aa4b;p=powerpc.git diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index f92856b98b..a9c148a093 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -16,6 +16,19 @@ #include "signal.h" +#ifdef CONFIG_PPC64 +static inline int is_32bit_task(void) +{ + return test_thread_flag(TIF_32BIT); +} +#else +static inline int is_32bit_task(void) +{ + return 1; +} +#endif + + /* * Restore the user process's signal mask */ @@ -28,8 +41,8 @@ void restore_sigmask(sigset_t *set) spin_unlock_irq(¤t->sighand->siglock); } -void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, - int has_handler) +static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, + int has_handler) { unsigned long ret = regs->gpr[3]; int restart = 1; @@ -79,6 +92,84 @@ void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, } } +int do_signal(sigset_t *oldset, struct pt_regs *regs) +{ + siginfo_t info; + int signr; + struct k_sigaction ka; + int ret; + int is32 = is_32bit_task(); + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + + /* Is there any syscall restart business here ? */ + check_syscall_restart(regs, &ka, signr > 0); + + if (signr <= 0) { + /* No signal to deliver -- put the saved sigmask back */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + return 0; /* no signals delivered */ + } + +#ifdef CONFIG_PPC64 + /* + * Reenable the DABR before delivering the signal to + * user space. The DABR will have been cleared if it + * triggered inside the kernel. + */ + if (current->thread.dabr) + set_dabr(current->thread.dabr); +#endif + + if (is32) { + unsigned int newsp; + + if ((ka.sa.sa_flags & SA_ONSTACK) && + current->sas_ss_size && !on_sig_stack(regs->gpr[1])) + newsp = current->sas_ss_sp + current->sas_ss_size; + else + newsp = regs->gpr[1]; + + if (ka.sa.sa_flags & SA_SIGINFO) + ret = handle_rt_signal32(signr, &ka, &info, oldset, + regs, newsp); + else + ret = handle_signal32(signr, &ka, &info, oldset, + regs, newsp); +#ifdef CONFIG_PPC64 + } else { + ret = handle_rt_signal64(signr, &ka, &info, oldset, regs); +#endif + } + + if (ret) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, + &ka.sa.sa_mask); + if (!(ka.sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, signr); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + /* + * A signal was successfully delivered; the saved sigmask is in + * its frame, and we can clear the TIF_RESTORE_SIGMASK flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } + + return ret; +} + long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5, unsigned long r6, unsigned long r7, unsigned long r8, struct pt_regs *regs)