Unverified Commit a4261d4b authored by Christian Brauner's avatar Christian Brauner
Browse files

sparc: share process creation helpers between sparc and sparc64



As promised in the previous patch, this moves the process creation
helpers into a common process.c file that is shared between sparc and
sparc64. It allows us to get rid of quite a bit custom assembler and the
to remove the separe 32bit specific sparc_do_fork() call.

One thing to note, is that when clone() was called with a separate stack
for the child the assembler would align it. But copy_thread() has always
been doing that too so that line wasn't needed and can thus simply be
removed.

Signed-off-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Guo Ren <guoren@kernel.org>
Cc: linux-csky@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: sparclinux@vger.kernel.org
Link: https://lore.kernel.org/r/20200512171527.570109-3-christian.brauner@ubuntu.com
parent dcad2a62
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ obj-y += irq_$(BITS).o
obj-$(CONFIG_SPARC32)   += sun4m_irq.o sun4d_irq.o

obj-y                   += process_$(BITS).o
obj-y                   += process.o
obj-y                   += signal_$(BITS).o
obj-y                   += sigutil_$(BITS).o
obj-$(CONFIG_SPARC32)   += ioport.o
+7 −22
Original line number Diff line number Diff line
@@ -869,14 +869,11 @@ flush_patch_two:
	ld	[%curptr + TI_TASK], %o4
	rd	%psr, %g4
	WRITE_PAUSE
	mov	SIGCHLD, %o0			! arg0:	clone flags
	rd	%wim, %g5
	WRITE_PAUSE
	mov	%fp, %o1			! arg1:	usp
	std	%g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
	add	%sp, STACKFRAME_SZ, %o2		! arg2:	pt_regs ptr
	mov	0, %o3
	call	sparc_do_fork
	add	%sp, STACKFRAME_SZ, %o0
	call	sparc_fork
	 mov	%l5, %o7

	/* Whee, kernel threads! */
@@ -888,19 +885,11 @@ flush_patch_three:
	ld	[%curptr + TI_TASK], %o4
	rd	%psr, %g4
	WRITE_PAUSE

	/* arg0,1: flags,usp  -- loaded already */
	cmp	%o1, 0x0			! Is new_usp NULL?
	rd	%wim, %g5
	WRITE_PAUSE
	be,a	1f
	 mov	%fp, %o1			! yes, use callers usp
	andn	%o1, 7, %o1			! no, align to 8 bytes
1:
	std	%g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
	add	%sp, STACKFRAME_SZ, %o2		! arg2:	pt_regs ptr
	mov	0, %o3
	call	sparc_do_fork
	add	%sp, STACKFRAME_SZ, %o0
	call	sparc_clone
	 mov	%l5, %o7

	/* Whee, real vfork! */
@@ -914,13 +903,9 @@ flush_patch_four:
	rd	%wim, %g5
	WRITE_PAUSE
	std	%g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
	sethi	%hi(0x4000 | 0x0100 | SIGCHLD), %o0
	mov	%fp, %o1
	or	%o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
	sethi	%hi(sparc_do_fork), %l1
	mov	0, %o3
	jmpl	%l1 + %lo(sparc_do_fork), %g0
	 add	%sp, STACKFRAME_SZ, %o2
	sethi	%hi(sparc_vfork), %l1
	jmpl	%l1 + %lo(sparc_vfork), %g0
	 add	%sp, STACKFRAME_SZ, %o0

        .align  4
linux_sparc_ni_syscall:
+5 −6
Original line number Diff line number Diff line
@@ -14,6 +14,11 @@ extern const char *sparc_pmu_type;
extern unsigned int fsr_storage;
extern int ncpus_probed;

/* process{_32,_64}.c */
asmlinkage long sparc_clone(struct pt_regs *regs);
asmlinkage long sparc_fork(struct pt_regs *regs);
asmlinkage long sparc_vfork(struct pt_regs *regs);

#ifdef CONFIG_SPARC64
/* setup_64.c */
struct seq_file;
@@ -153,12 +158,6 @@ void floppy_hardint(void);
extern unsigned long sun4m_cpu_startup;
extern unsigned long sun4d_cpu_startup;

/* process_32.c */
asmlinkage int sparc_do_fork(unsigned long clone_flags,
                             unsigned long stack_start,
                             struct pt_regs *regs,
                             unsigned long stack_size);

/* signal_32.c */
asmlinkage void do_sigreturn(struct pt_regs *regs);
asmlinkage void do_rt_sigreturn(struct pt_regs *regs);
+110 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

