You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2022/04/01 19:19:50 UTC

[incubator-nuttx] branch master updated (c37474b -> 71ced1f)

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

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


    from c37474b  risc-v/esp32c3: Fix regression on IRQ handling for ECALL instruction
     new c15b670  RISC-V: Implement option to run NuttX in supervisor mode (S-mode)
     new 71ced1f  RISC-V: Implement skeleton for a per CPU structure

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 arch/risc-v/Kconfig                                |  26 ++++
 arch/risc-v/include/csr.h                          |  51 ++++++-
 arch/risc-v/include/irq.h                          |  24 +++-
 arch/risc-v/include/mode.h                         | 101 ++++++++++++++
 arch/risc-v/include/syscall.h                      |  69 +++-------
 arch/risc-v/src/Makefile                           |   6 +
 arch/risc-v/src/bl602/Make.defs                    |   1 +
 arch/risc-v/src/c906/Make.defs                     |   2 +-
 arch/risc-v/src/common/riscv_cpuindex.c            |  10 ++
 arch/risc-v/src/common/riscv_exception_common.S    | 142 ++++++--------------
 arch/risc-v/src/common/riscv_exception_macros.S    | 130 ++++++++++++++++++
 arch/risc-v/src/common/riscv_fpu.S                 |   3 +-
 arch/risc-v/src/common/riscv_getnewintctx.c        |  14 +-
 arch/risc-v/src/common/riscv_internal.h            |  48 +++++++
 .../bl602_systemreset.c => common/riscv_percpu.c}  |  83 ++++++------
 .../src/common/riscv_percpu.h}                     |  88 ++++++------
 arch/risc-v/src/common/riscv_schedulesigaction.c   |  25 ++--
 arch/risc-v/src/common/riscv_swint.c               |  20 +--
 arch/risc-v/src/common/riscv_vectors.S             |   9 +-
 .../risc-v/src/common/supervisor}/Make.defs        |  17 +--
 .../riscv_perform_syscall.c}                       |  45 ++++---
 .../src/common/supervisor/riscv_syscall_dispatch.S | 148 +++++++++++++++++++++
 arch/risc-v/src/esp32c3/Make.defs                  |   1 +
 arch/risc-v/src/fe310/Make.defs                    |   1 +
 arch/risc-v/src/k210/Make.defs                     |   1 +
 arch/risc-v/src/litex/Make.defs                    |   1 +
 arch/risc-v/src/mpfs/mpfs_irq_dispatch.c           |   2 +-
 arch/risc-v/src/qemu-rv/Make.defs                  |   1 +
 arch/risc-v/src/rv32m1/Make.defs                   |   1 +
 boards/risc-v/bl602/bl602evb/src/bl602_ostest.c    |   2 +
 boards/risc-v/c906/smartl-c906/src/c906_ostest.c   |   2 +
 boards/risc-v/mpfs/common/src/mpfs_ostest.c        |   2 +
 boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c |   2 +
 33 files changed, 775 insertions(+), 303 deletions(-)
 create mode 100644 arch/risc-v/include/mode.h
 create mode 100644 arch/risc-v/src/common/riscv_exception_macros.S
 copy arch/risc-v/src/{bl602/bl602_systemreset.c => common/riscv_percpu.c} (63%)
 copy arch/{arm/src/stm32/stm32_fdcan.h => risc-v/src/common/riscv_percpu.h} (64%)
 copy {drivers/crypto => arch/risc-v/src/common/supervisor}/Make.defs (74%)
 copy arch/risc-v/src/common/{addrenv.h => supervisor/riscv_perform_syscall.c} (65%)
 create mode 100644 arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.S

[incubator-nuttx] 01/02: RISC-V: Implement option to run NuttX in supervisor mode (S-mode)

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c15b6701ce2bd5ed9cfb8dd9a1ab248e5acd9948
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Thu Mar 17 11:20:42 2022 +0200

    RISC-V: Implement option to run NuttX in supervisor mode (S-mode)
    
    - Add config "ARCH_USE_S_MODE" which controls whether the kernel
      runs in M-mode or S-mode
    - Add more MSTATUS and most of the SSTATUS register definitions
    - Add more MIP flags for interrupt delegation
    - Add handling of interrupts from S-mode
    - Add handling of FPU from S-mode
    - Add new context handling functions that are not dependent on the trap
      handlers / ecall
    
    NOTE: S-mode requires a companion SW (SBI) which is not yet implemented,
          thus S-mode is not usable as is, yet.
---
 arch/risc-v/Kconfig                                |  22 +++
 arch/risc-v/include/csr.h                          |  51 ++++++-
 arch/risc-v/include/irq.h                          |  24 +++-
 arch/risc-v/include/mode.h                         | 101 ++++++++++++++
 arch/risc-v/include/syscall.h                      |  69 +++-------
 arch/risc-v/src/Makefile                           |   6 +
 arch/risc-v/src/bl602/Make.defs                    |   1 +
 arch/risc-v/src/c906/Make.defs                     |   2 +-
 arch/risc-v/src/common/riscv_cpuindex.c            |   9 ++
 arch/risc-v/src/common/riscv_exception_common.S    | 142 ++++++--------------
 arch/risc-v/src/common/riscv_exception_macros.S    | 130 ++++++++++++++++++
 arch/risc-v/src/common/riscv_fpu.S                 |   3 +-
 arch/risc-v/src/common/riscv_getnewintctx.c        |  14 +-
 arch/risc-v/src/common/riscv_internal.h            |  48 +++++++
 arch/risc-v/src/common/riscv_schedulesigaction.c   |  25 ++--
 arch/risc-v/src/common/riscv_swint.c               |  20 +--
 arch/risc-v/src/common/riscv_vectors.S             |   9 +-
 arch/risc-v/src/common/supervisor/Make.defs        |  28 ++++
 .../riscv_perform_syscall.c}                       |  46 +++++--
 .../src/common/supervisor/riscv_syscall_dispatch.S | 148 +++++++++++++++++++++
 arch/risc-v/src/esp32c3/Make.defs                  |   1 +
 arch/risc-v/src/fe310/Make.defs                    |   1 +
 arch/risc-v/src/k210/Make.defs                     |   1 +
 arch/risc-v/src/litex/Make.defs                    |   1 +
 arch/risc-v/src/mpfs/mpfs_irq_dispatch.c           |   2 +-
 arch/risc-v/src/qemu-rv/Make.defs                  |   1 +
 arch/risc-v/src/rv32m1/Make.defs                   |   1 +
 boards/risc-v/bl602/bl602evb/src/bl602_ostest.c    |   2 +
 boards/risc-v/c906/smartl-c906/src/c906_ostest.c   |   2 +
 boards/risc-v/mpfs/common/src/mpfs_ostest.c        |   2 +
 boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c |   2 +
 31 files changed, 714 insertions(+), 200 deletions(-)

diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig
index 6bc640e..97c66bd 100644
--- a/arch/risc-v/Kconfig
+++ b/arch/risc-v/Kconfig
@@ -102,6 +102,7 @@ config ARCH_CHIP_MPFS
 	select ARCH_HAVE_RESET
 	select ARCH_HAVE_SPI_CS_CONTROL
 	select ARCH_HAVE_PWM_MULTICHAN
+	select ARCH_HAVE_S_MODE
 	select PMP_HAS_LIMITED_FEATURES
 	---help---
 		MicroChip Polarfire processor (RISC-V 64bit core with GCVX extensions).
@@ -189,6 +190,27 @@ config ARCH_MMU_TYPE_SV39
 	bool
 	default n
 
+config ARCH_HAVE_S_MODE
+	bool
+	default n
+
+# Option to run NuttX in supervisor mode. This is obviously not usable in
+# flat mode, is questionable in protected mode, but is mandatory in kernel
+# mode.
+#
+# Kernel mode requires this as M-mode uses flat addressing and the kernel
+# memory must be mapped in order to share memory between the kernel and
+# different user tasks which reside in virtual memory.
+
+config ARCH_USE_S_MODE
+	bool "Run the NuttX kernel in S-mode"
+	default n
+	depends on ARCH_HAVE_S_MODE && BUILD_KERNEL && ARCH_USE_MMU
+	---help---
+		Most of the RISC-V implementations run in M-mode (flat addressing)
+		and/or U-mode (in case of separate kernel-/userspaces). This provides
+		an option to run the kernel in S-mode, if the target supports it.
+
 # MPU has certain architecture dependent configurations, which are presented
 # here. Default is that the full RISC-V PMP specification is supported.
 
diff --git a/arch/risc-v/include/csr.h b/arch/risc-v/include/csr.h
index 25b6316..ea17adb 100644
--- a/arch/risc-v/include/csr.h
+++ b/arch/risc-v/include/csr.h
@@ -299,13 +299,27 @@
 
 /* In mstatus register */
 
+#define MSTATUS_UIE       (0x1 << 0)  /* User Interrupt Enable */
+#define MSTATUS_SIE       (0x1 << 1)  /* Supervisor Interrupt Enable */
 #define MSTATUS_MIE       (0x1 << 3)  /* Machine Interrupt Enable */
+#define MSTATUS_SPIE      (0x1 << 5)  /* Supervisor Previous Interrupt Enable */
 #define MSTATUS_MPIE      (0x1 << 7)  /* Machine Previous Interrupt Enable */
+#define MSTATUS_SPPU      (0x0 << 8)  /* Supervisor Previous Privilege (u-mode) */
+#define MSTATUS_SPPS      (0x1 << 8)  /* Supervisor Previous Privilege (s-mode) */
+#define MSTATUS_MPPU      (0x0 << 11) /* Machine Previous Privilege (u-mode) */
+#define MSTATUS_MPPS      (0x1 << 11) /* Machine Previous Privilege (s-mode) */
 #define MSTATUS_MPPM      (0x3 << 11) /* Machine Previous Privilege (m-mode) */
