projects/linux·blob master · refs

134 lines · 3.2 KiB

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
19asmlinkage 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
46asmlinkage 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
74asmlinkage 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
123asmlinkage 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}