x86, um: switch to generic fork/vfork/clone
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
71613c3b87
Коммит
1d4b4b2994
|
@ -14,25 +14,6 @@
|
|||
#include <asm/uaccess.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
long sys_fork(void)
|
||||
{
|
||||
return do_fork(SIGCHLD, 0,
|
||||
¤t->thread.regs, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
long sys_vfork(void)
|
||||
{
|
||||
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
|
||||
¤t->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, ¤t->thread.regs, 0, parent_tid,
|
||||
child_tid);
|
||||
}
|
||||
|
||||
long old_mmap(unsigned long addr, unsigned long len,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long fd, unsigned long offset)
|
||||
|
|
|
@ -112,6 +112,7 @@ config X86
|
|||
select GENERIC_KERNEL_EXECVE
|
||||
select MODULES_USE_ELF_REL if X86_32
|
||||
select MODULES_USE_ELF_RELA if X86_64
|
||||
select CLONE_BACKWARDS if X86_32
|
||||
|
||||
config INSTRUCTION_DECODER
|
||||
def_bool y
|
||||
|
|
|
@ -467,10 +467,15 @@ GLOBAL(\label)
|
|||
PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
|
||||
PTREGSCALL stub32_execve, compat_sys_execve, %rcx
|
||||
PTREGSCALL stub32_fork, sys_fork, %rdi
|
||||
PTREGSCALL stub32_clone, sys32_clone, %rdx
|
||||
PTREGSCALL stub32_vfork, sys_vfork, %rdi
|
||||
PTREGSCALL stub32_iopl, sys_iopl, %rsi
|
||||
|
||||
ALIGN
|
||||
GLOBAL(stub32_clone)
|
||||
leaq sys_clone(%rip),%rax
|
||||
mov %r8, %rcx
|
||||
jmp ia32_ptregs_common
|
||||
|
||||
ALIGN
|
||||
ia32_ptregs_common:
|
||||
popq %r11
|
||||
|
|
|
@ -385,17 +385,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd,
|
|||
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
|
||||
* done by a generic wrapper.
|
||||
|
|
|
@ -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_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_kill(int, int);
|
||||
long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int);
|
||||
|
|
|
@ -21,10 +21,15 @@ asmlinkage long sys_ioperm(unsigned long, unsigned long, int);
|
|||
long sys_iopl(unsigned int, struct pt_regs *);
|
||||
|
||||
/* kernel/process.c */
|
||||
int sys_fork(struct pt_regs *);
|
||||
int sys_vfork(struct pt_regs *);
|
||||
long sys_clone(unsigned long, unsigned long, void __user *,
|
||||
void __user *, struct pt_regs *);
|
||||
asmlinkage long sys_fork(void);
|
||||
asmlinkage long sys_vfork(void);
|
||||
#ifdef CONFIG_CLONE_BACKWARDS
|
||||
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 */
|
||||
asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
|
||||
|
|
|
@ -51,6 +51,9 @@
|
|||
# define __ARCH_WANT_SYS_UTIME
|
||||
# define __ARCH_WANT_SYS_WAITPID
|
||||
# define __ARCH_WANT_SYS_EXECVE
|
||||
# define __ARCH_WANT_SYS_FORK
|
||||
# define __ARCH_WANT_SYS_VFORK
|
||||
# define __ARCH_WANT_SYS_CLONE
|
||||
|
||||
/*
|
||||
* "Conditional" syscalls
|
||||
|
|
|
@ -739,30 +739,12 @@ ENTRY(ptregs_##name) ; \
|
|||
ENDPROC(ptregs_##name)
|
||||
|
||||
PTREGSCALL1(iopl)
|
||||
PTREGSCALL0(fork)
|
||||
PTREGSCALL0(vfork)
|
||||
PTREGSCALL2(sigaltstack)
|
||||
PTREGSCALL0(sigreturn)
|
||||
PTREGSCALL0(rt_sigreturn)
|
||||
PTREGSCALL2(vm86)
|
||||
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
|
||||
/*
|
||||
* Switch back for ESPFIX stack to the normal zerobased stack
|
||||
|
|
|
@ -845,9 +845,25 @@ ENTRY(\label)
|
|||
END(\label)
|
||||
.endm
|
||||
|
||||
PTREGSCALL stub_clone, sys_clone, %r8
|
||||
PTREGSCALL stub_fork, sys_fork, %rdi
|
||||
PTREGSCALL stub_vfork, sys_vfork, %rdi
|
||||
.macro FORK_LIKE func
|
||||
ENTRY(stub_\func)
|
||||
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_iopl, sys_iopl, %rsi
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -129,7 +129,7 @@ void release_thread(struct task_struct *dead_task)
|
|||
|
||||
int copy_thread(unsigned long clone_flags, unsigned long sp,
|
||||
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 task_struct *tsk;
|
||||
|
@ -138,7 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
|||
p->thread.sp = (unsigned long) childregs;
|
||||
p->thread.sp0 = (unsigned long) (childregs+1);
|
||||
|
||||
if (unlikely(!regs)) {
|
||||
if (unlikely(p->flags & PF_KTHREAD)) {
|
||||
/* kernel thread */
|
||||
memset(childregs, 0, sizeof(struct pt_regs));
|
||||
p->thread.ip = (unsigned long) ret_from_kernel_thread;
|
||||
|
@ -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));
|
||||
return 0;
|
||||
}
|
||||
*childregs = *regs;
|
||||
*childregs = *current_pt_regs();
|
||||
childregs->ax = 0;
|
||||
childregs->sp = sp;
|
||||
if (sp)
|
||||
childregs->sp = sp;
|
||||
|
||||
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->thread.io_bitmap_ptr = NULL;
|
||||
|
|
|
@ -169,7 +169,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
|||
savesegment(ds, p->thread.ds);
|
||||
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
|
||||
|
||||
if (unlikely(!regs)) {
|
||||
if (unlikely(p->flags & PF_KTHREAD)) {
|
||||
/* kernel thread */
|
||||
memset(childregs, 0, sizeof(struct pt_regs));
|
||||
childregs->sp = (unsigned long)childregs;
|
||||
|
@ -181,10 +181,11 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
|||
childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
|
||||
return 0;
|
||||
}
|
||||
*childregs = *regs;
|
||||
*childregs = *current_pt_regs();
|
||||
|
||||
childregs->ax = 0;
|
||||
childregs->sp = sp;
|
||||
if (sp)
|
||||
childregs->sp = sp;
|
||||
|
||||
err = -ENOMEM;
|
||||
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#
|
||||
0 i386 restart_syscall sys_restart_syscall
|
||||
1 i386 exit sys_exit
|
||||
2 i386 fork ptregs_fork stub32_fork
|
||||
2 i386 fork sys_fork stub32_fork
|
||||
3 i386 read sys_read
|
||||
4 i386 write sys_write
|
||||
5 i386 open sys_open compat_sys_open
|
||||
|
@ -126,7 +126,7 @@
|
|||
117 i386 ipc sys_ipc sys32_ipc
|
||||
118 i386 fsync sys_fsync
|
||||
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
|
||||
122 i386 uname sys_newuname
|
||||
123 i386 modify_ldt sys_modify_ldt
|
||||
|
@ -196,7 +196,7 @@
|
|||
187 i386 sendfile sys_sendfile sys32_sendfile
|
||||
188 i386 getpmsg
|
||||
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
|
||||
192 i386 mmap2 sys_mmap_pgoff
|
||||
193 i386 truncate64 sys_truncate64 sys32_truncate64
|
||||
|
|
|
@ -25,6 +25,7 @@ config X86_32
|
|||
select HAVE_AOUT
|
||||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select MODULES_USE_ELF_REL
|
||||
select CLONE_BACKWARDS
|
||||
|
||||
config X86_64
|
||||
def_bool 64BIT
|
||||
|
|
|
@ -24,13 +24,10 @@
|
|||
|
||||
#define old_mmap sys_old_mmap
|
||||
|
||||
#define ptregs_fork sys_fork
|
||||
#define ptregs_iopl sys_iopl
|
||||
#define ptregs_vm86old sys_vm86old
|
||||
#define ptregs_clone i386_clone
|
||||
#define ptregs_vm86 sys_vm86
|
||||
#define ptregs_sigaltstack sys_sigaltstack
|
||||
#define ptregs_vfork sys_vfork
|
||||
|
||||
#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;
|
||||
#include <asm/syscalls_32.h>
|
||||
|
|
|
@ -6,21 +6,6 @@
|
|||
#include <linux/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,
|
||||
struct old_sigaction __user *oact)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче