diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index c3fdb3081d3d..47f0dd9a45ad 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -186,8 +186,8 @@ ret_from_fork: li r3,0 /* fork() return value */ b ret_from_syscall - .globl ret_from_kernel_thread -ret_from_kernel_thread: + .globl ret_from_kernel_user_thread +ret_from_kernel_user_thread: bl schedule_tail mtctr r14 mr r3,r15 @@ -196,6 +196,22 @@ ret_from_kernel_thread: li r3,0 b ret_from_syscall + .globl start_kernel_thread +start_kernel_thread: + bl schedule_tail + mtctr r14 + mr r3,r15 + PPC440EP_ERR42 + bctrl + /* + * This must not return. We actually want to BUG here, not WARN, + * because BUG will exit the process which is what the kernel thread + * should have done, which may give some hope of continuing. + */ +100: trap + EMIT_BUG_ENTRY 100b,__FILE__,__LINE__,0 + + /* * This routine switches between two different tasks. The process * state of one is saved on its kernel stack. Then the state diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S index bac1f89501ac..a44c8aab63ec 100644 --- a/arch/powerpc/kernel/interrupt_64.S +++ b/arch/powerpc/kernel/interrupt_64.S @@ -739,7 +739,7 @@ _GLOBAL(ret_from_fork) li r3,0 /* fork() return value */ b .Lsyscall_exit -_GLOBAL(ret_from_kernel_thread) +_GLOBAL(ret_from_kernel_user_thread) bl schedule_tail mtctr r14 mr r3,r15 @@ -749,3 +749,19 @@ _GLOBAL(ret_from_kernel_thread) bctrl li r3,0 b .Lsyscall_exit + +_GLOBAL(start_kernel_thread) + bl schedule_tail + mtctr r14 + mr r3,r15 +#ifdef CONFIG_PPC64_ELF_ABI_V2 + mr r12,r14 +#endif + bctrl + /* + * This must not return. We actually want to BUG here, not WARN, + * because BUG will exit the process which is what the kernel thread + * should have done, which may give some hope of continuing. + */ +100: trap + EMIT_BUG_ENTRY 100b,__FILE__,__LINE__,0 diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 88898ca7ab0b..14fe4702a098 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1741,7 +1741,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) struct pt_regs *kregs; /* Switch frame regs */ extern void ret_from_fork(void); extern void ret_from_fork_scv(void); - extern void ret_from_kernel_thread(void); + extern void ret_from_kernel_user_thread(void); + extern void start_kernel_thread(void); void (*f)(void); unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; struct thread_info *ti = task_thread_info(p); @@ -1758,7 +1759,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) sp -= STACK_FRAME_MIN_SIZE; ((unsigned long *)sp)[0] = 0; - f = ret_from_kernel_thread; + f = start_kernel_thread; p->thread.regs = NULL; /* no user register state */ clear_tsk_compat_task(p); } else { @@ -1784,7 +1785,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) childregs->softe = IRQS_ENABLED; #endif ti->flags |= _TIF_RESTOREALL; - f = ret_from_kernel_thread; + f = ret_from_kernel_user_thread; } else { struct pt_regs *regs = current_pt_regs(); unsigned long clone_flags = args->flags;