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 = kernel_clone(kargs: &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 = kernel_clone(kargs: &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 = kernel_clone(kargs: &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 | |