162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci * This file handles the architecture independent parts of process handling..
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/compat.h>
862306a36Sopenharmony_ci#include <linux/errno.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/ptrace.h>
1162306a36Sopenharmony_ci#include <linux/sched.h>
1262306a36Sopenharmony_ci#include <linux/sched/task.h>
1362306a36Sopenharmony_ci#include <linux/sched/task_stack.h>
1462306a36Sopenharmony_ci#include <linux/signal.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "kernel.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciasmlinkage long sparc_fork(struct pt_regs *regs)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	unsigned long orig_i1 = regs->u_regs[UREG_I1];
2162306a36Sopenharmony_ci	long ret;
2262306a36Sopenharmony_ci	struct kernel_clone_args args = {
2362306a36Sopenharmony_ci		.exit_signal	= SIGCHLD,
2462306a36Sopenharmony_ci		/* Reuse the parent's stack for the child. */
2562306a36Sopenharmony_ci		.stack		= regs->u_regs[UREG_FP],
2662306a36Sopenharmony_ci	};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	ret = kernel_clone(&args);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/* If we get an error and potentially restart the system
3162306a36Sopenharmony_ci	 * call, we're screwed because copy_thread() clobbered
3262306a36Sopenharmony_ci	 * the parent's %o1.  So detect that case and restore it
3362306a36Sopenharmony_ci	 * here.
3462306a36Sopenharmony_ci	 */
3562306a36Sopenharmony_ci	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
3662306a36Sopenharmony_ci		regs->u_regs[UREG_I1] = orig_i1;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	return ret;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciasmlinkage long sparc_vfork(struct pt_regs *regs)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	unsigned long orig_i1 = regs->u_regs[UREG_I1];
4462306a36Sopenharmony_ci	long ret;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	struct kernel_clone_args args = {
4762306a36Sopenharmony_ci		.flags		= CLONE_VFORK | CLONE_VM,
4862306a36Sopenharmony_ci		.exit_signal	= SIGCHLD,
4962306a36Sopenharmony_ci		/* Reuse the parent's stack for the child. */
5062306a36Sopenharmony_ci		.stack		= regs->u_regs[UREG_FP],
5162306a36Sopenharmony_ci	};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	ret = kernel_clone(&args);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* If we get an error and potentially restart the system
5662306a36Sopenharmony_ci	 * call, we're screwed because copy_thread() clobbered
5762306a36Sopenharmony_ci	 * the parent's %o1.  So detect that case and restore it
5862306a36Sopenharmony_ci	 * here.
5962306a36Sopenharmony_ci	 */
6062306a36Sopenharmony_ci	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
6162306a36Sopenharmony_ci		regs->u_regs[UREG_I1] = orig_i1;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return ret;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ciasmlinkage long sparc_clone(struct pt_regs *regs)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	unsigned long orig_i1 = regs->u_regs[UREG_I1];
6962306a36Sopenharmony_ci	unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]);
7062306a36Sopenharmony_ci	long ret;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	struct kernel_clone_args args = {
7362306a36Sopenharmony_ci		.flags		= (flags & ~CSIGNAL),
7462306a36Sopenharmony_ci		.exit_signal	= (flags & CSIGNAL),
7562306a36Sopenharmony_ci		.tls		= regs->u_regs[UREG_I3],
7662306a36Sopenharmony_ci	};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
7962306a36Sopenharmony_ci	if (test_thread_flag(TIF_32BIT)) {
8062306a36Sopenharmony_ci		args.pidfd	= compat_ptr(regs->u_regs[UREG_I2]);
8162306a36Sopenharmony_ci		args.child_tid	= compat_ptr(regs->u_regs[UREG_I4]);
8262306a36Sopenharmony_ci		args.parent_tid	= compat_ptr(regs->u_regs[UREG_I2]);
8362306a36Sopenharmony_ci	} else
8462306a36Sopenharmony_ci#endif
8562306a36Sopenharmony_ci	{
8662306a36Sopenharmony_ci		args.pidfd	= (int __user *)regs->u_regs[UREG_I2];
8762306a36Sopenharmony_ci		args.child_tid	= (int __user *)regs->u_regs[UREG_I4];
8862306a36Sopenharmony_ci		args.parent_tid	= (int __user *)regs->u_regs[UREG_I2];
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* Did userspace give setup a separate stack for the child or are we
9262306a36Sopenharmony_ci	 * reusing the parent's?
9362306a36Sopenharmony_ci	 */
9462306a36Sopenharmony_ci	if (regs->u_regs[UREG_I1])
9562306a36Sopenharmony_ci		args.stack = regs->u_regs[UREG_I1];
9662306a36Sopenharmony_ci	else
9762306a36Sopenharmony_ci		args.stack = regs->u_regs[UREG_FP];
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	ret = kernel_clone(&args);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* If we get an error and potentially restart the system
10262306a36Sopenharmony_ci	 * call, we're screwed because copy_thread() clobbered
10362306a36Sopenharmony_ci	 * the parent's %o1.  So detect that case and restore it
10462306a36Sopenharmony_ci	 * here.
10562306a36Sopenharmony_ci	 */
10662306a36Sopenharmony_ci	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
10762306a36Sopenharmony_ci		regs->u_regs[UREG_I1] = orig_i1;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return ret;
11062306a36Sopenharmony_ci}
111