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

Commit 253f29a4 authored by Brian Gerst's avatar Brian Gerst Committed by Ingo Molnar
Browse files

x86: pass in pt_regs pointer for syscalls that need it



Some syscalls need to access the pt_regs structure, either to copy
user register state or to modifiy it.  This patch adds stubs to load
the address of the pt_regs struct into the %eax register, and changes
the syscalls to regparm(1) to receive the pt_regs pointer as the
first argument.

Signed-off-by: default avatarBrian Gerst <brgerst@gmail.com>
Acked-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent aa78bcfa
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,13 @@
 */
 */
#define asmregparm __attribute__((regparm(3)))
#define asmregparm __attribute__((regparm(3)))


/*
 * For syscalls that need a pointer to the pt_regs struct (ie. fork).
 * The regs pointer is passed in %eax as the first argument.  The
 * remaining function arguments remain on the stack.
 */
#define ptregscall __attribute__((regparm(1)))

/*
/*
 * Make sure the compiler doesn't do anything stupid with the
 * Make sure the compiler doesn't do anything stupid with the
 * arguments on the stack - they are owned by the *caller*, not
 * arguments on the stack - they are owned by the *caller*, not
+15 −10
Original line number Original line Diff line number Diff line
@@ -29,21 +29,26 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *);
/* X86_32 only */
/* X86_32 only */
#ifdef CONFIG_X86_32
#ifdef CONFIG_X86_32
/* kernel/process_32.c */
/* kernel/process_32.c */
asmlinkage int sys_fork(struct pt_regs);
ptregscall int sys_fork(struct pt_regs *);
asmlinkage int sys_clone(struct pt_regs);
ptregscall int sys_clone(struct pt_regs *, unsigned long,
asmlinkage int sys_vfork(struct pt_regs);
			 unsigned long, int __user *,
asmlinkage int sys_execve(struct pt_regs);
			 unsigned long, int __user *);
ptregscall int sys_vfork(struct pt_regs *);
ptregscall int sys_execve(struct pt_regs *, char __user *,
			  char __user * __user *,
			  char __user * __user *);


/* kernel/signal_32.c */
/* kernel/signal_32.c */
asmlinkage int sys_sigsuspend(int, int, old_sigset_t);
asmlinkage int sys_sigsuspend(int, int, old_sigset_t);
asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
			     struct old_sigaction __user *);
			     struct old_sigaction __user *);
asmlinkage int sys_sigaltstack(unsigned long);
ptregscall int sys_sigaltstack(struct pt_regs *, const stack_t __user *,
asmlinkage unsigned long sys_sigreturn(unsigned long);
			       stack_t __user *);
asmlinkage int sys_rt_sigreturn(unsigned long);
ptregscall unsigned long sys_sigreturn(struct pt_regs *);
ptregscall int sys_rt_sigreturn(struct pt_regs *);


/* kernel/ioport.c */
/* kernel/ioport.c */
asmlinkage long sys_iopl(unsigned long);
ptregscall long sys_iopl(struct pt_regs *, unsigned int);


/* kernel/sys_i386_32.c */
/* kernel/sys_i386_32.c */
asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
@@ -59,8 +64,8 @@ struct oldold_utsname;
asmlinkage int sys_olduname(struct oldold_utsname __user *);
asmlinkage int sys_olduname(struct oldold_utsname __user *);


/* kernel/vm86_32.c */
/* kernel/vm86_32.c */
asmlinkage int sys_vm86old(struct pt_regs);
ptregscall int sys_vm86old(struct pt_regs *, struct vm86_struct __user *);
asmlinkage int sys_vm86(struct pt_regs);
ptregscall int sys_vm86(struct pt_regs *, unsigned long, unsigned long);


#else /* CONFIG_X86_32 */
#else /* CONFIG_X86_32 */


+20 −0
Original line number Original line Diff line number Diff line
@@ -697,6 +697,26 @@ syscall_badsys:
END(syscall_badsys)
END(syscall_badsys)
	CFI_ENDPROC
	CFI_ENDPROC


/*
 * System calls that need a pt_regs pointer.
 */
#define PTREGSCALL(name) \
	ALIGN; \
