arm64/task/pthread_start: Fix rare issue with context register location
There is a tiny possibility that when a process is started a trap is taken which causes a context switch. This moves the kernel stack unexpectedly and the task start logic no longer works. Fix this by recording the initial context location, and use that to trampoline into the user process with interrupts disabled. This ensures the context stays intact AND the kernel stack is fully unwound before the user process starts.
This commit is contained in:
parent
87d9dac817
commit
ca4bd482a0
4 changed files with 29 additions and 18 deletions
|
|
@ -280,6 +280,9 @@ struct xcptcontext
|
|||
/* task stack reg context */
|
||||
|
||||
uint64_t *regs;
|
||||
#ifndef CONFIG_BUILD_FLAT
|
||||
uint64_t *initregs;
|
||||
#endif
|
||||
|
||||
/* task context, for signal process */
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,10 @@ void arm64_new_task(struct tcb_s * tcb)
|
|||
pinitctx->tpidr_el1 = (uint64_t)tcb;
|
||||
|
||||
tcb->xcp.regs = (uint64_t *)pinitctx;
|
||||
|
||||
#ifndef CONFIG_BUILD_FLAT
|
||||
tcb->xcp.initregs = tcb->xcp.regs;
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
|
|
@ -68,8 +68,11 @@
|
|||
void up_pthread_start(pthread_trampoline_t startup,
|
||||
pthread_startroutine_t entrypt, pthread_addr_t arg)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
uint64_t spsr;
|
||||
uint64_t *regs = this_task()->xcp.initregs;
|
||||
|
||||
/* This must be performed atomically, the C-section ends upon user entry */
|
||||
|
||||
enter_critical_section();
|
||||
|
||||
/* Set up to enter the user-space pthread start-up function in
|
||||
* unprivileged mode. We need:
|
||||
|
|
@ -80,11 +83,10 @@ void up_pthread_start(pthread_trampoline_t startup,
|
|||
* SPSR = user mode
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_ELR] = (uint64_t)startup;
|
||||
tcb->xcp.regs[REG_X0] = (uint64_t)entrypt;
|
||||
tcb->xcp.regs[REG_X1] = (uint64_t)arg;
|
||||
spsr = tcb->xcp.regs[REG_SPSR] & ~SPSR_MODE_MASK;
|
||||
tcb->xcp.regs[REG_SPSR] = spsr | SPSR_MODE_EL0T;
|
||||
regs[REG_ELR] = (uint64_t)startup;
|
||||
regs[REG_X0] = (uint64_t)entrypt;
|
||||
regs[REG_X1] = (uint64_t)arg;
|
||||
regs[REG_SPSR] = (regs[REG_SPSR] & ~SPSR_MODE_MASK) | SPSR_MODE_EL0T;
|
||||
|
||||
/* Fully unwind the kernel stack and drop to user space */
|
||||
|
||||
|
|
@ -94,8 +96,8 @@ void up_pthread_start(pthread_trampoline_t startup,
|
|||
"mov sp, x0\n" /* Stack pointer = context */
|
||||
"b arm64_exit_exception\n"
|
||||
:
|
||||
: "r" (tcb->xcp.regs)
|
||||
: "memory"
|
||||
: "r" (regs)
|
||||
: "x0", "memory"
|
||||
);
|
||||
|
||||
PANIC();
|
||||
|
|
|
|||
|
|
@ -65,8 +65,11 @@
|
|||
|
||||
void up_task_start(main_t taskentry, int argc, char *argv[])
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
uint64_t spsr;
|
||||
uint64_t *regs = this_task()->xcp.initregs;
|
||||
|
||||
/* This must be performed atomically, the C-section ends upon user entry */
|
||||
|
||||
enter_critical_section();
|
||||
|
||||
/* Set up to return to the user-space _start function in
|
||||
* unprivileged mode. We need:
|
||||
|
|
@ -77,11 +80,10 @@ void up_task_start(main_t taskentry, int argc, char *argv[])
|
|||
* SPSR = user mode
|
||||
*/
|
||||
|
||||
tcb->xcp.regs[REG_ELR] = (uint64_t)taskentry;
|
||||
tcb->xcp.regs[REG_X0] = (uint64_t)argc;
|
||||
tcb->xcp.regs[REG_X1] = (uint64_t)argv;
|
||||
spsr = tcb->xcp.regs[REG_SPSR] & ~SPSR_MODE_MASK;
|
||||
tcb->xcp.regs[REG_SPSR] = spsr | SPSR_MODE_EL0T;
|
||||
regs[REG_ELR] = (uint64_t)taskentry;
|
||||
regs[REG_X0] = (uint64_t)argc;
|
||||
regs[REG_X1] = (uint64_t)argv;
|
||||
regs[REG_SPSR] = (regs[REG_SPSR] & ~SPSR_MODE_MASK) | SPSR_MODE_EL0T;
|
||||
|
||||
/* Fully unwind the kernel stack and drop to user space */
|
||||
|
||||
|
|
@ -91,8 +93,8 @@ void up_task_start(main_t taskentry, int argc, char *argv[])
|
|||
"mov sp, x0\n" /* Stack pointer = context */
|
||||
"b arm64_exit_exception\n"
|
||||
:
|
||||
: "r" (tcb->xcp.regs)
|
||||
: "memory"
|
||||
: "r" (regs)
|
||||
: "x0", "memory"
|
||||
);
|
||||
|
||||
PANIC();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue