arch/m68k/kernel/entry.S | 10 ++++++++++ arch/m68k/kernel/process.c | 14 +++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 9dd76fbb7c6b..499f14d79640 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -119,6 +119,15 @@ ENTRY(ret_from_fork) addql #4,%sp jra ret_from_exception + | A kernel thread will jump here directly from resume, + | with the stack containing the full register state + | (pt_regs and switch_stack). + | + | The argument will be in d7, and the kernel function + | to call will be in a3. + | + | If the kernel function returns, we want to return + | to user space - it has done a kernel_execve(). ENTRY(ret_from_kernel_thread) | a3 contains the kernel thread payload, d7 - its argument movel %d1,%sp@- @@ -126,6 +135,7 @@ ENTRY(ret_from_kernel_thread) movel %d7,(%sp) jsr %a3@ addql #4,%sp + RESTORE_SWITCH_STACK jra ret_from_exception #if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU) diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index da83cc83e791..0705f14871a3 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -158,13 +158,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, p->thread.fs = get_fs().seg; if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { - /* kernel thread */ - memset(frame, 0, sizeof(struct fork_frame)); + struct switch_stack *kstp = &frame->sw - 1; + + /* kernel thread - a kernel-side switch-stack and the full user fork_frame */ + memset(kstp, 0, sizeof(struct switch_stack) + sizeof(struct fork_frame)); + frame->regs.sr = PS_S; - frame->sw.a3 = usp; /* function */ - frame->sw.d7 = arg; - frame->sw.retpc = (unsigned long)ret_from_kernel_thread; + kstp->a3 = usp; /* function */ + kstp->d7 = arg; + kstp->retpc = (unsigned long)ret_from_kernel_thread; p->thread.usp = 0; + p->thread.ksp = (unsigned long)kstp; return 0; } memcpy(frame, container_of(current_pt_regs(), struct fork_frame, regs),