+#define MSTATUS_MPP_MASK  (0x3 << 11)
 #define MSTATUS_FS        (0x3 << 13) /* Machine Floating-point Status */
 #define MSTATUS_FS_INIT   (0x1 << 13)
 #define MSTATUS_FS_CLEAN  (0x2 << 13)
 #define MSTATUS_FS_DIRTY  (0x3 << 13)
+#define MSTATUS_MPRV      (0x1 << 17) /* Modify Privilege */
+#define MSTATUS_SUM       (0x1 << 18) /* S mode access to U mode memory */
+#define MSTATUS_MXR       (0x1 << 19) /* Make executable / readable */
+#define MSTATUS_TVM       (0x1 << 20) /* Trap access to satp from S mode */
+#define MSTATUS_TW        (0x1 << 21) /* Trap WFI instruction from S mode */
+#define MSTATUS_TSR       (0x1 << 22) /* Trap supervisor return (sret) */
 
 /* Mask of preserved bits for mstatus */
 
@@ -317,19 +331,50 @@
 
 /* In mie (machine interrupt enable) register */
 
+#define MIE_SSIE      (0x1 << 1)  /* Supervisor Software Interrupt Enable */
 #define MIE_MSIE      (0x1 << 3)  /* Machine Software Interrupt Enable */
+#define MIE_STIE      (0x1 << 5)  /* Supervisor Timer Interrupt Enable */
 #define MIE_MTIE      (0x1 << 7)  /* Machine Timer Interrupt Enable */
+#define MIE_SEIE      (0x1 << 9)  /* Supervisor External Interrupt Enable */
 #define MIE_MEIE      (0x1 << 11) /* Machine External Interrupt Enable */
 
 /* In mip (machine interrupt pending) register */
 
-#define MIP_MTIP      (0x1 << 7)
+#define MIP_SSIP        (0x1 << 1)
+#define MIP_STIP        (0x1 << 5)
+#define MIP_MTIP        (0x1 << 7)
+#define MIP_SEIP        (0x1 << 9)
+
+/* In sstatus register (which is a view of mstatus) */
+
+#define SSTATUS_SIE         MSTATUS_SIE
+#define SSTATUS_SPIE        MSTATUS_SPIE
+#define SSTATUS_SPPU        MSTATUS_SPPU
+#define SSTATUS_SPPS        MSTATUS_SPPS
+#define SSTATUS_FS          MSTATUS_FS
+#define SSTATUS_FS_INIT     MSTATUS_FS_INIT
+#define SSTATUS_FS_CLEAN    MSTATUS_FS_CLEAN
+#define SSTATUS_FS_DIRTY    MSTATUS_FS_DIRTY
+#define SSTATUS_SUM         MSTATUS_SUM
+#define SSTATUS_MXR         MSTATUS_MXR
+
+/* In sie register (which is a view of mie) */
+
+#define SIE_SSIE            MIE_SSIE
+#define SIE_STIE            MIE_STIE
+#define SIE_SEIE            MIE_SEIE
+
+/* In sip register (which is a view of mip) */
+
+#define SIP_SSIP            MIP_SSIP
+#define SIP_STIP            MIP_STIP
+#define SIP_SEIP            MIP_SEIP
 
 /* In pmpcfg (PMP configuration) register */
 
 #define PMPCFG_R        (1 << 0)  /* readable ? */
-#define PMPCFG_W        (1 << 1)  /* writeable ? */
-#define PMPCFG_X        (1 << 2)  /* excutable ? */
+#define PMPCFG_W        (1 << 1)  /* writable ? */
+#define PMPCFG_X        (1 << 2)  /* executable ? */
 #define PMPCFG_RWX_MASK (7 << 0)  /* access rights mask */
 #define PMPCFG_A_OFF    (0 << 3)  /* null region (disabled) */
 #define PMPCFG_A_TOR    (1 << 3)  /* top of range */
diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h
index dd97222..78799ad 100644
--- a/arch/risc-v/include/irq.h
+++ b/arch/risc-v/include/irq.h
@@ -35,8 +35,10 @@
 
 #include <arch/types.h>
 
+#include <arch/arch.h>
 #include <arch/csr.h>
 #include <arch/chip/irq.h>
+#include <arch/mode.h>
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -47,7 +49,7 @@
 /* IRQ 0-15 : (exception:interrupt=0) */
 
 #define RISCV_IRQ_IAMISALIGNED  (0)   /* Instruction Address Misaligned */
-#define RISCV_IRQ_IAFAULT       (1)   /* Instruction Address Fault */
+#define RISCV_IRQ_IAFAULT       (1)   /* Instruction Access Fault */
 #define RISCV_IRQ_IINSTRUCTION  (2)   /* Illegal Instruction */
 #define RISCV_IRQ_BPOINT        (3)   /* Break Point */
 #define RISCV_IRQ_LAMISALIGNED  (4)   /* Load Address Misaligned */
@@ -61,7 +63,7 @@
 #define RISCV_IRQ_INSTRUCTIONPF (12)  /* Instruction page fault */
 #define RISCV_IRQ_LOADPF        (13)  /* Load page fault */
 #define RISCV_IRQ_RESERVED      (14)  /* Reserved */
-#define RISCV_IRQ_SROREPF       (15)  /* Store/AMO page fault */
+#define RISCV_IRQ_STOREPF       (15)  /* Store/AMO page fault */
 
 #define RISCV_MAX_EXCEPTION     (15)
 
@@ -96,6 +98,16 @@
 #  define CONFIG_SYS_NNEST  2
 #endif
 
+/* Amount of interrupt stacks (amount of harts) */
+
+#ifdef CONFIG_IRQ_NSTACKS
+#  define IRQ_NSTACKS       CONFIG_IRQ_NSTACKS
+#elif defined CONFIG_SMP
+#  define IRQ_NSTACKS       CONFIG_SMP_NCPUS
+#else
+#  define IRQ_NSTACKS       1
+#endif
+
 /* Processor PC */
 
 #define REG_EPC_NDX         0
@@ -469,7 +481,7 @@ struct xcpt_syscall_s
 {
   uintptr_t sysreturn;   /* The return PC */
 #ifndef CONFIG_BUILD_FLAT
-  uintptr_t int_ctx;     /* Interrupt context (i.e. mstatus) */
+  uintptr_t int_ctx;     /* Interrupt context (i.e. m-/sstatus) */
 #endif
 };
 #endif
@@ -577,9 +589,9 @@ static inline irqstate_t up_irq_save(void)
 
   __asm__ __volatile__
     (
-      "csrrc %0, mstatus, %1\n"
+      "csrrc %0, " __XSTR(CSR_STATUS) ", %1\n"
       : "=r" (flags)
-      : "r"(MSTATUS_MIE)
+      : "r"(STATUS_IE)
       : "memory"
     );
 
