Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03ff9a23 authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

[S390] System call cleanup.



Remove system call glue for sys_clone, sys_fork, sys_vfork, sys_execve,
sys_sigreturn, sys_rt_sigreturn and sys_sigaltstack. Call do_execve from
kernel_execve directly, move pt_regs to the right place and branch to
sysc_return to start the user space program. This removes the last
in-kernel system call.

Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
parent ef99516c
Loading
Loading
Loading
Loading
+33 −27
Original line number Diff line number Diff line
@@ -495,29 +495,34 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
 * sys32_execve() executes a new program after the asm stub has set
 * things up for us.  This should basically do what I want it to.
 */
asmlinkage long
sys32_execve(struct pt_regs regs)
asmlinkage long sys32_execve(void)
{
        int error;
	struct pt_regs *regs = task_pt_regs(current);
	char *filename;
	unsigned long result;
	int rc;

        filename = getname(compat_ptr(regs.orig_gpr2));
        error = PTR_ERR(filename);
        if (IS_ERR(filename))
	filename = getname(compat_ptr(regs->orig_gpr2));
	if (IS_ERR(filename)) {
		result = PTR_ERR(filename);
                goto out;
        error = compat_do_execve(filename, compat_ptr(regs.gprs[3]),
				 compat_ptr(regs.gprs[4]), &regs);
	if (error == 0)
	{
	}
	rc = compat_do_execve(filename, compat_ptr(regs->gprs[3]),
			      compat_ptr(regs->gprs[4]), regs);
	if (rc) {
		result = rc;
		goto out_putname;
	}
	task_lock(current);
	current->ptrace &= ~PT_DTRACE;
	task_unlock(current);
	current->thread.fp_regs.fpc=0;
	asm volatile("sfpc %0,0" : : "d" (0));
	}
	result = regs->gprs[2];
out_putname:
        putname(filename);
out:
        return error;
	return result;
}


@@ -918,19 +923,20 @@ asmlinkage long sys32_write(unsigned int fd, char __user * buf, size_t count)
	return sys_write(fd, buf, count);
}

asmlinkage long sys32_clone(struct pt_regs regs)
asmlinkage long sys32_clone(void)
{
	struct pt_regs *regs = task_pt_regs(current);
	unsigned long clone_flags;
	unsigned long newsp;
	int __user *parent_tidptr, *child_tidptr;

        clone_flags = regs.gprs[3] & 0xffffffffUL;
        newsp = regs.orig_gpr2 & 0x7fffffffUL;
	parent_tidptr = compat_ptr(regs.gprs[4]);
	child_tidptr = compat_ptr(regs.gprs[5]);
	clone_flags = regs->gprs[3] & 0xffffffffUL;
	newsp = regs->orig_gpr2 & 0x7fffffffUL;
	parent_tidptr = compat_ptr(regs->gprs[4]);
	child_tidptr = compat_ptr(regs->gprs[5]);
	if (!newsp)
                newsp = regs.gprs[15];
        return do_fork(clone_flags, newsp, &regs, 0,
		newsp = regs->gprs[15];
	return do_fork(clone_flags, newsp, regs, 0,
		       parent_tidptr, child_tidptr);
}

+8 −6
Original line number Diff line number Diff line
@@ -255,9 +255,9 @@ sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
}

asmlinkage long
sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss,
							struct pt_regs *regs)
sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss)
{
	struct pt_regs *regs = task_pt_regs(current);
	stack_t kss, koss;
	unsigned long ss_sp;
	int ret, err = 0;
@@ -344,8 +344,9 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
	return 0;
}

asmlinkage long sys32_sigreturn(struct pt_regs *regs)
asmlinkage long sys32_sigreturn(void)
{
	struct pt_regs *regs = task_pt_regs(current);
	sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
	sigset_t set;

@@ -370,8 +371,9 @@ asmlinkage long sys32_sigreturn(struct pt_regs *regs)
	return 0;
}

asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
asmlinkage long sys32_rt_sigreturn(void)
{
	struct pt_regs *regs = task_pt_regs(current);
	rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
	sigset_t set;
	stack_t st;
+32 −55
Original line number Diff line number Diff line
@@ -249,8 +249,6 @@ sysc_do_restart:
	bnz	BASED(sysc_tracesys)
	basr	%r14,%r8	  # call sys_xxxx
	st	%r2,SP_R2(%r15)   # store return value (change R2 on stack)
				  # ATTENTION: check sys_execve_glue before
				  # changing anything here !!

sysc_return:
	tm	SP_PSW+1(%r15),0x01	# returning to user ?
@@ -381,50 +379,37 @@ ret_from_fork:
	b	BASED(sysc_return)

#
# clone, fork, vfork, exec and sigreturn need glue,
# because they all expect pt_regs as parameter,
# but are called with different parameter.
# return-address is set up above
# kernel_execve function needs to deal with pt_regs that is not
# at the usual place
#
sys_clone_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	l	%r1,BASED(.Lclone)
	br	%r1			# branch to sys_clone

sys_fork_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	l	%r1,BASED(.Lfork)
	br	%r1			# branch to sys_fork

sys_vfork_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	l	%r1,BASED(.Lvfork)
	br	%r1			# branch to sys_vfork

sys_execve_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	l	%r1,BASED(.Lexecve)
	lr	%r12,%r14		# save return address
	basr	%r14,%r1		# call sys_execve
	ltr	%r2,%r2			# check if execve failed
	bnz	0(%r12)			# it did fail -> store result in gpr2
	b	4(%r12)			# SKIP ST 2,SP_R2(15) after BASR 14,8
					# in system_call/sysc_tracesys

sys_sigreturn_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs as parameter
	l	%r1,BASED(.Lsigreturn)
	br	%r1			# branch to sys_sigreturn

sys_rt_sigreturn_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs as parameter
	l	%r1,BASED(.Lrt_sigreturn)
	br	%r1			# branch to sys_sigreturn

sys_sigaltstack_glue:
	la	%r4,SP_PTREGS(%r15)	# load pt_regs as parameter
	l	%r1,BASED(.Lsigaltstack)
	br	%r1			# branch to sys_sigreturn
	.globl	kernel_execve
kernel_execve:
	stm	%r12,%r15,48(%r15)
	lr	%r14,%r15
	l	%r13,__LC_SVC_NEW_PSW+4
	s	%r15,BASED(.Lc_spsize)
	st	%r14,__SF_BACKCHAIN(%r15)
	la	%r12,SP_PTREGS(%r15)
	xc	0(__PT_SIZE,%r12),0(%r12)
	l	%r1,BASED(.Ldo_execve)
	lr	%r5,%r12
	basr	%r14,%r1
	ltr	%r2,%r2
	be	BASED(0f)
	a	%r15,BASED(.Lc_spsize)
	lm	%r12,%r15,48(%r15)
	br	%r14
	# execve succeeded.
0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
	l	%r15,__LC_KERNEL_STACK	# load ksp
	s	%r15,BASED(.Lc_spsize)	# make room for registers & psw
	l	%r9,__LC_THREAD_INFO
	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	l	%r1,BASED(.Lexecve_tail)
	basr	%r14,%r1
	b	BASED(sysc_return)

/*
 * Program check handler routine
@@ -1031,19 +1016,11 @@ cleanup_io_leave_insn:
.Ldo_extint:	.long	do_extint
.Ldo_signal:	.long	do_signal
.Lhandle_per:	.long	do_single_step
.Ldo_execve:	.long	do_execve
.Lexecve_tail:	.long	execve_tail
.Ljump_table:	.long	pgm_check_table
.Lschedule:	.long	schedule
.Lclone:	.long	sys_clone
.Lexecve:	.long	sys_execve
.Lfork: 	.long	sys_fork
.Lrt_sigreturn: .long	sys_rt_sigreturn
.Lrt_sigsuspend:
		.long	sys_rt_sigsuspend
.Lsigreturn:	.long	sys_sigreturn
.Lsigsuspend:	.long	sys_sigsuspend
.Lsigaltstack:	.long	sys_sigaltstack
.Ltrace:	.long	syscall_trace
.Lvfork:	.long	sys_vfork
.Lschedtail:	.long	schedule_tail
.Lsysc_table:	.long	sys_call_table
#ifdef CONFIG_TRACE_IRQFLAGS
+28 −72
Original line number Diff line number Diff line
@@ -244,8 +244,6 @@ sysc_noemu:
	jnz	sysc_tracesys
	basr	%r14,%r8	# call sys_xxxx
	stg	%r2,SP_R2(%r15) # store return value (change R2 on stack)
				# ATTENTION: check sys_execve_glue before
				# changing anything here !!

sysc_return:
	tm	SP_PSW+1(%r15),0x01	# returning to user ?
@@ -371,77 +369,35 @@ ret_from_fork:
	j	sysc_return

#
# clone, fork, vfork, exec and sigreturn need glue,
# because they all expect pt_regs as parameter,
# but are called with different parameter.
# return-address is set up above
# kernel_execve function needs to deal with pt_regs that is not
# at the usual place
#
sys_clone_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	jg	sys_clone		# branch to sys_clone

#ifdef CONFIG_COMPAT
sys32_clone_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	jg	sys32_clone		# branch to sys32_clone
#endif

sys_fork_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	jg	sys_fork		# branch to sys_fork

sys_vfork_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	jg	sys_vfork		# branch to sys_vfork

sys_execve_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	lgr	%r12,%r14		# save return address
	brasl	%r14,sys_execve 	# call sys_execve
	ltgr	%r2,%r2 		# check if execve failed
	bnz	0(%r12) 		# it did fail -> store result in gpr2
	b	6(%r12) 		# SKIP STG 2,SP_R2(15) in
					# system_call/sysc_tracesys
#ifdef CONFIG_COMPAT
sys32_execve_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs
	lgr	%r12,%r14		# save return address
	brasl	%r14,sys32_execve	# call sys32_execve
	ltgr	%r2,%r2 		# check if execve failed
	bnz	0(%r12) 		# it did fail -> store result in gpr2
	b	6(%r12) 		# SKIP STG 2,SP_R2(15) in
					# system_call/sysc_tracesys
#endif

sys_sigreturn_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs as parameter
	jg	sys_sigreturn		# branch to sys_sigreturn

#ifdef CONFIG_COMPAT
sys32_sigreturn_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs as parameter
	jg	sys32_sigreturn 	# branch to sys32_sigreturn
#endif

sys_rt_sigreturn_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs as parameter
	jg	sys_rt_sigreturn	# branch to sys_sigreturn

#ifdef CONFIG_COMPAT
sys32_rt_sigreturn_glue:
	la	%r2,SP_PTREGS(%r15)	# load pt_regs as parameter
	jg	sys32_rt_sigreturn	# branch to sys32_sigreturn
#endif

sys_sigaltstack_glue:
	la	%r4,SP_PTREGS(%r15)	# load pt_regs as parameter
	jg	sys_sigaltstack 	# branch to sys_sigreturn

#ifdef CONFIG_COMPAT
sys32_sigaltstack_glue:
	la	%r4,SP_PTREGS(%r15)	# load pt_regs as parameter
	jg	sys32_sigaltstack_wrapper # branch to sys_sigreturn
#endif
	.globl	kernel_execve
kernel_execve:
	stmg	%r12,%r15,96(%r15)
	lgr	%r14,%r15
	aghi	%r15,-SP_SIZE
	stg	%r14,__SF_BACKCHAIN(%r15)
	la	%r12,SP_PTREGS(%r15)
	xc	0(__PT_SIZE,%r12),0(%r12)
	lgr	%r5,%r12
	brasl	%r14,do_execve
	ltgfr	%r2,%r2
	je	0f
	aghi	%r15,SP_SIZE
	lmg	%r12,%r15,96(%r15)
	br	%r14
	# execve succeeded.
0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
	lg	%r15,__LC_KERNEL_STACK	# load ksp
	aghi	%r15,-SP_SIZE		# make room for registers & psw
	lg	%r13,__LC_SVC_NEW_PSW+8
	lg	%r9,__LC_THREAD_INFO
	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
	brasl	%r14,execve_tail
	j	sysc_return

/*
 * Program check handler routine
+48 −34
Original line number Diff line number Diff line
@@ -280,24 +280,26 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
        return 0;
}

asmlinkage long sys_fork(struct pt_regs regs)
asmlinkage long sys_fork(void)
{
	return do_fork(SIGCHLD, regs.gprs[15], &regs, 0, NULL, NULL);
	struct pt_regs *regs = task_pt_regs(current);
	return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL);
}

asmlinkage long sys_clone(struct pt_regs regs)
asmlinkage long sys_clone(void)
{
	struct pt_regs *regs = task_pt_regs(current);
	unsigned long clone_flags;
	unsigned long newsp;
	int __user *parent_tidptr, *child_tidptr;

        clone_flags = regs.gprs[3];
        newsp = regs.orig_gpr2;
	parent_tidptr = (int __user *) regs.gprs[4];
	child_tidptr = (int __user *) regs.gprs[5];
	clone_flags = regs->gprs[3];
	newsp = regs->orig_gpr2;
	parent_tidptr = (int __user *) regs->gprs[4];
	child_tidptr = (int __user *) regs->gprs[5];
	if (!newsp)
                newsp = regs.gprs[15];
        return do_fork(clone_flags, newsp, &regs, 0,
		newsp = regs->gprs[15];
	return do_fork(clone_flags, newsp, regs, 0,
		       parent_tidptr, child_tidptr);
}

@@ -311,27 +313,15 @@ asmlinkage long sys_clone(struct pt_regs regs)
 * do not have enough call-clobbered registers to hold all
 * the information you need.
 */
asmlinkage long sys_vfork(struct pt_regs regs)
asmlinkage long sys_vfork(void)
{
	struct pt_regs *regs = task_pt_regs(current);
	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
		       regs.gprs[15], &regs, 0, NULL, NULL);
		       regs->gprs[15], regs, 0, NULL, NULL);
}

/*
 * sys_execve() executes a new program.
 */
asmlinkage long sys_execve(struct pt_regs regs)
asmlinkage void execve_tail(void)
{
        int error;
        char * filename;

        filename = getname((char __user *) regs.orig_gpr2);
        error = PTR_ERR(filename);
        if (IS_ERR(filename))
                goto out;
        error = do_execve(filename, (char __user * __user *) regs.gprs[3],
			  (char __user * __user *) regs.gprs[4], &regs);
	if (error == 0) {
	task_lock(current);
	current->ptrace &= ~PT_DTRACE;
	task_unlock(current);
@@ -339,12 +329,36 @@ asmlinkage long sys_execve(struct pt_regs regs)
	if (MACHINE_HAS_IEEE)
		asm volatile("sfpc %0,%0" : : "d" (0));
}

/*
 * sys_execve() executes a new program.
 */
asmlinkage long sys_execve(void)
{
	struct pt_regs *regs = task_pt_regs(current);
	char *filename;
	unsigned long result;
	int rc;

	filename = getname((char __user *) regs->orig_gpr2);
	if (IS_ERR(filename)) {
		result = PTR_ERR(filename);
		goto out;
	}
	rc = do_execve(filename, (char __user * __user *) regs->gprs[3],
		       (char __user * __user *) regs->gprs[4], regs);
	if (rc) {
		result = rc;
		goto out_putname;
	}
	execve_tail();
	result = regs->gprs[2];
out_putname:
	putname(filename);
out:
        return error;
	return result;
}


/*
 * fill in the FPU structure for a core dump.
 */
Loading