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