@@ -602,7 +614,7 @@ static inline void up_irq_restore(irqstate_t flags)
 {
   __asm__ __volatile__
     (
-      "csrw mstatus, %0\n"
+      "csrw " __XSTR(CSR_STATUS) ", %0\n"
       : /* no output */
       : "r" (flags)
       : "memory"
diff --git a/arch/risc-v/include/mode.h b/arch/risc-v/include/mode.h
new file mode 100644
index 0000000..144fd73
--- /dev/null
+++ b/arch/risc-v/include/mode.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+ * arch/risc-v/include/mode.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_RISCV_INCLUDE_MODE_H
+#define __ARCH_RISCV_INCLUDE_MODE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/irq.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_USE_S_MODE
+
+/* CSR definitions */
+
+#  define CSR_STATUS        sstatus          /* Global status register */
+#  define CSR_EPC           sepc             /* Exception program counter */
+#  define CSR_IE            sie              /* Interrupt enable register */
+#  define CSR_CAUSE         scause           /* Interrupt cause register */
+
+/* In status register */
+
+#  define STATUS_IE         SSTATUS_SIE      /* Global interrupt enable */
+#  define STATUS_PIE        SSTATUS_SPIE     /* Previous interrupt enable */
+#  define STATUS_PPP        SSTATUS_SPPS     /* Previous privilege */
+#  define STATUS_SUM        SSTATUS_SUM      /* Access to user memory */
+
+/* Interrupt bits */
+
+#  define IE_EIE            SIE_SEIE         /* External interrupt enable */
+#  define IE_SIE            SIE_SSIE         /* Software interrupt enable */
+#  define IE_TIE            SIE_STIE         /* Timer interrupt enable */
+
+/* External, timer and software interrupt */
+
+#  define RISCV_IRQ_EXT     RISCV_IRQ_SEXT   /* PLIC IRQ */
+#  define RISCV_IRQ_TIMER   RISCV_IRQ_STIMER /* Timer IRQ */
+#  define RISCV_IRQ_SOFT    RISCV_IRQ_SSOFT  /* SW IRQ */
+
+/* Define return from exception */
+
+#  define ERET              sret
+
+#else
+
+/* CSR definitions */
+
+#  define CSR_STATUS        mstatus          /* Global status register */
+#  define CSR_EPC           mepc             /* Exception program counter */
+#  define CSR_IE            mie              /* Interrupt enable register */
+#  define CSR_CAUSE         mcause           /* Interrupt cause register */
+
+/* In status register */
+
+#  define STATUS_IE         MSTATUS_MIE      /* Global interrupt enable */
+#  define STATUS_PIE        MSTATUS_MPIE     /* Previous interrupt enable */
+#  define STATUS_PPP        MSTATUS_MPPM     /* Previous privilege */
+#  define STATUS_SUM        0                /* Not needed in M-mode */
+
+/* Interrupt bits */
+
+#  define IE_EIE            MIE_MEIE         /* External interrupt enable */
+#  define IE_SIE            MIE_MSIE         /* Software interrupt enable */
+#  define IE_TIE            MIE_MTIE         /* Timer interrupt enable */
+
+/* External, timer and software interrupt */
+
+#  define RISCV_IRQ_EXT     RISCV_IRQ_MEXT   /* PLIC IRQ */
+#  define RISCV_IRQ_TIMER   RISCV_IRQ_MTIMER /* Timer IRQ */
+#  define RISCV_IRQ_SOFT    RISCV_IRQ_MSOFT  /* SW IRQ */
+
+/* Define return from exception */
+
+#  define ERET              mret
+
+#endif
+
+#endif /* __ARCH_RISCV_INCLUDE_MODE_H */
diff --git a/arch/risc-v/include/syscall.h b/arch/risc-v/include/syscall.h
index a357d1d..0a212a6 100644
--- a/arch/risc-v/include/syscall.h
+++ b/arch/risc-v/include/syscall.h
@@ -31,6 +31,8 @@
 
 #include <nuttx/config.h>
 
+#include <arch/arch.h>
+
 #ifndef __ASSEMBLY__
 #  include <stdint.h>
 #endif
@@ -122,50 +124,17 @@
 #define SYS_signal_handler_return (7)
 #endif /* !CONFIG_BUILD_FLAT */
 
-/* sys_call macros **********************************************************/
-
-#ifndef __ASSEMBLY__
-
-/* Context switching system calls *******************************************/
-
-/* SYS call 0:
- *
- * int riscv_saveusercontext(uintptr_t *saveregs);
- *
- * Return:
- * 0: Normal Return
- * 1: Context Switch Return
- */
-
-#define riscv_saveusercontext(saveregs) \
-  (int)sys_call1(SYS_save_context, (uintptr_t)(saveregs))
-
-/* SYS call 1:
- *
- * void riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function;
- */
-
-#define riscv_fullcontextrestore(restoreregs) \
-  sys_call1(SYS_restore_context, (uintptr_t)(restoreregs))
-
-/* SYS call 2:
- *
- * void riscv_switchcontext(uintptr_t **saveregs, uintptr_t *restoreregs);
- */
-
-#define riscv_switchcontext(saveregs, restoreregs) \
-  sys_call2(SYS_switch_context, (uintptr_t)(saveregs), (uintptr_t)(restoreregs))
-
-#ifdef CONFIG_BUILD_KERNEL
-/* SYS call 3:
- *
- * void riscv_syscall_return(void);
- */
-
-#define riscv_syscall_return() sys_call0(SYS_syscall_return)
-
+#if defined (CONFIG_ARCH_USE_S_MODE) && defined (__KERNEL__)
+#  define ASM_SYS_CALL \
+     " addi sp, sp, -16\n"                  /* Make room */ \
+     REGSTORE " ra, 0(sp)\n"                /* Save ra */ \
+     " jal  ra, riscv_syscall_dispatch\n"   /* Dispatch (modifies ra) */ \
+     REGLOAD " ra, 0(sp)\n"                 /* Restore ra */ \
+     " addi sp, sp, 16\n"                   /* Restore sp */
+#else
+#  define ASM_SYS_CALL \
+     "ecall"
 #endif
-#endif /* __ASSEMBLY__ */
 
 /****************************************************************************
  * Public Types
@@ -207,7 +176,7 @@ static inline uintptr_t sys_call0(unsigned int nbr)
 
   asm volatile
     (
-     "ecall"
+     ASM_SYS_CALL
      :: "r"(r0)
      : "memory"
      );
@@ -232,7 +201,7 @@ static inline uintptr_t sys_call1(unsigned int nbr, uintptr_t parm1)
 
   asm volatile
     (
-     "ecall"
+     ASM_SYS_CALL
      :: "r"(r0), "r"(r1)
      : "memory"
      );
@@ -259,7 +228,7 @@ static inline uintptr_t sys_call2(unsigned int nbr, uintptr_t parm1,
 
   asm volatile
     (
-     "ecall"
+     ASM_SYS_CALL
      :: "r"(r0), "r"(r1), "r"(r2)
      : "memory"
      );
@@ -287,7 +256,7 @@ static inline uintptr_t sys_call3(unsigned int nbr, uintptr_t parm1,
 
   asm volatile
     (
-     "ecall"
+     ASM_SYS_CALL
      :: "r"(r0), "r"(r1), "r"(r2), "r"(r3)
      : "memory"
      );
@@ -317,7 +286,7 @@ static inline uintptr_t sys_call4(unsigned int nbr, uintptr_t parm1,
 
   asm volatile
     (
-     "ecall"
+     ASM_SYS_CALL
      :: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4)
      : "memory"
      );
@@ -348,7 +317,7 @@ static inline uintptr_t sys_call5(unsigned int nbr, uintptr_t parm1,
 
   asm volatile
     (
-     "ecall"
+     ASM_SYS_CALL
      :: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5)
      : "memory"
      );
@@ -381,7 +350,7 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1,
 
   asm volatile
     (
-     "ecall"
+     ASM_SYS_CALL
      :: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5), "r"(r6)
      : "memory"
      );
diff --git a/arch/risc-v/src/Makefile b/arch/risc-v/src/Makefile
index f598c6f..ad45227 100644
--- a/arch/risc-v/src/Makefile
+++ b/arch/risc-v/src/Makefile
@@ -24,6 +24,12 @@ ifeq ($(CONFIG_OPENSBI),y)
 include opensbi/Make.defs
 endif
 
+# Kernel runs in supervisor mode or machine mode ?
+
+ifeq ($(CONFIG_ARCH_USE_S_MODE),y)
+include common/supervisor/Make.defs
+endif
+
 ARCH_SRCDIR = $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src
 
 INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)chip}
diff --git a/arch/risc-v/src/bl602/Make.defs b/arch/risc-v/src/bl602/Make.defs
index b33f44c..5f4c854 100644
--- a/arch/risc-v/src/bl602/Make.defs
+++ b/arch/risc-v/src/bl602/Make.defs
@@ -34,6 +34,7 @@ CMN_CSRCS += riscv_releasepending.c riscv_reprioritizertr.c
 CMN_CSRCS += riscv_releasestack.c riscv_stackframe.c riscv_schedulesigaction.c
 CMN_CSRCS += riscv_sigdeliver.c riscv_udelay.c riscv_unblocktask.c riscv_usestack.c
 CMN_CSRCS += riscv_idle.c riscv_tcbinfo.c riscv_getnewintctx.c riscv_doirq.c
+CMN_CSRCS += riscv_cpuindex.c
 
 ifeq ($(CONFIG_SCHED_BACKTRACE),y)
 CMN_CSRCS += riscv_backtrace.c
diff --git a/arch/risc-v/src/c906/Make.defs b/arch/risc-v/src/c906/Make.defs
index 889bdcb..6406e8c 100644
--- a/arch/risc-v/src/c906/Make.defs
+++ b/arch/risc-v/src/c906/Make.defs
@@ -34,7 +34,7 @@ CMN_CSRCS += riscv_releasepending.c riscv_reprioritizertr.c
 CMN_CSRCS += riscv_releasestack.c riscv_stackframe.c riscv_schedulesigaction.c
 CMN_CSRCS += riscv_sigdeliver.c riscv_unblocktask.c riscv_usestack.c
 CMN_CSRCS += riscv_mdelay.c riscv_idle.c riscv_doirq.c
-CMN_CSRCS += riscv_tcbinfo.c riscv_getnewintctx.c
+CMN_CSRCS += riscv_tcbinfo.c riscv_getnewintctx.c riscv_cpuindex.c
 
 ifeq ($(CONFIG_SCHED_BACKTRACE),y)
 CMN_CSRCS += riscv_backtrace.c
diff --git a/arch/risc-v/src/common/riscv_cpuindex.c b/arch/risc-v/src/common/riscv_cpuindex.c
index 45e252f..fe49065 100644
--- a/arch/risc-v/src/common/riscv_cpuindex.c
+++ b/arch/risc-v/src/common/riscv_cpuindex.c
@@ -48,7 +48,16 @@
 
 uintptr_t riscv_mhartid(void)
 {
+#ifdef CONFIG_ARCH_USE_S_MODE
+  /* Kernel is in S-mode */
+
+#error "Missing functionality..."
+
+#else
+  /* Kernel is in M-mode */
+
   return READ_CSR(mhartid);
+#endif
 }
 
 /****************************************************************************
diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/riscv_exception_common.S
index 3daa5ce..f0603f9 100644
--- a/arch/risc-v/src/common/riscv_exception_common.S
+++ b/arch/risc-v/src/common/riscv_exception_common.S
@@ -26,6 +26,9 @@
 
 #include <arch/arch.h>
 #include <arch/irq.h>
+#include <arch/mode.h>
+
+#include "riscv_exception_macros.S"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -50,16 +53,13 @@
  * Public Symbols
  ****************************************************************************/
 
-#ifdef CONFIG_IRQ_NSTACKS
-#  define IRQ_NSTACKS CONFIG_IRQ_NSTACKS
-#elif defined CONFIG_SMP
-#  define IRQ_NSTACKS CONFIG_SMP_NCPUS
-#else
-#  define IRQ_NSTACKS 1
-#endif
-
 /****************************************************************************
  * Name: exception_common
+ *
+ * Description:
+ *   Handles interrupts. If kernel is in S-mode, handles delegated interrupts
+ *   in S-mode interrupt handler.
+ *
  ****************************************************************************/
 
   .section .text
@@ -69,48 +69,16 @@
 exception_common:
 
   addi       sp, sp, -XCPTCONTEXT_SIZE
+  save_ctx   sp
 
-  REGSTORE   x1,  REG_X1(sp)   /* ra */
-#ifdef RISCV_SAVE_GP
-  REGSTORE   x3,  REG_X3(sp)   /* gp */
-#endif
-  REGSTORE   x4,  REG_X4(sp)   /* tp */
-  REGSTORE   x5,  REG_X5(sp)   /* t0 */
-  REGSTORE   x6,  REG_X6(sp)   /* t1 */
-  REGSTORE   x7,  REG_X7(sp)   /* t2 */
-  REGSTORE   x8,  REG_X8(sp)   /* s0 */
-  REGSTORE   x9,  REG_X9(sp)   /* s1 */
-  REGSTORE   x10, REG_X10(sp)  /* a0 */
-  REGSTORE   x11, REG_X11(sp)  /* a1 */
-  REGSTORE   x12, REG_X12(sp)  /* a2 */
-  REGSTORE   x13, REG_X13(sp)  /* a3 */
-  REGSTORE   x14, REG_X14(sp)  /* a4 */
-  REGSTORE   x15, REG_X15(sp)  /* a5 */
-  REGSTORE   x16, REG_X16(sp)  /* a6 */
-  REGSTORE   x17, REG_X17(sp)  /* a7 */
-  REGSTORE   x18, REG_X18(sp)  /* s2 */
-  REGSTORE   x19, REG_X19(sp)  /* s3 */
-  REGSTORE   x20, REG_X20(sp)  /* s4 */
-  REGSTORE   x21, REG_X21(sp)  /* s5 */
-  REGSTORE   x22, REG_X22(sp)  /* s6 */
-  REGSTORE   x23, REG_X23(sp)  /* s7 */
-  REGSTORE   x24, REG_X24(sp)  /* s8 */
-  REGSTORE   x25, REG_X25(sp)  /* s9 */
-  REGSTORE   x26, REG_X26(sp)  /* s10 */
-  REGSTORE   x27, REG_X27(sp)  /* s11 */
-  REGSTORE   x28, REG_X28(sp)  /* t3 */
-  REGSTORE   x29, REG_X29(sp)  /* t4 */
-  REGSTORE   x30, REG_X30(sp)  /* t5 */
-  REGSTORE   x31, REG_X31(sp)  /* t6 */
-
-  csrr       s0, mstatus
-  REGSTORE   s0, REG_INT_CTX(sp)  /* mstatus          */
+  csrr       s0, CSR_STATUS
+  REGSTORE   s0, REG_INT_CTX(sp)  /* status */
 
   addi       s0, sp, XCPTCONTEXT_SIZE
-  REGSTORE   s0, REG_X2(sp)       /* original SP      */
+  REGSTORE   s0, REG_X2(sp)       /* original SP */
 
-  csrr       s0, mepc
-  REGSTORE   s0, REG_EPC(sp)      /* exception PC     */
+  csrr       s0, CSR_EPC
+  REGSTORE   s0, REG_EPC(sp)      /* exception PC */
 
 #ifdef CONFIG_ARCH_FPU
   mv         a0, sp
@@ -119,24 +87,29 @@ exception_common:
 
   /* Setup arg0(exception cause), arg1(context) */
 
-  csrr       a0, mcause           /* exception cause  */
+  csrr       a0, CSR_CAUSE        /* exception cause */
   mv         a1, sp               /* context = sp */
 
 #if CONFIG_ARCH_INTERRUPTSTACK > 15
-  /* Load mhartid (cpuid) */
 
-  csrr       s0, mhartid
+  /* Offset to hartid */
+
+  mv         s0, a0               /* save cause */
+  jal        x1, riscv_mhartid    /* get hartid */
 
   /* Switch to interrupt stack */
+
 #if IRQ_NSTACKS > 1
   li         t0, (CONFIG_ARCH_INTERRUPTSTACK & ~15)
-  mul        t0, s0, t0
-  la         s0, g_intstacktop
-  sub        sp, s0, t0
+  mul        t0, a0, t0
+  la         a0, g_intstacktop
+  sub        sp, a0, t0
 #else
   la         sp, g_intstacktop
 #endif
 
+  mv         a0, s0               /* restore cause */
+
   /* Call interrupt handler in C */
 
   jal        x1, riscv_dispatch_irq
@@ -159,62 +132,27 @@ exception_common:
   jal        x1, riscv_restorefpu /* restore FPU context */
 #endif
 
-  /* If context switch is needed, return a new sp     */
+  /* If context switch is needed, return a new sp */
 
   mv         sp, a0
-  REGLOAD    s0, REG_EPC(sp)     /* restore mepc      */
-  csrw       mepc, s0
 
-  REGLOAD    s0, REG_INT_CTX(sp) /* restore mstatus   */
-  csrw       mstatus, s0
+  REGLOAD    s0, REG_EPC(sp)      /* restore sepc */
+  csrw       CSR_EPC, s0
 
-#ifdef RISCV_SAVE_GP
-  REGLOAD    x3,  REG_X3(sp)   /* gp */
-#endif
-  REGLOAD    x4,  REG_X4(sp)   /* tp */
-  REGLOAD    x5,  REG_X5(sp)   /* t0 */
-  REGLOAD    x6,  REG_X6(sp)   /* t1 */
-  REGLOAD    x7,  REG_X7(sp)   /* t2 */
-  REGLOAD    x8,  REG_X8(sp)   /* s0 */
-  REGLOAD    x9,  REG_X9(sp)   /* s1 */
-  REGLOAD    x10, REG_X10(sp)  /* a0 */
-  REGLOAD    x11, REG_X11(sp)  /* a1 */
-  REGLOAD    x12, REG_X12(sp)  /* a2 */
-  REGLOAD    x13, REG_X13(sp)  /* a3 */
-  REGLOAD    x14, REG_X14(sp)  /* a4 */
-  REGLOAD    x15, REG_X15(sp)  /* a5 */
-  REGLOAD    x16, REG_X16(sp)  /* a6 */
-  REGLOAD    x17, REG_X17(sp)  /* a7 */
-  REGLOAD    x18, REG_X18(sp)  /* s2 */
-  REGLOAD    x19, REG_X19(sp)  /* s3 */
-  REGLOAD    x20, REG_X20(sp)  /* s4 */
-  REGLOAD    x21, REG_X21(sp)  /* s5 */
-  REGLOAD    x22, REG_X22(sp)  /* s6 */
-  REGLOAD    x23, REG_X23(sp)  /* s7 */
-  REGLOAD    x24, REG_X24(sp)  /* s8 */
-  REGLOAD    x25, REG_X25(sp)  /* s9 */
-  REGLOAD    x26, REG_X26(sp)  /* s10 */
-  REGLOAD    x27, REG_X27(sp)  /* s11 */
-  REGLOAD    x28, REG_X28(sp)  /* t3 */
-  REGLOAD    x29, REG_X29(sp)  /* t4 */
-  REGLOAD    x30, REG_X30(sp)  /* t5 */
-  REGLOAD    x31, REG_X31(sp)  /* t6 */
-
-  REGLOAD    x1,  REG_X1(sp)   /* ra */
-
-  REGLOAD    sp,  REG_X2(sp)   /* restore original sp */
-
-  /* Return from Machine Interrupt */
-
-  mret
-
-/************************************************************************************
- *  Name: g_intstackalloc and g_intstacktop
- ************************************************************************************/
+  REGLOAD    s0, REG_INT_CTX(sp)  /* restore sstatus */
+  csrw       CSR_STATUS, s0
+
+  load_ctx   sp
 
-/************************************************************************************
+  REGLOAD    sp, REG_SP(sp)       /* restore original sp */
+
+  /* Return from exception */
+
+  ERET
+
+/*****************************************************************************
  *  Name: g_intstackalloc and g_intstacktop
- ************************************************************************************/
+ ****************************************************************************/
 
 #if CONFIG_ARCH_INTERRUPTSTACK > 15
   .bss
diff --git a/arch/risc-v/src/common/riscv_exception_macros.S b/arch/risc-v/src/common/riscv_exception_macros.S
new file mode 100644
index 0000000..d2f3291
--- /dev/null
+++ b/arch/risc-v/src/common/riscv_exception_macros.S
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * arch/risc-v/src/common/supervisor/riscv_exception_macros.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.
+ *
+ ****************************************************************************/
+
+.file "riscv_exception_macros.S"
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <arch/arch.h>
+#include <arch/irq.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: save_ctx
+ *
+ * Parameter:
+ *   in - Pointer to where the save is performed (e.g. sp)
+ *
+ * Description:
+ *   Save the common context registers (i.e. work / temp / etc).
+ *
+ ****************************************************************************/
+
+.macro save_ctx in
+
+  REGSTORE   x1,  REG_X1(\in)    /* ra */
+#ifdef RISCV_SAVE_GP
+  REGSTORE   x3,  REG_X3(\in)    /* gp */
+#endif
+  REGSTORE   x4,  REG_X4(\in)    /* tp */
+  REGSTORE   x5,  REG_X5(\in)    /* t0 */
+  REGSTORE   x6,  REG_X6(\in)    /* t1 */
+  REGSTORE   x7,  REG_X7(\in)    /* t2 */
+  REGSTORE   x8,  REG_X8(\in)    /* s0 */
+  REGSTORE   x9,  REG_X9(\in)    /* s1 */
+  REGSTORE   x10, REG_X10(\in)   /* a0 */
+  REGSTORE   x11, REG_X11(\in)   /* a1 */
+  REGSTORE   x12, REG_X12(\in)   /* a2 */
+  REGSTORE   x13, REG_X13(\in)   /* a3 */
+  REGSTORE   x14, REG_X14(\in)   /* a4 */
+  REGSTORE   x15, REG_X15(\in)   /* a5 */
+  REGSTORE   x16, REG_X16(\in)   /* a6 */
+  REGSTORE   x17, REG_X17(\in)   /* a7 */
+  REGSTORE   x18, REG_X18(\in)   /* s2 */
+  REGSTORE   x19, REG_X19(\in)   /* s3 */
+  REGSTORE   x20, REG_X20(\in)   /* s4 */
+  REGSTORE   x21, REG_X21(\in)   /* s5 */
+  REGSTORE   x22, REG_X22(\in)   /* s6 */
+  REGSTORE   x23, REG_X23(\in)   /* s7 */
+  REGSTORE   x24, REG_X24(\in)   /* s8 */
+  REGSTORE   x25, REG_X25(\in)   /* s9 */
+  REGSTORE   x26, REG_X26(\in)   /* s10 */
+  REGSTORE   x27, REG_X27(\in)   /* s11 */
+  REGSTORE   x28, REG_X28(\in)   /* t3 */
+  REGSTORE   x29, REG_X29(\in)   /* t4 */
+  REGSTORE   x30, REG_X30(\in)   /* t5 */
+  REGSTORE   x31, REG_X31(\in)   /* t6 */
+
+.endm
+
+/****************************************************************************
+ * Name: load_ctx
+ *
+ * Parameter:
+ *   out - Pointer to where the load is performed (e.g. sp)
+ *
+ * Description:
+ *   Load the common context registers (i.e. work / temp / etc).
+ *
+ ****************************************************************************/
+
+.macro load_ctx out
+
+  REGLOAD    x1,  REG_X1(\out)   /* ra */
+#ifdef RISCV_SAVE_GP
+  REGLOAD    x3,  REG_X3(\out)   /* gp */
+#endif
+  REGLOAD    x4,  REG_X4(\out)   /* tp */
+  REGLOAD    x5,  REG_X5(\out)   /* t0 */
+  REGLOAD    x6,  REG_X6(\out)   /* t1 */
+  REGLOAD    x7,  REG_X7(\out)   /* t2 */
+  REGLOAD    x8,  REG_X8(\out)   /* s0 */
+  REGLOAD    x9,  REG_X9(\out)   /* s1 */
+  REGLOAD    x10, REG_X10(\out)  /* a0 */
+  REGLOAD    x11, REG_X11(\out)  /* a1 */
+  REGLOAD    x12, REG_X12(\out)  /* a2 */
+  REGLOAD    x13, REG_X13(\out)  /* a3 */
+  REGLOAD    x14, REG_X14(\out)  /* a4 */
+  REGLOAD    x15, REG_X15(\out)  /* a5 */
+  REGLOAD    x16, REG_X16(\out)  /* a6 */
+  REGLOAD    x17, REG_X17(\out)  /* a7 */
+  REGLOAD    x18, REG_X18(\out)  /* s2 */
+  REGLOAD    x19, REG_X19(\out)  /* s3 */
+  REGLOAD    x20, REG_X20(\out)  /* s4 */
+  REGLOAD    x21, REG_X21(\out)  /* s5 */
+  REGLOAD    x22, REG_X22(\out)  /* s6 */
+  REGLOAD    x23, REG_X23(\out)  /* s7 */
+  REGLOAD    x24, REG_X24(\out)  /* s8 */
+  REGLOAD    x25, REG_X25(\out)  /* s9 */
+  REGLOAD    x26, REG_X26(\out)  /* s10 */
+  REGLOAD    x27, REG_X27(\out)  /* s11 */
+  REGLOAD    x28, REG_X28(\out)  /* t3 */
+  REGLOAD    x29, REG_X29(\out)  /* t4 */
+  REGLOAD    x30, REG_X30(\out)  /* t5 */
+  REGLOAD    x31, REG_X31(\out)  /* t6 */
+
+.endm
diff --git a/arch/risc-v/src/common/riscv_fpu.S b/arch/risc-v/src/common/riscv_fpu.S
index 2d3de5b..3c29465 100644
--- a/arch/risc-v/src/common/riscv_fpu.S
+++ b/arch/risc-v/src/common/riscv_fpu.S
@@ -26,6 +26,7 @@
 
 #include <arch/arch.h>
 #include <arch/irq.h>
+#include <arch/mode.h>
 
 #ifdef CONFIG_ARCH_FPU
 
@@ -74,7 +75,7 @@
 
 riscv_fpuconfig:
     li           a0, FS_INITIAL
-    csrs         mstatus, a0
+    csrs         CSR_STATUS, a0
     csrwi        fcsr, 0
     ret
 
diff --git a/arch/risc-v/src/common/riscv_getnewintctx.c b/arch/risc-v/src/common/riscv_getnewintctx.c
index 6b7619a..f1fa4cf 100644
--- a/arch/risc-v/src/common/riscv_getnewintctx.c
+++ b/arch/risc-v/src/common/riscv_getnewintctx.c
@@ -32,6 +32,8 @@
 #include <nuttx/arch.h>
 #include <nuttx/irq.h>
 
+#include <arch/mode.h>
+
 #include "riscv_internal.h"
 
 /****************************************************************************
@@ -48,23 +50,23 @@
 
 uintptr_t riscv_get_newintctx(void)
 {
-  /* Set machine previous privilege mode to machine mode. Reegardless of
+  /* Set machine previous privilege mode to privileged mode. Regardless of
    * how NuttX is configured and of what kind of thread is being started.
    * That is because all threads, even user-mode threads will start in
    * kernel trampoline at nxtask_start() or pthread_start().
    * The thread's privileges will be dropped before transitioning to
-   * user code. Also set machine previous interrupt enable.
+   * user code. Also set machine / supervisor previous interrupt enable.
    *
    * Mask the bits which should be preserved (from ISA spec)
    */
 
-  uintptr_t mstatus = READ_CSR(mstatus);
+  uintptr_t status = READ_CSR(CSR_STATUS);
 
-  mstatus &= MSTATUS_WPRI;
+  status &= MSTATUS_WPRI;
 
-  return (mstatus | MSTATUS_MPPM | MSTATUS_MPIE
+  return (status | STATUS_PPP | STATUS_SUM | STATUS_PIE
 #ifdef CONFIG_ARCH_FPU
-                  | MSTATUS_FS_INIT
+                 | MSTATUS_FS_INIT
 #endif
   );
 }
diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h
index 34317d7..976a7f6 100644
--- a/arch/risc-v/src/common/riscv_internal.h
+++ b/arch/risc-v/src/common/riscv_internal.h
@@ -32,6 +32,7 @@
 #  include <nuttx/arch.h>
 #  include <sys/types.h>
 #  include <stdint.h>
+#  include <syscall.h>
 #endif
 
 /****************************************************************************
@@ -315,6 +316,53 @@ int riscv_pause_handler(int irq, void *c, void *arg);
 
 uintptr_t riscv_mhartid(void);
 
+/* If kernel runs in Supervisor mode, a system call trampoline is needed */
+
+#ifdef CONFIG_ARCH_USE_S_MODE
+void riscv_syscall_dispatch(void) noreturn_function;
+void *riscv_perform_syscall(uintptr_t *regs);
+#endif
+
+/* Context switching via system calls ***************************************/
+
+/* SYS call 0:
+ *
+ * int riscv_saveusercontext(uintptr_t *saveregs);
+ *
+ * Return:
+ * 0: Normal Return
+ * 1: Context Switch Return
+ */
+
+#define riscv_saveusercontext(saveregs) \
+  sys_call1(SYS_save_context, (uintptr_t)saveregs)
+
+/* SYS call 1:
+ *
+ * void riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function;
+ */
+
+#define riscv_fullcontextrestore(restoreregs) \
+  sys_call1(SYS_restore_context, (uintptr_t)restoreregs)
+
+/* SYS call 2:
+ *
+ * void riscv_switchcontext(uintptr_t *saveregs, uintptr_t *restoreregs);
+ */
+
+#define riscv_switchcontext(saveregs, restoreregs) \
+  sys_call2(SYS_switch_context, (uintptr_t)saveregs, (uintptr_t)restoreregs)
+
+#ifdef CONFIG_BUILD_KERNEL
+/* SYS call 3:
+ *
+ * void riscv_syscall_return(void);
+ */
+
+#define riscv_syscall_return() sys_call0(SYS_syscall_return)
+
+#endif /* CONFIG_BUILD_KERNEL */
+
 #undef EXTERN
 #ifdef __cplusplus
 }
