[PARISC] factor syscall_restart code out of do_signal
authorKyle McMartin <kyle@parisc-linux.org>
Mon, 15 Jan 2007 05:36:26 +0000 (00:36 -0500)
committerKyle McMartin <kyle@athena.road.mcmartin.ca>
Sat, 17 Feb 2007 06:11:06 +0000 (01:11 -0500)
looks better this way... ;)

Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
arch/parisc/kernel/signal.c

index 8d781b0e668b3fd41cdb59c0ef336d512bba4d6b..64169ab82de2a575423ec39791d2c98db45483f7 100644 (file)
@@ -471,6 +471,97 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        return 1;
 }
 
+static inline void
+syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
+{
+       /* Check the return code */
+       switch (regs->gr[28]) {
+       case -ERESTART_RESTARTBLOCK:
+               current_thread_info()->restart_block.fn =
+                       do_no_restart_syscall;
+       case -ERESTARTNOHAND:
+               DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
+               regs->gr[28] = -EINTR;
+               break;
+
+       case -ERESTARTSYS:
+               if (!(ka->sa.sa_flags & SA_RESTART)) {
+                       DBG(1,"ERESTARTSYS: putting -EINTR\n");
+                       regs->gr[28] = -EINTR;
+                       break;
+               }
+               /* fallthrough */
+       case -ERESTARTNOINTR:
+               /* A syscall is just a branch, so all
+                * we have to do is fiddle the return pointer.
+                */
+               regs->gr[31] -= 8; /* delayed branching */
+               /* Preserve original r28. */
+               regs->gr[28] = regs->orig_r28;
+               break;
+       }
+}
+
+static inline void
+insert_restart_trampoline(struct pt_regs *regs)
+{
+       switch(regs->gr[28]) {
+       case -ERESTART_RESTARTBLOCK: {
+               /* Restart the system call - no handlers present */
+               unsigned int *usp = (unsigned int *)regs->gr[30];
+
+               /* Setup a trampoline to restart the syscall
+                * with __NR_restart_syscall
+                *
+                *  0: <return address (orig r31)>
+                *  4: <2nd half for 64-bit>
+                *  8: ldw 0(%sp), %r31
+                * 12: be 0x100(%sr2, %r0)
+                * 16: ldi __NR_restart_syscall, %r20
+                */
+#ifdef CONFIG_64BIT
+               put_user(regs->gr[31] >> 32, &usp[0]);
+               put_user(regs->gr[31] & 0xffffffff, &usp[1]);
+               put_user(0x0fc010df, &usp[2]);
+#else
+               put_user(regs->gr[31], &usp[0]);
+               put_user(0x0fc0109f, &usp[2]);
+#endif
+               put_user(0xe0008200, &usp[3]);
+               put_user(0x34140000, &usp[4]);
+
+               /* Stack is 64-byte aligned, and we only need
+                * to flush 1 cache line.
+                * Flushing one cacheline is cheap.
+                * "sync" on bigger (> 4 way) boxes is not.
+                */
+               flush_icache_range(regs->gr[30], regs->gr[30] + 4);
+
+               regs->gr[31] = regs->gr[30] + 8;
+               /* Preserve original r28. */
+               regs->gr[28] = regs->orig_r28;
+
+               return;
+       }
+       case -ERESTARTNOHAND:
+       case -ERESTARTSYS:
+       case -ERESTARTNOINTR: {
+               /* Hooray for delayed branching.  We don't
+                * have to restore %r20 (the system call
+                * number) because it gets loaded in the delay
+                * slot of the branch external instruction.
+                */
+               regs->gr[31] -= 8;
+               /* Preserve original r28. */
+               regs->gr[28] = regs->orig_r28;
+
+               return;
+       }
+       default:
+               break;
+       }
+}
+
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -482,7 +573,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
  * registers).  As noted below, the syscall number gets restored for
  * us due to the magic of delayed branching.
  */
