xref: /linux/arch/sparc/kernel/process.c (revision 714acdbd1c94e7e3ab90f6b6938f1ccb27b662f0)
1a4261d4bSChristian Brauner // SPDX-License-Identifier: GPL-2.0
2a4261d4bSChristian Brauner 
3a4261d4bSChristian Brauner /*
4a4261d4bSChristian Brauner  * This file handles the architecture independent parts of process handling..
5a4261d4bSChristian Brauner  */
6a4261d4bSChristian Brauner 
7a4261d4bSChristian Brauner #include <linux/compat.h>
8a4261d4bSChristian Brauner #include <linux/errno.h>
9a4261d4bSChristian Brauner #include <linux/kernel.h>
10a4261d4bSChristian Brauner #include <linux/ptrace.h>
11a4261d4bSChristian Brauner #include <linux/sched.h>
12a4261d4bSChristian Brauner #include <linux/sched/task.h>
13a4261d4bSChristian Brauner #include <linux/sched/task_stack.h>
14a4261d4bSChristian Brauner #include <linux/signal.h>
15a4261d4bSChristian Brauner 
16a4261d4bSChristian Brauner #include "kernel.h"
17a4261d4bSChristian Brauner 
18a4261d4bSChristian Brauner asmlinkage long sparc_fork(struct pt_regs *regs)
19a4261d4bSChristian Brauner {
20a4261d4bSChristian Brauner 	unsigned long orig_i1 = regs->u_regs[UREG_I1];
21a4261d4bSChristian Brauner 	long ret;
22a4261d4bSChristian Brauner 	struct kernel_clone_args args = {
23a4261d4bSChristian Brauner 		.exit_signal	= SIGCHLD,
24a4261d4bSChristian Brauner 		/* Reuse the parent's stack for the child. */
25a4261d4bSChristian Brauner 		.stack		= regs->u_regs[UREG_FP],
26a4261d4bSChristian Brauner 	};
27a4261d4bSChristian Brauner 
28a4261d4bSChristian Brauner 	ret = _do_fork(&args);
29a4261d4bSChristian Brauner 
30a4261d4bSChristian Brauner 	/* If we get an error and potentially restart the system
31*714acdbdSChristian Brauner 	 * call, we're screwed because copy_thread() clobbered
32a4261d4bSChristian Brauner 	 * the parent's %o1.  So detect that case and restore it
33a4261d4bSChristian Brauner 	 * here.
34a4261d4bSChristian Brauner 	 */
35a4261d4bSChristian Brauner 	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
36a4261d4bSChristian Brauner 		regs->u_regs[UREG_I1] = orig_i1;
37a4261d4bSChristian Brauner 
38a4261d4bSChristian Brauner 	return ret;
39a4261d4bSChristian Brauner }
40a4261d4bSChristian Brauner 
41a4261d4bSChristian Brauner asmlinkage long sparc_vfork(struct pt_regs *regs)
42a4261d4bSChristian Brauner {
43a4261d4bSChristian Brauner 	unsigned long orig_i1 = regs->u_regs[UREG_I1];
44a4261d4bSChristian Brauner 	long ret;
45a4261d4bSChristian Brauner 
46a4261d4bSChristian Brauner 	struct kernel_clone_args args = {
47a4261d4bSChristian Brauner 		.flags		= CLONE_VFORK | CLONE_VM,
48a4261d4bSChristian Brauner 		.exit_signal	= SIGCHLD,
49a4261d4bSChristian Brauner 		/* Reuse the parent's stack for the child. */
50a4261d4bSChristian Brauner 		.stack		= regs->u_regs[UREG_FP],
51a4261d4bSChristian Brauner 	};
52a4261d4bSChristian Brauner 
53a4261d4bSChristian Brauner 	ret = _do_fork(&args);
54a4261d4bSChristian Brauner 
55a4261d4bSChristian Brauner 	/* If we get an error and potentially restart the system
56*714acdbdSChristian Brauner 	 * call, we're screwed because copy_thread() clobbered
57a4261d4bSChristian Brauner 	 * the parent's %o1.  So detect that case and restore it
58a4261d4bSChristian Brauner 	 * here.
59a4261d4bSChristian Brauner 	 */
60a4261d4bSChristian Brauner 	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
61a4261d4bSChristian Brauner 		regs->u_regs[UREG_I1] = orig_i1;
62a4261d4bSChristian Brauner 
63a4261d4bSChristian Brauner 	return ret;
64a4261d4bSChristian Brauner }
65a4261d4bSChristian Brauner 
66a4261d4bSChristian Brauner asmlinkage long sparc_clone(struct pt_regs *regs)
67a4261d4bSChristian Brauner {
68a4261d4bSChristian Brauner 	unsigned long orig_i1 = regs->u_regs[UREG_I1];
69a4261d4bSChristian Brauner 	unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]);
70a4261d4bSChristian Brauner 	long ret;
71a4261d4bSChristian Brauner 
72a4261d4bSChristian Brauner 	struct kernel_clone_args args = {
73a4261d4bSChristian Brauner 		.flags		= (flags & ~CSIGNAL),
74a4261d4bSChristian Brauner 		.exit_signal	= (flags & CSIGNAL),
75a4261d4bSChristian Brauner 		.tls		= regs->u_regs[UREG_I3],
76a4261d4bSChristian Brauner 	};
77a4261d4bSChristian Brauner 
78a4261d4bSChristian Brauner #ifdef CONFIG_COMPAT
79a4261d4bSChristian Brauner 	if (test_thread_flag(TIF_32BIT)) {
80a4261d4bSChristian Brauner 		args.pidfd	= compat_ptr(regs->u_regs[UREG_I2]);
81a4261d4bSChristian Brauner 		args.child_tid	= compat_ptr(regs->u_regs[UREG_I4]);
82a4261d4bSChristian Brauner 		args.parent_tid	= compat_ptr(regs->u_regs[UREG_I2]);
83a4261d4bSChristian Brauner 	} else
84a4261d4bSChristian Brauner #endif
85a4261d4bSChristian Brauner 	{
86a4261d4bSChristian Brauner 		args.pidfd	= (int __user *)regs->u_regs[UREG_I2];
87a4261d4bSChristian Brauner 		args.child_tid	= (int __user *)regs->u_regs[UREG_I4];
88a4261d4bSChristian Brauner 		args.parent_tid	= (int __user *)regs->u_regs[UREG_I2];
89a4261d4bSChristian Brauner 	}
90a4261d4bSChristian Brauner 
91a4261d4bSChristian Brauner 	/* Did userspace give setup a separate stack for the child or are we
92a4261d4bSChristian Brauner 	 * reusing the parent's?
93a4261d4bSChristian Brauner 	 */
94a4261d4bSChristian Brauner 	if (regs->u_regs[UREG_I1])
95a4261d4bSChristian Brauner 		args.stack = regs->u_regs[UREG_I1];
96a4261d4bSChristian Brauner 	else
97a4261d4bSChristian Brauner 		args.stack = regs->u_regs[UREG_FP];
98a4261d4bSChristian Brauner 
99a4261d4bSChristian Brauner 	ret = _do_fork(&args);
100a4261d4bSChristian Brauner 
101a4261d4bSChristian Brauner 	/* If we get an error and potentially restart the system
102*714acdbdSChristian Brauner 	 * call, we're screwed because copy_thread() clobbered
103a4261d4bSChristian Brauner 	 * the parent's %o1.  So detect that case and restore it
104a4261d4bSChristian Brauner 	 * here.
105a4261d4bSChristian Brauner 	 */
106a4261d4bSChristian Brauner 	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
107a4261d4bSChristian Brauner 		regs->u_regs[UREG_I1] = orig_i1;
108a4261d4bSChristian Brauner 
109a4261d4bSChristian Brauner 	return ret;
110a4261d4bSChristian Brauner }
111