/*
 * This file handles the architecture independent parts of process handling..
 */

#include <linux/compat.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <linux/sched/task.h>
#include <linux/sched/task_stack.h>
#include <linux/signal.h>

#include "kernel.h"

asmlinkage long sparc_fork(struct pt_regs *regs)
{
	unsigned long orig_i1 = regs->u_regs[UREG_I1];
	long ret;
	struct kernel_clone_args args = {
		.exit_signal	= SIGCHLD,
		/* Reuse the parent's stack for the child. */
		.stack		= regs->u_regs[UREG_FP],
	};

	ret = _do_fork(&args);

	/* If we get an error and potentially restart the system
	 * call, we're screwed because copy_thread_tls() clobbered
	 * the parent's %o1.  So detect that case and restore it
	 * here.
	 */
	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
		regs->u_regs[UREG_I1] = orig_i1;

	return ret;
}

asmlinkage long sparc_vfork(struct pt_regs *regs)
{
	unsigned long orig_i1 = regs->u_regs[UREG_I1];
	long ret;

	struct kernel_clone_args args = {
		.flags		= CLONE_VFORK | CLONE_VM,
		.exit_signal	= SIGCHLD,
		/* Reuse the parent's stack for the child. */
		.stack		= regs->u_regs[UREG_FP],
	};

	ret = _do_fork(&args);

	/* If we get an error and potentially restart the system
	 * call, we're screwed because copy_thread_tls() clobbered
	 * the parent's %o1.  So detect that case and restore it
	 * here.
	 */
	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
		regs->u_regs[UREG_I1] = orig_i1;

	return ret;
}

asmlinkage long sparc_clone(struct pt_regs *regs)
{
	unsigned long orig_i1 = regs->u_regs[UREG_I1];
	unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]);
	long ret;

	struct kernel_clone_args args = {
		.flags		= (flags & ~CSIGNAL),
		.exit_signal	= (flags & CSIGNAL),
		.tls		= regs->u_regs[UREG_I3],
	};

#ifdef CONFIG_COMPAT
	if (test_thread_flag(TIF_32BIT)) {
		args.pidfd	= compat_ptr(regs->u_regs[UREG_I2]);
		args.child_tid	= compat_ptr(regs->u_regs[UREG_I4]);
		args.parent_tid	= compat_ptr(regs->u_regs[UREG_I2]);
	} else
#endif
	{
		args.pidfd	= (int __user *)regs->u_regs[UREG_I2];
		args.child_tid	= (int __user *)regs->u_regs[UREG_I4];
		args.parent_tid	= (int __user *)regs->u_regs[UREG_I2];
	}

	/* Did userspace give setup a separate stack for the child or are we
	 * reusing the parent's?
	 */
	if (regs->u_regs[UREG_I1])
		args.stack = regs->u_regs[UREG_I1];
	else
		args.stack = regs->u_regs[UREG_FP];

	ret = _do_fork(&args);

	/* If we get an error and potentially restart the system
	 * call, we're screwed because copy_thread_tls() clobbered
	 * the parent's %o1.  So detect that case and restore it
	 * here.
	 */
	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
		regs->u_regs[UREG_I1] = orig_i1;

	return ret;
}
+0 −27
Original line number Diff line number Diff line
@@ -257,33 +257,6 @@ clone_stackframe(struct sparc_stackf __user *dst,
	return sp;
}

asmlinkage int sparc_do_fork(unsigned long clone_flags,
                             unsigned long stack_start,
                             struct pt_regs *regs,
                             unsigned long stack_size)
{
	unsigned long parent_tid_ptr, child_tid_ptr;
	unsigned long orig_i1 = regs->u_regs[UREG_I1];
	long ret;

	parent_tid_ptr = regs->u_regs[UREG_I2];
	child_tid_ptr = regs->u_regs[UREG_I4];

	ret = do_fork(clone_flags, stack_start, stack_size,
		      (int __user *) parent_tid_ptr,
		      (int __user *) child_tid_ptr);

	/* If we get an error and potentially restart the system
	 * call, we're screwed because copy_thread() clobbered
	 * the parent's %o1.  So detect that case and restore it
	 * here.
	 */
	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
		regs->u_regs[UREG_I1] = orig_i1;

	return ret;
}

/* Copy a Sparc thread.  The fork() return value conventions
 * under SunOS are nothing short of bletcherous:
 * Parent -->  %o0 == childs  pid, %o1 == 0
Loading