Commit b504b6aa authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman

powerpc: differentiate kthread from user kernel thread start

Kernel created user threads start similarly to kernel threads in that
they call a kernel function after first returning from _switch, so
they share ret_from_kernel_thread for this. Kernel threads never return
from that function though, whereas user threads often do (although some
don't, e.g., IO threads).

Split these startup functions in two, and catch kernel threads that
improperly return from their function. This is intended to make the
complicated code a little bit easier to understand.
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-7-npiggin@gmail.com
parent eed7c420
...@@ -186,8 +186,8 @@ ret_from_fork: ...@@ -186,8 +186,8 @@ ret_from_fork:
li r3,0 /* fork() return value */ li r3,0 /* fork() return value */
b ret_from_syscall b ret_from_syscall
.globl ret_from_kernel_thread .globl ret_from_kernel_user_thread
ret_from_kernel_thread: ret_from_kernel_user_thread:
bl schedule_tail bl schedule_tail
mtctr r14 mtctr r14
mr r3,r15 mr r3,r15
...@@ -196,6 +196,22 @@ ret_from_kernel_thread: ...@@ -196,6 +196,22 @@ ret_from_kernel_thread:
li r3,0 li r3,0
b ret_from_syscall 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 * This routine switches between two different tasks. The process
* state of one is saved on its kernel stack. Then the state * state of one is saved on its kernel stack. Then the state
......
...@@ -739,7 +739,7 @@ _GLOBAL(ret_from_fork) ...@@ -739,7 +739,7 @@ _GLOBAL(ret_from_fork)
li r3,0 /* fork() return value */ li r3,0 /* fork() return value */
b .Lsyscall_exit b .Lsyscall_exit
_GLOBAL(ret_from_kernel_thread) _GLOBAL(ret_from_kernel_user_thread)
bl schedule_tail bl schedule_tail
mtctr r14 mtctr r14
mr r3,r15 mr r3,r15
...@@ -749,3 +749,19 @@ _GLOBAL(ret_from_kernel_thread) ...@@ -749,3 +749,19 @@ _GLOBAL(ret_from_kernel_thread)
bctrl bctrl
li r3,0 li r3,0
b .Lsyscall_exit 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
...@@ -1741,7 +1741,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) ...@@ -1741,7 +1741,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
struct pt_regs *kregs; /* Switch frame regs */ struct pt_regs *kregs; /* Switch frame regs */
extern void ret_from_fork(void); extern void ret_from_fork(void);
extern void ret_from_fork_scv(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); void (*f)(void);
unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
struct thread_info *ti = task_thread_info(p); 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) ...@@ -1758,7 +1759,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
sp -= STACK_FRAME_MIN_SIZE; sp -= STACK_FRAME_MIN_SIZE;
((unsigned long *)sp)[0] = 0; ((unsigned long *)sp)[0] = 0;
f = ret_from_kernel_thread; f = start_kernel_thread;
p->thread.regs = NULL; /* no user register state */ p->thread.regs = NULL; /* no user register state */
clear_tsk_compat_task(p); clear_tsk_compat_task(p);
} else { } else {
...@@ -1784,7 +1785,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) ...@@ -1784,7 +1785,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
childregs->softe = IRQS_ENABLED; childregs->softe = IRQS_ENABLED;
#endif #endif
ti->flags |= _TIF_RESTOREALL; ti->flags |= _TIF_RESTOREALL;
f = ret_from_kernel_thread; f = ret_from_kernel_user_thread;
} else { } else {
struct pt_regs *regs = current_pt_regs(); struct pt_regs *regs = current_pt_regs();
unsigned long clone_flags = args->flags; unsigned long clone_flags = args->flags;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment