Commit 1d4b4b29 authored by Al Viro's avatar Al Viro

x86, um: switch to generic fork/vfork/clone

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 71613c3b
...@@ -14,25 +14,6 @@ ...@@ -14,25 +14,6 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unistd.h> #include <asm/unistd.h>
long sys_fork(void)
{
return do_fork(SIGCHLD, 0,
&current->thread.regs, 0, NULL, NULL);
}
long sys_vfork(void)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
&current->thread.regs, 0, NULL, NULL);
}
long sys_clone(unsigned long clone_flags, unsigned long newsp,
void __user *parent_tid, void __user *child_tid)
{
return do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
child_tid);
}
long old_mmap(unsigned long addr, unsigned long len, long old_mmap(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags, unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long offset) unsigned long fd, unsigned long offset)
......
...@@ -112,6 +112,7 @@ config X86 ...@@ -112,6 +112,7 @@ config X86
select GENERIC_KERNEL_EXECVE select GENERIC_KERNEL_EXECVE
select MODULES_USE_ELF_REL if X86_32 select MODULES_USE_ELF_REL if X86_32
select MODULES_USE_ELF_RELA if X86_64 select MODULES_USE_ELF_RELA if X86_64
select CLONE_BACKWARDS if X86_32
config INSTRUCTION_DECODER config INSTRUCTION_DECODER
def_bool y def_bool y
......
...@@ -467,10 +467,15 @@ GLOBAL(\label) ...@@ -467,10 +467,15 @@ GLOBAL(\label)
PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
PTREGSCALL stub32_execve, compat_sys_execve, %rcx PTREGSCALL stub32_execve, compat_sys_execve, %rcx
PTREGSCALL stub32_fork, sys_fork, %rdi PTREGSCALL stub32_fork, sys_fork, %rdi
PTREGSCALL stub32_clone, sys32_clone, %rdx
PTREGSCALL stub32_vfork, sys_vfork, %rdi PTREGSCALL stub32_vfork, sys_vfork, %rdi
PTREGSCALL stub32_iopl, sys_iopl, %rsi PTREGSCALL stub32_iopl, sys_iopl, %rsi
ALIGN
GLOBAL(stub32_clone)
leaq sys_clone(%rip),%rax
mov %r8, %rcx
jmp ia32_ptregs_common
ALIGN ALIGN
ia32_ptregs_common: ia32_ptregs_common:
popq %r11 popq %r11
......
...@@ -385,17 +385,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, ...@@ -385,17 +385,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd,
return ret; return ret;
} }
asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
struct pt_regs *regs)
{
void __user *parent_tid = (void __user *)regs->dx;
void __user *child_tid = (void __user *)regs->di;
if (!newsp)
newsp = regs->sp;
return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}
/* /*
* Some system calls that need sign extended arguments. This could be * Some system calls that need sign extended arguments. This could be
* done by a generic wrapper. * done by a generic wrapper.
......
...@@ -54,8 +54,6 @@ asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32); ...@@ -54,8 +54,6 @@ asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32);
asmlinkage long sys32_personality(unsigned long); asmlinkage long sys32_personality(unsigned long);
asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32); asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32);
asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *);
long sys32_lseek(unsigned int, int, unsigned int); long sys32_lseek(unsigned int, int, unsigned int);
long sys32_kill(int, int); long sys32_kill(int, int);
long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int); long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int);
......
...@@ -21,10 +21,15 @@ asmlinkage long sys_ioperm(unsigned long, unsigned long, int); ...@@ -21,10 +21,15 @@ asmlinkage long sys_ioperm(unsigned long, unsigned long, int);
long sys_iopl(unsigned int, struct pt_regs *); long sys_iopl(unsigned int, struct pt_regs *);
/* kernel/process.c */ /* kernel/process.c */
int sys_fork(struct pt_regs *); asmlinkage long sys_fork(void);
int sys_vfork(struct pt_regs *); asmlinkage long sys_vfork(void);
long sys_clone(unsigned long, unsigned long, void __user *, #ifdef CONFIG_CLONE_BACKWARDS
void __user *, struct pt_regs *); asmlinkage long sys_clone(unsigned long, unsigned long, void __user *, int,
void __user *);
#else
asmlinkage long sys_clone(unsigned long, unsigned long, void __user *,
void __user *, int);
#endif
/* kernel/ldt.c */ /* kernel/ldt.c */
asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
......
...@@ -51,6 +51,9 @@ ...@@ -51,6 +51,9 @@
# define __ARCH_WANT_SYS_UTIME # define __ARCH_WANT_SYS_UTIME
# define __ARCH_WANT_SYS_WAITPID # define __ARCH_WANT_SYS_WAITPID
# define __ARCH_WANT_SYS_EXECVE # define __ARCH_WANT_SYS_EXECVE
# define __ARCH_WANT_SYS_FORK
# define __ARCH_WANT_SYS_VFORK
# define __ARCH_WANT_SYS_CLONE
/* /*
* "Conditional" syscalls * "Conditional" syscalls
......
...@@ -739,30 +739,12 @@ ENTRY(ptregs_##name) ; \ ...@@ -739,30 +739,12 @@ ENTRY(ptregs_##name) ; \
ENDPROC(ptregs_##name) ENDPROC(ptregs_##name)
PTREGSCALL1(iopl) PTREGSCALL1(iopl)
PTREGSCALL0(fork)
PTREGSCALL0(vfork)
PTREGSCALL2(sigaltstack) PTREGSCALL2(sigaltstack)
PTREGSCALL0(sigreturn) PTREGSCALL0(sigreturn)
PTREGSCALL0(rt_sigreturn) PTREGSCALL0(rt_sigreturn)
PTREGSCALL2(vm86) PTREGSCALL2(vm86)
PTREGSCALL1(vm86old) PTREGSCALL1(vm86old)
/* Clone is an oddball. The 4th arg is in %edi */
ENTRY(ptregs_clone)
CFI_STARTPROC
leal 4(%esp),%eax
pushl_cfi %eax
pushl_cfi PT_EDI(%eax)
movl PT_EDX(%eax),%ecx
movl PT_ECX(%eax),%edx
movl PT_EBX(%eax),%eax
call sys_clone
addl $8,%esp
CFI_ADJUST_CFA_OFFSET -8
ret
CFI_ENDPROC
ENDPROC(ptregs_clone)
.macro FIXUP_ESPFIX_STACK .macro FIXUP_ESPFIX_STACK
/* /*
* Switch back for ESPFIX stack to the normal zerobased stack * Switch back for ESPFIX stack to the normal zerobased stack
......
...@@ -845,9 +845,25 @@ ENTRY(\label) ...@@ -845,9 +845,25 @@ ENTRY(\label)
END(\label) END(\label)
.endm .endm
PTREGSCALL stub_clone, sys_clone, %r8 .macro FORK_LIKE func
PTREGSCALL stub_fork, sys_fork, %rdi ENTRY(stub_\func)
PTREGSCALL stub_vfork, sys_vfork, %rdi CFI_STARTPROC
popq %r11 /* save return address */
PARTIAL_FRAME 0
SAVE_REST
pushq %r11 /* put it back on stack */
FIXUP_TOP_OF_STACK %r11, 8
DEFAULT_FRAME 0 8 /* offset 8: return address */
call sys_\func
RESTORE_TOP_OF_STACK %r11, 8
ret $REST_SKIP /* pop extended registers */
CFI_ENDPROC
END(stub_\func)
.endm
FORK_LIKE clone
FORK_LIKE fork
FORK_LIKE vfork
PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
PTREGSCALL stub_iopl, sys_iopl, %rsi PTREGSCALL stub_iopl, sys_iopl, %rsi
......
...@@ -262,36 +262,6 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, ...@@ -262,36 +262,6 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
propagate_user_return_notify(prev_p, next_p); propagate_user_return_notify(prev_p, next_p);
} }
int sys_fork(struct pt_regs *regs)
{
return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
}
/*
* This is trivial, and on the face of it looks like it
* could equally well be done in user mode.
*
* Not so, for quite unobvious reasons - register pressure.
* In user mode vfork() cannot have a stack frame, and if
* done by calling the "clone()" system call directly, you
* do not have enough call-clobbered registers to hold all
* the information you need.
*/
int sys_vfork(struct pt_regs *regs)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0,
NULL, NULL);
}
long
sys_clone(unsigned long clone_flags, unsigned long newsp,
void __user *parent_tid, void __user *child_tid, struct pt_regs *regs)
{
if (!newsp)
newsp = regs->sp;
return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}
/* /*
* Idle related variables and functions * Idle related variables and functions
*/ */
......
...@@ -129,7 +129,7 @@ void release_thread(struct task_struct *dead_task) ...@@ -129,7 +129,7 @@ void release_thread(struct task_struct *dead_task)
int copy_thread(unsigned long clone_flags, unsigned long sp, int copy_thread(unsigned long clone_flags, unsigned long sp,
unsigned long arg, unsigned long arg,
struct task_struct *p, struct pt_regs *regs) struct task_struct *p, struct pt_regs *unused)
{ {
struct pt_regs *childregs = task_pt_regs(p); struct pt_regs *childregs = task_pt_regs(p);
struct task_struct *tsk; struct task_struct *tsk;
...@@ -138,7 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, ...@@ -138,7 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
p->thread.sp = (unsigned long) childregs; p->thread.sp = (unsigned long) childregs;
p->thread.sp0 = (unsigned long) (childregs+1); p->thread.sp0 = (unsigned long) (childregs+1);
if (unlikely(!regs)) { if (unlikely(p->flags & PF_KTHREAD)) {
/* kernel thread */ /* kernel thread */
memset(childregs, 0, sizeof(struct pt_regs)); memset(childregs, 0, sizeof(struct pt_regs));
p->thread.ip = (unsigned long) ret_from_kernel_thread; p->thread.ip = (unsigned long) ret_from_kernel_thread;
...@@ -156,12 +156,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, ...@@ -156,12 +156,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
return 0; return 0;
} }
*childregs = *regs; *childregs = *current_pt_regs();
childregs->ax = 0; childregs->ax = 0;
childregs->sp = sp; if (sp)
childregs->sp = sp;
p->thread.ip = (unsigned long) ret_from_fork; p->thread.ip = (unsigned long) ret_from_fork;
task_user_gs(p) = get_user_gs(regs); task_user_gs(p) = get_user_gs(current_pt_regs());
p->fpu_counter = 0; p->fpu_counter = 0;
p->thread.io_bitmap_ptr = NULL; p->thread.io_bitmap_ptr = NULL;
......
...@@ -169,7 +169,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, ...@@ -169,7 +169,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
savesegment(ds, p->thread.ds); savesegment(ds, p->thread.ds);
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
if (unlikely(!regs)) { if (unlikely(p->flags & PF_KTHREAD)) {
/* kernel thread */ /* kernel thread */
memset(childregs, 0, sizeof(struct pt_regs)); memset(childregs, 0, sizeof(struct pt_regs));
childregs->sp = (unsigned long)childregs; childregs->sp = (unsigned long)childregs;
...@@ -181,10 +181,11 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, ...@@ -181,10 +181,11 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
return 0; return 0;
} }
*childregs = *regs; *childregs = *current_pt_regs();
childregs->ax = 0; childregs->ax = 0;
childregs->sp = sp; if (sp)
childregs->sp = sp;
err = -ENOMEM; err = -ENOMEM;
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
# #
0 i386 restart_syscall sys_restart_syscall 0 i386 restart_syscall sys_restart_syscall
1 i386 exit sys_exit 1 i386 exit sys_exit
2 i386 fork ptregs_fork stub32_fork 2 i386 fork sys_fork stub32_fork
3 i386 read sys_read 3 i386 read sys_read
4 i386 write sys_write 4 i386 write sys_write
5 i386 open sys_open compat_sys_open 5 i386 open sys_open compat_sys_open
...@@ -126,7 +126,7 @@ ...@@ -126,7 +126,7 @@
117 i386 ipc sys_ipc sys32_ipc 117 i386 ipc sys_ipc sys32_ipc
118 i386 fsync sys_fsync 118 i386 fsync sys_fsync
119 i386 sigreturn ptregs_sigreturn stub32_sigreturn 119 i386 sigreturn ptregs_sigreturn stub32_sigreturn
120 i386 clone ptregs_clone stub32_clone 120 i386 clone sys_clone stub32_clone
121 i386 setdomainname sys_setdomainname 121 i386 setdomainname sys_setdomainname
122 i386 uname sys_newuname 122 i386 uname sys_newuname
123 i386 modify_ldt sys_modify_ldt 123 i386 modify_ldt sys_modify_ldt
...@@ -196,7 +196,7 @@ ...@@ -196,7 +196,7 @@
187 i386 sendfile sys_sendfile sys32_sendfile 187 i386 sendfile sys_sendfile sys32_sendfile
188 i386 getpmsg 188 i386 getpmsg
189 i386 putpmsg 189 i386 putpmsg
190 i386 vfork ptregs_vfork stub32_vfork 190 i386 vfork sys_vfork stub32_vfork
191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit 191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit
192 i386 mmap2 sys_mmap_pgoff 192 i386 mmap2 sys_mmap_pgoff
193 i386 truncate64 sys_truncate64 sys32_truncate64 193 i386 truncate64 sys_truncate64 sys32_truncate64
......
...@@ -25,6 +25,7 @@ config X86_32 ...@@ -25,6 +25,7 @@ config X86_32
select HAVE_AOUT select HAVE_AOUT
select ARCH_WANT_IPC_PARSE_VERSION select ARCH_WANT_IPC_PARSE_VERSION
select MODULES_USE_ELF_REL select MODULES_USE_ELF_REL
select CLONE_BACKWARDS
config X86_64 config X86_64
def_bool 64BIT def_bool 64BIT
......
...@@ -24,13 +24,10 @@ ...@@ -24,13 +24,10 @@
#define old_mmap sys_old_mmap #define old_mmap sys_old_mmap
#define ptregs_fork sys_fork
#define ptregs_iopl sys_iopl #define ptregs_iopl sys_iopl
#define ptregs_vm86old sys_vm86old #define ptregs_vm86old sys_vm86old
#define ptregs_clone i386_clone
#define ptregs_vm86 sys_vm86 #define ptregs_vm86 sys_vm86
#define ptregs_sigaltstack sys_sigaltstack #define ptregs_sigaltstack sys_sigaltstack
#define ptregs_vfork sys_vfork
#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ; #define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;
#include <asm/syscalls_32.h> #include <asm/syscalls_32.h>
......
...@@ -6,21 +6,6 @@ ...@@ -6,21 +6,6 @@
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <sysdep/syscalls.h> #include <sysdep/syscalls.h>
/*
* The prototype on i386 is:
*
* int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls
*
* and the "newtls" arg. on i386 is read by copy_thread directly from the
* register saved on the stack.
*/
long i386_clone(unsigned long clone_flags, unsigned long newsp,
int __user *parent_tid, void *newtls, int __user *child_tid)
{
return sys_clone(clone_flags, newsp, parent_tid, child_tid);
}
long sys_sigaction(int sig, const struct old_sigaction __user *act, long sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact) struct old_sigaction __user *oact)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment