Skip to content

Commit

Permalink
arm64/task/pthread_start: Fix rare issue with context register location
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
pussuw committed Sep 10, 2024
1 parent a124de0 commit d22a8c5
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 18 deletions.
3 changes: 3 additions & 0 deletions arch/arm64/include/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,9 @@ struct xcptcontext
/* task stack reg context */

uint64_t *regs;
#ifndef CONFIG_BUILD_FLAT
uint64_t *initregs;
#endif

/* task context, for signal process */

Expand Down
4 changes: 4 additions & 0 deletions arch/arm64/src/common/arm64_initialstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

/****************************************************************************
Expand Down
20 changes: 11 additions & 9 deletions arch/arm64/src/common/arm64_pthread_start.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 */

Expand All @@ -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();
Expand Down
20 changes: 11 additions & 9 deletions arch/arm64/src/common/arm64_task_start.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 */

Expand All @@ -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();
Expand Down

0 comments on commit d22a8c5

Please sign in to comment.