You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/03/23 16:15:37 UTC

[incubator-nuttx] 01/02: RISC-V: Include support for kernel stack

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 77e90d9c8750a588e275f46b827a65387ec8577c
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Wed Mar 23 13:08:01 2022 +0200

    RISC-V: Include support for kernel stack
    
    Preparation for CONFIG_BUILD_KERNEL=y, which requires that a kernel
    stack is allocated for each user process.
---
 arch/risc-v/include/irq.h                     |  16 ++++
 arch/risc-v/src/common/addrenv.h              |  52 ++++++++++++
 arch/risc-v/src/common/riscv_addrenv_kstack.c | 111 ++++++++++++++++++++++++++
 arch/risc-v/src/common/riscv_swint.c          |  61 ++++++++++++++
 arch/risc-v/src/mpfs/Make.defs                |   4 +
 5 files changed, 244 insertions(+)

diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h
index a8a3bb4..638e056 100644
--- a/arch/risc-v/include/irq.h
+++ b/arch/risc-v/include/irq.h
@@ -519,6 +519,22 @@ struct xcptcontext
 
 #endif
 
+#ifdef CONFIG_ARCH_ADDRENV
+#ifdef CONFIG_ARCH_KERNEL_STACK
+  /* In this configuration, all syscalls execute from an internal kernel
+   * stack.  Why?  Because when we instantiate and initialize the address
+   * environment of the new user process, we will temporarily lose the
+   * address environment of the old user process, including its stack
+   * contents.  The kernel C logic will crash immediately with no valid
+   * stack in place.
+   */
+
+  uintptr_t *ustkptr;  /* Saved user stack pointer */
+  uintptr_t *kstack;   /* Allocate base of the (aligned) kernel stack */
+  uintptr_t *kstkptr;  /* Saved kernel stack pointer */
+#endif
+#endif
+
   /* Register save area */
 
   uintptr_t regs[XCPTCONTEXT_REGS];
diff --git a/arch/risc-v/src/common/addrenv.h b/arch/risc-v/src/common/addrenv.h
new file mode 100644
index 0000000..fc89138
--- /dev/null
+++ b/arch/risc-v/src/common/addrenv.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+ * arch/risc-v/src/common/addrenv.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_RISC_V_SRC_COMMON_ADDRENV_H
+#define __ARCH_RISC_V_SRC_COMMON_ADDRENV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include "riscv_internal.h"
+
+#ifdef CONFIG_ARCH_ADDRENV
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Aligned size of the kernel stack */
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+#  define ARCH_KERNEL_STACKSIZE STACK_ALIGN_UP(CONFIG_ARCH_KERNEL_STACKSIZE)
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#endif /* CONFIG_ARCH_ADDRENV */
+#endif /* __ARCH_RISC_V_SRC_COMMON_ADDRENV_H */
diff --git a/arch/risc-v/src/common/riscv_addrenv_kstack.c b/arch/risc-v/src/common/riscv_addrenv_kstack.c
new file mode 100644
index 0000000..c0fd0f0
--- /dev/null
+++ b/arch/risc-v/src/common/riscv_addrenv_kstack.c
@@ -0,0 +1,111 @@
+/****************************************************************************
+ * arch/risc-v/src/common/riscv_addrenv_kstack.c
+ *
+ * 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 <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/sched.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/addrenv.h>
+#include <nuttx/arch.h>
+
+#include "addrenv.h"
+#include "riscv_internal.h"
+
+#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_addrenv_kstackalloc
+ *
+ * Description:
+ *   This function is called when a new thread is created to allocate
+ *   the new thread's kernel stack.   This function may be called for certain
+ *   terminating threads which have no kernel stack.  It must be tolerant of
+ *   that case.
+ *
+ * Input Parameters:
+ *   tcb - The TCB of the thread that requires the kernel stack.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_addrenv_kstackalloc(FAR struct tcb_s *tcb)
+{
+  DEBUGASSERT(tcb && tcb->xcp.kstack == NULL);
+
+  /* Allocate the kernel stack */
+
+  tcb->xcp.kstack = (uintptr_t *)kmm_memalign(STACK_ALIGNMENT,
+                                              ARCH_KERNEL_STACKSIZE);
+  if (!tcb->xcp.kstack)
+    {
+      berr("ERROR: Failed to allocate the kernel stack\n");
+      return -ENOMEM;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: up_addrenv_kstackfree
+ *
+ * Description:
+ *   This function is called when any thread exits.  This function frees
+ *   the kernel stack.
+ *
+ * Input Parameters:
+ *   tcb - The TCB of the thread that no longer requires the kernel stack.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_addrenv_kstackfree(FAR struct tcb_s *tcb)
+{
+  DEBUGASSERT(tcb);
+
+  /* Does the exiting thread have a kernel stack? */
+
+  if (tcb->xcp.kstack)
+    {
+      /* Yes.. Free the kernel stack */
+
+      kmm_free(tcb->xcp.kstack);
+      tcb->xcp.kstack = NULL;
+    }
+
+  return OK;
+}
+
+#endif /* CONFIG_ARCH_ADDRENV && CONFIG_ARCH_KERNEL_STACK */
diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c
index 95d20e8..0bff030 100644
--- a/arch/risc-v/src/common/riscv_swint.c
+++ b/arch/risc-v/src/common/riscv_swint.c
@@ -41,6 +41,7 @@
 
 #include "signal/signal.h"
 #include "riscv_internal.h"
+#include "addrenv.h"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -286,6 +287,19 @@ int riscv_swint(int irq, void *context, void *arg)
 
           regs[REG_A0]         = regs[REG_A2];
 
+#ifdef CONFIG_ARCH_KERNEL_STACK
+          /* If this is the outermost SYSCALL and if there is a saved user
+           * stack pointer, then restore the user stack pointer on this
+           * final return to user code.
+           */
+
+          if (index == 0 && rtcb->xcp.ustkptr != NULL)
+            {
+              regs[REG_SP]      = (uintptr_t)rtcb->xcp.ustkptr;
+              rtcb->xcp.ustkptr = NULL;
+            }
+#endif
+
           /* Save the new SYSCALL nesting level */
 
           rtcb->xcp.nsyscalls  = index;
@@ -415,6 +429,24 @@ int riscv_swint(int irq, void *context, void *arg)
           regs[REG_A1]         = regs[REG_A2]; /* signal */
           regs[REG_A2]         = regs[REG_A3]; /* info */
           regs[REG_A3]         = regs[REG_A4]; /* ucontext */
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+          /* If we are signalling a user process, then we must be operating
+           * on the kernel stack now.  We need to switch back to the user
+           * stack before dispatching the signal handler to the user code.
+           * The existence of an allocated kernel stack is sufficient
+           * information to make this decision.
+           */
+
+          if (rtcb->xcp.kstack != NULL)
+            {
+              DEBUGASSERT(rtcb->xcp.kstkptr == NULL &&
+                          rtcb->xcp.ustkptr != NULL);
+
+              rtcb->xcp.kstkptr = (uintptr_t *)regs[REG_SP];
+              regs[REG_SP]      = (uintptr_t)rtcb->xcp.ustkptr;
+            }
+#endif
         }
         break;
 #endif
