aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-10-22 22:34:11 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-11-28 22:13:44 -0500
commit1d4b4b2994b5fc208963c0b795291f8c1f18becf (patch)
treebefe27a3e2abc333b5bd81ee7381e4c5541f543f /arch/x86
parent71613c3b871c5a9f27cc48f124251bcd3aa23be1 (diff)
x86, um: switch to generic fork/vfork/clone
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/ia32/ia32entry.S7
-rw-r--r--arch/x86/ia32/sys_ia32.c11
-rw-r--r--arch/x86/include/asm/sys_ia32.h2
-rw-r--r--arch/x86/include/asm/syscalls.h13
-rw-r--r--arch/x86/include/asm/unistd.h3
-rw-r--r--arch/x86/kernel/entry_32.S18
-rw-r--r--arch/x86/kernel/entry_64.S22
-rw-r--r--arch/x86/kernel/process.c30
-rw-r--r--arch/x86/kernel/process_32.c11
-rw-r--r--arch/x86/kernel/process_64.c7
-rw-r--r--arch/x86/syscalls/syscall_32.tbl6
-rw-r--r--arch/x86/um/Kconfig1
-rw-r--r--arch/x86/um/sys_call_table_32.c3
-rw-r--r--arch/x86/um/syscalls_32.c15
15 files changed, 52 insertions, 98 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 46c3bff3ced2..0df6e7d84539 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -112,6 +112,7 @@ config X86
112 select GENERIC_KERNEL_EXECVE 112 select GENERIC_KERNEL_EXECVE
113 select MODULES_USE_ELF_REL if X86_32 113 select MODULES_USE_ELF_REL if X86_32
114 select MODULES_USE_ELF_RELA if X86_64 114 select MODULES_USE_ELF_RELA if X86_64
115 select CLONE_BACKWARDS if X86_32
115 116
116config INSTRUCTION_DECODER 117config INSTRUCTION_DECODER
117 def_bool y 118 def_bool y
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 076745fc8045..32e6f05ddaaa 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -467,11 +467,16 @@ GLOBAL(\label)
467 PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx 467 PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
468 PTREGSCALL stub32_execve, compat_sys_execve, %rcx 468 PTREGSCALL stub32_execve, compat_sys_execve, %rcx
469 PTREGSCALL stub32_fork, sys_fork, %rdi 469 PTREGSCALL stub32_fork, sys_fork, %rdi
470 PTREGSCALL stub32_clone, sys32_clone, %rdx
471 PTREGSCALL stub32_vfork, sys_vfork, %rdi 470 PTREGSCALL stub32_vfork, sys_vfork, %rdi
472 PTREGSCALL stub32_iopl, sys_iopl, %rsi 471 PTREGSCALL stub32_iopl, sys_iopl, %rsi
473 472
474 ALIGN 473 ALIGN
474GLOBAL(stub32_clone)
475 leaq sys_clone(%rip),%rax
476 mov %r8, %rcx
477 jmp ia32_ptregs_common
478
479 ALIGN
475ia32_ptregs_common: 480ia32_ptregs_common:
476 popq %r11 481 popq %r11
477 CFI_ENDPROC 482 CFI_ENDPROC
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index 86d68d1c8806..d0b689ba7be2 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -385,17 +385,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd,
385 return ret; 385 return ret;
386} 386}
387 387
388asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
389 struct pt_regs *regs)
390{
391 void __user *parent_tid = (void __user *)regs->dx;
392 void __user *child_tid = (void __user *)regs->di;
393
394 if (!newsp)
395 newsp = regs->sp;
396 return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
397}
398
399/* 388/*
400 * Some system calls that need sign extended arguments. This could be 389 * Some system calls that need sign extended arguments. This could be
401 * done by a generic wrapper. 390 * done by a generic wrapper.
diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h
index a9a8cf3da49d..c76fae4d90be 100644
--- a/arch/x86/include/asm/sys_ia32.h
+++ b/arch/x86/include/asm/sys_ia32.h
@@ -54,8 +54,6 @@ asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32);
54asmlinkage long sys32_personality(unsigned long); 54asmlinkage long sys32_personality(unsigned long);
55asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32); 55asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32);
56 56
57asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *);
58
59long sys32_lseek(unsigned int, int, unsigned int); 57long sys32_lseek(unsigned int, int, unsigned int);
60long sys32_kill(int, int); 58long sys32_kill(int, int);
61long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int); 59long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int);
diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h
index 9e5aef3a2598..f7252d11416b 100644
--- a/arch/x86/include/asm/syscalls.h
+++ b/arch/x86/include/asm/syscalls.h
@@ -21,10 +21,15 @@ asmlinkage long sys_ioperm(unsigned long, unsigned long, int);
21long sys_iopl(unsigned int, struct pt_regs *); 21long sys_iopl(unsigned int, struct pt_regs *);
22 22
23/* kernel/process.c */ 23/* kernel/process.c */
24int sys_fork(struct pt_regs *); 24asmlinkage long sys_fork(void);
25int sys_vfork(struct pt_regs *); 25asmlinkage long sys_vfork(void);
26long sys_clone(unsigned long, unsigned long, void __user *, 26#ifdef CONFIG_CLONE_BACKWARDS
27 void __user *, struct pt_regs *); 27asmlinkage long sys_clone(unsigned long, unsigned long, void __user *, int,
28 void __user *);
29#else
30asmlinkage long sys_clone(unsigned long, unsigned long, void __user *,
31 void __user *, int);
32#endif
28 33
29/* kernel/ldt.c */ 34/* kernel/ldt.c */
30asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); 35asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h
index 16f3fc6ebf2e..0e7dea7d3669 100644
--- a/arch/x86/include/asm/unistd.h
+++ b/arch/x86/include/asm/unistd.h
@@ -51,6 +51,9 @@
51# define __ARCH_WANT_SYS_UTIME 51# define __ARCH_WANT_SYS_UTIME
52# define __ARCH_WANT_SYS_WAITPID 52# define __ARCH_WANT_SYS_WAITPID
53# define __ARCH_WANT_SYS_EXECVE 53# define __ARCH_WANT_SYS_EXECVE
54# define __ARCH_WANT_SYS_FORK
55# define __ARCH_WANT_SYS_VFORK
56# define __ARCH_WANT_SYS_CLONE
54 57
55/* 58/*
56 * "Conditional" syscalls 59 * "Conditional" syscalls
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 88b725aa1d52..c763116c5359 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -739,30 +739,12 @@ ENTRY(ptregs_##name) ; \
739ENDPROC(ptregs_##name) 739ENDPROC(ptregs_##name)
740 740
741PTREGSCALL1(iopl) 741PTREGSCALL1(iopl)
742PTREGSCALL0(fork)
743PTREGSCALL0(vfork)
744PTREGSCALL2(sigaltstack) 742PTREGSCALL2(sigaltstack)
745PTREGSCALL0(sigreturn) 743PTREGSCALL0(sigreturn)
746PTREGSCALL0(rt_sigreturn) 744PTREGSCALL0(rt_sigreturn)
747PTREGSCALL2(vm86) 745PTREGSCALL2(vm86)
748PTREGSCALL1(vm86old) 746PTREGSCALL1(vm86old)
749 747
750/* Clone is an oddball. The 4th arg is in %edi */
751ENTRY(ptregs_clone)
752 CFI_STARTPROC
753 leal 4(%esp),%eax
754 pushl_cfi %eax
755 pushl_cfi PT_EDI(%eax)
756 movl PT_EDX(%eax),%ecx
757 movl PT_ECX(%eax),%edx
758 movl PT_EBX(%eax),%eax
759 call sys_clone
760 addl $8,%esp
761 CFI_ADJUST_CFA_OFFSET -8
762 ret
763 CFI_ENDPROC
764ENDPROC(ptregs_clone)
765
766.macro FIXUP_ESPFIX_STACK 748.macro FIXUP_ESPFIX_STACK
767/* 749/*
768 * Switch back for ESPFIX stack to the normal zerobased stack 750 * Switch back for ESPFIX stack to the normal zerobased stack
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 1328fe49a3f1..2363e820ed68 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -845,9 +845,25 @@ ENTRY(\label)
845END(\label) 845END(\label)
846 .endm 846 .endm
847 847
848 PTREGSCALL stub_clone, sys_clone, %r8 848 .macro FORK_LIKE func
849 PTREGSCALL stub_fork, sys_fork, %rdi 849ENTRY(stub_\func)
850 PTREGSCALL stub_vfork, sys_vfork, %rdi 850 CFI_STARTPROC
851 popq %r11 /* save return address */
852 PARTIAL_FRAME 0
853 SAVE_REST
854 pushq %r11 /* put it back on stack */
855 FIXUP_TOP_OF_STACK %r11, 8
856 DEFAULT_FRAME 0 8 /* offset 8: return address */
857 call sys_\func
858 RESTORE_TOP_OF_STACK %r11, 8
859 ret $REST_SKIP /* pop extended registers */
860 CFI_ENDPROC
861END(stub_\func)
862 .endm
863
864 FORK_LIKE clone
865 FORK_LIKE fork
866 FORK_LIKE vfork
851 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx 867 PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
852 PTREGSCALL stub_iopl, sys_iopl, %rsi 868 PTREGSCALL stub_iopl, sys_iopl, %rsi
853 869
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index b644e1c765dc..fe9459593257 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -262,36 +262,6 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
262 propagate_user_return_notify(prev_p, next_p); 262 propagate_user_return_notify(prev_p, next_p);
263} 263}
264 264
265int sys_fork(struct pt_regs *regs)
266{
267 return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
268}
269
270/*
271 * This is trivial, and on the face of it looks like it
272 * could equally well be done in user mode.
273 *
274 * Not so, for quite unobvious reasons - register pressure.
275 * In user mode vfork() cannot have a stack frame, and if
276 * done by calling the "clone()" system call directly, you
277 * do not have enough call-clobbered registers to hold all
278 * the information you need.
279 */
280int sys_vfork(struct pt_regs *regs)
281{
282 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0,
283 NULL, NULL);
284}
285
286long
287sys_clone(unsigned long clone_flags, unsigned long newsp,
288 void __user *parent_tid, void __user *child_tid, struct pt_regs *regs)
289{
290 if (!newsp)
291 newsp = regs->sp;
292 return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
293}
294
295/* 265/*
296 * Idle related variables and functions 266 * Idle related variables and functions
297 */ 267 */
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 44e0bff38e72..16efa974532b 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -129,7 +129,7 @@ void release_thread(struct task_struct *dead_task)
129 129
130int copy_thread(unsigned long clone_flags, unsigned long sp, 130int copy_thread(unsigned long clone_flags, unsigned long sp,
131 unsigned long arg, 131 unsigned long arg,
132 struct task_struct *p, struct pt_regs *regs) 132 struct task_struct *p, struct pt_regs *unused)
133{ 133{
134 struct pt_regs *childregs = task_pt_regs(p); 134 struct pt_regs *childregs = task_pt_regs(p);
135 struct task_struct *tsk; 135 struct task_struct *tsk;
@@ -138,7 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
138 p->thread.sp = (unsigned long) childregs; 138 p->thread.sp = (unsigned long) childregs;
139 p->thread.sp0 = (unsigned long) (childregs+1); 139 p->thread.sp0 = (unsigned long) (childregs+1);
140 140
141 if (unlikely(!regs)) { 141 if (unlikely(p->flags & PF_KTHREAD)) {
142 /* kernel thread */ 142 /* kernel thread */
143 memset(childregs, 0, sizeof(struct pt_regs)); 143 memset(childregs, 0, sizeof(struct pt_regs));
144 p->thread.ip = (unsigned long) ret_from_kernel_thread; 144 p->thread.ip = (unsigned long) ret_from_kernel_thread;
@@ -156,12 +156,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
156 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); 156 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
157 return 0; 157 return 0;
158 } 158 }
159 *childregs = *regs; 159 *childregs = *current_pt_regs();
160 childregs->ax = 0; 160 childregs->ax = 0;
161 childregs->sp = sp; 161 if (sp)
162 childregs->sp = sp;
162 163
163 p->thread.ip = (unsigned long) ret_from_fork; 164 p->thread.ip = (unsigned long) ret_from_fork;
164 task_user_gs(p) = get_user_gs(regs); 165 task_user_gs(p) = get_user_gs(current_pt_regs());
165 166
166 p->fpu_counter = 0; 167 p->fpu_counter = 0;
167 p->thread.io_bitmap_ptr = NULL; 168 p->thread.io_bitmap_ptr = NULL;
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 16c6365e2b86..74aac76c6e34 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -169,7 +169,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
169 savesegment(ds, p->thread.ds); 169 savesegment(ds, p->thread.ds);
170 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); 170 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
171 171
172 if (unlikely(!regs)) { 172 if (unlikely(p->flags & PF_KTHREAD)) {
173 /* kernel thread */ 173 /* kernel thread */
174 memset(childregs, 0, sizeof(struct pt_regs)); 174 memset(childregs, 0, sizeof(struct pt_regs));
175 childregs->sp = (unsigned long)childregs; 175 childregs->sp = (unsigned long)childregs;
@@ -181,10 +181,11 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
181 childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; 181 childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
182 return 0; 182 return 0;
183 } 183 }
184 *childregs = *regs; 184 *childregs = *current_pt_regs();
185 185
186 childregs->ax = 0; 186 childregs->ax = 0;
187 childregs->sp = sp; 187 if (sp)
188 childregs->sp = sp;
188 189
189 err = -ENOMEM; 190 err = -ENOMEM;
190 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); 191 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index a47103fbc692..ee3c220ee500 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -8,7 +8,7 @@
8# 8#
90 i386 restart_syscall sys_restart_syscall 90 i386 restart_syscall sys_restart_syscall
101 i386 exit sys_exit 101 i386 exit sys_exit
112 i386 fork ptregs_fork stub32_fork 112 i386 fork sys_fork stub32_fork
123 i386 read sys_read 123 i386 read sys_read
134 i386 write sys_write 134 i386 write sys_write
145 i386 open sys_open compat_sys_open 145 i386 open sys_open compat_sys_open
@@ -126,7 +126,7 @@
126117 i386 ipc sys_ipc sys32_ipc 126117 i386 ipc sys_ipc sys32_ipc
127118 i386 fsync sys_fsync 127118 i386 fsync sys_fsync
128119 i386 sigreturn ptregs_sigreturn stub32_sigreturn 128119 i386 sigreturn ptregs_sigreturn stub32_sigreturn
129120 i386 clone ptregs_clone stub32_clone 129120 i386 clone sys_clone stub32_clone
130121 i386 setdomainname sys_setdomainname 130121 i386 setdomainname sys_setdomainname
131122 i386 uname sys_newuname 131122 i386 uname sys_newuname
132123 i386 modify_ldt sys_modify_ldt 132123 i386 modify_ldt sys_modify_ldt
@@ -196,7 +196,7 @@
196187 i386 sendfile sys_sendfile sys32_sendfile 196187 i386 sendfile sys_sendfile sys32_sendfile
197188 i386 getpmsg 197188 i386 getpmsg
198189 i386 putpmsg 198189 i386 putpmsg
199190 i386 vfork ptregs_vfork stub32_vfork 199190 i386 vfork sys_vfork stub32_vfork
200191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit 200191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit
201192 i386 mmap2 sys_mmap_pgoff 201192 i386 mmap2 sys_mmap_pgoff
202193 i386 truncate64 sys_truncate64 sys32_truncate64 202193 i386 truncate64 sys_truncate64 sys32_truncate64
diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig
index 07611759ce35..8f51c39750d1 100644
--- a/arch/x86/um/Kconfig
+++ b/arch/x86/um/Kconfig
@@ -25,6 +25,7 @@ config X86_32
25 select HAVE_AOUT 25 select HAVE_AOUT
26 select ARCH_WANT_IPC_PARSE_VERSION 26 select ARCH_WANT_IPC_PARSE_VERSION
27 select MODULES_USE_ELF_REL 27 select MODULES_USE_ELF_REL
28 select CLONE_BACKWARDS
28 29
29config X86_64 30config X86_64
30 def_bool 64BIT 31 def_bool 64BIT
diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c
index 232e60504b3a..812e98c098e4 100644
--- a/arch/x86/um/sys_call_table_32.c
+++ b/arch/x86/um/sys_call_table_32.c
@@ -24,13 +24,10 @@
24 24
25#define old_mmap sys_old_mmap 25#define old_mmap sys_old_mmap
26 26
27#define ptregs_fork sys_fork
28#define ptregs_iopl sys_iopl 27#define ptregs_iopl sys_iopl
29#define ptregs_vm86old sys_vm86old 28#define ptregs_vm86old sys_vm86old
30#define ptregs_clone i386_clone
31#define ptregs_vm86 sys_vm86 29#define ptregs_vm86 sys_vm86
32#define ptregs_sigaltstack sys_sigaltstack 30#define ptregs_sigaltstack sys_sigaltstack
33#define ptregs_vfork sys_vfork
34 31
35#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ; 32#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;
36#include <asm/syscalls_32.h> 33#include <asm/syscalls_32.h>
diff --git a/arch/x86/um/syscalls_32.c b/arch/x86/um/syscalls_32.c
index db444c7218fe..e8bcea99acdb 100644
--- a/arch/x86/um/syscalls_32.c
+++ b/arch/x86/um/syscalls_32.c
@@ -6,21 +6,6 @@
6#include <linux/syscalls.h> 6#include <linux/syscalls.h>
7#include <sysdep/syscalls.h> 7#include <sysdep/syscalls.h>
8 8
9/*
10 * The prototype on i386 is:
11 *
12 * int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls
13 *
14 * and the "newtls" arg. on i386 is read by copy_thread directly from the
15 * register saved on the stack.
16 */
17long i386_clone(unsigned long clone_flags, unsigned long newsp,
18 int __user *parent_tid, void *newtls, int __user *child_tid)
19{
20 return sys_clone(clone_flags, newsp, parent_tid, child_tid);
21}
22
23
24long sys_sigaction(int sig, const struct old_sigaction __user *act, 9long sys_sigaction(int sig, const struct old_sigaction __user *act,
25 struct old_sigaction __user *oact) 10 struct old_sigaction __user *oact)
26{ 11{