diff --git a/arch/risc-v/src/common/riscv_schedulesigaction.c b/arch/risc-v/src/common/riscv_schedulesigaction.c
index e8c5eab..a68b077 100644
--- a/arch/risc-v/src/common/riscv_schedulesigaction.c
+++ b/arch/risc-v/src/common/riscv_schedulesigaction.c
@@ -146,12 +146,13 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
                * privileged thread mode.
                */
 
-              tcb->xcp.sigdeliver         = sigdeliver;
-              CURRENT_REGS[REG_EPC]       = (uintptr_t)riscv_sigdeliver;
-              int_ctx                     = CURRENT_REGS[REG_INT_CTX];
-              int_ctx                    &= ~MSTATUS_MPIE;
+              tcb->xcp.sigdeliver       = sigdeliver;
+              CURRENT_REGS[REG_EPC]     = (uintptr_t)riscv_sigdeliver;
+
+              int_ctx                   = CURRENT_REGS[REG_INT_CTX];
+              int_ctx                  &= ~STATUS_PIE;
 #ifndef CONFIG_BUILD_FLAT
-              int_ctx                    |= MSTATUS_MPPM;
+              int_ctx                  |= STATUS_PPP;
 #endif
 
               CURRENT_REGS[REG_INT_CTX] = int_ctx;
