diff options
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, |
