summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2023-03-25 22:28:59 +1000
committerMichael Ellerman <mpe@ellerman.id.au>2023-04-11 23:13:32 +1000
commitaf5ca9d5c8b45244b237d7a5534e1ec2d01cce8e (patch)
treeeb23a6cd9966f8b18a903abbb9d7338b4194f4f7
parent959791e45fd2a580403e03611a5aefb9e7abcfc0 (diff)
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: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://msgid.link/20230325122904.2375060-4-npiggin@gmail.com
-rw-r--r--arch/powerpc/kernel/entry_32.S1
-rw-r--r--arch/powerpc/kernel/interrupt_64.S1
-rw-r--r--arch/powerpc/kernel/process.c13
3 files changed, 9 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 755408c63be8..c3fdb3081d3d 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -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
diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S
index fccc34489add..d60e7e7564df 100644
--- a/arch/powerpc/kernel/interrupt_64.S
+++ b/arch/powerpc/kernel/interrupt_64.S
@@ -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
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 18f697112193..3b34bd9a6dff 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -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