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:51 UTC

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

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
  ****************************************************************************/