parisc: optimizations in copy_thread() and friends
* 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>
This commit is contained in:
@ -719,7 +719,7 @@ ENTRY(ret_from_kernel_thread)
|
|||||||
BL schedule_tail, %r2
|
BL schedule_tail, %r2
|
||||||
nop
|
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
|
LDREG TASK_PT_GR25(%r1), %r26
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
LDREG TASK_PT_GR27(%r1), %r27
|
LDREG TASK_PT_GR27(%r1), %r27
|
||||||
@ -743,9 +743,8 @@ ENDPROC(ret_from_kernel_thread)
|
|||||||
|
|
||||||
ENTRY(ret_from_kernel_execve)
|
ENTRY(ret_from_kernel_execve)
|
||||||
mfctl %cr30, %r1
|
mfctl %cr30, %r1
|
||||||
ldo THREAD_SZ_ALGN(%r1), %r30
|
b syscall_exit /* forward */
|
||||||
b intr_return /* forward */
|
ldo THREAD_SZ_ALGN+FRAME_SIZE(%r1), %r30
|
||||||
copy %r26,%r16 /* pt_regs into r16 */
|
|
||||||
ENDPROC(ret_from_kernel_execve)
|
ENDPROC(ret_from_kernel_execve)
|
||||||
|
|
||||||
|
|
||||||
@ -1709,39 +1708,13 @@ ENTRY(sys_fork_wrapper)
|
|||||||
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
|
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
|
||||||
ldo TASK_REGS(%r1),%r1
|
ldo TASK_REGS(%r1),%r1
|
||||||
reg_save %r1
|
reg_save %r1
|
||||||
mfctl %cr27, %r3
|
mfctl %cr27, %r28
|
||||||
STREG %r3, PT_CR27(%r1)
|
STREG %r28, 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)
|
|
||||||
|
|
||||||
LDREG PT_GR30(%r1),%r25
|
LDREG PT_GR30(%r1),%r25
|
||||||
copy %r1,%r24
|
copy %r1,%r24
|
||||||
BL sys_clone,%r2
|
b sys_clone
|
||||||
ldi SIGCHLD,%r26
|
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)
|
ENDPROC(sys_fork_wrapper)
|
||||||
|
|
||||||
/* Set the return value for the child */
|
/* Set the return value for the child */
|
||||||
@ -1749,9 +1722,13 @@ ENTRY(child_return)
|
|||||||
BL schedule_tail, %r2
|
BL schedule_tail, %r2
|
||||||
nop
|
nop
|
||||||
|
|
||||||
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
|
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
|
||||||
LDREG TASK_PT_GR19(%r1),%r2
|
ldo TASK_REGS(%r1),%r1 /* get pt regs */
|
||||||
b wrapper_exit
|
|
||||||
|
LDREG PT_CR27(%r1), %r3
|
||||||
|
mtctl %r3, %cr27
|
||||||
|
reg_restore %r1
|
||||||
|
b syscall_exit
|
||||||
copy %r0,%r28
|
copy %r0,%r28
|
||||||
ENDPROC(child_return)
|
ENDPROC(child_return)
|
||||||
|
|
||||||
@ -1760,23 +1737,10 @@ ENTRY(sys_clone_wrapper)
|
|||||||
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
|
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
|
||||||
ldo TASK_REGS(%r1),%r1 /* get pt regs */
|
ldo TASK_REGS(%r1),%r1 /* get pt regs */
|
||||||
reg_save %r1
|
reg_save %r1
|
||||||
mfctl %cr27, %r3
|
mfctl %cr27, %r28
|
||||||
STREG %r3, PT_CR27(%r1)
|
STREG %r28, PT_CR27(%r1)
|
||||||
|
b sys_clone
|
||||||
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
|
|
||||||
copy %r1,%r24
|
copy %r1,%r24
|
||||||
|
|
||||||
b wrapper_exit
|
|
||||||
LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
|
|
||||||
ENDPROC(sys_clone_wrapper)
|
ENDPROC(sys_clone_wrapper)
|
||||||
|
|
||||||
|
|
||||||
@ -1784,23 +1748,11 @@ ENTRY(sys_vfork_wrapper)
|
|||||||
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
|
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
|
||||||
ldo TASK_REGS(%r1),%r1 /* get pt regs */
|
ldo TASK_REGS(%r1),%r1 /* get pt regs */
|
||||||
reg_save %r1
|
reg_save %r1
|
||||||
mfctl %cr27, %r3
|
mfctl %cr27, %r28
|
||||||
STREG %r3, PT_CR27(%r1)
|
STREG %r28, PT_CR27(%r1)
|
||||||
|
|
||||||
STREG %r2,-RP_OFFSET(%r30)
|
b sys_vfork
|
||||||
ldo FRAME_SIZE(%r30),%r30
|
|
||||||
#ifdef CONFIG_64BIT
|
|
||||||
ldo -16(%r30),%r29 /* Reference param save area */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
STREG %r2,PT_GR19(%r1) /* save for child */
|
|
||||||
STREG %r30,PT_GR21(%r1)
|
|
||||||
|
|
||||||
BL sys_vfork,%r2
|
|
||||||
copy %r1,%r26
|
copy %r1,%r26
|
||||||
|
|
||||||
b wrapper_exit
|
|
||||||
LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
|
|
||||||
ENDPROC(sys_vfork_wrapper)
|
ENDPROC(sys_vfork_wrapper)
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/asm-offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
#include <asm/assembly.h>
|
||||||
#include <asm/pdc.h>
|
#include <asm/pdc.h>
|
||||||
#include <asm/pdc_chassis.h>
|
#include <asm/pdc_chassis.h>
|
||||||
#include <asm/pgalloc.h>
|
#include <asm/pgalloc.h>
|
||||||
@ -253,14 +254,16 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
|
|||||||
#ifdef CONFIG_HPUX
|
#ifdef CONFIG_HPUX
|
||||||
extern void * const hpux_child_return;
|
extern void * const hpux_child_return;
|
||||||
#endif
|
#endif
|
||||||
|
if (unlikely(p->flags & PF_KTHREAD)) {
|
||||||
if (unlikely((p->flags & PF_KTHREAD) && usp != 0)) {
|
|
||||||
memset(cregs, 0, sizeof(struct pt_regs));
|
memset(cregs, 0, sizeof(struct pt_regs));
|
||||||
|
if (!usp) /* idle thread */
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* kernel thread */
|
/* kernel thread */
|
||||||
cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN;
|
|
||||||
/* Must exit via ret_from_kernel_thread in order
|
/* Must exit via ret_from_kernel_thread in order
|
||||||
* to call schedule_tail()
|
* to call schedule_tail()
|
||||||
*/
|
*/
|
||||||
|
cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
|
||||||
cregs->kpc = (unsigned long) &ret_from_kernel_thread;
|
cregs->kpc = (unsigned long) &ret_from_kernel_thread;
|
||||||
/*
|
/*
|
||||||
* Copy function and argument to be called from
|
* 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;
|
cregs->gr[25] = arg;
|
||||||
} else {
|
} else {
|
||||||
/* user thread */
|
/* 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->gr[30] = usp;
|
||||||
|
cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
|
||||||
if (personality(p->personality) == PER_HPUX) {
|
if (personality(p->personality) == PER_HPUX) {
|
||||||
#ifdef CONFIG_HPUX
|
#ifdef CONFIG_HPUX
|
||||||
cregs->kpc = (unsigned long) &hpux_child_return;
|
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 */
|
/* Setup thread TLS area from the 4th parameter in clone */
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
cregs->cr27 = pregs->gr[23];
|
cregs->cr27 = pregs->gr[23];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user