@@ -201,7 +202,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
 
           tcb->xcp.regs[REG_EPC]      = (uintptr_t)riscv_sigdeliver;
           int_ctx                     = tcb->xcp.regs[REG_INT_CTX];
-          int_ctx                    &= ~MSTATUS_MPIE;
+          int_ctx                    &= ~STATUS_PIE;
 
           tcb->xcp.regs[REG_INT_CTX]  = int_ctx;
 
@@ -312,9 +313,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
 
                   tcb->xcp.regs[REG_EPC]     = (uintptr_t)riscv_sigdeliver;
                   int_ctx                    = tcb->xcp.regs[REG_INT_CTX];
-                  int_ctx                   &= ~MSTATUS_MPIE;
-#ifdef CONFIG_BUILD_PROTECTED
-                  int_ctx                   |= MSTATUS_MPPM;
+                  int_ctx                   &= ~STATUS_PIE;
+#ifndef CONFIG_BUILD_FLAT
+                  int_ctx                   |= STATUS_PPP;
 #endif
                   tcb->xcp.regs[REG_INT_CTX] = int_ctx;
                 }
@@ -353,9 +354,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
                   CURRENT_REGS[REG_EPC]     = (uintptr_t)riscv_sigdeliver;
 
                   int_ctx                   = CURRENT_REGS[REG_INT_CTX];
