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
sparc_fork(struct pt_regs * regs)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
28*a66ef2eeSChristian Brauner ret = kernel_clone(&args);
29a4261d4bSChristian Brauner
30a4261d4bSChristian Brauner /* If we get an error and potentially restart the system
31714acdbdSChristian 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
sparc_vfork(struct pt_regs * regs)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
53*a66ef2eeSChristian Brauner ret = kernel_clone(&args);
54a4261d4bSChristian Brauner
55a4261d4bSChristian Brauner /* If we get an error and potentially restart the system
56714acdbdSChristian 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
sparc_clone(struct pt_regs * regs)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
99*a66ef2eeSChristian Brauner ret = kernel_clone(&args);
100a4261d4bSChristian Brauner
101a4261d4bSChristian Brauner /* If we get an error and potentially restart the system
102714acdbdSChristian 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