Commit af5ca9d5 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc: use switch frame for ret_from_kernel_thread parameters



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: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230325122904.2375060-4-npiggin@gmail.com
parent 959791e4
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -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
+0 −1
Original line number Diff line number Diff line
@@ -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
+9 −4
Original line number Diff line number Diff line
@@ -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;
@@ -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