-                  int_ctx                  &= ~MSTATUS_MPIE;
+                  int_ctx                  &= ~STATUS_PIE;
 #ifndef CONFIG_BUILD_FLAT
-                  int_ctx                  |= MSTATUS_MPPM;
+                  int_ctx                  |= STATUS_PPP;
 #endif
 
                   CURRENT_REGS[REG_INT_CTX] = int_ctx;
@@ -429,7 +430,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
           tcb->xcp.regs[REG_EPC]     = (uintptr_t)riscv_sigdeliver;
 
           int_ctx                    = tcb->xcp.regs[REG_INT_CTX];
-          int_ctx                   &= ~MSTATUS_MPIE;
+          int_ctx                   &= ~STATUS_PIE;
 
           tcb->xcp.regs[REG_INT_CTX] = int_ctx;
         }
diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c
index d2955a4..c01866d 100644
--- a/arch/risc-v/src/common/riscv_swint.c
+++ b/arch/risc-v/src/common/riscv_swint.c
@@ -122,13 +122,17 @@ static void dispatch_syscall(void)
      "slli a0, a0, 3\n"                     /* a0=Offset for the stub lookup table */
 #endif
      "add  t0, t0, a0\n"                    /* t0=The address in the table */
-     REGLOAD "   t0, 0(t0)\n"               /* t0=The address of the stub for this syscall */
+     REGLOAD " t0, 0(t0)\n"                 /* t0=The address of the stub for this syscall */
      "jalr ra, t0\n"                        /* Call the stub (modifies ra) */
      REGLOAD " ra, 0(sp)\n"                 /* Restore ra */
      "addi sp, sp, " STACK_FRAME_SIZE "\n"  /* Destroy the stack frame */
      "mv   a2, a0\n"                        /* a2=Save return value in a0 */
      "li   a0, 3\n"                         /* a0=SYS_syscall_return (3) */
-     "ecall"                                /* Return from the syscall */
+#ifdef CONFIG_ARCH_USE_S_MODE
+     " j    riscv_syscall_dispatch"         /* Return from the syscall */
+#else
+     " ecall"                               /* Return from the syscall */
+#endif
   );
 }
 #endif
@@ -332,7 +336,7 @@ int riscv_swint(int irq, void *context, void *arg)
           regs[REG_A0]       = regs[REG_A2]; /* argc */
           regs[REG_A1]       = regs[REG_A3]; /* argv */
 #endif
-          regs[REG_INT_CTX] &= ~MSTATUS_MPPM; /* User mode */
+          regs[REG_INT_CTX] &= ~STATUS_PPP; /* User mode */
         }
         break;
 #endif
@@ -364,7 +368,7 @@ int riscv_swint(int irq, void *context, void *arg)
 
           regs[REG_A0]       = regs[REG_A2];  /* pthread entry */
           regs[REG_A1]       = regs[REG_A3];  /* arg */
-          regs[REG_INT_CTX] &= ~MSTATUS_MPPM; /* User mode */
+          regs[REG_INT_CTX] &= ~STATUS_PPP;   /* User mode */
         }
         break;
 #endif
@@ -403,7 +407,7 @@ int riscv_swint(int irq, void *context, void *arg)
           regs[REG_EPC]        =
               (uintptr_t)ARCH_DATA_RESERVE->ar_sigtramp & ~1;
 #endif
-          regs[REG_INT_CTX]   &= ~MSTATUS_MPPM; /* User mode */
+          regs[REG_INT_CTX]   &= ~STATUS_PPP; /* User mode */
 
           /* Change the parameter ordering to match the expectation of struct
            * userpace_s signal_handler.
@@ -453,7 +457,7 @@ int riscv_swint(int irq, void *context, void *arg)
 
           DEBUGASSERT(rtcb->xcp.sigreturn != 0);
           regs[REG_EPC]        = rtcb->xcp.sigreturn & ~1;
-          regs[REG_INT_CTX]   |= MSTATUS_MPPM; /* Machine mode */
+          regs[REG_INT_CTX]   |= STATUS_PPP; /* Privileged mode */
 
           rtcb->xcp.sigreturn  = 0;
 
@@ -501,7 +505,7 @@ int riscv_swint(int irq, void *context, void *arg)
 
           rtcb->xcp.syscall[index].sysreturn  = regs[REG_EPC];
 #ifndef CONFIG_BUILD_FLAT
-          rtcb->xcp.syscall[index].int_ctx     = regs[REG_INT_CTX];
+          rtcb->xcp.syscall[index].int_ctx    = regs[REG_INT_CTX];
 #endif
 
           rtcb->xcp.nsyscalls  = index + 1;
@@ -509,7 +513,7 @@ int riscv_swint(int irq, void *context, void *arg)
           regs[REG_EPC]        = (uintptr_t)dispatch_syscall & ~1;
 
 #ifndef CONFIG_BUILD_FLAT
-          regs[REG_INT_CTX]   |= MSTATUS_MPPM; /* Machine mode */
+          regs[REG_INT_CTX]   |= STATUS_PPP; /* Privileged mode */
 #endif
 
           /* Offset A0 to account for the reserved values */
diff --git a/arch/risc-v/src/common/riscv_vectors.S b/arch/risc-v/src/common/riscv_vectors.S
index d7f0163..8f68eda 100644
--- a/arch/risc-v/src/common/riscv_vectors.S
+++ b/arch/risc-v/src/common/riscv_vectors.S
@@ -23,11 +23,16 @@
  ****************************************************************************/
 
   .section .text
-  .balign  4
+  .balign  8
   .global  __trap_vec
 
 /****************************************************************************
- * Name: exception_common
+ * Name: __trap_vec
+ *
+ * Description:
+ *   All M-mode exceptions and interrupts will be handled from here. If
+ *   kernel is in S-mode delegated exceptions and interrupts are handled.
+ *
  ****************************************************************************/
 
 __trap_vec:
diff --git a/arch/risc-v/src/common/supervisor/Make.defs b/arch/risc-v/src/common/supervisor/Make.defs
new file mode 100644
index 0000000..3146d4e
--- /dev/null
+++ b/arch/risc-v/src/common/supervisor/Make.defs
@@ -0,0 +1,28 @@
+############################################################################
+# arch/risc-v/src/common/supervisor/Make.defs
+#
+# 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.
+#
+############################################################################
+
+# If the NuttX kernel runs in S-mode
+
+CMN_ASRCS += riscv_syscall_dispatch.S
+CMN_CSRCS += riscv_sbi.c riscv_perform_syscall.c
+CMN_CSRCS += riscv_percpu.c
+
+INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)common$(DELIM)supervisor}
+VPATH += common$(DELIM)supervisor
diff --git a/arch/risc-v/src/common/riscv_vectors.S b/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c
similarity index 60%
copy from arch/risc-v/src/common/riscv_vectors.S
copy to arch/risc-v/src/common/supervisor/riscv_perform_syscall.c
index d7f0163..af32ec2 100644
--- a/arch/risc-v/src/common/riscv_vectors.S
+++ b/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/risc-v/src/common/riscv_vectors.S
+ * arch/risc-v/src/common/supervisor/riscv_perform_syscall.c
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,14 +22,44 @@
  * Included Files
  ****************************************************************************/
 
-  .section .text
-  .balign  4
-  .global  __trap_vec
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include "riscv_internal.h"
+#include "group/group.h"
 
 /****************************************************************************
- * Name: exception_common
+ * Public Functions
  ****************************************************************************/
 
