RISC-V: Add implementation for vfork

This commit is contained in:
Ville Juven 2022-04-19 15:41:09 +03:00 committed by Xiang Xiao
parent 2580520828
commit a014daf44f
13 changed files with 201 additions and 55 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <arch/irq.h>
#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

View File

@ -26,7 +26,7 @@
****************************************************************************/
#include <nuttx/config.h>
#include <arch/mips32/irq.h>
#include <arch/irq.h>
/****************************************************************************
* 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) */

View File

@ -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 <nuttx/config.h>
#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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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