Skip to content

Commit

Permalink
powerpc: use switch frame for ret_from_kernel_thread parameters
Browse files Browse the repository at this point in the history
The kernel thread path in copy_thread creates a user interrupt frame on
stack and stores the function and arg parameters there, and
ret_from_kernel_thread loads them. This is a slightly confusing way to
overload that frame. Non-volatile registers are loaded from the switch
frame, so the parameters can be stored there. The user interrupt frame
is now only used by user threads when they return to user.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230325122904.2375060-4-npiggin@gmail.com
  • Loading branch information
Nicholas Piggin authored and Michael Ellerman committed Apr 11, 2023
1 parent 959791e commit af5ca9d
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 6 deletions.
1 change: 0 additions & 1 deletion arch/powerpc/kernel/entry_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ ret_from_fork:

.globl ret_from_kernel_thread
ret_from_kernel_thread:
REST_NVGPRS(r1)
bl schedule_tail
mtctr r14
mr r3,r15
Expand Down
1 change: 0 additions & 1 deletion arch/powerpc/kernel/interrupt_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,6 @@ _GLOBAL(ret_from_fork)

_GLOBAL(ret_from_kernel_thread)
bl schedule_tail
REST_NVGPRS(r1)
mtctr r14
mr r3,r15
#ifdef CONFIG_PPC64_ELF_ABI_V2
Expand Down
13 changes: 9 additions & 4 deletions arch/powerpc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -1765,14 +1765,10 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
((unsigned long *)sp)[0] = 0;
memset(childregs, 0, sizeof(struct pt_regs));
childregs->gpr[1] = sp + STACK_USER_INT_FRAME_SIZE;
/* function */
if (args->fn)
childregs->gpr[14] = ppc_function_entry((void *)args->fn);
#ifdef CONFIG_PPC64
clear_tsk_thread_flag(p, TIF_32BIT);
childregs->softe = IRQS_ENABLED;
#endif
childregs->gpr[15] = (unsigned long)args->fn_arg;
p->thread.regs = NULL; /* no user register state */
ti->flags |= _TIF_RESTOREALL;
f = ret_from_kernel_thread;
Expand Down Expand Up @@ -1811,6 +1807,15 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
((unsigned long *)sp)[0] = sp + STACK_SWITCH_FRAME_SIZE;
kregs = (struct pt_regs *)(sp + STACK_SWITCH_FRAME_REGS);
kregs->nip = ppc_function_entry(f);
if (unlikely(args->fn)) {
/*
* Put kthread fn, arg parameters in non-volatile GPRs in the
* switch frame so they are loaded by _switch before it returns
* to ret_from_kernel_thread.
*/
kregs->gpr[14] = ppc_function_entry((void *)args->fn);
kregs->gpr[15] = (unsigned long)args->fn_arg;
}
p->thread.ksp = sp;

#ifdef CONFIG_HAVE_HW_BREAKPOINT
Expand Down

0 comments on commit af5ca9d

Please sign in to comment.