@@ -440,6 +472,22 @@ int riscv_swint(int irq, void *context, void *arg)
           regs[REG_INT_CTX]   |= MSTATUS_MPPM; /* Machine mode */
 
           rtcb->xcp.sigreturn  = 0;
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+          /* We must enter here be using the user stack.  We need to switch
+           * to back to the kernel user stack before returning to the kernel
+           * mode signal trampoline.
+           */
+
+          if (rtcb->xcp.kstack != NULL)
+            {
+              DEBUGASSERT(rtcb->xcp.kstkptr != NULL &&
+                          (uintptr_t)rtcb->xcp.ustkptr == regs[REG_SP]);
+
+              regs[REG_SP]      = (uintptr_t)rtcb->xcp.kstkptr;
+              rtcb->xcp.kstkptr = NULL;
+            }
+#endif
         }
         break;
 #endif
@@ -490,6 +538,19 @@ int riscv_swint(int irq, void *context, void *arg)
 #else
           svcerr("ERROR: Bad SYS call: %" PRIdPTR "\n", regs[REG_A0]);
 #endif
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+          /* If this is the first SYSCALL and if there is an allocated
+           * kernel stack, then switch to the kernel stack.
+           */
+
+          if (index == 0 && rtcb->xcp.kstack != NULL)
+            {
+              rtcb->xcp.ustkptr = (uintptr_t *)regs[REG_SP];
+              regs[REG_SP]      = (uintptr_t)rtcb->xcp.kstack +
+                                  ARCH_KERNEL_STACKSIZE;
+            }
+#endif
         }
         break;
     }
diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs
index e46bf5e..58b0ca5 100755
--- a/arch/risc-v/src/mpfs/Make.defs
+++ b/arch/risc-v/src/mpfs/Make.defs
@@ -81,6 +81,10 @@ ifeq ($(CONFIG_ARCH_USE_MMU),y)
 CMN_CSRCS += riscv_mmu.c
 endif
 
+ifeq ($(CONFIG_ARCH_KERNEL_STACK),y)
+CMN_CSRCS += riscv_addrenv_kstack.c
+endif
+
 ifeq ($(CONFIG_SPI),y)
 CHIP_CSRCS += mpfs_spi.c
 endif