]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/sparc/kernel/signal.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6-omap-h63xx.git] / arch / sparc / kernel / signal.c
index 368157926d2410f6d426ea131359eb987c75331d..c94f91c8b6e0996dba7f057a815d0005376925d7 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/smp.h>
 #include <linux/binfmts.h>     /* do_coredum */
 #include <linux/bitops.h>
+#include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
 #include <asm/ptrace.h>
@@ -145,6 +146,9 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
        regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
                  | (regs->psr & (PSR_ICC | PSR_EF));
 
+       /* Prevent syscall restart.  */
+       pt_regs_clear_syscall(regs);
+
        err |= __get_user(fpu_save, &sf->fpu_save);
 
        if (fpu_save)
@@ -199,6 +203,9 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
 
        regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC);
 
+       /* Prevent syscall restart.  */
+       pt_regs_clear_syscall(regs);
+
        err |= __get_user(fpu_save, &sf->fpu_save);
 
        if (fpu_save)
@@ -507,26 +514,36 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int restart_syscall)
+static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
 {
-       siginfo_t info;
-       struct sparc_deliver_cookie cookie;
        struct k_sigaction ka;
-       int signr;
+       int restart_syscall;
        sigset_t *oldset;
+       siginfo_t info;
+       int signr;
 
-       cookie.restart_syscall = restart_syscall;
-       cookie.orig_i0 = orig_i0;
+       if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
+               restart_syscall = 1;
+       else
+               restart_syscall = 0;
 
        if (test_thread_flag(TIF_RESTORE_SIGMASK))
                oldset = &current->saved_sigmask;
        else
                oldset = &current->blocked;
 
-       signr = get_signal_to_deliver(&info, &ka, regs, &cookie);
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+       /* If the debugger messes with the program counter, it clears
+        * the software "in syscall" bit, directing us to not perform
+        * a syscall restart.
+        */
+       if (restart_syscall && !pt_regs_is_syscall(regs))
+               restart_syscall = 0;
+
        if (signr > 0) {
-               if (cookie.restart_syscall)
-                       syscall_restart(cookie.orig_i0, regs, &ka.sa);
+               if (restart_syscall)
+                       syscall_restart(orig_i0, regs, &ka.sa);
                handle_signal(signr, &ka, &info, oldset, regs);
 
                /* a signal was successfully delivered; the saved
@@ -536,18 +553,20 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest
                 */
                if (test_thread_flag(TIF_RESTORE_SIGMASK))
                        clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+               tracehook_signal_handler(signr, &info, &ka, regs, 0);
                return;
        }
-       if (cookie.restart_syscall &&
+       if (restart_syscall &&
            (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
             regs->u_regs[UREG_I0] == ERESTARTSYS ||
             regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
                /* replay the system call when we are done */
-               regs->u_regs[UREG_I0] = cookie.orig_i0;
+               regs->u_regs[UREG_I0] = orig_i0;
                regs->pc -= 4;
                regs->npc -= 4;
        }
-       if (cookie.restart_syscall &&
+       if (restart_syscall &&
            regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
                regs->u_regs[UREG_G1] = __NR_restart_syscall;
                regs->pc -= 4;
@@ -563,6 +582,17 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest
        }
 }
 
+void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
+                     unsigned long thread_info_flags)
+{
+       if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+               do_signal(regs, orig_i0);
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+       }
+}
+
 asmlinkage int
 do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr,
                unsigned long sp)
@@ -599,27 +629,3 @@ do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr,
 out:
        return ret;
 }
-
-void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
-{
-       struct sparc_deliver_cookie *cp = cookie;
-
-       if (cp->restart_syscall &&
-           (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
-            regs->u_regs[UREG_I0] == ERESTARTSYS ||
-            regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
-               /* replay the system call when we are done */
-               regs->u_regs[UREG_I0] = cp->orig_i0;
-               regs->pc -= 4;
-               regs->npc -= 4;
-               cp->restart_syscall = 0;
-       }
-
-       if (cp->restart_syscall &&
-           regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
-               regs->u_regs[UREG_G1] = __NR_restart_syscall;
-               regs->pc -= 4;
-               regs->npc -= 4;
-               cp->restart_syscall = 0;
-       }
-}