diff --git a/arch/Kconfig b/arch/Kconfig index 365ffbd314..530f2d0d45 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -64,6 +64,7 @@ config ARCH_RISCV select ARCH_HAVE_BACKTRACE select ARCH_HAVE_INTERRUPTSTACK select ARCH_HAVE_STACKCHECK + select ARCH_HAVE_VFORK select ARCH_HAVE_CUSTOMOPT select ARCH_HAVE_SETJMP select ARCH_HAVE_STDARG_H diff --git a/arch/risc-v/src/bl602/Make.defs b/arch/risc-v/src/bl602/Make.defs index 72e53b5484..205af29f26 100644 --- a/arch/risc-v/src/bl602/Make.defs +++ b/arch/risc-v/src/bl602/Make.defs @@ -51,6 +51,7 @@ CMN_CSRCS += riscv_fpucmp.c endif ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) +CMN_ASRCS += vfork.S CMN_CSRCS += riscv_vfork.c endif diff --git a/arch/risc-v/src/c906/Make.defs b/arch/risc-v/src/c906/Make.defs index 52c7cac166..075b739e16 100644 --- a/arch/risc-v/src/c906/Make.defs +++ b/arch/risc-v/src/c906/Make.defs @@ -51,6 +51,7 @@ CMN_CSRCS += riscv_fpucmp.c endif ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) +CMN_ASRCS += vfork.S CMN_CSRCS += riscv_vfork.c endif diff --git a/arch/risc-v/src/common/riscv_vfork.c b/arch/risc-v/src/common/riscv_vfork.c index 29e091b03f..0e2c3ebc82 100644 --- a/arch/risc-v/src/common/riscv_vfork.c +++ b/arch/risc-v/src/common/riscv_vfork.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/risc-v/src/rv32im/riscv_vfork.c + * arch/risc-v/src/common/riscv_vfork.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -35,6 +35,8 @@ #include #include "riscv_vfork.h" +#include "riscv_internal.h" + #include "sched/sched.h" /**************************************************************************** @@ -95,40 +97,39 @@ #ifdef CONFIG_ARCH_HAVE_VFORK -#error This part of the port is not done yet!! - pid_t up_vfork(const struct vfork_s *context) { struct tcb_s *parent = this_task(); struct task_tcb_s *child; - uint32_t newsp; + uintptr_t newsp; #ifdef CONFIG_RISCV_FRAMEPOINTER - uint32_t newfp; + uintptr_t newfp; #endif - uint32_t newtop; - uint32_t stacktop; - uint32_t stackutil; + uintptr_t newtop; + uintptr_t stacktop; + uintptr_t stackutil; - sinfo("s0:%08x s1:%08x s2:%08x s3:%08x s4:%08x\n", + sinfo("s0:%" PRIxREG " s1:%" PRIxREG " s2:%" PRIxREG " s3:%" PRIxREG "" + " s4:%" PRIxREG "\n", context->s0, context->s1, context->s2, context->s3, context->s4); #ifdef CONFIG_RISCV_FRAMEPOINTER - sinfo("s5:%08x s6:%08x s7:%08x\n", + sinfo("s5:%" PRIxREG " s6:%" PRIxREG " s7:%" PRIxREG "\n", context->s5, context->s6, context->s7); #ifdef RISCV_SAVE_GP - sinfo("fp:%08x sp:%08x ra:%08x gp:%08x\n", + sinfo("fp:%" PRIxREG " sp:%" PRIxREG " ra:%" PRIxREG " gp:%" PRIxREG "\n", context->fp, context->sp, context->ra, context->gp); #else - sinfo("fp:%08x sp:%08x ra:%08x\n", + sinfo("fp:%" PRIxREG " sp:%" PRIxREG " ra:%" PRIxREG "\n", context->fp context->sp, context->ra); #endif #else - sinfo("s5:%08x s6:%08x s7:%08x s8:%08x\n", + sinfo("s5:%" PRIxREG " s6:%" PRIxREG " s7:%" PRIxREG " s8:%" PRIxREG "\n", context->s5, context->s6, context->s7, context->s8); #ifdef RISCV_SAVE_GP - sinfo("sp:%08x ra:%08x gp:%08x\n", + sinfo("sp:%" PRIxREG " ra:%" PRIxREG " gp:%" PRIxREG "\n", context->sp, context->ra, context->gp); #else - sinfo("sp:%08x ra:%08x\n", + sinfo("sp:%" PRIxREG " ra:%" PRIxREG "\n", context->sp, context->ra); #endif #endif @@ -150,12 +151,11 @@ pid_t up_vfork(const struct vfork_s *context) * stack usage should be the difference between those two. */ - stacktop = (uint32_t)parent->stack_base_ptr + - parent->adj_stack_size; + stacktop = (uintptr_t)parent->stack_base_ptr + parent->adj_stack_size; DEBUGASSERT(stacktop > context->sp); stackutil = stacktop - context->sp; - sinfo("Parent: stackutil:%" PRIu32 "\n", stackutil); + sinfo("Parent: stackutil:%" PRIxREG "\n", stackutil); /* Make some feeble effort to preserve the stack contents. This is * feeble because the stack surely contains invalid pointers and other @@ -164,9 +164,15 @@ pid_t up_vfork(const struct vfork_s *context) * effort is overkill. */ - newtop = (uint32_t)child->cmn.stack_base_ptr + - child->cmn.adj_stack_size; + newtop = (uintptr_t)child->cmn.stack_base_ptr + child->cmn.adj_stack_size; newsp = newtop - stackutil; + + /* Set up frame for context */ + + memcpy((void *)(newsp - XCPTCONTEXT_SIZE), + child->cmn.xcp.regs, XCPTCONTEXT_SIZE); + + child->cmn.xcp.regs = (void *)(newsp - XCPTCONTEXT_SIZE); memcpy((void *)newsp, (const void *)context->sp, stackutil); /* Was there a frame pointer in place before? */ @@ -174,7 +180,7 @@ pid_t up_vfork(const struct vfork_s *context) #ifdef CONFIG_RISCV_FRAMEPOINTER if (context->fp >= context->sp && context->fp < stacktop) { - uint32_t frameutil = stacktop - context->fp; + uintptr_t frameutil = stacktop - context->fp; newfp = newtop - frameutil; } else @@ -182,14 +188,14 @@ pid_t up_vfork(const struct vfork_s *context) newfp = context->fp; } - sinfo("Old stack top:%08x SP:%08x FP:%08x\n", + sinfo("Old stack top:%" PRIxREG " SP:%" PRIxREG " FP:%" PRIxREG "\n", stacktop, context->sp, context->fp); - sinfo("New stack top:%08x SP:%08x FP:%08x\n", + sinfo("New stack top:%" PRIxREG " SP:%" PRIxREG " FP:%" PRIxREG "\n", newtop, newsp, newfp); #else - sinfo("Old stack top:%08x SP:%08x\n", + sinfo("Old stack top:%" PRIxREG " SP:%" PRIxREG "\n", stacktop, context->sp); - sinfo("New stack top:%08x SP:%08x\n", + sinfo("New stack top:%" PRIxREG " SP:%" PRIxREG "\n", newtop, newsp); #endif diff --git a/arch/risc-v/src/common/riscv_vfork.h b/arch/risc-v/src/common/riscv_vfork.h index cf07984b47..24fed6942b 100644 --- a/arch/risc-v/src/common/riscv_vfork.h +++ b/arch/risc-v/src/common/riscv_vfork.h @@ -26,7 +26,7 @@ ****************************************************************************/ #include -#include +#include /**************************************************************************** * Pre-processor Definitions @@ -60,28 +60,28 @@ * r31 ra Return address. */ -#define VFORK_S0_OFFSET (0*4) /* Saved register s0 */ -#define VFORK_S1_OFFSET (1*4) /* Saved register s1 */ -#define VFORK_S2_OFFSET (2*4) /* Saved register s2 */ -#define VFORK_S3_OFFSET (3*4) /* Saved register s3 */ -#define VFORK_S4_OFFSET (4*4) /* Saved register s4 */ -#define VFORK_S5_OFFSET (5*4) /* Saved register s5 */ -#define VFORK_S6_OFFSET (6*4) /* Saved register s6 */ -#define VFORK_S7_OFFSET (7*4) /* Saved register s7 */ +#define VFORK_S0_OFFSET (0*INT_REG_SIZE) /* Saved register s0 */ +#define VFORK_S1_OFFSET (1*INT_REG_SIZE) /* Saved register s1 */ +#define VFORK_S2_OFFSET (2*INT_REG_SIZE) /* Saved register s2 */ +#define VFORK_S3_OFFSET (3*INT_REG_SIZE) /* Saved register s3 */ +#define VFORK_S4_OFFSET (4*INT_REG_SIZE) /* Saved register s4 */ +#define VFORK_S5_OFFSET (5*INT_REG_SIZE) /* Saved register s5 */ +#define VFORK_S6_OFFSET (6*INT_REG_SIZE) /* Saved register s6 */ +#define VFORK_S7_OFFSET (7*INT_REG_SIZE) /* Saved register s7 */ #ifdef CONFIG_RISCV_FRAMEPOINTER -# define VFORK_FP_OFFSET (8*4) /* Frame pointer */ +# define VFORK_FP_OFFSET (8*INT_REG_SIZE) /* Frame pointer */ #else -# define VFORK_S8_OFFSET (8*4) /* Saved register s8 */ +# define VFORK_S8_OFFSET (8*INT_REG_SIZE) /* Saved register s8 */ #endif -#define VFORK_SP_OFFSET (9*4) /* Stack pointer*/ -#define VFORK_RA_OFFSET (10*4) /* Return address*/ +#define VFORK_SP_OFFSET (9*INT_REG_SIZE) /* Stack pointer*/ +#define VFORK_RA_OFFSET (10*INT_REG_SIZE) /* Return address*/ #ifdef RISCV_SAVE_GP -# define VFORK_GP_OFFSET (11*4) /* Global pointer */ -# define VFORK_SIZEOF (12*4) +# define VFORK_GP_OFFSET (11*INT_REG_SIZE) /* Global pointer */ +# define VFORK_SIZEOF (12*INT_REG_SIZE) #else -# define VFORK_SIZEOF (11*4) +# define VFORK_SIZEOF (11*INT_REG_SIZE) #endif /**************************************************************************** @@ -93,23 +93,23 @@ struct vfork_s { /* CPU registers */ - uint32_t s0; /* Saved register s0 */ - uint32_t s1; /* Saved register s1 */ - uint32_t s2; /* Saved register s2 */ - uint32_t s3; /* Saved register s3 */ - uint32_t s4; /* Saved register s4 */ - uint32_t s5; /* Saved register s5 */ - uint32_t s6; /* Saved register s6 */ - uint32_t s7; /* Saved register s7 */ + uintptr_t s0; /* Saved register s0 */ + uintptr_t s1; /* Saved register s1 */ + uintptr_t s2; /* Saved register s2 */ + uintptr_t s3; /* Saved register s3 */ + uintptr_t s4; /* Saved register s4 */ + uintptr_t s5; /* Saved register s5 */ + uintptr_t s6; /* Saved register s6 */ + uintptr_t s7; /* Saved register s7 */ #ifdef CONFIG_RISCV_FRAMEPOINTER - uint32_t fp; /* Frame pointer */ + uintptr_t fp; /* Frame pointer */ #else - uint32_t s8; /* Saved register s8 */ + uintptr_t s8; /* Saved register s8 */ #endif - uint32_t sp; /* Stack pointer */ - uint32_t ra; /* Return address */ + uintptr_t sp; /* Stack pointer */ + uintptr_t ra; /* Return address */ #ifdef RISCV_SAVE_GP - uint32_t gp; /* Global pointer */ + uintptr_t gp; /* Global pointer */ #endif /* Floating point registers (not yet) */ diff --git a/arch/risc-v/src/common/vfork.S b/arch/risc-v/src/common/vfork.S new file mode 100644 index 0000000000..379f5fa3bf --- /dev/null +++ b/arch/risc-v/src/common/vfork.S @@ -0,0 +1,130 @@ +/**************************************************************************** + * arch/risc-v/src/common/vfork.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "riscv_vfork.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "vfork.S" + .globl up_vfork + .globl vfork + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: vfork + * + * Description: + * The vfork() function has the same effect as fork(), except that the + * behavior is undefined if the process created by vfork() either modifies + * any data other than a variable of type pid_t used to store the return + * value from vfork(), or returns from the function in which vfork() was + * called, or calls any other function before successfully calling _exit() + * or one of the exec family of functions. + * + * This thin layer implements vfork by simply calling up_vfork() with the + * vfork() context as an argument. The overall sequence is: + * + * 1) User code calls vfork(). vfork() collects context information and + * transfers control up up_vfork(). + * 2) up_vfork() and calls nxtask_setup_vfork(). + * 3) nxtask_setup_vfork() allocates and configures the child task's TCB. + * This consists of: + * - Allocation of the child task's TCB. + * - Initialization of file descriptors and streams + * - Configuration of environment variables + * - Allocate and initialize the stack + * - Setup the input parameters for the task. + * - Initialization of the TCB (including call to up_initial_state()) + * 4) up_vfork() provides any additional operating context. up_vfork must: + * - Initialize special values in any CPU registers that were not + * already configured by up_initial_state() + * 5) up_vfork() then calls nxtask_start_vfork() + * 6) nxtask_start_vfork() then executes the child thread. + * + * Input Parameters: + * None + * + * Returned Value: + * Upon successful completion, vfork() returns 0 to the child process and + * returns the process ID of the child process to the parent process. + * Otherwise, -1 is returned to the parent, no child process is created, + * and errno is set to indicate the error. + * + ****************************************************************************/ + +.type vfork, function + +vfork: + /* Create a stack frame */ + + addi sp, sp, -VFORK_SIZEOF + + /* CPU registers */ + /* Save the volatile registers */ + + REGSTORE s0, VFORK_S0_OFFSET(sp) + REGSTORE s1, VFORK_S1_OFFSET(sp) + REGSTORE s2, VFORK_S2_OFFSET(sp) + REGSTORE s3, VFORK_S3_OFFSET(sp) + REGSTORE s4, VFORK_S4_OFFSET(sp) + REGSTORE s5, VFORK_S5_OFFSET(sp) + REGSTORE s6, VFORK_S6_OFFSET(sp) + REGSTORE s7, VFORK_S7_OFFSET(sp) + + /* Save the frame pointer, stack pointer, and return address */ + +#ifdef CONFIG_RISCV_FRAMEPOINTER + REGSTORE fp, VFORK_FP_OFFSET(sp) +#endif + addi s0, sp, VFORK_SIZEOF + REGSTORE s0, VFORK_SP_OFFSET(sp) /* original SP */ + REGSTORE x1, VFORK_RA_OFFSET(sp) /* return address */ + + /* Floating point registers (not yet) */ + + /* Then, call up_vfork(), passing it a pointer to the stack frame */ + + mv a0, sp + jal x1, up_vfork + + /* Release the stack frame and return the value returned by up_vfork */ + + REGLOAD x1, VFORK_RA_OFFSET(sp) + addi sp, sp, VFORK_SIZEOF + ret + + .size vfork, .-vfork + .end diff --git a/arch/risc-v/src/esp32c3/Make.defs b/arch/risc-v/src/esp32c3/Make.defs index 15640d9392..db2ff2b812 100644 --- a/arch/risc-v/src/esp32c3/Make.defs +++ b/arch/risc-v/src/esp32c3/Make.defs @@ -52,7 +52,8 @@ CMN_CSRCS += riscv_checkstack.c endif ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) -CMN_CSRCS += riscv_vfork.c +CMN_ASRCS += vfork.S +CMN_CSRCS += riscv_vfork.c endif # Specify our C code within this directory to be included diff --git a/arch/risc-v/src/fe310/Make.defs b/arch/risc-v/src/fe310/Make.defs index 4b09e739cc..0d865f393b 100644 --- a/arch/risc-v/src/fe310/Make.defs +++ b/arch/risc-v/src/fe310/Make.defs @@ -45,6 +45,7 @@ CMN_CSRCS += riscv_checkstack.c endif ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) +CMN_ASRCS += vfork.S CMN_CSRCS += riscv_vfork.c endif diff --git a/arch/risc-v/src/k210/Make.defs b/arch/risc-v/src/k210/Make.defs index 9f2d6411d1..8912c37960 100644 --- a/arch/risc-v/src/k210/Make.defs +++ b/arch/risc-v/src/k210/Make.defs @@ -51,6 +51,7 @@ CMN_CSRCS += riscv_checkstack.c endif ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) +CMN_ASRCS += vfork.S CMN_CSRCS += riscv_vfork.c endif diff --git a/arch/risc-v/src/litex/Make.defs b/arch/risc-v/src/litex/Make.defs index 768d5269ad..f4230c03b1 100644 --- a/arch/risc-v/src/litex/Make.defs +++ b/arch/risc-v/src/litex/Make.defs @@ -45,6 +45,7 @@ CMN_CSRCS += riscv_checkstack.c endif ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) +CMN_ASRCS += vfork.S CMN_CSRCS += riscv_vfork.c endif diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index c58e938036..479d00c825 100755 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -52,6 +52,7 @@ CMN_CSRCS += riscv_fpucmp.c endif ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) +CMN_ASRCS += vfork.S CMN_CSRCS += riscv_vfork.c endif diff --git a/arch/risc-v/src/qemu-rv/Make.defs b/arch/risc-v/src/qemu-rv/Make.defs index 0d4d701333..a222285990 100644 --- a/arch/risc-v/src/qemu-rv/Make.defs +++ b/arch/risc-v/src/qemu-rv/Make.defs @@ -51,6 +51,7 @@ CMN_CSRCS += riscv_checkstack.c endif ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) +CMN_ASRCS += vfork.S CMN_CSRCS += riscv_vfork.c endif diff --git a/arch/risc-v/src/rv32m1/Make.defs b/arch/risc-v/src/rv32m1/Make.defs index f1dc2d0dea..3fcacd53f1 100644 --- a/arch/risc-v/src/rv32m1/Make.defs +++ b/arch/risc-v/src/rv32m1/Make.defs @@ -45,6 +45,7 @@ CMN_CSRCS += riscv_checkstack.c endif ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) +CMN_ASRCS += vfork.S CMN_CSRCS += riscv_vfork.c endif