From 2d3c94411bb89c20916e10bcfdeb16320dfb2836 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 26 Sep 2024 11:57:09 +0300 Subject: [PATCH] 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. --- arch/risc-v/src/common/riscv_fork.c | 38 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/arch/risc-v/src/common/riscv_fork.c b/arch/risc-v/src/common/riscv_fork.c index 896d8d46c4..6f17f8d540 100644 --- a/arch/risc-v/src/common/riscv_fork.c +++ b/arch/risc-v/src/common/riscv_fork.c @@ -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;