sparc: share process creation helpers between sparc and sparc64
authorChristian Brauner <christian.brauner@ubuntu.com>
Tue, 12 May 2020 17:15:26 +0000 (19:15 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 23 Jun 2020 08:49:56 +0000 (10:49 +0200)
As promised in the previous patch, this moves the process creation
helpers into a common process.c file that is shared between sparc and
sparc64. It allows us to get rid of quite a bit custom assembler and the
to remove the separe 32bit specific sparc_do_fork() call.

One thing to note, is that when clone() was called with a separate stack
for the child the assembler would align it. But copy_thread() has always
been doing that too so that line wasn't needed and can thus simply be
removed.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Acked-by: David S. Miller <davem@davemloft.net>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Guo Ren <guoren@kernel.org>
Cc: linux-csky@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: sparclinux@vger.kernel.org
Link: https://lore.kernel.org/r/20200512171527.570109-3-christian.brauner@ubuntu.com
arch/sparc/kernel/Makefile
arch/sparc/kernel/entry.S
arch/sparc/kernel/kernel.h
arch/sparc/kernel/process.c [new file with mode: 0644]
arch/sparc/kernel/process_32.c
arch/sparc/kernel/process_64.c

index 97c0e19..d3a0e07 100644 (file)
@@ -33,6 +33,7 @@ obj-y                   += irq_$(BITS).o
 obj-$(CONFIG_SPARC32)   += sun4m_irq.o sun4d_irq.o
 
 obj-y                   += process_$(BITS).o
+obj-y                   += process.o
 obj-y                   += signal_$(BITS).o
 obj-y                   += sigutil_$(BITS).o
 obj-$(CONFIG_SPARC32)   += ioport.o
index f636acf..d589402 100644 (file)
@@ -869,14 +869,11 @@ flush_patch_two:
        ld      [%curptr + TI_TASK], %o4
        rd      %psr, %g4
        WRITE_PAUSE
-       mov     SIGCHLD, %o0                    ! arg0: clone flags
        rd      %wim, %g5
        WRITE_PAUSE
-       mov     %fp, %o1                        ! arg1: usp
        std     %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
-       add     %sp, STACKFRAME_SZ, %o2         ! arg2: pt_regs ptr
-       mov     0, %o3
-       call    sparc_do_fork
+       add     %sp, STACKFRAME_SZ, %o0
+       call    sparc_fork
         mov    %l5, %o7
 
        /* Whee, kernel threads! */
@@ -888,19 +885,11 @@ flush_patch_three:
        ld      [%curptr + TI_TASK], %o4
        rd      %psr, %g4
        WRITE_PAUSE
-
-       /* arg0,1: flags,usp  -- loaded already */
-       cmp     %o1, 0x0                        ! Is new_usp NULL?
        rd      %wim, %g5
        WRITE_PAUSE
-       be,a    1f
-        mov    %fp, %o1                        ! yes, use callers usp
-       andn    %o1, 7, %o1                     ! no, align to 8 bytes
-1:
        std     %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
-       add     %sp, STACKFRAME_SZ, %o2         ! arg2: pt_regs ptr
-       mov     0, %o3
-       call    sparc_do_fork
+       add     %sp, STACKFRAME_SZ, %o0
+       call    sparc_clone
         mov    %l5, %o7
 
        /* Whee, real vfork! */
@@ -914,13 +903,9 @@ flush_patch_four:
        rd      %wim, %g5
        WRITE_PAUSE
        std     %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
-       sethi   %hi(0x4000 | 0x0100 | SIGCHLD), %o0
-       mov     %fp, %o1
-       or      %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
-       sethi   %hi(sparc_do_fork), %l1
-       mov     0, %o3
-       jmpl    %l1 + %lo(sparc_do_fork), %g0
-        add    %sp, STACKFRAME_SZ, %o2
+       sethi   %hi(sparc_vfork), %l1
+       jmpl    %l1 + %lo(sparc_vfork), %g0
+        add    %sp, STACKFRAME_SZ, %o0
 
         .align  4
 linux_sparc_ni_syscall:
index f6f498b..9cd09a3 100644 (file)
@@ -14,6 +14,11 @@ extern const char *sparc_pmu_type;
 extern unsigned int fsr_storage;
 extern int ncpus_probed;
 
+/* process{_32,_64}.c */
+asmlinkage long sparc_clone(struct pt_regs *regs);
+asmlinkage long sparc_fork(struct pt_regs *regs);
+asmlinkage long sparc_vfork(struct pt_regs *regs);
+
 #ifdef CONFIG_SPARC64
 /* setup_64.c */
 struct seq_file;
@@ -153,12 +158,6 @@ void floppy_hardint(void);
 extern unsigned long sun4m_cpu_startup;
 extern unsigned long sun4d_cpu_startup;
 
-/* process_32.c */
-asmlinkage int sparc_do_fork(unsigned long clone_flags,
-                             unsigned long stack_start,
-                             struct pt_regs *regs,
-                             unsigned long stack_size);
-
 /* signal_32.c */
 asmlinkage void do_sigreturn(struct pt_regs *regs);
 asmlinkage void do_rt_sigreturn(struct pt_regs *regs);
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
new file mode 100644 (file)
index 0000000..8bbe62d
--- /dev/null
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * This file handles the architecture independent parts of process handling..
+ */
+
+#include <linux/compat.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/sched/task.h>
+#include <linux/sched/task_stack.h>
+#include <linux/signal.h>
+
+#include "kernel.h"
+
+asmlinkage long sparc_fork(struct pt_regs *regs)
+{
+       unsigned long orig_i1 = regs->u_regs[UREG_I1];
+       long ret;
+       struct kernel_clone_args args = {
+               .exit_signal    = SIGCHLD,
+               /* Reuse the parent's stack for the child. */
+               .stack          = regs->u_regs[UREG_FP],
+       };
+
+       ret = _do_fork(&args);
+
+       /* If we get an error and potentially restart the system
+        * call, we're screwed because copy_thread_tls() clobbered
+        * the parent's %o1.  So detect that case and restore it
+        * here.
+        */
+       if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
+               regs->u_regs[UREG_I1] = orig_i1;
+
+       return ret;
+}
+
+asmlinkage long sparc_vfork(struct pt_regs *regs)
+{
+       unsigned long orig_i1 = regs->u_regs[UREG_I1];
+       long ret;
+
+       struct kernel_clone_args args = {
+               .flags          = CLONE_VFORK | CLONE_VM,
+               .exit_signal    = SIGCHLD,
+               /* Reuse the parent's stack for the child. */
+               .stack          = regs->u_regs[UREG_FP],
+       };
+
+       ret = _do_fork(&args);
+
+       /* If we get an error and potentially restart the system
+        * call, we're screwed because copy_thread_tls() clobbered
+        * the parent's %o1.  So detect that case and restore it
+        * here.
+        */
+       if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
+               regs->u_regs[UREG_I1] = orig_i1;
+
+       return ret;
+}
+
+asmlinkage long sparc_clone(struct pt_regs *regs)
+{
+       unsigned long orig_i1 = regs->u_regs[UREG_I1];
+       unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]);
+       long ret;
+
+       struct kernel_clone_args args = {
+               .flags          = (flags & ~CSIGNAL),
+               .exit_signal    = (flags & CSIGNAL),
+               .tls            = regs->u_regs[UREG_I3],
+       };
+
+#ifdef CONFIG_COMPAT
+       if (test_thread_flag(TIF_32BIT)) {
+               args.pidfd      = compat_ptr(regs->u_regs[UREG_I2]);
+               args.child_tid  = compat_ptr(regs->u_regs[UREG_I4]);
+               args.parent_tid = compat_ptr(regs->u_regs[UREG_I2]);
+       } else
+#endif
+       {
+               args.pidfd      = (int __user *)regs->u_regs[UREG_I2];
+               args.child_tid  = (int __user *)regs->u_regs[UREG_I4];
+               args.parent_tid = (int __user *)regs->u_regs[UREG_I2];
+       }
+
+       /* Did userspace give setup a separate stack for the child or are we
+        * reusing the parent's?
+        */
+       if (regs->u_regs[UREG_I1])
+               args.stack = regs->u_regs[UREG_I1];
+       else
+               args.stack = regs->u_regs[UREG_FP];
+
+       ret = _do_fork(&args);
+
+       /* If we get an error and potentially restart the system
+        * call, we're screwed because copy_thread_tls() clobbered
+        * the parent's %o1.  So detect that case and restore it
+        * here.
+        */
+       if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
+               regs->u_regs[UREG_I1] = orig_i1;
+
+       return ret;
+}
index 13cb563..229a10b 100644 (file)
@@ -257,33 +257,6 @@ clone_stackframe(struct sparc_stackf __user *dst,
        return sp;
 }
 
