parisc: optimizations in copy_thread() and friends
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 5 Oct 2012 22:55:57 +0000 (18:55 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 14 Oct 2012 23:36:37 +0000 (19:36 -0400)
* in user thread case the registers had been copied as part of task_struct
already; no need to do it in copy_thread().
* no need to store kernel stack pointer into regs->r21; we know its offset
anyway.
* no need to clobber r3 in sys_fork_wrapper and friends - r28 will do just
as well and *it* will be overwritten anyway.
* no need to mess with storing the return address for child - it should just
use syscall_exit.
* no need to bother with separate stack frame for sys_clone() - just branch
there and be done with that.
* no need to bother with wrapper_exit - we need it only on the child_return,
so let's just do it there.
* use the same ksp for kernel threads and userland ones, while we are at it,
and let ret_from_kernel_execve() go through the normal syscall_exit.  More
straightforward is better here...

[fixes from jejb folded]

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/parisc/kernel/entry.S
arch/parisc/kernel/process.c

index 7d22e97347b7e714fa6e073db54a48027a744874..47fb6ddcf12e6daa71c0ab40fd67508aa38bff3e 100644 (file)
@@ -719,7 +719,7 @@ ENTRY(ret_from_kernel_thread)
        BL      schedule_tail, %r2
        nop
 
-       LDREG   TI_TASK-THREAD_SZ_ALGN(%r30), %r1
+       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
        LDREG   TASK_PT_GR25(%r1), %r26
 #ifdef CONFIG_64BIT
        LDREG   TASK_PT_GR27(%r1), %r27
@@ -743,9 +743,8 @@ ENDPROC(ret_from_kernel_thread)
 
 ENTRY(ret_from_kernel_execve)
        mfctl   %cr30, %r1
-       ldo     THREAD_SZ_ALGN(%r1), %r30
-       b       intr_return     /* forward */
-       copy    %r26,%r16       /* pt_regs into r16 */
+       b       syscall_exit    /* forward */
+       ldo     THREAD_SZ_ALGN+FRAME_SIZE(%r1), %r30
 ENDPROC(ret_from_kernel_execve)
 
 
@@ -1709,39 +1708,13 @@ ENTRY(sys_fork_wrapper)
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
        ldo     TASK_REGS(%r1),%r1
        reg_save %r1
-       mfctl   %cr27, %r3
-       STREG   %r3, PT_CR27(%r1)
-
-       STREG   %r2,-RP_OFFSET(%r30)
-       ldo     FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#endif
-
-       /* These are call-clobbered registers and therefore
-          also syscall-clobbered (we hope). */
-       STREG   %r2,PT_GR19(%r1)        /* save for child */
-       STREG   %r30,PT_GR21(%r1)
+       mfctl   %cr27, %r28
+       STREG   %r28, PT_CR27(%r1)
 
        LDREG   PT_GR30(%r1),%r25
        copy    %r1,%r24
-       BL      sys_clone,%r2
+       b       sys_clone
        ldi     SIGCHLD,%r26
-
-       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
-wrapper_exit:
-       ldo     -FRAME_SIZE(%r30),%r30          /* get the stackframe */
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
-       ldo     TASK_REGS(%r1),%r1       /* get pt regs */
-
-       LDREG   PT_CR27(%r1), %r3
-       mtctl   %r3, %cr27
-       reg_restore %r1
-
-       /* strace expects syscall # to be preserved in r20 */
-       ldi     __NR_fork,%r20
-       bv %r0(%r2)
-       STREG   %r20,PT_GR20(%r1)
 ENDPROC(sys_fork_wrapper)
 
        /* Set the return value for the child */
@@ -1749,9 +1722,13 @@ ENTRY(child_return)
        BL      schedule_tail, %r2
        nop
 
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
-       LDREG   TASK_PT_GR19(%r1),%r2
-       b       wrapper_exit
+       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
+       ldo     TASK_REGS(%r1),%r1       /* get pt regs */
+
+       LDREG   PT_CR27(%r1), %r3
+       mtctl   %r3, %cr27
+       reg_restore %r1
+       b       syscall_exit
        copy    %r0,%r28
 ENDPROC(child_return)
 
@@ -1760,23 +1737,10 @@ ENTRY(sys_clone_wrapper)
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
        ldo     TASK_REGS(%r1),%r1      /* get pt regs */
        reg_save %r1
-       mfctl   %cr27, %r3
-       STREG   %r3, PT_CR27(%r1)
-
-       STREG   %r2,-RP_OFFSET(%r30)
-       ldo     FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#endif
-
-       /* WARNING - Clobbers r19 and r21, userspace must save these! */
-       STREG   %r2,PT_GR19(%r1)        /* save for child */
-       STREG   %r30,PT_GR21(%r1)
-       BL      sys_clone,%r2
+       mfctl   %cr27, %r28
+       STREG   %r28, PT_CR27(%r1)
+       b       sys_clone
        copy    %r1,%r24
-
-       b       wrapper_exit
-       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
 ENDPROC(sys_clone_wrapper)
 
 
@@ -1784,23 +1748,11 @@ ENTRY(sys_vfork_wrapper)
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
        ldo     TASK_REGS(%r1),%r1      /* get pt regs */
        reg_save %r1
-       mfctl   %cr27, %r3
-       STREG   %r3, PT_CR27(%r1)
-
-       STREG   %r2,-RP_OFFSET(%r30)
-       ldo     FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#endif
+       mfctl   %cr27, %r28
+       STREG   %r28, PT_CR27(%r1)
 
-       STREG   %r2,PT_GR19(%r1)        /* save for child */
-       STREG   %r30,PT_GR21(%r1)
-
-       BL      sys_vfork,%r2
+       b       sys_vfork
        copy    %r1,%r26
-
-       b       wrapper_exit
-       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
 ENDPROC(sys_vfork_wrapper)
 
        
index 44e8534c52e984437078d22b2111e2c31d0d4d44..38db36f64307a9bafa8db66db12e8403fc873f97 100644 (file)
@@ -52,6 +52,7 @@
 
 #include <asm/io.h>
 #include <asm/asm-offsets.h>
+#include <asm/assembly.h>
 #include <asm/pdc.h>
 #include <asm/pdc_chassis.h>
 #include <asm/pgalloc.h>
@@ -253,14 +254,16 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
 #ifdef CONFIG_HPUX
        extern void * const hpux_child_return;
 #endif
-
-       if (unlikely((p->flags & PF_KTHREAD) && usp != 0)) {
+       if (unlikely(p->flags & PF_KTHREAD)) {
                memset(cregs, 0, sizeof(struct pt_regs));
+               if (!usp) /* idle thread */
+                       return 0;
+
                /* kernel thread */
-               cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN;
                /* Must exit via ret_from_kernel_thread in order
                 * to call schedule_tail()
                 */
+               cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
                cregs->kpc = (unsigned long) &ret_from_kernel_thread;
                /*
                 * Copy function and argument to be called from
@@ -275,22 +278,8 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
                cregs->gr[25] = arg;
        } else {
                /* user thread */
-               /*
-                * Note that the fork wrappers are responsible
-                * for setting gr[21].
-                */
-
-               *cregs = *pregs;
-
-               /* Set the return value for the child.  Note that this is not
-                  actually restored by the syscall exit path, but we put it
-                  here for consistency in case of signals. */
-               cregs->gr[28] = 0; /* child */
-
-               /* Use same stack depth as parent */
-               cregs->ksp = (unsigned long)stack
-                       + (pregs->gr[21] & (THREAD_SIZE - 1));
                cregs->gr[30] = usp;
+               cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
                if (personality(p->personality) == PER_HPUX) {
 #ifdef CONFIG_HPUX
                        cregs->kpc = (unsigned long) &hpux_child_return;
@@ -302,8 +291,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
                }
                /* Setup thread TLS area from the 4th parameter in clone */
                if (clone_flags & CLONE_SETTLS)
-                 cregs->cr27 = pregs->gr[23];
-       
+                       cregs->cr27 = pregs->gr[23];
        }
 
        return 0;