-
 asmlinkage void
 do_signal(struct pt_regs *regs, long in_syscall)
 {
@@ -518,36 +608,14 @@ do_signal(struct pt_regs *regs, long in_syscall)
                  break;
                
                /* Restart a system call if necessary. */
-               if (in_syscall) {
-                       /* Check the return code */
-                       switch (regs->gr[28]) {
-                       case -ERESTART_RESTARTBLOCK:
-                               current_thread_info()->restart_block.fn = do_no_restart_syscall;
-                       case -ERESTARTNOHAND:
-                               DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
-                               regs->gr[28] = -EINTR;
-                               break;
-
-                       case -ERESTARTSYS:
-                               if (!(ka.sa.sa_flags & SA_RESTART)) {
-                                       DBG(1,"ERESTARTSYS: putting -EINTR\n");
-                                       regs->gr[28] = -EINTR;
-                                       break;
-                               }
-                       /* fallthrough */
-                       case -ERESTARTNOINTR:
-                               /* A syscall is just a branch, so all
-                                  we have to do is fiddle the return pointer. */
-                               regs->gr[31] -= 8; /* delayed branching */
-                               /* Preserve original r28. */
-                               regs->gr[28] = regs->orig_r28;
-                               break;
-                       }
-               }
+               if (in_syscall)
+                       syscall_restart(regs, &ka);
+
                /* Whee!  Actually deliver the signal.  If the
                   delivery failed, we need to continue to iterate in
                   this loop so we can deliver the SIGSEGV... */
-               if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) {
+               if (handle_signal(signr, &info, &ka, oldset,
+                                 regs, in_syscall)) {
                        DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",
                                regs->gr[28]);
                        if (test_thread_flag(TIF_RESTORE_SIGMASK))
@@ -558,57 +626,8 @@ do_signal(struct pt_regs *regs, long in_syscall)
        /* end of while(1) looping forever if we can't force a signal */
 
        /* Did we come from a system call? */
-       if (in_syscall) {
-               /* Restart the system call - no handlers present */
-               if (regs->gr[28] == -ERESTART_RESTARTBLOCK) {
-                       unsigned int *usp = (unsigned int *)regs->gr[30];
-
-                       /* Setup a trampoline to restart the syscall
-                        * with __NR_restart_syscall
-                        *
-                        *  0: <return address (orig r31)>
-                        *  4: <2nd half for 64-bit>
-                        *  8: ldw 0(%sp), %r31
-                        * 12: be 0x100(%sr2, %r0)
-                        * 16: ldi __NR_restart_syscall, %r20
-                        */
-#ifndef __LP64__
-                       put_user(regs->gr[31], &usp[0]);
-                       put_user(0x0fc0109f, &usp[2]);
-#else
-                       put_user(regs->gr[31] >> 32, &usp[0]);
-                       put_user(regs->gr[31] & 0xffffffff, &usp[1]);
-                       put_user(0x0fc010df, &usp[2]);
-#endif
-                       put_user(0xe0008200, &usp[3]);
-                       put_user(0x34140000, &usp[4]);
-
-                       /* Stack is 64-byte aligned, and we only need
-                        * to flush 1 cache line.
-                        * Flushing one cacheline is cheap.
-                        * "sync" on bigger (> 4 way) boxes is not.
-                        */
-                       asm("fdc %%r0(%%sr3, %0)\n"
-                           "sync\n"
-                           "fic %%r0(%%sr3, %0)\n"
-                           "sync\n"
-                           : : "r"(regs->gr[30]));
-
-                       regs->gr[31] = regs->gr[30] + 8;
-                       /* Preserve original r28. */
-                       regs->gr[28] = regs->orig_r28;
-               } else if (regs->gr[28] == -ERESTARTNOHAND ||
-                          regs->gr[28] == -ERESTARTSYS ||
-                          regs->gr[28] == -ERESTARTNOINTR) {
-                       /* Hooray for delayed branching.  We don't
-                           have to restore %r20 (the system call
-                           number) because it gets loaded in the delay
-                           slot of the branch external instruction. */
-                       regs->gr[31] -= 8;
-                       /* Preserve original r28. */
-                       regs->gr[28] = regs->orig_r28;
-               }
-       }
+       if (in_syscall)
+               insert_restart_trampoline(regs);
        
        DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", 
                regs->gr[28]);