riscv_fork.c: Fix vfork() for kernel mode + SMP
There was an error in the fork() routine when system calls are in use: the child context is saved on the child's user stack, which is incorrect, the context must be saved on the kernel stack instead. The result is a full system crash if (when) the child executes on a different CPU which does not have the same MMU mappings active.
This commit is contained in:
parent
d1fec65e1b
commit
2d3c94411b
@ -133,34 +133,48 @@ pid_t riscv_fork(const struct fork_s *context)
|
||||
DEBUGASSERT(stacktop > parent->xcp.regs[REG_SP]);
|
||||
stackutil = stacktop - parent->xcp.regs[REG_SP];
|
||||
|
||||
/* Copy the parent stack contents (overwrites child's SP and TP) */
|
||||
/* Copy goes to child's user stack top */
|
||||
|
||||
newtop = (uintptr_t)child->cmn.stack_base_ptr + child->cmn.adj_stack_size;
|
||||
newsp = newtop - stackutil;
|
||||
|
||||
memcpy((void *)newsp, (const void *)parent->xcp.regs[REG_SP], stackutil);
|
||||
|
||||
#ifdef CONFIG_SCHED_THREAD_LOCAL
|
||||
/* Save child's thread pointer */
|
||||
|
||||
tp = child->cmn.xcp.regs[REG_TP];
|
||||
#endif
|
||||
|
||||
/* Set up frame for context and copy the parent's user context there */
|
||||
/* Determine the integer context save area */
|
||||
|
||||
memcpy((void *)(newsp - XCPTCONTEXT_SIZE),
|
||||
parent->xcp.regs, XCPTCONTEXT_SIZE);
|
||||
#ifdef CONFIG_ARCH_KERNEL_STACK
|
||||
if (child->cmn.xcp.kstack)
|
||||
{
|
||||
/* Set context to kernel stack */
|
||||
|
||||
stacktop = (uintptr_t)child->cmn.xcp.ktopstk;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Set context to user stack */
|
||||
|
||||
stacktop = newsp;
|
||||
}
|
||||
|
||||
/* Set the new register restore area to the new stack top */
|
||||
|
||||
child->cmn.xcp.regs = (void *)(stacktop - XCPTCONTEXT_SIZE);
|
||||
|
||||
/* Copy the parent integer context (overwrites child's SP and TP) */
|
||||
|
||||
memcpy(child->cmn.xcp.regs, parent->xcp.regs, XCPTCONTEXT_SIZE);
|
||||
|
||||
/* Save FPU */
|
||||
|
||||
riscv_savefpu(child->cmn.xcp.regs, riscv_fpuregs(&child->cmn));
|
||||
|
||||
/* Copy the parent stack contents */
|
||||
|
||||
memcpy((void *)newsp, (const void *)parent->xcp.regs[REG_SP], stackutil);
|
||||
|
||||
/* Set the new register restore area to the new stack top */
|
||||
|
||||
child->cmn.xcp.regs = (void *)(newsp - XCPTCONTEXT_SIZE);
|
||||
|
||||
/* Return 0 to child */
|
||||
|
||||
child->cmn.xcp.regs[REG_A0] = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user