ptregs_##name: \
	leal 4(%esp),%eax; \
	jmp sys_##name;

PTREGSCALL(iopl)
PTREGSCALL(fork)
PTREGSCALL(clone)
PTREGSCALL(vfork)
PTREGSCALL(execve)
PTREGSCALL(sigaltstack)
PTREGSCALL(sigreturn)
PTREGSCALL(rt_sigreturn)
PTREGSCALL(vm86)
PTREGSCALL(vm86old)

.macro FIXUP_ESPFIX_STACK
.macro FIXUP_ESPFIX_STACK
	/* since we are on a wrong stack, we cant make it a C code :( */
	/* since we are on a wrong stack, we cant make it a C code :( */
	PER_CPU(gdt_page, %ebx)
	PER_CPU(gdt_page, %ebx)
+1 −3
Original line number Original line Diff line number Diff line
@@ -131,10 +131,8 @@ static int do_iopl(unsigned int level, struct pt_regs *regs)
}
}


#ifdef CONFIG_X86_32
#ifdef CONFIG_X86_32
asmlinkage long sys_iopl(unsigned long regsp)
ptregscall long sys_iopl(struct pt_regs *regs, unsigned int level)
{
{
	struct pt_regs *regs = (struct pt_regs *)&regsp;
	unsigned int level = regs->bx;
	struct thread_struct *t = &current->thread;
	struct thread_struct *t = &current->thread;
	int rc;
	int rc;


+14 −21
Original line number Original line Diff line number Diff line
@@ -603,24 +603,18 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
	return prev_p;
	return prev_p;
}
}


asmlinkage int sys_fork(struct pt_regs regs)
ptregscall int sys_fork(struct pt_regs *regs)
{
{
	return do_fork(SIGCHLD, regs.sp, &regs, 0, NULL, NULL);
	return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
}
}


asmlinkage int sys_clone(struct pt_regs regs)
ptregscall int sys_clone(struct pt_regs *regs, unsigned long clone_flags,
			 unsigned long newsp, int __user *parent_tidptr,
			 unsigned long unused, int __user *child_tidptr)
{
{
	unsigned long clone_flags;
	unsigned long newsp;
	int __user *parent_tidptr, *child_tidptr;

	clone_flags = regs.bx;
	newsp = regs.cx;
	parent_tidptr = (int __user *)regs.dx;
	child_tidptr = (int __user *)regs.di;
	if (!newsp)
	if (!newsp)
		newsp = regs.sp;
		newsp = regs->sp;
	return do_fork(clone_flags, newsp, &regs, 0, parent_tidptr, child_tidptr);
	return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
}
}


/*
/*
@@ -633,27 +627,26 @@ asmlinkage int sys_clone(struct pt_regs regs)
 * do not have enough call-clobbered registers to hold all
 * do not have enough call-clobbered registers to hold all
 * the information you need.
 * the information you need.
 */
 */
asmlinkage int sys_vfork(struct pt_regs regs)
ptregscall int sys_vfork(struct pt_regs *regs)
{
{
	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, &regs, 0, NULL, NULL);
	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL);
}
}


/*
/*
 * sys_execve() executes a new program.
 * sys_execve() executes a new program.
 */
 */
asmlinkage int sys_execve(struct pt_regs regs)
ptregscall int sys_execve(struct pt_regs *regs, char __user *u_filename,
			  char __user * __user *argv,
			  char __user * __user *envp)
{
{
	int error;
	int error;
	char *filename;
	char *filename;


	filename = getname((char __user *) regs.bx);
	filename = getname(u_filename);
	error = PTR_ERR(filename);
	error = PTR_ERR(filename);
	if (IS_ERR(filename))
	if (IS_ERR(filename))
		goto out;
		goto out;
	error = do_execve(filename,
	error = do_execve(filename, argv, envp, regs);
			(char __user * __user *) regs.cx,
			(char __user * __user *) regs.dx,
			&regs);
	if (error == 0) {
	if (error == 0) {
		/* Make sure we don't return using sysenter.. */
		/* Make sure we don't return using sysenter.. */
		set_thread_flag(TIF_IRET);
		set_thread_flag(TIF_IRET);
Loading