aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-10-05 18:55:57 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-10-14 19:36:37 -0400
commitff0ab8af9c3f36e7b6f716c3b9e8811a4202eec6 (patch)
tree78f5dba557a1f91b868fa0118516562b6cd28244 /arch/parisc
parent7f1f311ac7b7b9c779fd207a20369f7fa3a61ba6 (diff)
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>
Diffstat (limited to 'arch/parisc')
-rw-r--r--arch/parisc/kernel/entry.S86
-rw-r--r--arch/parisc/kernel/process.c28
2 files changed, 27 insertions, 87 deletions
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 7d22e97347b7..47fb6ddcf12e 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -719,7 +719,7 @@ ENTRY(ret_from_kernel_thread)
719 BL schedule_tail, %r2 719 BL schedule_tail, %r2
720 nop 720 nop
721 721
722 LDREG TI_TASK-THREAD_SZ_ALGN(%r30), %r1 722 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
723 LDREG TASK_PT_GR25(%r1), %r26 723 LDREG TASK_PT_GR25(%r1), %r26
724#ifdef CONFIG_64BIT 724#ifdef CONFIG_64BIT
725 LDREG TASK_PT_GR27(%r1), %r27 725 LDREG TASK_PT_GR27(%r1), %r27
@@ -743,9 +743,8 @@ ENDPROC(ret_from_kernel_thread)
743 743
744ENTRY(ret_from_kernel_execve) 744ENTRY(ret_from_kernel_execve)
745 mfctl %cr30, %r1 745 mfctl %cr30, %r1
746 ldo THREAD_SZ_ALGN(%r1), %r30 746 b syscall_exit /* forward */
747 b intr_return /* forward */ 747 ldo THREAD_SZ_ALGN+FRAME_SIZE(%r1), %r30
748 copy %r26,%r16 /* pt_regs into r16 */
749ENDPROC(ret_from_kernel_execve) 748ENDPROC(ret_from_kernel_execve)
750 749
751 750
@@ -1709,39 +1708,13 @@ ENTRY(sys_fork_wrapper)
1709 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 1708 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
1710 ldo TASK_REGS(%r1),%r1 1709 ldo TASK_REGS(%r1),%r1
1711 reg_save %r1 1710 reg_save %r1
1712 mfctl %cr27, %r3 1711 mfctl %cr27, %r28
1713 STREG %r3, PT_CR27(%r1) 1712 STREG %r28, PT_CR27(%r1)
1714
1715 STREG %r2,-RP_OFFSET(%r30)
1716 ldo FRAME_SIZE(%r30),%r30
1717#ifdef CONFIG_64BIT
1718 ldo -16(%r30),%r29 /* Reference param save area */
1719#endif
1720
1721 /* These are call-clobbered registers and therefore
1722 also syscall-clobbered (we hope). */
1723 STREG %r2,PT_GR19(%r1) /* save for child */
1724 STREG %r30,PT_GR21(%r1)
1725 1713
1726 LDREG PT_GR30(%r1),%r25 1714 LDREG PT_GR30(%r1),%r25
1727 copy %r1,%r24 1715 copy %r1,%r24
1728 BL sys_clone,%r2 1716 b sys_clone
1729 ldi SIGCHLD,%r26 1717 ldi SIGCHLD,%r26
1730
1731 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
1732wrapper_exit:
1733 ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */
1734 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
1735 ldo TASK_REGS(%r1),%r1 /* get pt regs */
1736
1737 LDREG PT_CR27(%r1), %r3
1738 mtctl %r3, %cr27
1739 reg_restore %r1
1740
1741 /* strace expects syscall # to be preserved in r20 */
1742 ldi __NR_fork,%r20
1743 bv %r0(%r2)
1744 STREG %r20,PT_GR20(%r1)
1745ENDPROC(sys_fork_wrapper) 1718ENDPROC(sys_fork_wrapper)
1746 1719
1747 /* Set the return value for the child */ 1720 /* Set the return value for the child */
@@ -1749,9 +1722,13 @@ ENTRY(child_return)
1749 BL schedule_tail, %r2 1722 BL schedule_tail, %r2
1750 nop 1723 nop
1751 1724
1752 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1 1725 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
1753 LDREG TASK_PT_GR19(%r1),%r2 1726 ldo TASK_REGS(%r1),%r1 /* get pt regs */
1754 b wrapper_exit 1727
1728 LDREG PT_CR27(%r1), %r3
1729 mtctl %r3, %cr27
1730 reg_restore %r1
1731 b syscall_exit
1755 copy %r0,%r28 1732 copy %r0,%r28
1756ENDPROC(child_return) 1733ENDPROC(child_return)
1757 1734
@@ -1760,23 +1737,10 @@ ENTRY(sys_clone_wrapper)
1760 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 1737 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
1761 ldo TASK_REGS(%r1),%r1 /* get pt regs */ 1738 ldo TASK_REGS(%r1),%r1 /* get pt regs */
1762 reg_save %r1 1739 reg_save %r1
1763 mfctl %cr27, %r3 1740 mfctl %cr27, %r28
1764 STREG %r3, PT_CR27(%r1) 1741 STREG %r28, PT_CR27(%r1)
1765 1742 b sys_clone
1766 STREG %r2,-RP_OFFSET(%r30)
1767 ldo FRAME_SIZE(%r30),%r30
1768#ifdef CONFIG_64BIT
1769 ldo -16(%r30),%r29 /* Reference param save area */
1770#endif
1771
1772 /* WARNING - Clobbers r19 and r21, userspace must save these! */
1773 STREG %r2,PT_GR19(%r1) /* save for child */
1774 STREG %r30,PT_GR21(%r1)
1775 BL sys_clone,%r2
1776 copy %r1,%r24 1743 copy %r1,%r24
1777
1778 b wrapper_exit
1779 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
1780ENDPROC(sys_clone_wrapper) 1744ENDPROC(sys_clone_wrapper)
1781 1745
1782 1746
@@ -1784,23 +1748,11 @@ ENTRY(sys_vfork_wrapper)
1784 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 1748 LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
1785 ldo TASK_REGS(%r1),%r1 /* get pt regs */ 1749 ldo TASK_REGS(%r1),%r1 /* get pt regs */
1786 reg_save %r1 1750 reg_save %r1
1787 mfctl %cr27, %r3 1751 mfctl %cr27, %r28
1788 STREG %r3, PT_CR27(%r1) 1752 STREG %r28, PT_CR27(%r1)
1789
1790 STREG %r2,-RP_OFFSET(%r30)
1791 ldo FRAME_SIZE(%r30),%r30
1792#ifdef CONFIG_64BIT
1793 ldo -16(%r30),%r29 /* Reference param save area */
1794#endif
1795 1753
1796 STREG %r2,PT_GR19(%r1) /* save for child */ 1754 b sys_vfork
1797 STREG %r30,PT_GR21(%r1)
1798
1799 BL sys_vfork,%r2
1800 copy %r1,%r26 1755 copy %r1,%r26
1801
1802 b wrapper_exit
1803 LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
1804ENDPROC(sys_vfork_wrapper) 1756ENDPROC(sys_vfork_wrapper)
1805 1757
1806 1758
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 44e8534c52e9..38db36f64307 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -52,6 +52,7 @@
52 52
53#include <asm/io.h> 53#include <asm/io.h>
54#include <asm/asm-offsets.h> 54#include <asm/asm-offsets.h>
55#include <asm/assembly.h>
55#include <asm/pdc.h> 56#include <asm/pdc.h>
56#include <asm/pdc_chassis.h> 57#include <asm/pdc_chassis.h>
57#include <asm/pgalloc.h> 58#include <asm/pgalloc.h>
@@ -253,14 +254,16 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
253#ifdef CONFIG_HPUX 254#ifdef CONFIG_HPUX
254 extern void * const hpux_child_return; 255 extern void * const hpux_child_return;
255#endif 256#endif
256 257 if (unlikely(p->flags & PF_KTHREAD)) {
257 if (unlikely((p->flags & PF_KTHREAD) && usp != 0)) {
258 memset(cregs, 0, sizeof(struct pt_regs)); 258 memset(cregs, 0, sizeof(struct pt_regs));
259 if (!usp) /* idle thread */
260 return 0;
261
259 /* kernel thread */ 262 /* kernel thread */
260 cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN;
261 /* Must exit via ret_from_kernel_thread in order 263 /* Must exit via ret_from_kernel_thread in order
262 * to call schedule_tail() 264 * to call schedule_tail()
263 */ 265 */
266 cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
264 cregs->kpc = (unsigned long) &ret_from_kernel_thread; 267 cregs->kpc = (unsigned long) &ret_from_kernel_thread;
265 /* 268 /*
266 * Copy function and argument to be called from 269 * Copy function and argument to be called from
@@ -275,22 +278,8 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
275 cregs->gr[25] = arg; 278 cregs->gr[25] = arg;
276 } else { 279 } else {
277 /* user thread */ 280 /* user thread */
278 /*
279 * Note that the fork wrappers are responsible
280 * for setting gr[21].
281 */
282
283 *cregs = *pregs;
284
285 /* Set the return value for the child. Note that this is not
286 actually restored by the syscall exit path, but we put it
287 here for consistency in case of signals. */
288 cregs->gr[28] = 0; /* child */
289
290 /* Use same stack depth as parent */
291 cregs->ksp = (unsigned long)stack
292 + (pregs->gr[21] & (THREAD_SIZE - 1));
293 cregs->gr[30] = usp; 281 cregs->gr[30] = usp;
282 cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
294 if (personality(p->personality) == PER_HPUX) { 283 if (personality(p->personality) == PER_HPUX) {
295#ifdef CONFIG_HPUX 284#ifdef CONFIG_HPUX
296 cregs->kpc = (unsigned long) &hpux_child_return; 285 cregs->kpc = (unsigned long) &hpux_child_return;
@@ -302,8 +291,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
302 } 291 }
303 /* Setup thread TLS area from the 4th parameter in clone */ 292 /* Setup thread TLS area from the 4th parameter in clone */
304 if (clone_flags & CLONE_SETTLS) 293 if (clone_flags & CLONE_SETTLS)
305 cregs->cr27 = pregs->gr[23]; 294 cregs->cr27 = pregs->gr[23];
306
307 } 295 }
308 296
309 return 0; 297 return 0;