Commit | Line | Data |
---|---|---|
a4261d4b CB |
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 | ||
a66ef2ee | 28 | ret = kernel_clone(&args); |
a4261d4b CB |
29 | |
30 | /* If we get an error and potentially restart the system | |
714acdbd | 31 | * call, we're screwed because copy_thread() clobbered |
a4261d4b CB |
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 | ||
a66ef2ee | 53 | ret = kernel_clone(&args); |
a4261d4b CB |
54 | |
55 | /* If we get an error and potentially restart the system | |
714acdbd | 56 | * call, we're screwed because copy_thread() clobbered |
a4261d4b CB |
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 | ||
a66ef2ee | 99 | ret = kernel_clone(&args); |
a4261d4b CB |
100 | |
101 | /* If we get an error and potentially restart the system | |
714acdbd | 102 | * call, we're screwed because copy_thread() clobbered |
a4261d4b CB |
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 | } |