]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kernel/signal.c
kprobes: improve kretprobe scalability with hashed locking
[karo-tx-linux.git] / arch / powerpc / kernel / signal.c
index a9c148a09361d3442ff0294f8f6b81a96be72c08..ad55488939c376f7073b0770ca79ad1f5954ca1e 100644 (file)
 
 #include <linux/ptrace.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)
 {
-       return 1;
+        unsigned long oldsp, newsp;
+
+        /* Default to using normal stack */
+        oldsp = regs->gpr[1];
+
+       /* 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
 
 
 /*
@@ -100,7 +120,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
        int ret;
        int is32 = is_32bit_task();
 
-       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;
@@ -111,15 +131,15 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
        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
@@ -127,27 +147,16 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
         */
        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);
+                                       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) {
@@ -161,10 +170,9 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
 
                /*
                 * 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.
                 */
-               if (test_thread_flag(TIF_RESTORE_SIGMASK))
-                       clear_thread_flag(TIF_RESTORE_SIGMASK);
+               current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK;
        }
 
        return ret;