-asmlinkage int sparc_do_fork(unsigned long clone_flags,
-                             unsigned long stack_start,
-                             struct pt_regs *regs,
-                             unsigned long stack_size)
-{
-       unsigned long parent_tid_ptr, child_tid_ptr;
-       unsigned long orig_i1 = regs->u_regs[UREG_I1];
-       long ret;
-
-       parent_tid_ptr = regs->u_regs[UREG_I2];
-       child_tid_ptr = regs->u_regs[UREG_I4];
-
-       ret = do_fork(clone_flags, stack_start, stack_size,
-                     (int __user *) parent_tid_ptr,
-                     (int __user *) child_tid_ptr);
-
-       /* If we get an error and potentially restart the system
-        * call, we're screwed because copy_thread() clobbered
-        * the parent's %o1.  So detect that case and restore it
-        * here.
-        */
-       if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
-               regs->u_regs[UREG_I1] = orig_i1;
-
-       return ret;
-}
-
 /* Copy a Sparc thread.  The fork() return value conventions
  * under SunOS are nothing short of bletcherous:
  * Parent -->  %o0 == childs  pid, %o1 == 0
index 8c400fc..278bf28 100644 (file)
@@ -572,100 +572,6 @@ barf:
        force_sig(SIGSEGV);
 }
 
-asmlinkage long sparc_fork(struct pt_regs *regs)
-{
-       unsigned long orig_i1 = regs->u_regs[UREG_I1];
-       long ret;
-       struct kernel_clone_args args = {
-               .exit_signal    = SIGCHLD,
-               /* Reuse the parent's stack for the child. */
-               .stack          = regs->u_regs[UREG_FP],
-       };
-
-       ret = _do_fork(&args);
-
-       /* If we get an error and potentially restart the system
-        * call, we're screwed because copy_thread_tls() clobbered
-        * the parent's %o1.  So detect that case and restore it
-        * here.
-        */
-       if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
-               regs->u_regs[UREG_I1] = orig_i1;
-
-       return ret;
-}
-
-asmlinkage long sparc_vfork(struct pt_regs *regs)
-{
-       unsigned long orig_i1 = regs->u_regs[UREG_I1];
-       long ret;
-
-       struct kernel_clone_args args = {
-               .flags          = CLONE_VFORK | CLONE_VM,
-               .exit_signal    = SIGCHLD,
-               /* Reuse the parent's stack for the child. */
-               .stack          = regs->u_regs[UREG_FP],
-       };
-
-       ret = _do_fork(&args);
-
-       /* If we get an error and potentially restart the system
-        * call, we're screwed because copy_thread_tls() clobbered
-        * the parent's %o1.  So detect that case and restore it
-        * here.
-        */
-       if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
-               regs->u_regs[UREG_I1] = orig_i1;
-
-       return ret;
-}
-
-asmlinkage long sparc_clone(struct pt_regs *regs)
-{
-       unsigned long orig_i1 = regs->u_regs[UREG_I1];
-       unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]);
-       long ret;
-
-       struct kernel_clone_args args = {
-               .flags          = (flags & ~CSIGNAL),
-               .exit_signal    = (flags & CSIGNAL),
-               .tls            = regs->u_regs[UREG_I3],
-       };
-
-#ifdef CONFIG_COMPAT
-       if (test_thread_flag(TIF_32BIT)) {
-               args.pidfd      = compat_ptr(regs->u_regs[UREG_I2]);
-               args.child_tid  = compat_ptr(regs->u_regs[UREG_I4]);
-               args.parent_tid = compat_ptr(regs->u_regs[UREG_I2]);
-       } else
-#endif
-       {
-               args.pidfd      = (int __user *)regs->u_regs[UREG_I2];
-               args.child_tid  = (int __user *)regs->u_regs[UREG_I4];
-               args.parent_tid = (int __user *)regs->u_regs[UREG_I2];
-       }
-
-       /* Did userspace setup a separate stack for the child or are we
-        * copying the parent's?
-        */
-       if (regs->u_regs[UREG_I1])
-               args.stack = regs->u_regs[UREG_I1];
-       else
-               args.stack = regs->u_regs[UREG_FP];
-
-       ret = _do_fork(&args);
-
-       /* If we get an error and potentially restart the system
-        * call, we're screwed because copy_thread_tls() clobbered
-        * the parent's %o1.  So detect that case and restore it
-        * here.
-        */
-       if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
-               regs->u_regs[UREG_I1] = orig_i1;
-
-       return ret;
-}
-
 /* Copy a Sparc thread.  The fork() return value conventions
  * under SunOS are nothing short of bletcherous:
  * Parent -->  %o0 == childs  pid, %o1 == 0