Merge branch 'cpumask-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[safe/jmp/linux-2.6] / arch / powerpc / kernel / signal.c
index 640b5f3..00b5078 100644 (file)
@@ -9,25 +9,44 @@
  * this archive for more details.
  */
 
-#include <linux/freezer.h>
-#include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/signal.h>
+#include <asm/uaccess.h>
 #include <asm/unistd.h>
 
 #include "signal.h"
 
+/* Log an error when sending an unhandled signal to a process. Controlled
+ * through debug.exception-trace sysctl.
+ */
 
-#ifdef CONFIG_PPC64
-static inline int is_32bit_task(void)
-{
-       return test_thread_flag(TIF_32BIT);
-}
-#else
-static inline int is_32bit_task(void)
+int show_unhandled_signals = 0;
+
+/*
+ * Allocate space for the signal frame
+ */
+void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+                          size_t frame_size, int is_32)
 {
-       return 1;
+        unsigned long oldsp, newsp;
+
+        /* Default to using normal stack */
+        oldsp = get_clean_sp(regs, is_32);
+
+       /* Check for alt stack */
+       if ((ka->sa.sa_flags & SA_ONSTACK) &&
+           current->sas_ss_size && !on_sig_stack(oldsp))
+               oldsp = (current->sas_ss_sp + current->sas_ss_size);
+
+       /* Get aligned frame */
+       newsp = (oldsp - frame_size) & ~0xFUL;
+
+       /* Check access */
+       if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp))
+               return NULL;
+
+        return (void __user *)newsp;
 }
-#endif
 
 
 /*
@@ -93,7 +112,7 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
        }
 }
 
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
+static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs)
 {
        siginfo_t info;
        int signr;
@@ -101,65 +120,47 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
        int ret;
        int is32 = is_32bit_task();
 
-#ifdef CONFIG_PPC32
-       if (try_to_freeze()) {
-               signr = 0;
-               if (!signal_pending(current))
-                       goto no_signal;
-       }
-#endif
-
-       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+       if (current_thread_info()->local_flags & _TLF_RESTORE_SIGMASK)
                oldset = &current->saved_sigmask;
        else if (!oldset)
                oldset = &current->blocked;
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 
-#ifdef CONFIG_PPC32
-no_signal:
-#endif
        /* Is there any syscall restart business here ? */
        check_syscall_restart(regs, &ka, signr > 0);
 
        if (signr <= 0) {
+               struct thread_info *ti = current_thread_info();
                /* No signal to deliver -- put the saved sigmask back */
-               if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-                       clear_thread_flag(TIF_RESTORE_SIGMASK);
+               if (ti->local_flags & _TLF_RESTORE_SIGMASK) {
+                       ti->local_flags &= ~_TLF_RESTORE_SIGMASK;
                        sigprocmask(SIG_SETMASK, &current->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)
+       if (current->thread.dabr) {
                set_dabr(current->thread.dabr);
+#if defined(CONFIG_BOOKE)
+               mtspr(SPRN_DBCR0, current->thread.dbcr0);
 #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);
+                                       regs);
                else
                        ret = handle_signal32(signr, &ka, &info, oldset,
-                                       regs, newsp);
-#ifdef CONFIG_PPC64
+                                       regs);
        } else {
                ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
-#endif
        }
 
        if (ret) {
@@ -173,15 +174,31 @@ no_signal:
 
                /*
                 * A signal was successfully delivered; the saved sigmask is in
-                * its frame, and we can clear the TIF_RESTORE_SIGMASK flag.
+                * its frame, and we can clear the TLF_RESTORE_SIGMASK flag.
+                */
+               current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK;
+
+               /*
+                * Let tracing know that we've done the handler setup.
                 */
-               if (test_thread_flag(TIF_RESTORE_SIGMASK))
-                       clear_thread_flag(TIF_RESTORE_SIGMASK);
+               tracehook_signal_handler(signr, &info, &ka, regs,
+                                        test_thread_flag(TIF_SINGLESTEP));
        }
 
        return ret;
 }
 
+void do_signal(struct pt_regs *regs, unsigned long thread_info_flags)
+{
+       if (thread_info_flags & _TIF_SIGPENDING)
+               do_signal_pending(NULL, regs);
+
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+       }
+}
+
 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)