summaryrefslogtreecommitdiff
path: root/arch/sparc/kernel/process.c
diff options
context:
space:
mode:
authorChristian Brauner <christian.brauner@ubuntu.com>2020-05-12 19:15:26 +0200
committerChristian Brauner <christian.brauner@ubuntu.com>2020-06-23 10:49:56 +0200
commita4261d4bb45022e1b8b95df13dbb05abac490165 (patch)
tree72504dbe0f99175dbed9f47851dcb114f8036282 /arch/sparc/kernel/process.c
parentdcad2a62bc7948342404217831233957e8f169cc (diff)
sparc: share process creation helpers between sparc and sparc64
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
Diffstat (limited to 'arch/sparc/kernel/process.c')
-rw-r--r--arch/sparc/kernel/process.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
new file mode 100644
index 000000000000..8bbe62d77b77
--- /dev/null
+++ b/arch/sparc/kernel/process.c
@@ -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;
+}