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