x86, um: switch to generic fork/vfork/clone
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 23 Oct 2012 02:34:11 +0000 (22:34 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 29 Nov 2012 03:13:44 +0000 (22:13 -0500)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
16 files changed:
arch/um/kernel/syscall.c
arch/x86/Kconfig
arch/x86/ia32/ia32entry.S
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/sys_ia32.h
arch/x86/include/asm/syscalls.h
arch/x86/include/asm/unistd.h
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/syscalls/syscall_32.tbl
arch/x86/um/Kconfig
arch/x86/um/sys_call_table_32.c
arch/x86/um/syscalls_32.c

index 3a875226c8efd4610f2a07b0d4dd801882255f8f..c1d0ae069b5343f9876b723743e695aea0c26bd8 100644 (file)
 #include <asm/uaccess.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,
              unsigned long prot, unsigned long flags,
              unsigned long fd, unsigned long offset)
index 46c3bff3ced20e31c379bdde1c9a50c95206ff8e..0df6e7d845398549317502cecc2a411084edb6aa 100644 (file)
@@ -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
index 076745fc8045a8c35d1df646ede41d3c191c52e6..32e6f05ddaaab84f71d2501c07185776055cf855 100644 (file)
@@ -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
index 86d68d1c8806b27fdf5506d0807d6fe874b48438..d0b689ba7be2255cd62d365292a0172354982b32 100644 (file)
@@ -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.
index a9a8cf3da49d72ae78eb3e98af8ad3e0523ce6e3..c76fae4d90be0802e6bf659d8e998e4010791c75 100644 (file)
@@ -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);
index 9e5aef3a25981a7f564b64d4b8107c104235744b..f7252d11416b28f2ed851a5ccabd49be863a22a5 100644 (file)
@@ -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);
index 16f3fc6ebf2e858d495507f5609916baaa673104..0e7dea7d366982d18ab89cfe17a6a6b99edc255f 100644 (file)
@@ -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
index 88b725aa1d52463d7534882a187da4c392bf3947..c763116c5359c650be0a2847ebd110bd52b3b9e2 100644 (file)
@@ -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
index 1328fe49a3f14d7a33615e892efca8d110aeb6e6..2363e820ed68c49ba64361c63e1ba1dd7a01097b 100644 (file)
@@ -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
 
index b644e1c765dc211dbb07b6ee7570081e5cd0e6c6..fe94595932572af84317ef2cb3f0762915a55938 100644 (file)
@@ -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
  */
index 44e0bff38e724de5b9e02e5bd9581133999ad40e..16efa974532b50ddcd7787bd06d3a4f3f3a21b5a 100644 (file)
@@ -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;
index 16c6365e2b867c883805061f533349751f9bfbf0..74aac76c6e3486110fcbef330ca8e2d98bf99aa2 100644 (file)
@@ -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));
index a47103fbc6925ac7c717ef1ed2d1f9eccaa35fa4..ee3c220ee5009fec90afff372c3cff543d90c658 100644 (file)
@@ -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
 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
 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
index 07611759ce35b4cdcd298b402c22d39ada73e39a..8f51c39750d19c42700397506df03869d8f8dd43 100644 (file)
@@ -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
index 232e60504b3a8c6c62db26a29b35b07c295d6ac9..812e98c098e40eeb771212dc40f9d6955d2e7de8 100644 (file)
 
 #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>
index db444c7218fe53bcabf105b5e2303b7d21a5fd15..e8bcea99acdbc66cc39cffebca6aa132b4009248 100644 (file)
@@ -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)
 {