-__trap_vec:
-  j    exception_common
-  nop
+void *riscv_perform_syscall(uintptr_t *regs)
+{
+  /* Set up the interrupt register set needed by swint() */
+
+  CURRENT_REGS = regs;
+
+  /* Run the system call handler (swint) */
+
+  riscv_swint(0, regs, NULL);
+
+#ifdef CONFIG_ARCH_ADDRENV
+  if (regs != CURRENT_REGS)
+    {
+      /* Make sure that the address environment for the previously
+       * running task is closed down gracefully (data caches dump,
+       * MMU flushed) and set up the address environment for the new
+       * thread at the head of the ready-to-run list.
+       */
+
+      group_addrenv(NULL);
+    }
+#endif
+
+  /* Set new context */
+
+  regs = (uintptr_t *)CURRENT_REGS;
+  CURRENT_REGS = NULL;
+
+  return regs;
+}
diff --git a/arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.S b/arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.S
new file mode 100644
index 0000000..5e2fd2f
--- /dev/null
+++ b/arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.S
@@ -0,0 +1,148 @@
+/****************************************************************************
+ * arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.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.
+ *
+ ****************************************************************************/
+
+.file "riscv_syscall_dispatch.S"
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <arch/mode.h>
+
+#include "riscv_exception_macros.S"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Symbols
+ ****************************************************************************/
+
+    .globl  riscv_syscall_dispatch
+
+/****************************************************************************
+ * Name: riscv_syscall_dispatch
+ *
+ * Description:
+ *   Dispatch syscall from kernel
+ *
+ * C Function Prototype:
+ *   void riscv_syscall_dispatch(void);
+ *
+ * Input Parameters:
+ *   Assumes the context to return is already set up
+ *
+ * Returned Value:
+ *   Return value of system call is returned into contex
+ *
+ * Assumptions:
+ *   Task is running in privileged mode
+ *
+ ****************************************************************************/
+
+.type riscv_syscall_dispatch, function
+
+riscv_syscall_dispatch:
+
+  addi       sp, sp, -XCPTCONTEXT_SIZE /* make room */
+  save_ctx   sp                        /* save current context */
+
+  /* Mask interrupts and store the status register to context */
+
+  li         s1, STATUS_IE             /* move IE -> PIE */
+  csrrc      s0, CSR_STATUS, s1
+  and        s1, s0, s1                /* if (STATUS & IE) */
+  beqz       s1, 1f
+  li         s1, ~STATUS_IE            /* clear IE */
+  and        s0, s0, s1
+  li         s1, STATUS_PIE            /* set PIE */
+  or         s0, s0, s1
+
+ 1:
+  /* Set previous privilege, we are in privileged mode now */
+
+  li         s1, STATUS_PPP            /* set previous privilege */
+  or         s0, s0, s1
+  REGSTORE   s0, REG_INT_CTX(sp)       /* store status to context */
+
+  REGSTORE   x1, REG_EPC(sp)           /* save ra to epc */
+
+  addi       s0, sp, XCPTCONTEXT_SIZE
+  REGSTORE   s0, REG_SP(sp)            /* original SP */
+
+#ifdef CONFIG_ARCH_FPU
+  mv         a0, sp
+  jal        x1, riscv_savefpu         /* FP registers */
+#endif
+
+  mv         a0, sp                    /* a0 = context */
+
+  /* Switch to interrupt stack */
+
+#if CONFIG_ARCH_INTERRUPTSTACK > 15
+#if IRQ_NSTACKS > 1
+  jal        x1, riscv_mhartid    /* get hartid */
+  li         t0, (CONFIG_ARCH_INTERRUPTSTACK & ~15)
+  mul        t0, a0, t0
+  la         a0, g_intstacktop
+  sub        sp, a0, t0
+#else
+  la         sp, g_intstacktop
+#endif
+#endif
+
+  /* Run the handler */
+
+  jal        x1, riscv_perform_syscall
+
+  /* Restore (potentially new) context */
+
+  mv         sp, a0                    /* use sp, as a0 gets wiped */
+
+#ifdef CONFIG_ARCH_FPU
+  jal        x1, riscv_restorefpu      /* FP registers */
+#endif
+
+  REGLOAD    s0, REG_EPC(sp)           /* restore epc */
+  csrw       CSR_EPC, s0
+
+  /* Restore status register, but don't enable interrupts yet */
+
+  REGLOAD    s0, REG_INT_CTX(sp)       /* restore status */
+  li         s1, STATUS_IE             /* move IE -> PIE */
+  and        s1, s0, s1                /* if (STATUS & IE) */
+  beqz       s1, 1f
+  li         s1, ~STATUS_IE            /* clear IE */
+  and        s0, s0, s1
+  li         s1, STATUS_PIE            /* set PIE */
+  or         s0, s0, s1
+
+1:
+  csrw       CSR_STATUS, s0
+
+  load_ctx   sp
+
+  REGLOAD    sp, REG_SP(sp)            /* restore original sp */
+
+  /* return from exception, which updates the status register */
+
+  ERET
diff --git a/arch/risc-v/src/esp32c3/Make.defs b/arch/risc-v/src/esp32c3/Make.defs
index 0161d90..74e83b5 100644
--- a/arch/risc-v/src/esp32c3/Make.defs
+++ b/arch/risc-v/src/esp32c3/Make.defs
@@ -37,6 +37,7 @@ CMN_CSRCS += riscv_releasepending.c riscv_reprioritizertr.c
 CMN_CSRCS += riscv_releasestack.c riscv_stackframe.c riscv_schedulesigaction.c
 CMN_CSRCS += riscv_sigdeliver.c riscv_udelay.c riscv_unblocktask.c riscv_usestack.c
 CMN_CSRCS += riscv_tcbinfo.c riscv_getnewintctx.c riscv_doirq.c
+CMN_CSRCS += riscv_cpuindex.c
 
 ifeq ($(CONFIG_SCHED_BACKTRACE),y)
 CMN_CSRCS += riscv_backtrace.c
diff --git a/arch/risc-v/src/fe310/Make.defs b/arch/risc-v/src/fe310/Make.defs
index 8ebd460..751d3ed 100644
--- a/arch/risc-v/src/fe310/Make.defs
+++ b/arch/risc-v/src/fe310/Make.defs
@@ -34,6 +34,7 @@ CMN_CSRCS += riscv_releasepending.c riscv_reprioritizertr.c
 CMN_CSRCS += riscv_releasestack.c riscv_stackframe.c riscv_schedulesigaction.c
 CMN_CSRCS += riscv_sigdeliver.c riscv_udelay.c riscv_unblocktask.c riscv_usestack.c
 CMN_CSRCS += riscv_idle.c riscv_tcbinfo.c riscv_getnewintctx.c riscv_doirq.c
+CMN_CSRCS += riscv_cpuindex.c
 
 ifeq ($(CONFIG_SCHED_BACKTRACE),y)
 CMN_CSRCS += riscv_backtrace.c
diff --git a/arch/risc-v/src/k210/Make.defs b/arch/risc-v/src/k210/Make.defs
index c1f3e89..df63897 100644
--- a/arch/risc-v/src/k210/Make.defs
+++ b/arch/risc-v/src/k210/Make.defs
@@ -35,6 +35,7 @@ CMN_CSRCS += riscv_releasestack.c riscv_stackframe.c riscv_schedulesigaction.c
 CMN_CSRCS += riscv_sigdeliver.c riscv_unblocktask.c riscv_usestack.c
 CMN_CSRCS += riscv_mdelay.c riscv_idle.c riscv_doirq.c
 CMN_CSRCS += riscv_tcbinfo.c riscv_cpuidlestack.c riscv_getnewintctx.c
+CMN_CSRCS += riscv_cpuindex.c
 
 ifeq ($(CONFIG_SMP), y)
 CMN_CSRCS += riscv_cpuindex.c riscv_cpupause.c riscv_cpustart.c
diff --git a/arch/risc-v/src/litex/Make.defs b/arch/risc-v/src/litex/Make.defs
index 667fe01..c9727e8 100644
--- a/arch/risc-v/src/litex/Make.defs
+++ b/arch/risc-v/src/litex/Make.defs
@@ -34,6 +34,7 @@ CMN_CSRCS += riscv_releasepending.c riscv_reprioritizertr.c
 CMN_CSRCS += riscv_releasestack.c riscv_stackframe.c riscv_schedulesigaction.c
 CMN_CSRCS += riscv_sigdeliver.c riscv_udelay.c riscv_unblocktask.c riscv_usestack.c
 CMN_CSRCS += riscv_idle.c riscv_tcbinfo.c riscv_getnewintctx.c
+CMN_CSRCS += riscv_cpuindex.c
 
 ifeq ($(CONFIG_SCHED_BACKTRACE),y)
 CMN_CSRCS += riscv_backtrace.c
diff --git a/arch/risc-v/src/mpfs/mpfs_irq_dispatch.c b/arch/risc-v/src/mpfs/mpfs_irq_dispatch.c
index 77849ff..01e471c 100755
--- a/arch/risc-v/src/mpfs/mpfs_irq_dispatch.c
+++ b/arch/risc-v/src/mpfs/mpfs_irq_dispatch.c
@@ -58,7 +58,7 @@ void *riscv_dispatch_irq(uintptr_t vector, uintptr_t *regs)
   if (vector < RISCV_IRQ_ECALLU ||
       vector == RISCV_IRQ_INSTRUCTIONPF ||
       vector == RISCV_IRQ_LOADPF ||
-      vector == RISCV_IRQ_SROREPF ||
+      vector == RISCV_IRQ_STOREPF ||
       vector == RISCV_IRQ_RESERVED)
     {
       riscv_fault(irq, regs);
diff --git a/arch/risc-v/src/qemu-rv/Make.defs b/arch/risc-v/src/qemu-rv/Make.defs
index 7813400..3d2e6db 100644
--- a/arch/risc-v/src/qemu-rv/Make.defs
+++ b/arch/risc-v/src/qemu-rv/Make.defs
@@ -35,6 +35,7 @@ CMN_CSRCS += riscv_releasestack.c riscv_stackframe.c riscv_schedulesigaction.c
 CMN_CSRCS += riscv_sigdeliver.c riscv_unblocktask.c riscv_usestack.c
 CMN_CSRCS += riscv_idle.c riscv_tcbinfo.c riscv_cpuidlestack.c
 CMN_CSRCS += riscv_fault.c riscv_getnewintctx.c riscv_doirq.c
+CMN_CSRCS += riscv_cpuindex.c
 
 ifeq ($(CONFIG_SMP), y)
 CMN_CSRCS += riscv_cpuindex.c riscv_cpupause.c riscv_cpustart.c
diff --git a/arch/risc-v/src/rv32m1/Make.defs b/arch/risc-v/src/rv32m1/Make.defs
index 4adb7c4..745bae6 100644
--- a/arch/risc-v/src/rv32m1/Make.defs
+++ b/arch/risc-v/src/rv32m1/Make.defs
@@ -34,6 +34,7 @@ CMN_CSRCS += riscv_releasepending.c riscv_reprioritizertr.c
 CMN_CSRCS += riscv_releasestack.c riscv_stackframe.c riscv_schedulesigaction.c
 CMN_CSRCS += riscv_sigdeliver.c riscv_unblocktask.c riscv_usestack.c
 CMN_CSRCS += riscv_idle.c riscv_tcbinfo.c riscv_getnewintctx.c
+CMN_CSRCS += riscv_cpuindex.c
 
 ifeq ($(CONFIG_SCHED_BACKTRACE),y)
 CMN_CSRCS += riscv_backtrace.c
diff --git a/boards/risc-v/bl602/bl602evb/src/bl602_ostest.c b/boards/risc-v/bl602/bl602evb/src/bl602_ostest.c
index 3d3f029..bd11c4e 100644
--- a/boards/risc-v/bl602/bl602evb/src/bl602_ostest.c
+++ b/boards/risc-v/bl602/bl602evb/src/bl602_ostest.c
@@ -31,6 +31,8 @@
 
 #include <nuttx/irq.h>
 
+#include "riscv_internal.h"
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
diff --git a/boards/risc-v/c906/smartl-c906/src/c906_ostest.c b/boards/risc-v/c906/smartl-c906/src/c906_ostest.c
index f3a5c8a..dd6bc11 100644
--- a/boards/risc-v/c906/smartl-c906/src/c906_ostest.c
+++ b/boards/risc-v/c906/smartl-c906/src/c906_ostest.c
@@ -31,6 +31,8 @@
 
 #include <nuttx/irq.h>
 
+#include "riscv_internal.h"
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
diff --git a/boards/risc-v/mpfs/common/src/mpfs_ostest.c b/boards/risc-v/mpfs/common/src/mpfs_ostest.c
index 587b441..6b4e3db 100755
--- a/boards/risc-v/mpfs/common/src/mpfs_ostest.c
+++ b/boards/risc-v/mpfs/common/src/mpfs_ostest.c
@@ -31,6 +31,8 @@
 
 #include <nuttx/irq.h>
 
+#include "riscv_internal.h"
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
diff --git a/boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c b/boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c
index d06f3e1..4fefb06 100644
--- a/boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c
+++ b/boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c
@@ -31,6 +31,8 @@
 
 #include <nuttx/irq.h>
 
+#include "riscv_internal.h"
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/

[incubator-nuttx] 02/02: RISC-V: Implement skeleton for a per CPU structure

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 71ced1f1a98dc7cef31043c76efd61778ed47b62
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Tue Mar 29 16:37:19 2022 +0300

    RISC-V: Implement skeleton for a per CPU structure
    
    It might be useful to store things in memory per CPU. The tricky part
    is that all CPUs run the same code and see the same memory, so some
    kind of centralized access is required.
    
    For now, the structure contains the hart id.
    
    Access to the structure elements is provided via sscratch, which is
    unique for every hart!
---
 arch/risc-v/Kconfig                                |   4 +
 arch/risc-v/src/common/riscv_cpuindex.c            |   3 +-
 .../common/{riscv_cpuindex.c => riscv_percpu.c}    |  89 ++++++++++++------
 arch/risc-v/src/common/riscv_percpu.h              | 104 +++++++++++++++++++++
 4 files changed, 171 insertions(+), 29 deletions(-)

diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig
index 97c66bd..7eef93d 100644
--- a/arch/risc-v/Kconfig
+++ b/arch/risc-v/Kconfig
@@ -234,6 +234,10 @@ config ARCH_MPU_HAS_NAPOT
 	bool "PMP supports NAPOT"
 	default y	if !PMP_HAS_LIMITED_FEATURES
 
+config ARCH_CPU_COUNT
+    int "Amount of CPUs in SoC"
+    default 5 if ARCH_CHIP_MPFS
+
 source "arch/risc-v/src/opensbi/Kconfig"
 source "arch/risc-v/src/common/Kconfig"
 
diff --git a/arch/risc-v/src/common/riscv_cpuindex.c b/arch/risc-v/src/common/riscv_cpuindex.c
index fe49065..5f06c2c 100644
--- a/arch/risc-v/src/common/riscv_cpuindex.c
+++ b/arch/risc-v/src/common/riscv_cpuindex.c
@@ -30,6 +30,7 @@
 #include <nuttx/irq.h>
 
 #include "riscv_internal.h"
+#include "riscv_percpu.h"
 
 /****************************************************************************
  * Public Functions
@@ -51,7 +52,7 @@ uintptr_t riscv_mhartid(void)
 #ifdef CONFIG_ARCH_USE_S_MODE
   /* Kernel is in S-mode */
 
-#error "Missing functionality..."
+  return riscv_percpu_get_hartid();
 
 #else
   /* Kernel is in M-mode */
diff --git a/arch/risc-v/src/common/riscv_cpuindex.c b/arch/risc-v/src/common/riscv_percpu.c
similarity index 51%
copy from arch/risc-v/src/common/riscv_cpuindex.c
copy to arch/risc-v/src/common/riscv_percpu.c
index fe49065..25e4ef9 100644
--- a/arch/risc-v/src/common/riscv_cpuindex.c
+++ b/arch/risc-v/src/common/riscv_percpu.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/risc-v/src/common/riscv_cpuindex.c
+ * arch/risc-v/src/common/riscv_percpu.c
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,62 +23,95 @@
  ****************************************************************************/
 
 #include <nuttx/config.h>
+#include <nuttx/irq.h>
 
-#include <stdint.h>
+#include <arch/barriers.h>
 
-#include <nuttx/arch.h>
-#include <nuttx/irq.h>
+#include <assert.h>
+#include <stdint.h>
 
 #include "riscv_internal.h"
+#include "riscv_percpu.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define HART_CNT    (CONFIG_ARCH_CPU_COUNT)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct riscv_percpu_s g_scratch[HART_CNT];
 
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: riscv_mhartid
+ * Name: riscv_percpu_init
  *
  * Description:
- *   Context aware way to query hart id
+ *   Initialize the per CPU structures, should only be done on the boot
+ *   hart.
  *
- * Returned Value:
- *   Hart id
+ ****************************************************************************/
+
+void riscv_percpu_init(void)
+{
+  int i;
+
+  for (i = 0; i < HART_CNT; i++)
+    {
+      g_scratch[i].hartid = i;
+    }
+}
+
+/****************************************************************************
+ * Name: riscv_percpu_get_addr
+ *
+ * Description:
+ *   Get add a hart to the per CPU area
+ *
+ * Input Parameters:
+ *   hartid - Hart number
  *
  ****************************************************************************/
 
-uintptr_t riscv_mhartid(void)
+void riscv_percpu_add_hart(uintptr_t hartid)
 {
-#ifdef CONFIG_ARCH_USE_S_MODE
-  /* Kernel is in S-mode */
+  /* Hart IDs go from 0...4 */
+
+  DEBUGASSERT(hartid < HART_CNT);
 
-#error "Missing functionality..."
+  /* Set the scratch register value to point to the scratch area */
 
-#else
-  /* Kernel is in M-mode */
+  WRITE_CSR(sscratch, &g_scratch[hartid]);
 
-  return READ_CSR(mhartid);
-#endif
+  /* Make sure it sticks */
+
+  __DMB();
 }
 
 /****************************************************************************
- * Name: up_cpu_index
+ * Name: riscv_percpu_get_hartid
  *
  * Description:
- *   Return an index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
- *   corresponds to the currently executing CPU.
- *
- * Input Parameters:
- *   None
+ *   Get harts own hartid by reading it from the per CPU area. This is safe
+ *   to use from lower privilege modes (than M-mode).
  *
  * Returned Value:
- *   An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
- *   corresponds to the currently executing CPU.
+ *   Hart id
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SMP
-int up_cpu_index(void)
+uintptr_t riscv_percpu_get_hartid(void)
 {
-  return (int)riscv_mhartid();
+  uintptr_t scratch = READ_CSR(sscratch);
+
+  DEBUGASSERT(scratch >= (uintptr_t) &g_scratch &&
+              scratch <= (uintptr_t) &g_scratch + sizeof(g_scratch));
+
+  return ((struct riscv_percpu_s *)scratch)->hartid;
 }
-#endif
diff --git a/arch/risc-v/src/common/riscv_percpu.h b/arch/risc-v/src/common/riscv_percpu.h
new file mode 100644
index 0000000..ddb35a5
--- /dev/null
+++ b/arch/risc-v/src/common/riscv_percpu.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+ * arch/risc-v/src/common/riscv_percpu.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_RISCV_PERCPU_H
+#define __ARCH_RISC_V_SRC_COMMON_RISCV_PERCPU_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <arch/irq.h>
+
+#ifndef __ASSEMBLY__
+#  include <stdint.h>
+#  include <nuttx/arch.h>
+#endif /* __ASSEMBLY__ */
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef __ASSEMBLY__
+#define SCRATCH_HARTID_OFFSET   (0 * INT_REG_SIZE)
+#else
+#define SCRATCH_HARTID_OFFSET   offsetof(riscv_percpu_s, hartid)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Per CPU save area. Access to this structure can be gained via the
+ * supervisor scratch (sscratch) register. Prior to this, every CPU that
+ * wishes to access this information must call riscv_percpu_add_hart() which
+ * will set up sscratch to point to the CPUs own area
+ */
+
+struct riscv_percpu_s
+{
+  uintptr_t hartid;  /* Hart ID */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: riscv_percpu_init
+ *
+ * Description:
+ *   Initialize the per CPU structures, should only be done on the boot
+ *   hart.
+ *
+ ****************************************************************************/
+
+void riscv_percpu_init(void);
+
+/****************************************************************************
+ * Name: riscv_percpu_get_addr
+ *
+ * Description:
+ *   Get add a hart to the per CPU area
+ *
+ * Input Parameters:
+ *   hartid - Hart number
+ *
+ ****************************************************************************/
+
+void riscv_percpu_add_hart(uintptr_t hartid);
+
+/****************************************************************************
+ * Name: riscv_percpu_get_hartid
+ *
+ * Description:
+ *   Get harts own hartid by reading it from the per CPU area. This is safe
+ *   to use from lower privilege modes than M-mode.
+ *
+ * Returned Value:
+ *   Hart id
+ *
+ ****************************************************************************/
+
+uintptr_t riscv_percpu_get_hartid(void);
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_RISC_V_SRC_COMMON_RISCV_PERCPU_H */