diff options
Diffstat (limited to 'arch/powerpc/kernel/process.c')
-rw-r--r-- | arch/powerpc/kernel/process.c | 41 |
1 files changed, 9 insertions, 32 deletions
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index ba48233500f6..f6d244db9203 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -745,25 +745,24 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
745 | /* Copy registers */ | 745 | /* Copy registers */ |
746 | sp -= sizeof(struct pt_regs); | 746 | sp -= sizeof(struct pt_regs); |
747 | childregs = (struct pt_regs *) sp; | 747 | childregs = (struct pt_regs *) sp; |
748 | if (!regs) { | 748 | if (unlikely(p->flags & PF_KTHREAD)) { |
749 | /* for kernel thread, set `current' and stackptr in new task */ | 749 | struct thread_info *ti = (void *)task_stack_page(p); |
750 | memset(childregs, 0, sizeof(struct pt_regs)); | 750 | memset(childregs, 0, sizeof(struct pt_regs)); |
751 | childregs->gpr[1] = sp + sizeof(struct pt_regs); | 751 | childregs->gpr[1] = sp + sizeof(struct pt_regs); |
752 | childregs->gpr[14] = usp; /* function */ | ||
752 | #ifdef CONFIG_PPC64 | 753 | #ifdef CONFIG_PPC64 |
753 | childregs->gpr[14] = *(unsigned long *)usp; | ||
754 | childregs->gpr[2] = ((unsigned long *)usp)[1], | ||
755 | clear_tsk_thread_flag(p, TIF_32BIT); | 754 | clear_tsk_thread_flag(p, TIF_32BIT); |
756 | #else | 755 | childregs->softe = 1; |
757 | childregs->gpr[14] = usp; /* function */ | ||
758 | childregs->gpr[2] = (unsigned long) p; | ||
759 | #endif | 756 | #endif |
760 | childregs->gpr[15] = arg; | 757 | childregs->gpr[15] = arg; |
761 | p->thread.regs = NULL; /* no user register state */ | 758 | p->thread.regs = NULL; /* no user register state */ |
759 | ti->flags |= _TIF_RESTOREALL; | ||
762 | f = ret_from_kernel_thread; | 760 | f = ret_from_kernel_thread; |
763 | } else { | 761 | } else { |
764 | CHECK_FULL_REGS(regs); | 762 | CHECK_FULL_REGS(regs); |
765 | *childregs = *regs; | 763 | *childregs = *regs; |
766 | childregs->gpr[1] = usp; | 764 | if (usp) |
765 | childregs->gpr[1] = usp; | ||
767 | p->thread.regs = childregs; | 766 | p->thread.regs = childregs; |
768 | childregs->gpr[3] = 0; /* Result from fork() */ | 767 | childregs->gpr[3] = 0; /* Result from fork() */ |
769 | if (clone_flags & CLONE_SETTLS) { | 768 | if (clone_flags & CLONE_SETTLS) { |
@@ -1027,22 +1026,11 @@ int get_unalign_ctl(struct task_struct *tsk, unsigned long adr) | |||
1027 | return put_user(tsk->thread.align_ctl, (unsigned int __user *)adr); | 1026 | return put_user(tsk->thread.align_ctl, (unsigned int __user *)adr); |
1028 | } | 1027 | } |
1029 | 1028 | ||
1030 | #define TRUNC_PTR(x) ((typeof(x))(((unsigned long)(x)) & 0xffffffff)) | ||
1031 | |||
1032 | int sys_clone(unsigned long clone_flags, unsigned long usp, | 1029 | int sys_clone(unsigned long clone_flags, unsigned long usp, |
1033 | int __user *parent_tidp, void __user *child_threadptr, | 1030 | int __user *parent_tidp, void __user *child_threadptr, |
1034 | int __user *child_tidp, int p6, | 1031 | int __user *child_tidp, int p6, |
1035 | struct pt_regs *regs) | 1032 | struct pt_regs *regs) |
1036 | { | 1033 | { |
1037 | CHECK_FULL_REGS(regs); | ||
1038 | if (usp == 0) | ||
1039 | usp = regs->gpr[1]; /* stack pointer for child */ | ||
1040 | #ifdef CONFIG_PPC64 | ||
1041 | if (is_32bit_task()) { | ||
1042 | parent_tidp = TRUNC_PTR(parent_tidp); | ||
1043 | child_tidp = TRUNC_PTR(child_tidp); | ||
1044 | } | ||
1045 | #endif | ||
1046 | return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp); | 1034 | return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp); |
1047 | } | 1035 | } |
1048 | 1036 | ||
@@ -1050,28 +1038,17 @@ int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3, | |||
1050 | unsigned long p4, unsigned long p5, unsigned long p6, | 1038 | unsigned long p4, unsigned long p5, unsigned long p6, |
1051 | struct pt_regs *regs) | 1039 | struct pt_regs *regs) |
1052 | { | 1040 | { |
1053 | CHECK_FULL_REGS(regs); | 1041 | return do_fork(SIGCHLD, 0, regs, 0, NULL, NULL); |
1054 | return do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL); | ||
1055 | } | 1042 | } |
1056 | 1043 | ||
1057 | int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, | 1044 | int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, |
1058 | unsigned long p4, unsigned long p5, unsigned long p6, | 1045 | unsigned long p4, unsigned long p5, unsigned long p6, |
1059 | struct pt_regs *regs) | 1046 | struct pt_regs *regs) |
1060 | { | 1047 | { |
1061 | CHECK_FULL_REGS(regs); | 1048 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, |
1062 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], | ||
1063 | regs, 0, NULL, NULL); | 1049 | regs, 0, NULL, NULL); |
1064 | } | 1050 | } |
1065 | 1051 | ||
1066 | void __ret_from_kernel_execve(struct pt_regs *normal) | ||
1067 | __noreturn; | ||
1068 | |||
1069 | void ret_from_kernel_execve(struct pt_regs *normal) | ||
1070 | { | ||
1071 | set_thread_flag(TIF_RESTOREALL); | ||
1072 | __ret_from_kernel_execve(normal); | ||
1073 | } | ||
1074 | |||
1075 | static inline int valid_irq_stack(unsigned long sp, struct task_struct *p, | 1052 | static inline int valid_irq_stack(unsigned long sp, struct task_struct *p, |
1076 | unsigned long nbytes) | 1053 | unsigned long nbytes) |
1077 | { | 1054 | { |