diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 23:02:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 23:02:25 -0400 |
commit | 42859eea96ba6beabfb0369a1eeffa3c7d2bd9cb (patch) | |
tree | fa38aeda0d6e7a4c48a882b166b8643594a1ad50 /arch/x86 | |
parent | f59b51fe3d3092c08d7d554ecb40db24011b2ebc (diff) | |
parent | f322220d6159455da2b5a8a596d802c8695fed30 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull generic execve() changes from Al Viro:
"This introduces the generic kernel_thread() and kernel_execve()
functions, and switches x86, arm, alpha, um and s390 over to them."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (26 commits)
s390: convert to generic kernel_execve()
s390: switch to generic kernel_thread()
s390: fold kernel_thread_helper() into ret_from_fork()
s390: fold execve_tail() into start_thread(), convert to generic sys_execve()
um: switch to generic kernel_thread()
x86, um/x86: switch to generic sys_execve and kernel_execve
x86: split ret_from_fork
alpha: introduce ret_from_kernel_execve(), switch to generic kernel_execve()
alpha: switch to generic kernel_thread()
alpha: switch to generic sys_execve()
arm: get rid of execve wrapper, switch to generic execve() implementation
arm: optimized current_pt_regs()
arm: introduce ret_from_kernel_execve(), switch to generic kernel_execve()
arm: split ret_from_fork, simplify kernel_thread() [based on patch by rmk]
generic sys_execve()
generic kernel_execve()
new helper: current_pt_regs()
preparation for generic kernel_thread()
um: kill thread->forking
um: let signal_delivered() do SIGTRAP on singlestepping into handler
...
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/ia32/ia32entry.S | 2 | ||||
-rw-r--r-- | arch/x86/ia32/sys_ia32.c | 15 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/sys_ia32.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/syscalls.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/thread_info.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/unistd.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/kernel/asm-offsets.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/entry_32.S | 26 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 74 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 65 | ||||
-rw-r--r-- | arch/x86/kernel/process_32.c | 37 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 35 | ||||
-rw-r--r-- | arch/x86/kernel/signal.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/sys_i386_32.c | 40 | ||||
-rw-r--r-- | arch/x86/kernel/vm86_32.c | 6 | ||||
-rw-r--r-- | arch/x86/syscalls/syscall_32.tbl | 2 | ||||
-rw-r--r-- | arch/x86/um/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/um/sys_call_table_32.c | 1 |
21 files changed, 108 insertions, 219 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 1ae94bcae5d..42d2c35a5bb 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -108,6 +108,7 @@ config X86 | |||
108 | select GENERIC_STRNLEN_USER | 108 | select GENERIC_STRNLEN_USER |
109 | select HAVE_RCU_USER_QS if X86_64 | 109 | select HAVE_RCU_USER_QS if X86_64 |
110 | select HAVE_IRQ_TIME_ACCOUNTING | 110 | select HAVE_IRQ_TIME_ACCOUNTING |
111 | select GENERIC_KERNEL_THREAD | ||
111 | 112 | ||
112 | config INSTRUCTION_DECODER | 113 | config INSTRUCTION_DECODER |
113 | def_bool y | 114 | def_bool y |
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 9c289504e68..076745fc804 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S | |||
@@ -465,7 +465,7 @@ GLOBAL(\label) | |||
465 | PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi | 465 | PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi |
466 | PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi | 466 | PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi |
467 | PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx | 467 | PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx |
468 | PTREGSCALL stub32_execve, sys32_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 | 470 | PTREGSCALL stub32_clone, sys32_clone, %rdx |
471 | PTREGSCALL stub32_vfork, sys_vfork, %rdi | 471 | PTREGSCALL stub32_vfork, sys_vfork, %rdi |
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c index c5b938d92ea..86d68d1c880 100644 --- a/arch/x86/ia32/sys_ia32.c +++ b/arch/x86/ia32/sys_ia32.c | |||
@@ -385,21 +385,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, | |||
385 | return ret; | 385 | return ret; |
386 | } | 386 | } |
387 | 387 | ||
388 | asmlinkage long sys32_execve(const char __user *name, compat_uptr_t __user *argv, | ||
389 | compat_uptr_t __user *envp, struct pt_regs *regs) | ||
390 | { | ||
391 | long error; | ||
392 | char *filename; | ||
393 | |||
394 | filename = getname(name); | ||
395 | error = PTR_ERR(filename); | ||
396 | if (IS_ERR(filename)) | ||
397 | return error; | ||
398 | error = compat_do_execve(filename, argv, envp, regs); | ||
399 | putname(filename); | ||
400 | return error; | ||
401 | } | ||
402 | |||
403 | asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, | 388 | asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, |
404 | struct pt_regs *regs) | 389 | struct pt_regs *regs) |
405 | { | 390 | { |
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index b98c0d958eb..ad1fc851167 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -588,11 +588,6 @@ typedef struct { | |||
588 | } mm_segment_t; | 588 | } mm_segment_t; |
589 | 589 | ||
590 | 590 | ||
591 | /* | ||
592 | * create a kernel thread without removing it from tasklists | ||
593 | */ | ||
594 | extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
595 | |||
596 | /* Free all resources held by a thread. */ | 591 | /* Free all resources held by a thread. */ |
597 | extern void release_thread(struct task_struct *); | 592 | extern void release_thread(struct task_struct *); |
598 | 593 | ||
diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h index 4ca1c611b55..a9a8cf3da49 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); | |||
54 | asmlinkage long sys32_personality(unsigned long); | 54 | asmlinkage long sys32_personality(unsigned long); |
55 | asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32); | 55 | asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32); |
56 | 56 | ||
57 | asmlinkage long sys32_execve(const char __user *, compat_uptr_t __user *, | ||
58 | compat_uptr_t __user *, struct pt_regs *); | ||
59 | asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *); | 57 | asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *); |
60 | 58 | ||
61 | long sys32_lseek(unsigned int, int, unsigned int); | 59 | long sys32_lseek(unsigned int, int, unsigned int); |
diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index f1d8b441fc7..2be0b880417 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h | |||
@@ -25,7 +25,7 @@ int sys_fork(struct pt_regs *); | |||
25 | int sys_vfork(struct pt_regs *); | 25 | int sys_vfork(struct pt_regs *); |
26 | long sys_execve(const char __user *, | 26 | long sys_execve(const char __user *, |
27 | const char __user *const __user *, | 27 | const char __user *const __user *, |
28 | const char __user *const __user *, struct pt_regs *); | 28 | const char __user *const __user *); |
29 | long sys_clone(unsigned long, unsigned long, void __user *, | 29 | long sys_clone(unsigned long, unsigned long, void __user *, |
30 | void __user *, struct pt_regs *); | 30 | void __user *, struct pt_regs *); |
31 | 31 | ||
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index c535d847e3b..2d946e63ee8 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h | |||
@@ -79,7 +79,6 @@ struct thread_info { | |||
79 | #define TIF_SIGPENDING 2 /* signal pending */ | 79 | #define TIF_SIGPENDING 2 /* signal pending */ |
80 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ | 80 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ |
81 | #define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ | 81 | #define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ |
82 | #define TIF_IRET 5 /* force IRET */ | ||
83 | #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ | 82 | #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ |
84 | #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ | 83 | #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ |
85 | #define TIF_SECCOMP 8 /* secure computing */ | 84 | #define TIF_SECCOMP 8 /* secure computing */ |
@@ -105,7 +104,6 @@ struct thread_info { | |||
105 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | 104 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) |
106 | #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) | 105 | #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) |
107 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | 106 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
108 | #define _TIF_IRET (1 << TIF_IRET) | ||
109 | #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU) | 107 | #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU) |
110 | #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) | 108 | #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) |
111 | #define _TIF_SECCOMP (1 << TIF_SECCOMP) | 109 | #define _TIF_SECCOMP (1 << TIF_SECCOMP) |
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 0d9776e9e2d..55d155560fd 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h | |||
@@ -50,6 +50,8 @@ | |||
50 | # define __ARCH_WANT_SYS_TIME | 50 | # define __ARCH_WANT_SYS_TIME |
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 | ||
54 | # define __ARCH_WANT_KERNEL_EXECVE | ||
53 | 55 | ||
54 | /* | 56 | /* |
55 | * "Conditional" syscalls | 57 | * "Conditional" syscalls |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index a48ea05157d..91ce48f05f9 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -23,7 +23,7 @@ obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o | |||
23 | obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o | 23 | obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o |
24 | obj-$(CONFIG_IRQ_WORK) += irq_work.o | 24 | obj-$(CONFIG_IRQ_WORK) += irq_work.o |
25 | obj-y += probe_roms.o | 25 | obj-y += probe_roms.o |
26 | obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o | 26 | obj-$(CONFIG_X86_32) += i386_ksyms_32.o |
27 | obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o | 27 | obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o |
28 | obj-y += syscall_$(BITS).o | 28 | obj-y += syscall_$(BITS).o |
29 | obj-$(CONFIG_X86_64) += vsyscall_64.o | 29 | obj-$(CONFIG_X86_64) += vsyscall_64.o |
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 68de2dc962e..28610822fb3 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c | |||
@@ -69,4 +69,7 @@ void common(void) { | |||
69 | OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); | 69 | OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); |
70 | OFFSET(BP_pref_address, boot_params, hdr.pref_address); | 70 | OFFSET(BP_pref_address, boot_params, hdr.pref_address); |
71 | OFFSET(BP_code32_start, boot_params, hdr.code32_start); | 71 | OFFSET(BP_code32_start, boot_params, hdr.code32_start); |
72 | |||
73 | BLANK(); | ||
74 | DEFINE(PTREGS_SIZE, sizeof(struct pt_regs)); | ||
72 | } | 75 | } |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 0750e3ba87c..8f9ed1afde8 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -299,6 +299,13 @@ ENTRY(ret_from_fork) | |||
299 | CFI_ENDPROC | 299 | CFI_ENDPROC |
300 | END(ret_from_fork) | 300 | END(ret_from_fork) |
301 | 301 | ||
302 | ENTRY(ret_from_kernel_execve) | ||
303 | movl %eax, %esp | ||
304 | movl $0,PT_EAX(%esp) | ||
305 | GET_THREAD_INFO(%ebp) | ||
306 | jmp syscall_exit | ||
307 | END(ret_from_kernel_execve) | ||
308 | |||
302 | /* | 309 | /* |
303 | * Interrupt exit functions should be protected against kprobes | 310 | * Interrupt exit functions should be protected against kprobes |
304 | */ | 311 | */ |
@@ -323,8 +330,7 @@ ret_from_intr: | |||
323 | andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax | 330 | andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax |
324 | #else | 331 | #else |
325 | /* | 332 | /* |
326 | * We can be coming here from a syscall done in the kernel space, | 333 | * We can be coming here from child spawned by kernel_thread(). |
327 | * e.g. a failed kernel_execve(). | ||
328 | */ | 334 | */ |
329 | movl PT_CS(%esp), %eax | 335 | movl PT_CS(%esp), %eax |
330 | andl $SEGMENT_RPL_MASK, %eax | 336 | andl $SEGMENT_RPL_MASK, %eax |
@@ -732,7 +738,6 @@ ENDPROC(ptregs_##name) | |||
732 | PTREGSCALL1(iopl) | 738 | PTREGSCALL1(iopl) |
733 | PTREGSCALL0(fork) | 739 | PTREGSCALL0(fork) |
734 | PTREGSCALL0(vfork) | 740 | PTREGSCALL0(vfork) |
735 | PTREGSCALL3(execve) | ||
736 | PTREGSCALL2(sigaltstack) | 741 | PTREGSCALL2(sigaltstack) |
737 | PTREGSCALL0(sigreturn) | 742 | PTREGSCALL0(sigreturn) |
738 | PTREGSCALL0(rt_sigreturn) | 743 | PTREGSCALL0(rt_sigreturn) |
@@ -1015,15 +1020,20 @@ END(spurious_interrupt_bug) | |||
1015 | */ | 1020 | */ |
1016 | .popsection | 1021 | .popsection |
1017 | 1022 | ||
1018 | ENTRY(kernel_thread_helper) | 1023 | ENTRY(ret_from_kernel_thread) |
1019 | pushl $0 # fake return address for unwinder | ||
1020 | CFI_STARTPROC | 1024 | CFI_STARTPROC |
1021 | movl %edi,%eax | 1025 | pushl_cfi %eax |
1022 | call *%esi | 1026 | call schedule_tail |
1027 | GET_THREAD_INFO(%ebp) | ||
1028 | popl_cfi %eax | ||
1029 | pushl_cfi $0x0202 # Reset kernel eflags | ||
1030 | popfl_cfi | ||
1031 | movl PT_EBP(%esp),%eax | ||
1032 | call *PT_EBX(%esp) | ||
1023 | call do_exit | 1033 | call do_exit |
1024 | ud2 # padding for call trace | 1034 | ud2 # padding for call trace |
1025 | CFI_ENDPROC | 1035 | CFI_ENDPROC |
1026 | ENDPROC(kernel_thread_helper) | 1036 | ENDPROC(ret_from_kernel_thread) |
1027 | 1037 | ||
1028 | #ifdef CONFIG_XEN | 1038 | #ifdef CONFIG_XEN |
1029 | /* Xen doesn't set %esp to be precisely what the normal sysenter | 1039 | /* Xen doesn't set %esp to be precisely what the normal sysenter |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 44531acd9a8..cdc790c78f3 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -554,7 +554,7 @@ ENTRY(ret_from_fork) | |||
554 | RESTORE_REST | 554 | RESTORE_REST |
555 | 555 | ||
556 | testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread? | 556 | testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread? |
557 | jz retint_restore_args | 557 | jz 1f |
558 | 558 | ||
559 | testl $_TIF_IA32, TI_flags(%rcx) # 32-bit compat task needs IRET | 559 | testl $_TIF_IA32, TI_flags(%rcx) # 32-bit compat task needs IRET |
560 | jnz int_ret_from_sys_call | 560 | jnz int_ret_from_sys_call |
@@ -562,6 +562,16 @@ ENTRY(ret_from_fork) | |||
562 | RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET | 562 | RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET |
563 | jmp ret_from_sys_call # go to the SYSRET fastpath | 563 | jmp ret_from_sys_call # go to the SYSRET fastpath |
564 | 564 | ||
565 | 1: | ||
566 | subq $REST_SKIP, %rsp # move the stack pointer back | ||
567 | CFI_ADJUST_CFA_OFFSET REST_SKIP | ||
568 | movq %rbp, %rdi | ||
569 | call *%rbx | ||
570 | # exit | ||
571 | mov %eax, %edi | ||
572 | call do_exit | ||
573 | ud2 # padding for call trace | ||
574 | |||
565 | CFI_ENDPROC | 575 | CFI_ENDPROC |
566 | END(ret_from_fork) | 576 | END(ret_from_fork) |
567 | 577 | ||
@@ -862,7 +872,6 @@ ENTRY(stub_execve) | |||
862 | PARTIAL_FRAME 0 | 872 | PARTIAL_FRAME 0 |
863 | SAVE_REST | 873 | SAVE_REST |
864 | FIXUP_TOP_OF_STACK %r11 | 874 | FIXUP_TOP_OF_STACK %r11 |
865 | movq %rsp, %rcx | ||
866 | call sys_execve | 875 | call sys_execve |
867 | RESTORE_TOP_OF_STACK %r11 | 876 | RESTORE_TOP_OF_STACK %r11 |
868 | movq %rax,RAX(%rsp) | 877 | movq %rax,RAX(%rsp) |
@@ -912,8 +921,7 @@ ENTRY(stub_x32_execve) | |||
912 | PARTIAL_FRAME 0 | 921 | PARTIAL_FRAME 0 |
913 | SAVE_REST | 922 | SAVE_REST |
914 | FIXUP_TOP_OF_STACK %r11 | 923 | FIXUP_TOP_OF_STACK %r11 |
915 | movq %rsp, %rcx | 924 | call compat_sys_execve |
916 | call sys32_execve | ||
917 | RESTORE_TOP_OF_STACK %r11 | 925 | RESTORE_TOP_OF_STACK %r11 |
918 | movq %rax,RAX(%rsp) | 926 | movq %rax,RAX(%rsp) |
919 | RESTORE_REST | 927 | RESTORE_REST |
@@ -1318,51 +1326,19 @@ bad_gs: | |||
1318 | jmp 2b | 1326 | jmp 2b |
1319 | .previous | 1327 | .previous |
1320 | 1328 | ||
1321 | ENTRY(kernel_thread_helper) | 1329 | ENTRY(ret_from_kernel_execve) |
1322 | pushq $0 # fake return address | 1330 | movq %rdi, %rsp |
1323 | CFI_STARTPROC | 1331 | movl $0, RAX(%rsp) |
1324 | /* | 1332 | // RESTORE_REST |
1325 | * Here we are in the child and the registers are set as they were | 1333 | movq 0*8(%rsp), %r15 |
1326 | * at kernel_thread() invocation in the parent. | 1334 | movq 1*8(%rsp), %r14 |
1327 | */ | 1335 | movq 2*8(%rsp), %r13 |
1328 | call *%rsi | 1336 | movq 3*8(%rsp), %r12 |
1329 | # exit | 1337 | movq 4*8(%rsp), %rbp |
1330 | mov %eax, %edi | 1338 | movq 5*8(%rsp), %rbx |
1331 | call do_exit | 1339 | addq $(6*8), %rsp |
1332 | ud2 # padding for call trace | 1340 | jmp int_ret_from_sys_call |
1333 | CFI_ENDPROC | 1341 | END(ret_from_kernel_execve) |
1334 | END(kernel_thread_helper) | ||
1335 | |||
1336 | /* | ||
1337 | * execve(). This function needs to use IRET, not SYSRET, to set up all state properly. | ||
1338 | * | ||
1339 | * C extern interface: | ||
1340 | * extern long execve(const char *name, char **argv, char **envp) | ||
1341 | * | ||
1342 | * asm input arguments: | ||
1343 | * rdi: name, rsi: argv, rdx: envp | ||
1344 | * | ||
1345 | * We want to fallback into: | ||
1346 | * extern long sys_execve(const char *name, char **argv,char **envp, struct pt_regs *regs) | ||
1347 | * | ||
1348 | * do_sys_execve asm fallback arguments: | ||
1349 | * rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack | ||
1350 | */ | ||
1351 | ENTRY(kernel_execve) | ||
1352 | CFI_STARTPROC | ||
1353 | FAKE_STACK_FRAME $0 | ||
1354 | SAVE_ALL | ||
1355 | movq %rsp,%rcx | ||
1356 | call sys_execve | ||
1357 | movq %rax, RAX(%rsp) | ||
1358 | RESTORE_REST | ||
1359 | testq %rax,%rax | ||
1360 | je int_ret_from_sys_call | ||
1361 | RESTORE_ARGS | ||
1362 | UNFAKE_STACK_FRAME | ||
1363 | ret | ||
1364 | CFI_ENDPROC | ||
1365 | END(kernel_execve) | ||
1366 | 1342 | ||
1367 | /* Call softirq on interrupt stack. Interrupts are off. */ | 1343 | /* Call softirq on interrupt stack. Interrupts are off. */ |
1368 | ENTRY(call_softirq) | 1344 | ENTRY(call_softirq) |
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index dc3567e083f..b644e1c765d 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -293,71 +293,6 @@ sys_clone(unsigned long clone_flags, unsigned long newsp, | |||
293 | } | 293 | } |
294 | 294 | ||
295 | /* | 295 | /* |
296 | * This gets run with %si containing the | ||
297 | * function to call, and %di containing | ||
298 | * the "args". | ||
299 | */ | ||
300 | extern void kernel_thread_helper(void); | ||
301 | |||
302 | /* | ||
303 | * Create a kernel thread | ||
304 | */ | ||
305 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
306 | { | ||
307 | struct pt_regs regs; | ||
308 | |||
309 | memset(®s, 0, sizeof(regs)); | ||
310 | |||
311 | regs.si = (unsigned long) fn; | ||
312 | regs.di = (unsigned long) arg; | ||
313 | |||
314 | #ifdef CONFIG_X86_32 | ||
315 | regs.ds = __USER_DS; | ||
316 | regs.es = __USER_DS; | ||
317 | regs.fs = __KERNEL_PERCPU; | ||
318 | regs.gs = __KERNEL_STACK_CANARY; | ||
319 | #else | ||
320 | regs.ss = __KERNEL_DS; | ||
321 | #endif | ||
322 | |||
323 | regs.orig_ax = -1; | ||
324 | regs.ip = (unsigned long) kernel_thread_helper; | ||
325 | regs.cs = __KERNEL_CS | get_kernel_rpl(); | ||
326 | regs.flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; | ||
327 | |||
328 | /* Ok, create the new process.. */ | ||
329 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
330 | } | ||
331 | EXPORT_SYMBOL(kernel_thread); | ||
332 | |||
333 | /* | ||
334 | * sys_execve() executes a new program. | ||
335 | */ | ||
336 | long sys_execve(const char __user *name, | ||
337 | const char __user *const __user *argv, | ||
338 | const char __user *const __user *envp, struct pt_regs *regs) | ||
339 | { | ||
340 | long error; | ||
341 | char *filename; | ||
342 | |||
343 | filename = getname(name); | ||
344 | error = PTR_ERR(filename); | ||
345 | if (IS_ERR(filename)) | ||
346 | return error; | ||
347 | error = do_execve(filename, argv, envp, regs); | ||
348 | |||
349 | #ifdef CONFIG_X86_32 | ||
350 | if (error == 0) { | ||
351 | /* Make sure we don't return using sysenter.. */ | ||
352 | set_thread_flag(TIF_IRET); | ||
353 | } | ||
354 | #endif | ||
355 | |||
356 | putname(filename); | ||
357 | return error; | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * Idle related variables and functions | 296 | * Idle related variables and functions |
362 | */ | 297 | */ |
363 | unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE; | 298 | unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE; |
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index b9ff83c7135..44e0bff38e7 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #include <asm/switch_to.h> | 57 | #include <asm/switch_to.h> |
58 | 58 | ||
59 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 59 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
60 | asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); | ||
60 | 61 | ||
61 | /* | 62 | /* |
62 | * Return saved PC of a blocked thread. | 63 | * Return saved PC of a blocked thread. |
@@ -127,23 +128,39 @@ void release_thread(struct task_struct *dead_task) | |||
127 | } | 128 | } |
128 | 129 | ||
129 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 130 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
130 | unsigned long unused, | 131 | unsigned long arg, |
131 | struct task_struct *p, struct pt_regs *regs) | 132 | struct task_struct *p, struct pt_regs *regs) |
132 | { | 133 | { |
133 | struct pt_regs *childregs; | 134 | struct pt_regs *childregs = task_pt_regs(p); |
134 | struct task_struct *tsk; | 135 | struct task_struct *tsk; |
135 | int err; | 136 | int err; |
136 | 137 | ||
137 | childregs = task_pt_regs(p); | 138 | p->thread.sp = (unsigned long) childregs; |
139 | p->thread.sp0 = (unsigned long) (childregs+1); | ||
140 | |||
141 | if (unlikely(!regs)) { | ||
142 | /* kernel thread */ | ||
143 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
144 | p->thread.ip = (unsigned long) ret_from_kernel_thread; | ||
145 | task_user_gs(p) = __KERNEL_STACK_CANARY; | ||
146 | childregs->ds = __USER_DS; | ||
147 | childregs->es = __USER_DS; | ||
148 | childregs->fs = __KERNEL_PERCPU; | ||
149 | childregs->bx = sp; /* function */ | ||
150 | childregs->bp = arg; | ||
151 | childregs->orig_ax = -1; | ||
152 | childregs->cs = __KERNEL_CS | get_kernel_rpl(); | ||
153 | childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; | ||
154 | p->fpu_counter = 0; | ||
155 | p->thread.io_bitmap_ptr = NULL; | ||
156 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); | ||
157 | return 0; | ||
158 | } | ||
138 | *childregs = *regs; | 159 | *childregs = *regs; |
139 | childregs->ax = 0; | 160 | childregs->ax = 0; |
140 | childregs->sp = sp; | 161 | childregs->sp = sp; |
141 | 162 | ||
142 | p->thread.sp = (unsigned long) childregs; | ||
143 | p->thread.sp0 = (unsigned long) (childregs+1); | ||
144 | |||
145 | p->thread.ip = (unsigned long) ret_from_fork; | 163 | p->thread.ip = (unsigned long) ret_from_fork; |
146 | |||
147 | task_user_gs(p) = get_user_gs(regs); | 164 | task_user_gs(p) = get_user_gs(regs); |
148 | 165 | ||
149 | p->fpu_counter = 0; | 166 | p->fpu_counter = 0; |
@@ -190,6 +207,12 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) | |||
190 | regs->cs = __USER_CS; | 207 | regs->cs = __USER_CS; |
191 | regs->ip = new_ip; | 208 | regs->ip = new_ip; |
192 | regs->sp = new_sp; | 209 | regs->sp = new_sp; |
210 | regs->flags = X86_EFLAGS_IF; | ||
211 | /* | ||
212 | * force it to the iret return path by making it look as if there was | ||
213 | * some work pending. | ||
214 | */ | ||
215 | set_thread_flag(TIF_NOTIFY_RESUME); | ||
193 | } | 216 | } |
194 | EXPORT_SYMBOL_GPL(start_thread); | 217 | EXPORT_SYMBOL_GPL(start_thread); |
195 | 218 | ||
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 8a6d20ce197..16c6365e2b8 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -146,29 +146,18 @@ static inline u32 read_32bit_tls(struct task_struct *t, int tls) | |||
146 | } | 146 | } |
147 | 147 | ||
148 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 148 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
149 | unsigned long unused, | 149 | unsigned long arg, |
150 | struct task_struct *p, struct pt_regs *regs) | 150 | struct task_struct *p, struct pt_regs *regs) |
151 | { | 151 | { |
152 | int err; | 152 | int err; |
153 | struct pt_regs *childregs; | 153 | struct pt_regs *childregs; |
154 | struct task_struct *me = current; | 154 | struct task_struct *me = current; |
155 | 155 | ||
156 | childregs = ((struct pt_regs *) | 156 | p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE; |
157 | (THREAD_SIZE + task_stack_page(p))) - 1; | 157 | childregs = task_pt_regs(p); |
158 | *childregs = *regs; | ||
159 | |||
160 | childregs->ax = 0; | ||
161 | if (user_mode(regs)) | ||
162 | childregs->sp = sp; | ||
163 | else | ||
164 | childregs->sp = (unsigned long)childregs; | ||
165 | |||
166 | p->thread.sp = (unsigned long) childregs; | 158 | p->thread.sp = (unsigned long) childregs; |
167 | p->thread.sp0 = (unsigned long) (childregs+1); | ||
168 | p->thread.usersp = me->thread.usersp; | 159 | p->thread.usersp = me->thread.usersp; |
169 | |||
170 | set_tsk_thread_flag(p, TIF_FORK); | 160 | set_tsk_thread_flag(p, TIF_FORK); |
171 | |||
172 | p->fpu_counter = 0; | 161 | p->fpu_counter = 0; |
173 | p->thread.io_bitmap_ptr = NULL; | 162 | p->thread.io_bitmap_ptr = NULL; |
174 | 163 | ||
@@ -178,6 +167,24 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
178 | p->thread.fs = p->thread.fsindex ? 0 : me->thread.fs; | 167 | p->thread.fs = p->thread.fsindex ? 0 : me->thread.fs; |
179 | savesegment(es, p->thread.es); | 168 | savesegment(es, p->thread.es); |
180 | savesegment(ds, p->thread.ds); | 169 | savesegment(ds, p->thread.ds); |
170 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); | ||
171 | |||
172 | if (unlikely(!regs)) { | ||
173 | /* kernel thread */ | ||
174 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
175 | childregs->sp = (unsigned long)childregs; | ||
176 | childregs->ss = __KERNEL_DS; | ||
177 | childregs->bx = sp; /* function */ | ||
178 | childregs->bp = arg; | ||
179 | childregs->orig_ax = -1; | ||
180 | childregs->cs = __KERNEL_CS | get_kernel_rpl(); | ||
181 | childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1; | ||
182 | return 0; | ||
183 | } | ||
184 | *childregs = *regs; | ||
185 | |||
186 | childregs->ax = 0; | ||
187 | childregs->sp = sp; | ||
181 | 188 | ||
182 | err = -ENOMEM; | 189 | err = -ENOMEM; |
183 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); | 190 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); |
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index b33144c8b30..29ad351804e 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -840,10 +840,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | |||
840 | if (thread_info_flags & _TIF_USER_RETURN_NOTIFY) | 840 | if (thread_info_flags & _TIF_USER_RETURN_NOTIFY) |
841 | fire_user_return_notifiers(); | 841 | fire_user_return_notifiers(); |
842 | 842 | ||
843 | #ifdef CONFIG_X86_32 | ||
844 | clear_thread_flag(TIF_IRET); | ||
845 | #endif /* CONFIG_X86_32 */ | ||
846 | |||
847 | rcu_user_enter(); | 843 | rcu_user_enter(); |
848 | } | 844 | } |
849 | 845 | ||
diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c deleted file mode 100644 index 0b0cb5fede1..00000000000 --- a/arch/x86/kernel/sys_i386_32.c +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | /* | ||
2 | * This file contains various random system calls that | ||
3 | * have a non-standard calling sequence on the Linux/i386 | ||
4 | * platform. | ||
5 | */ | ||
6 | |||
7 | #include <linux/errno.h> | ||
8 | #include <linux/sched.h> | ||
9 | #include <linux/mm.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/smp.h> | ||
12 | #include <linux/sem.h> | ||
13 | #include <linux/msg.h> | ||
14 | #include <linux/shm.h> | ||
15 | #include <linux/stat.h> | ||
16 | #include <linux/syscalls.h> | ||
17 | #include <linux/mman.h> | ||
18 | #include <linux/file.h> | ||
19 | #include <linux/utsname.h> | ||
20 | #include <linux/ipc.h> | ||
21 | |||
22 | #include <linux/uaccess.h> | ||
23 | #include <linux/unistd.h> | ||
24 | |||
25 | #include <asm/syscalls.h> | ||
26 | |||
27 | /* | ||
28 | * Do a system call from kernel instead of calling sys_execve so we | ||
29 | * end up with proper pt_regs. | ||
30 | */ | ||
31 | int kernel_execve(const char *filename, | ||
32 | const char *const argv[], | ||
33 | const char *const envp[]) | ||
34 | { | ||
35 | long __res; | ||
36 | asm volatile ("int $0x80" | ||
37 | : "=a" (__res) | ||
38 | : "0" (__NR_execve), "b" (filename), "c" (argv), "d" (envp) : "memory"); | ||
39 | return __res; | ||
40 | } | ||
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 54abcc0baf2..5c9687b1bde 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c | |||
@@ -561,9 +561,9 @@ int handle_vm86_trap(struct kernel_vm86_regs *regs, long error_code, int trapno) | |||
561 | if ((trapno == 3) || (trapno == 1)) { | 561 | if ((trapno == 3) || (trapno == 1)) { |
562 | KVM86->regs32->ax = VM86_TRAP + (trapno << 8); | 562 | KVM86->regs32->ax = VM86_TRAP + (trapno << 8); |
563 | /* setting this flag forces the code in entry_32.S to | 563 | /* setting this flag forces the code in entry_32.S to |
564 | call save_v86_state() and change the stack pointer | 564 | the path where we call save_v86_state() and change |
565 | to KVM86->regs32 */ | 565 | the stack pointer to KVM86->regs32 */ |
566 | set_thread_flag(TIF_IRET); | 566 | set_thread_flag(TIF_NOTIFY_RESUME); |
567 | return 0; | 567 | return 0; |
568 | } | 568 | } |
569 | do_int(regs, trapno, (unsigned char __user *) (regs->pt.ss << 4), SP(regs)); | 569 | do_int(regs, trapno, (unsigned char __user *) (regs->pt.ss << 4), SP(regs)); |
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl index 7a35a6e71d4..a47103fbc69 100644 --- a/arch/x86/syscalls/syscall_32.tbl +++ b/arch/x86/syscalls/syscall_32.tbl | |||
@@ -17,7 +17,7 @@ | |||
17 | 8 i386 creat sys_creat | 17 | 8 i386 creat sys_creat |
18 | 9 i386 link sys_link | 18 | 9 i386 link sys_link |
19 | 10 i386 unlink sys_unlink | 19 | 10 i386 unlink sys_unlink |
20 | 11 i386 execve ptregs_execve stub32_execve | 20 | 11 i386 execve sys_execve stub32_execve |
21 | 12 i386 chdir sys_chdir | 21 | 12 i386 chdir sys_chdir |
22 | 13 i386 time sys_time compat_sys_time | 22 | 13 i386 time sys_time compat_sys_time |
23 | 14 i386 mknod sys_mknod | 23 | 14 i386 mknod sys_mknod |
diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig index aeaff8bef2f..30c4eec033a 100644 --- a/arch/x86/um/Kconfig +++ b/arch/x86/um/Kconfig | |||
@@ -13,6 +13,7 @@ endmenu | |||
13 | config UML_X86 | 13 | config UML_X86 |
14 | def_bool y | 14 | def_bool y |
15 | select GENERIC_FIND_FIRST_BIT | 15 | select GENERIC_FIND_FIRST_BIT |
16 | select GENERIC_KERNEL_THREAD | ||
16 | 17 | ||
17 | config 64BIT | 18 | config 64BIT |
18 | bool "64-bit kernel" if SUBARCH = "x86" | 19 | bool "64-bit kernel" if SUBARCH = "x86" |
diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c index b5408cecac6..232e60504b3 100644 --- a/arch/x86/um/sys_call_table_32.c +++ b/arch/x86/um/sys_call_table_32.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #define old_mmap sys_old_mmap | 25 | #define old_mmap sys_old_mmap |
26 | 26 | ||
27 | #define ptregs_fork sys_fork | 27 | #define ptregs_fork sys_fork |
28 | #define ptregs_execve sys_execve | ||
29 | #define ptregs_iopl sys_iopl | 28 | #define ptregs_iopl sys_iopl |
30 | #define ptregs_vm86old sys_vm86old | 29 | #define ptregs_vm86old sys_vm86old |
31 | #define ptregs_clone i386_clone | 30 | #define ptregs_clone i386_clone |