diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-11 21:49:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-11 21:49:08 -0400 |
commit | 8213a2f3eeafdecf06dd718cb4130372263f6067 (patch) | |
tree | 0d02e3201dac64d1429f8552ee1163d4a1ef1646 /arch/powerpc/kernel/process.c | |
parent | 40924754f2cabd5d9af4bcd4dcecc362b5e0baa1 (diff) | |
parent | 12f79be93d94698778ff2b3f921073fc5f6780d6 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull pile 2 of execve and kernel_thread unification work from Al Viro:
"Stuff in there: kernel_thread/kernel_execve/sys_execve conversions for
several more architectures plus assorted signal fixes and cleanups.
There'll be more (in particular, real fixes for the alpha
do_notify_resume() irq mess)..."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (43 commits)
alpha: don't open-code trace_report_syscall_{enter,exit}
Uninclude linux/freezer.h
m32r: trim masks
avr32: trim masks
tile: don't bother with SIGTRAP in setup_frame
microblaze: don't bother with SIGTRAP in setup_rt_frame()
mn10300: don't bother with SIGTRAP in setup_frame()
frv: no need to raise SIGTRAP in setup_frame()
x86: get rid of duplicate code in case of CONFIG_VM86
unicore32: remove pointless test
h8300: trim _TIF_WORK_MASK
parisc: decide whether to go to slow path (tracesys) based on thread flags
parisc: don't bother looping in do_signal()
parisc: fix double restarts
bury the rest of TIF_IRET
sanitize tsk_is_polling()
bury _TIF_RESTORE_SIGMASK
unicore32: unobfuscate _TIF_WORK_MASK
mips: NOTIFY_RESUME is not needed in TIF masks
mips: merge the identical "return from syscall" per-ABI code
...
Conflicts:
arch/arm/include/asm/thread_info.h
Diffstat (limited to 'arch/powerpc/kernel/process.c')
-rw-r--r-- | arch/powerpc/kernel/process.c | 59 |
1 files changed, 27 insertions, 32 deletions
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index d5ad666efd8b..ba48233500f6 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -733,30 +733,39 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) | |||
733 | extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */ | 733 | extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */ |
734 | 734 | ||
735 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 735 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
736 | unsigned long unused, struct task_struct *p, | 736 | unsigned long arg, struct task_struct *p, |
737 | struct pt_regs *regs) | 737 | struct pt_regs *regs) |
738 | { | 738 | { |
739 | struct pt_regs *childregs, *kregs; | 739 | struct pt_regs *childregs, *kregs; |
740 | extern void ret_from_fork(void); | 740 | extern void ret_from_fork(void); |
741 | extern void ret_from_kernel_thread(void); | ||
742 | void (*f)(void); | ||
741 | unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; | 743 | unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; |
742 | 744 | ||
743 | CHECK_FULL_REGS(regs); | ||
744 | /* Copy registers */ | 745 | /* Copy registers */ |
745 | sp -= sizeof(struct pt_regs); | 746 | sp -= sizeof(struct pt_regs); |
746 | childregs = (struct pt_regs *) sp; | 747 | childregs = (struct pt_regs *) sp; |
747 | *childregs = *regs; | 748 | if (!regs) { |
748 | if ((childregs->msr & MSR_PR) == 0) { | ||
749 | /* for kernel thread, set `current' and stackptr in new task */ | 749 | /* for kernel thread, set `current' and stackptr in new task */ |
750 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
750 | childregs->gpr[1] = sp + sizeof(struct pt_regs); | 751 | childregs->gpr[1] = sp + sizeof(struct pt_regs); |
751 | #ifdef CONFIG_PPC32 | 752 | #ifdef CONFIG_PPC64 |
752 | childregs->gpr[2] = (unsigned long) p; | 753 | childregs->gpr[14] = *(unsigned long *)usp; |
753 | #else | 754 | childregs->gpr[2] = ((unsigned long *)usp)[1], |
754 | clear_tsk_thread_flag(p, TIF_32BIT); | 755 | clear_tsk_thread_flag(p, TIF_32BIT); |
756 | #else | ||
757 | childregs->gpr[14] = usp; /* function */ | ||
758 | childregs->gpr[2] = (unsigned long) p; | ||
755 | #endif | 759 | #endif |
760 | childregs->gpr[15] = arg; | ||
756 | p->thread.regs = NULL; /* no user register state */ | 761 | p->thread.regs = NULL; /* no user register state */ |
762 | f = ret_from_kernel_thread; | ||
757 | } else { | 763 | } else { |
764 | CHECK_FULL_REGS(regs); | ||
765 | *childregs = *regs; | ||
758 | childregs->gpr[1] = usp; | 766 | childregs->gpr[1] = usp; |
759 | p->thread.regs = childregs; | 767 | p->thread.regs = childregs; |
768 | childregs->gpr[3] = 0; /* Result from fork() */ | ||
760 | if (clone_flags & CLONE_SETTLS) { | 769 | if (clone_flags & CLONE_SETTLS) { |
761 | #ifdef CONFIG_PPC64 | 770 | #ifdef CONFIG_PPC64 |
762 | if (!is_32bit_task()) | 771 | if (!is_32bit_task()) |
@@ -765,8 +774,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
765 | #endif | 774 | #endif |
766 | childregs->gpr[2] = childregs->gpr[6]; | 775 | childregs->gpr[2] = childregs->gpr[6]; |
767 | } | 776 | } |
777 | |||
778 | f = ret_from_fork; | ||
768 | } | 779 | } |
769 | childregs->gpr[3] = 0; /* Result from fork() */ | ||
770 | sp -= STACK_FRAME_OVERHEAD; | 780 | sp -= STACK_FRAME_OVERHEAD; |
771 | 781 | ||
772 | /* | 782 | /* |
@@ -805,19 +815,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
805 | p->thread.dscr = current->thread.dscr; | 815 | p->thread.dscr = current->thread.dscr; |
806 | } | 816 | } |
807 | #endif | 817 | #endif |
808 | |||
809 | /* | 818 | /* |
810 | * The PPC64 ABI makes use of a TOC to contain function | 819 | * The PPC64 ABI makes use of a TOC to contain function |
811 | * pointers. The function (ret_from_except) is actually a pointer | 820 | * pointers. The function (ret_from_except) is actually a pointer |
812 | * to the TOC entry. The first entry is a pointer to the actual | 821 | * to the TOC entry. The first entry is a pointer to the actual |
813 | * function. | 822 | * function. |
814 | */ | 823 | */ |
815 | #ifdef CONFIG_PPC64 | 824 | #ifdef CONFIG_PPC64 |
816 | kregs->nip = *((unsigned long *)ret_from_fork); | 825 | kregs->nip = *((unsigned long *)f); |
817 | #else | 826 | #else |
818 | kregs->nip = (unsigned long)ret_from_fork; | 827 | kregs->nip = (unsigned long)f; |
819 | #endif | 828 | #endif |
820 | |||
821 | return 0; | 829 | return 0; |
822 | } | 830 | } |
823 | 831 | ||
@@ -1055,26 +1063,13 @@ int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, | |||
1055 | regs, 0, NULL, NULL); | 1063 | regs, 0, NULL, NULL); |
1056 | } | 1064 | } |
1057 | 1065 | ||
1058 | int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, | 1066 | void __ret_from_kernel_execve(struct pt_regs *normal) |
1059 | unsigned long a3, unsigned long a4, unsigned long a5, | 1067 | __noreturn; |
1060 | struct pt_regs *regs) | 1068 | |
1069 | void ret_from_kernel_execve(struct pt_regs *normal) | ||
1061 | { | 1070 | { |
1062 | int error; | 1071 | set_thread_flag(TIF_RESTOREALL); |
1063 | char *filename; | 1072 | __ret_from_kernel_execve(normal); |
1064 | |||
1065 | filename = getname((const char __user *) a0); | ||
1066 | error = PTR_ERR(filename); | ||
1067 | if (IS_ERR(filename)) | ||
1068 | goto out; | ||
1069 | flush_fp_to_thread(current); | ||
1070 | flush_altivec_to_thread(current); | ||
1071 | flush_spe_to_thread(current); | ||
1072 | error = do_execve(filename, | ||
1073 | (const char __user *const __user *) a1, | ||
1074 | (const char __user *const __user *) a2, regs); | ||
1075 | putname(filename); | ||
1076 | out: | ||
1077 | return error; | ||
1078 | } | 1073 | } |
1079 | 1074 | ||
1080 | static inline int valid_irq_stack(unsigned long sp, struct task_struct *p, | 1075 | static inline int valid_irq_stack(unsigned long sp, struct task_struct *p, |