xref: /linux/arch/sparc/kernel/process.c (revision 37a93dd5c49b5fda807fd204edf2547c3493319c)
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 #include <linux/syscalls.h>
16 
17 #include "kernel.h"
18 
19 asmlinkage long sparc_fork(struct pt_regs *regs)
20 {
21 	unsigned long orig_i1;
22 	long ret;
23 	struct kernel_clone_args args = {
24 		.exit_signal	= SIGCHLD,
25 	};
26 
27 	synchronize_user_stack();
28 
29 	orig_i1 = regs->u_regs[UREG_I1];
30 	/* Reuse the parent's stack for the child. */
31 	args.stack = regs->u_regs[UREG_FP];
32 
33 	ret = kernel_clone(&args);
34 
35 	/* If we get an error and potentially restart the system
36 	 * call, we're screwed because copy_thread() clobbered
37 	 * the parent's %o1.  So detect that case and restore it
38 	 * here.
39 	 */
40 	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
41 		regs->u_regs[UREG_I1] = orig_i1;
42 
43 	return ret;
44 }
45 
46 asmlinkage long sparc_vfork(struct pt_regs *regs)
47 {
48 	unsigned long orig_i1;
49 	long ret;
50 	struct kernel_clone_args args = {
51 		.flags		= CLONE_VFORK | CLONE_VM,
52 		.exit_signal	= SIGCHLD,
53 	};
54 
55 	synchronize_user_stack();
56 
57 	orig_i1 = regs->u_regs[UREG_I1];
58 	/* Reuse the parent's stack for the child. */
59 	args.stack = regs->u_regs[UREG_FP];
60 
61 	ret = kernel_clone(&args);
62 
63 	/* If we get an error and potentially restart the system
64 	 * call, we're screwed because copy_thread() clobbered
65 	 * the parent's %o1.  So detect that case and restore it
66 	 * here.
67 	 */
68 	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
69 		regs->u_regs[UREG_I1] = orig_i1;
70 
71 	return ret;
72 }
73 
74 asmlinkage long sparc_clone(struct pt_regs *regs)
75 {
76 	unsigned long orig_i1;
77 	unsigned int flags;
78 	long ret;
79 	struct kernel_clone_args args = {0};
80 
81 	synchronize_user_stack();
82 
83 	orig_i1 = regs->u_regs[UREG_I1];
84 	flags = lower_32_bits(regs->u_regs[UREG_I0]);
85 	args.flags		= (flags & ~CSIGNAL);
86 	args.exit_signal	= (flags & CSIGNAL);
87 	args.tls		= regs->u_regs[UREG_I3];
88 
89 #ifdef CONFIG_COMPAT
90 	if (test_thread_flag(TIF_32BIT)) {
91 		args.pidfd	= compat_ptr(regs->u_regs[UREG_I2]);
92 		args.child_tid	= compat_ptr(regs->u_regs[UREG_I4]);
93 		args.parent_tid	= compat_ptr(regs->u_regs[UREG_I2]);
94 	} else
95 #endif
96 	{
97 		args.pidfd	= (int __user *)regs->u_regs[UREG_I2];
98 		args.child_tid	= (int __user *)regs->u_regs[UREG_I4];
99 		args.parent_tid	= (int __user *)regs->u_regs[UREG_I2];
100 	}
101 
102 	/* Did userspace give setup a separate stack for the child or are we
103 	 * reusing the parent's?
104 	 */
105 	if (regs->u_regs[UREG_I1])
106 		args.stack = regs->u_regs[UREG_I1];
107 	else
108 		args.stack = regs->u_regs[UREG_FP];
109 
110 	ret = kernel_clone(&args);
111 
112 	/* If we get an error and potentially restart the system
113 	 * call, we're screwed because copy_thread() clobbered
114 	 * the parent's %o1.  So detect that case and restore it
115 	 * here.
116 	 */
117 	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
118 		regs->u_regs[UREG_I1] = orig_i1;
119 
120 	return ret;
121 }
122 
123 asmlinkage long sparc_clone3(struct pt_regs *regs)
124 {
125 	unsigned long sz;
126 	struct clone_args __user *cl_args;
127 
128 	synchronize_user_stack();
129 
130 	cl_args = (struct clone_args __user *)regs->u_regs[UREG_I0];
131 	sz = regs->u_regs[UREG_I1];
132 
133 	return sys_clone3(cl_args, sz);
134 }
135