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

[incubator-nuttx] 01/02: risc-v/esp32c3: Add support for Protected Mode

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

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

commit c778f35f08fd8e8867fe9d8ae4ccfa33ee2dacd5
Author: Gustavo Henrique Nihei <gu...@espressif.com>
AuthorDate: Mon Apr 11 21:09:25 2022 -0300

    risc-v/esp32c3: Add support for Protected Mode
    
    Signed-off-by: Gustavo Henrique Nihei <gu...@espressif.com>
---
 arch/risc-v/Kconfig                                |   1 +
 arch/risc-v/src/esp32c3/Bootloader.mk              |   2 +
 arch/risc-v/src/esp32c3/Kconfig                    |  10 +
 arch/risc-v/src/esp32c3/Make.defs                  |  10 +
 arch/risc-v/src/esp32c3/esp32c3_allocateheap.c     |  82 ++++-
 arch/risc-v/src/esp32c3/esp32c3_start.c            |  25 +-
 arch/risc-v/src/esp32c3/esp32c3_userspace.c        | 403 +++++++++++++++++++++
 arch/risc-v/src/esp32c3/esp32c3_userspace.h        |  49 +++
 .../esp32c3/esp32c3-devkit/configs/knsh/defconfig  |  57 +++
 .../esp32c3-devkit/include/board_memorymap.h       | 116 ++++++
 .../risc-v/esp32c3/esp32c3-devkit/kernel/Makefile  |  98 +++++
 .../esp32c3-devkit/kernel/esp32c3_userspace.c      | 114 ++++++
 .../esp32c3/esp32c3-devkit/scripts/Make.defs       |  10 +-
 .../esp32c3/esp32c3-devkit/scripts/kernel-space.ld | 230 ++++++++++++
 .../esp32c3-devkit/scripts/protected.template.ld   |  95 +++++
 .../esp32c3/esp32c3-devkit/scripts/user-space.ld   | 214 +++++++++++
 boards/risc-v/esp32c3/esp32c3-devkit/src/Makefile  |   4 +
 tools/esp32c3/Config.mk                            |   4 +
 18 files changed, 1507 insertions(+), 17 deletions(-)

diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig
index 025e186d97..f2e05f50fa 100644
--- a/arch/risc-v/Kconfig
+++ b/arch/risc-v/Kconfig
@@ -67,6 +67,7 @@ config ARCH_CHIP_ESP32C3
 	select ARCH_RV_ISA_M
 	select ARCH_RV_ISA_C
 	select ARCH_VECNOTIRQ
+	select ARCH_HAVE_MPU
 	select ARCH_HAVE_RESET
 	select LIBC_ARCH_ATOMIC
 	select LIBC_ARCH_MEMCPY
diff --git a/arch/risc-v/src/esp32c3/Bootloader.mk b/arch/risc-v/src/esp32c3/Bootloader.mk
index ba399457da..7b6429f4a1 100644
--- a/arch/risc-v/src/esp32c3/Bootloader.mk
+++ b/arch/risc-v/src/esp32c3/Bootloader.mk
@@ -34,6 +34,7 @@ $(BOOTLOADER_SRCDIR):
 # Helpers for creating the configuration file
 
 cfg_en  = echo "$(1)=$(if $(CONFIG_ESP32C3_APP_FORMAT_MCUBOOT),1,y)";
+cfg_dis = echo "$(1)=$(if $(CONFIG_ESP32C3_APP_FORMAT_MCUBOOT),0,n)";
 cfg_val = echo "$(1)=$(2)";
 
 # Commands for colored and formatted output
@@ -96,6 +97,7 @@ ifeq ($(CONFIG_ESP32C3_APP_FORMAT_MCUBOOT),y)
 	} >> $(BOOTLOADER_CONFIG)
 else ifeq ($(CONFIG_ESP32C3_APP_FORMAT_LEGACY),y)
 	$(Q) { \
+		$(if $(CONFIG_BUILD_PROTECTED),$(call cfg_dis,CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE)) \
 		$(call cfg_en,CONFIG_PARTITION_TABLE_CUSTOM) \
 		$(call cfg_val,CONFIG_PARTITION_TABLE_CUSTOM_FILENAME,\"partitions.csv\") \
 		$(call cfg_val,CONFIG_PARTITION_TABLE_OFFSET,$(CONFIG_ESP32C3_PARTITION_TABLE_OFFSET)) \
diff --git a/arch/risc-v/src/esp32c3/Kconfig b/arch/risc-v/src/esp32c3/Kconfig
index 92b9e1cba6..aa91feb89a 100644
--- a/arch/risc-v/src/esp32c3/Kconfig
+++ b/arch/risc-v/src/esp32c3/Kconfig
@@ -1150,6 +1150,16 @@ config ESP32C3_PARTITION_TABLE_OFFSET
 	default 0x8000
 	depends on ESP32C3_APP_FORMAT_LEGACY
 
+if BUILD_PROTECTED
+
+config ESP32C3_USER_IMAGE_OFFSET
+	hex "User image offset"
+	default 0x90000
+	---help---
+		Offset in SPI Flash for flashing the User application firmware image.
+
+endif
+
 source "arch/risc-v/src/esp32c3/Kconfig.security"
 
 endmenu # Application Image Configuration
diff --git a/arch/risc-v/src/esp32c3/Make.defs b/arch/risc-v/src/esp32c3/Make.defs
index db2ff2b812..ab16d97406 100644
--- a/arch/risc-v/src/esp32c3/Make.defs
+++ b/arch/risc-v/src/esp32c3/Make.defs
@@ -56,6 +56,10 @@ CMN_ASRCS += vfork.S
 CMN_CSRCS += riscv_vfork.c
 endif
 
+ifeq ($(CONFIG_ARCH_USE_MPU),y)
+CMN_CSRCS += riscv_pmp.c
+endif
+
 # Specify our C code within this directory to be included
 
 CHIP_CSRCS  = esp32c3_allocateheap.c esp32c3_start.c esp32c3_wdt.c esp32c3_idle.c
@@ -65,6 +69,12 @@ CHIP_CSRCS += esp32c3_lowputc.c esp32c3_serial.c
 CHIP_CSRCS += esp32c3_systemreset.c esp32c3_resetcause.c
 CHIP_CSRCS += esp32c3_uid.c
 
+ifeq ($(CONFIG_BUILD_PROTECTED),y)
+CHIP_CSRCS += esp32c3_userspace.c
+CMN_UASRCS += riscv_signal_handler.S
+CMN_CSRCS  += riscv_task_start.c riscv_pthread_start.c riscv_signal_dispatch.c
+endif
+
 ifeq ($(CONFIG_SCHED_TICKLESS),y)
 CHIP_CSRCS += esp32c3_tickless.c
 else
diff --git a/arch/risc-v/src/esp32c3/esp32c3_allocateheap.c b/arch/risc-v/src/esp32c3/esp32c3_allocateheap.c
index 42d68e1961..f5997a6f3c 100644
--- a/arch/risc-v/src/esp32c3/esp32c3_allocateheap.c
+++ b/arch/risc-v/src/esp32c3/esp32c3_allocateheap.c
@@ -24,16 +24,19 @@
 
 #include <nuttx/config.h>
 
-#include <sys/types.h>
 #include <debug.h>
+#include <sys/types.h>
 
-#include <nuttx/mm/mm.h>
 #include <nuttx/arch.h>
 #include <nuttx/board.h>
+#include <nuttx/mm/mm.h>
+#include <nuttx/userspace.h>
 #include <arch/board/board.h>
+#ifdef CONFIG_MM_KERNEL_HEAP
+#include <arch/board/board_memorymap.h>
+#endif
 
 #include "esp32c3.h"
-
 #include "hardware/esp32c3_rom_layout.h"
 
 /****************************************************************************
@@ -50,19 +53,42 @@
  * Description:
  *   This function will be called to dynamically set aside the heap region.
  *
- *   For the kernel build (CONFIG_BUILD_KERNEL=y) with both kernel- and
- *   user-space heaps (CONFIG_MM_KERNEL_HEAP=y), this function provides the
- *   size of the unprotected, user-space heap.
+ *   For the kernel build (CONFIG_BUILD_KERNEL=y) with both kernel and
+ *   userspace heaps (CONFIG_MM_KERNEL_HEAP=y), this function provides the
+ *   size of the unprotected, userspace heap.
  *
- *   If a protected kernel-space heap is provided, the kernel heap must be
+ *   If a protected kernel space heap is provided, the kernel heap must be
  *   allocated (and protected) by an analogous up_allocate_kheap().
  *
  ****************************************************************************/
 
 void up_allocate_heap(void **heap_start, size_t *heap_size)
 {
+#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP)
+  extern const struct esp32c3_rom_layout_s *ets_rom_layout_p;
+
+  uintptr_t ubase = USERSPACE->us_dataend;
+  uintptr_t utop  = ets_rom_layout_p->dram0_rtos_reserved_start;
+  size_t    usize = utop - ubase;
+
+  minfo("Heap: start=%" PRIxPTR " end=%" PRIxPTR " size=%zu\n",
+        ubase, utop, usize);
+
+  board_autoled_on(LED_HEAPALLOCATE);
+
+  /* Return the userspace heap settings */
+
+  *heap_start = (void *)ubase;
+  *heap_size  = usize;
+
+  /* Allow user-mode access to the user heap memory in PMP
+   * is already done in esp32c3_userspace().
+   */
+
+#else
   /* These values come from the linker scripts (esp32c3.ld and
-   * esp32c3.template.ld.)  Check boards/risc-v/esp32c3.
+   * esp32c3.template.ld).
+   * Check boards/risc-v/esp32c3.
    */
 
   extern uint8_t *_sheap;
@@ -71,9 +97,47 @@ void up_allocate_heap(void **heap_start, size_t *heap_size)
   board_autoled_on(LED_HEAPALLOCATE);
 
   *heap_start = (void *)&_sheap;
-  *heap_size = (size_t)(ets_rom_layout_p->dram0_rtos_reserved_start -
+  *heap_size  = (size_t)(ets_rom_layout_p->dram0_rtos_reserved_start -
                         (uintptr_t)&_sheap);
+#endif /* CONFIG_BUILD_PROTECTED && CONFIG_MM_KERNEL_HEAP */
+}
+
+/****************************************************************************
+ * Name: up_allocate_kheap
+ *
+ * Description:
+ *   This function will be called to dynamically set aside the heap region.
+ *
+ *   For the kernel build (CONFIG_BUILD_PROTECTED=y) with both kernel and
+ *   userspace heaps (CONFIG_MM_KERNEL_HEAP=y), this function allocates
+ *   (and protects) the kernel space heap.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) && \
+    defined(__KERNEL__)
+void up_allocate_kheap(void **heap_start, size_t *heap_size)
+{
+  /* These values come from the linker scripts (kernel-space.ld and
+   * protected.template.ld).
+   * Check boards/risc-v/esp32c3.
+   */
+
+  extern uint8_t *_sheap;
+
+  uintptr_t kbase = (uintptr_t)&_sheap;
+  uintptr_t ktop  = KDRAM_END;
+  size_t    ksize = ktop - kbase;
+
+  minfo("Heap: start=%" PRIxPTR " end=%" PRIxPTR " size=%zu\n",
+        kbase, ktop, ksize);
+
+  board_autoled_on(LED_HEAPALLOCATE);
+
+  *heap_start = (void *)kbase;
+  *heap_size  = ksize;
 }
+#endif /* CONFIG_BUILD_PROTECTED && CONFIG_MM_KERNEL_HEAP */
 
 /****************************************************************************
  * Name: riscv_addregion
diff --git a/arch/risc-v/src/esp32c3/esp32c3_start.c b/arch/risc-v/src/esp32c3/esp32c3_start.c
index 0bc54c7a1c..2679cd6d15 100644
--- a/arch/risc-v/src/esp32c3/esp32c3_start.c
+++ b/arch/risc-v/src/esp32c3/esp32c3_start.c
@@ -30,19 +30,21 @@
 #include <arch/board/board.h>
 
 #include "esp32c3.h"
+#ifdef CONFIG_ESP32C3_BROWNOUT_DET
+#  include "esp32c3_brownout.h"
+#endif
 #include "esp32c3_clockconfig.h"
 #include "esp32c3_irq.h"
 #include "esp32c3_lowputc.h"
+#include "esp32c3_rtc.h"
 #include "esp32c3_start.h"
 #include "esp32c3_wdt.h"
-#include "esp32c3_rtc.h"
+#ifdef CONFIG_BUILD_PROTECTED
+#  include "esp32c3_userspace.h"
+#endif
 #include "hardware/esp32c3_cache_memory.h"
 #include "hardware/extmem_reg.h"
 
-#ifdef CONFIG_ESP32C3_BROWNOUT_DET
-#  include "esp32c3_brownout.h"
-#endif
-
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -292,6 +294,19 @@ void __esp32c3_start(void)
 
   esp32c3_board_initialize();
 
+  showprogress('C');
+
+  /* For the case of the separate user-/kernel-space build, perform whatever
+   * platform specific initialization of the user memory is required.
+   * Normally this just means initializing the user space .data and .bss
+   * segments.
+   */
+
+#ifdef CONFIG_BUILD_PROTECTED
+  esp32c3_userspace();
+  showprogress('D');
+#endif
+
   /* Bring up NuttX */
 
   nx_start();
diff --git a/arch/risc-v/src/esp32c3/esp32c3_userspace.c b/arch/risc-v/src/esp32c3/esp32c3_userspace.c
new file mode 100755
index 0000000000..9f885a92e5
--- /dev/null
+++ b/arch/risc-v/src/esp32c3/esp32c3_userspace.c
@@ -0,0 +1,403 @@
+/****************************************************************************
+ * arch/risc-v/src/esp32c3/esp32c3_userspace.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <nuttx/userspace.h>
+
+#include <arch/board/board_memorymap.h>
+
+#include "riscv_internal.h"
+#include "esp32c3.h"
+#include "esp32c3_userspace.h"
+#include "hardware/esp32c3_cache_memory.h"
+#include "hardware/extmem_reg.h"
+
+#ifdef CONFIG_BUILD_PROTECTED
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define USER_IMAGE_OFFSET   CONFIG_ESP32C3_USER_IMAGE_OFFSET
+
+#define MMU_BLOCK0_VADDR    SOC_DROM_LOW
+#define MMU_SIZE            0x3f0000
+#define MMU_BLOCK63_VADDR   (MMU_BLOCK0_VADDR + MMU_SIZE)
+
+/* Cache MMU block size */
+
+#define MMU_BLOCK_SIZE      0x00010000  /* 64 KB */
+
+/* Cache MMU address mask (MMU tables ignore bits which are zero) */
+
+#define MMU_FLASH_MASK      (~(MMU_BLOCK_SIZE - 1))
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct user_image_load_header_s
+{
+  uintptr_t drom_vma;      /* Destination address (VMA) for DROM region */
+  uintptr_t drom_lma;      /* Flash offset (LMA) for start of DROM region */
+  uintptr_t drom_size;     /* Size of DROM region */
+  uintptr_t irom_vma;      /* Destination address (VMA) for IROM region */
+  uintptr_t irom_lma;      /* Flash offset (LMA) for start of IROM region */
+  uintptr_t irom_size;     /* Size of IROM region */
+};
+
+/****************************************************************************
+ * ROM Function Prototypes
+ ****************************************************************************/
+
+extern uint32_t cache_suspend_icache(void);
+extern void cache_resume_icache(uint32_t val);
+extern void cache_invalidate_icache_all(void);
+extern int cache_dbus_mmu_set(uint32_t ext_ram, uint32_t vaddr,
+                              uint32_t paddr, uint32_t psize, uint32_t num,
+                              uint32_t fixed);
+extern int cache_ibus_mmu_set(uint32_t ext_ram, uint32_t vaddr,
+                              uint32_t paddr, uint32_t psize, uint32_t num,
+                              uint32_t fixed);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct user_image_load_header_s g_header;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: calc_mmu_pages
+ *
+ * Description:
+ *   Calculate the required number of MMU pages for mapping a given region
+ *   from External Flash into Internal RAM.
+ *
+ * Input Parameters:
+ *   size          - Length of the region to map
+ *   vaddr         - Starting External Flash offset to map to Internal RAM
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline uint32_t calc_mmu_pages(uint32_t size, uint32_t vaddr)
+{
+  return (size + (vaddr - (vaddr & MMU_FLASH_MASK)) + MMU_BLOCK_SIZE - 1) /
+    MMU_BLOCK_SIZE;
+}
+
+/****************************************************************************
+ * Name: configure_mmu
+ *
+ * Description:
+ *   Configure the External Flash MMU and Cache for enabling access to code
+ *   and read-only data of the userspace image.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static noinline_function IRAM_ATTR void configure_mmu(void)
+{
+  uint32_t drom_lma_aligned;
+  uint32_t drom_vma_aligned;
+  uint32_t drom_page_count;
+  uint32_t irom_lma_aligned;
+  uint32_t irom_vma_aligned;
+  uint32_t irom_page_count;
+
+  size_t partition_offset = USER_IMAGE_OFFSET;
+  uint32_t app_drom_lma = partition_offset + g_header.drom_lma;
+  uint32_t app_drom_size = g_header.drom_size;
+  uint32_t app_drom_vma = g_header.drom_vma;
+  uint32_t app_irom_lma = partition_offset + g_header.irom_lma;
+  uint32_t app_irom_size = g_header.irom_size;
+  uint32_t app_irom_vma = g_header.irom_vma;
+
+  uint32_t autoload = cache_suspend_icache();
+  cache_invalidate_icache_all();
+
+  drom_lma_aligned = app_drom_lma & MMU_FLASH_MASK;
+  drom_vma_aligned = app_drom_vma & MMU_FLASH_MASK;
+  drom_page_count = calc_mmu_pages(app_drom_size, app_drom_vma);
+  DEBUGVERIFY(cache_dbus_mmu_set(MMU_ACCESS_FLASH, drom_vma_aligned,
+                                 drom_lma_aligned, 64,
+                                 (int)drom_page_count, 0));
+
+  irom_lma_aligned = app_irom_lma & MMU_FLASH_MASK;
+  irom_vma_aligned = app_irom_vma & MMU_FLASH_MASK;
+  irom_page_count = calc_mmu_pages(app_irom_size, app_irom_vma);
+  DEBUGVERIFY(cache_ibus_mmu_set(MMU_ACCESS_FLASH, irom_vma_aligned,
+                                 irom_lma_aligned, 64,
+                                 (int)irom_page_count, 0));
+
+  cache_resume_icache(autoload);
+}
+
+/****************************************************************************
+ * Name: map_flash
+ *
+ * Description:
+ *   Map a region of the External Flash memory to Internal RAM.
+ *
+ * Input Parameters:
+ *   src_addr      - Starting External Flash offset to map to Internal RAM
+ *   size          - Length of the region to map
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static noinline_function IRAM_ATTR const void *map_flash(uint32_t src_addr,
+                                                         uint32_t size)
+{
+  uint32_t src_addr_aligned;
+  uint32_t page_count;
+
+  uint32_t autoload = cache_suspend_icache();
+  cache_invalidate_icache_all();
+
+  src_addr_aligned = src_addr & MMU_FLASH_MASK;
+  page_count = calc_mmu_pages(size, src_addr);
+  DEBUGVERIFY(cache_dbus_mmu_set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR,
+                                 src_addr_aligned, 64, (int)page_count, 0));
+
+  cache_resume_icache(autoload);
+
+  return (void *)(MMU_BLOCK63_VADDR + (src_addr - src_addr_aligned));
+}
+
+/****************************************************************************
+ * Name: load_header
+ *
+ * Description:
+ *   Load IROM and DROM information from image header to enable the correct
+ *   configuration of the Flash MMU and Cache.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void load_header(void)
+{
+  size_t length = sizeof(struct user_image_load_header_s);
+  const uint8_t *data =
+    (const uint8_t *)map_flash(USER_IMAGE_OFFSET, length);
+
+  DEBUGASSERT(data != NULL);
+
+  memcpy(&g_header, data, length);
+}
+
+/****************************************************************************
+ * Name: initialize_data
+ *
+ * Description:
+ *   Initialize data sections of the userspace image.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void initialize_data(void)
+{
+  uint8_t *dest;
+  uint8_t *end;
+  size_t length = USERSPACE->us_dataend - USERSPACE->us_datastart;
+  const uint8_t *src =
+    (const uint8_t *)map_flash(USER_IMAGE_OFFSET + USERSPACE->us_datasource,
+                               length);
+
+  DEBUGASSERT(src != NULL);
+
+  dest = (uint8_t *)USERSPACE->us_datastart;
+  end  = (uint8_t *)USERSPACE->us_dataend;
+
+  while (dest != end)
+    {
+      *dest++ = *src++;
+    }
+}
+
+/****************************************************************************
+ * Name: configure_mpu
+ *
+ * Description:
+ *   Configure the MPU for kernel/userspace separation.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void configure_mpu(void)
+{
+  const uintptr_t R   = PMPCFG_R;
+  const uintptr_t RW  = PMPCFG_R | PMPCFG_W;
+  const uintptr_t RX  = PMPCFG_R | PMPCFG_X;
+  const uintptr_t RWX = PMPCFG_R | PMPCFG_W | PMPCFG_X;
+
+  /* Ensure PMP had not been previously configured by the bootloader */
+
+  DEBUGASSERT(riscv_configured_pmp_regions() == 0);
+
+  /* Region for the userspace read-only data in SPI Flash */
+
+  riscv_config_pmp_region(0, PMPCFG_A_TOR, UDROM_START, 0);
+  riscv_config_pmp_region(1, PMPCFG_A_TOR | R, UDROM_END, 0);
+
+  /* Region for the userspace data.
+   * NOTE: User-space heap may extend further than UDRAM_END.
+   */
+
+  riscv_config_pmp_region(2, PMPCFG_A_TOR, UDRAM_START, 0);
+  riscv_config_pmp_region(3, PMPCFG_A_TOR | RW, SOC_DRAM_HIGH, 0);
+
+  /* Region for the memory-mapped functions located in internal ROM */
+
+  riscv_config_pmp_region(4, PMPCFG_L | PMPCFG_A_NAPOT | R,
+                          SOC_DROM_MASK_LOW,
+                          SOC_DROM_MASK_HIGH - SOC_DROM_MASK_LOW);
+
+  riscv_config_pmp_region(5, PMPCFG_L | PMPCFG_A_TOR | RX,
+                          SOC_IROM_MASK_HIGH,
+                          0);
+
+  /* Region for the exception vectors located in internal SRAM area reserved
+   * for the kernel space.
+   */
+
+  riscv_config_pmp_region(6, PMPCFG_A_NAPOT | RX,
+                          VECTORS_START,
+                          VECTORS_END - VECTORS_START);
+
+  /* Region for the userspace code located in internal SRAM */
+
+  riscv_config_pmp_region(7, PMPCFG_A_TOR, UIRAM_START, 0);
+  riscv_config_pmp_region(8, PMPCFG_A_TOR | RWX, UIRAM_END, 0);
+
+  /* Region for the userspace code in SPI Flash */
+
+  riscv_config_pmp_region(9, PMPCFG_A_TOR, UIROM_START, 0);
+  riscv_config_pmp_region(10, PMPCFG_A_TOR | RX, UIROM_END, 0);
+
+  /* Region for peripheral addresses */
+
+  riscv_config_pmp_region(11, PMPCFG_A_TOR, SOC_PERIPHERAL_HIGH, 0);
+
+  /* Region for the remainder of the address space */
+
+  riscv_config_pmp_region(12, PMPCFG_L | PMPCFG_A_TOR, UINT32_MAX, 0);
+  riscv_config_pmp_region(13, PMPCFG_L | PMPCFG_A_NA4, UINT32_MAX, 0);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32c3_userspace
+ *
+ * Description:
+ *   For the case of the separate user/kernel space build, perform whatever
+ *   platform specific initialization of the user memory is required.
+ *   Normally this just means initializing the userspace .data and .bss
+ *   segments.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+void esp32c3_userspace(void)
+{
+  uint8_t *dest;
+  uint8_t *end;
+
+  /* Load IROM and DROM information from image header */
+
+  load_header();
+
+  /* Configure the MMU for enabling access to the userspace image */
+
+  configure_mmu();
+
+  /* Clear all of userspace .bss */
+
+  DEBUGASSERT(USERSPACE->us_bssstart != 0 && USERSPACE->us_bssend != 0 &&
+              USERSPACE->us_bssstart <= USERSPACE->us_bssend);
+
+  dest = (uint8_t *)USERSPACE->us_bssstart;
+  end  = (uint8_t *)USERSPACE->us_bssend;
+
+  while (dest != end)
+    {
+      *dest++ = 0;
+    }
+
+  /* Initialize all of userspace .data */
+
+  DEBUGASSERT(USERSPACE->us_datasource != 0 &&
+              USERSPACE->us_datastart != 0 && USERSPACE->us_dataend != 0 &&
+              USERSPACE->us_datastart <= USERSPACE->us_dataend);
+
+  initialize_data();
+
+  /* Configure MPU / PMP to grant access to the userspace */
+
+  configure_mpu();
+}
+
+#endif /* CONFIG_BUILD_PROTECTED */
diff --git a/arch/risc-v/src/esp32c3/esp32c3_userspace.h b/arch/risc-v/src/esp32c3/esp32c3_userspace.h
new file mode 100755
index 0000000000..bc1d135174
--- /dev/null
+++ b/arch/risc-v/src/esp32c3/esp32c3_userspace.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+ * arch/risc-v/src/esp32c3/esp32c3_userspace.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_SRC_ESP32C3_ESP32C3_USERSPACE_H
+#define __ARCH_RISCV_SRC_ESP32C3_ESP32C3_USERSPACE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32c3_userspace
+ *
+ * Description:
+ *   For the case of the separate user-/kernel-space build, perform whatever
+ *   platform specific initialization of the user memory is required.
+ *   Normally this just means initializing the user space .data and .bss
+ *   segments.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_BUILD_PROTECTED
+void esp32c3_userspace(void);
+#endif
+
+#endif /* __ARCH_RISCV_SRC_ESP32C3_ESP32C3_USERSPACE_H */
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/configs/knsh/defconfig b/boards/risc-v/esp32c3/esp32c3-devkit/configs/knsh/defconfig
new file mode 100644
index 0000000000..694a952499
--- /dev/null
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/configs/knsh/defconfig
@@ -0,0 +1,57 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_CMDPARMS is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="esp32c3-devkit"
+CONFIG_ARCH_BOARD_ESP32C3_DEVKIT=y
+CONFIG_ARCH_CHIP="esp32c3"
+CONFIG_ARCH_CHIP_ESP32C3=y
+CONFIG_ARCH_CHIP_ESP32C3WROOM02=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_USE_MPU=y
+CONFIG_BOARD_LOOPSPERMSEC=15000
+CONFIG_BUILD_PROTECTED=y
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_ERROR=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEBUG_WARN=y
+CONFIG_DEV_ZERO=y
+CONFIG_ESP32C3_BOOTLOADER_BUILD_FROM_SOURCE=y
+CONFIG_FS_PROCFS=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_STRERROR=y
+CONFIG_NUTTX_USERSPACE=0x3c080018
+CONFIG_PASS1_BUILDIR="boards/risc-v/esp32c3/esp32c3-devkit/kernel"
+CONFIG_PREALLOC_TIMERS=0
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_DAY=29
+CONFIG_START_MONTH=11
+CONFIG_START_YEAR=2019
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/include/board_memorymap.h b/boards/risc-v/esp32c3/esp32c3-devkit/include/board_memorymap.h
new file mode 100644
index 0000000000..31ee7d9af4
--- /dev/null
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/include/board_memorymap.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/esp32c3-devkit/include/board_memorymap.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 __BOARDS_RISCV_ESP32C3_ESP32C3_DEVKIT_INCLUDE_BOARD_MEMORYMAP_H
+#define __BOARDS_RISCV_ESP32C3_ESP32C3_DEVKIT_INCLUDE_BOARD_MEMORYMAP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Kernel ROM */
+
+#define KIROM_START     (uintptr_t)&__kirom_start
+#define KIROM_SIZE      (uintptr_t)&__kirom_size
+#define KDROM_START     (uintptr_t)&__kdrom_start
+#define KDROM_SIZE      (uintptr_t)&__kdrom_size
+
+/* Kernel RAM */
+
+#define KIRAM_START     (uintptr_t)&__kiram_start
+#define KIRAM_SIZE      (uintptr_t)&__kiram_size
+#define KIRAM_END       (uintptr_t)&__kiram_end
+#define KDRAM_START     (uintptr_t)&__kdram_start
+#define KDRAM_SIZE      (uintptr_t)&__kdram_size
+#define KDRAM_END       (uintptr_t)&__kdram_end
+
+/* Exception vectors */
+
+#define VECTORS_START   (uintptr_t)&__vectors_start
+#define VECTORS_END     (uintptr_t)&__vectors_end
+
+/* User ROM */
+
+#define UIROM_START     (uintptr_t)&__uirom_start
+#define UIROM_SIZE      (uintptr_t)&__uirom_size
+#define UIROM_END       (uintptr_t)&__uirom_end
+#define UDROM_START     (uintptr_t)&__udrom_start
+#define UDROM_SIZE      (uintptr_t)&__udrom_size
+#define UDROM_END       (uintptr_t)&__udrom_end
+
+/* User RAM */
+
+#define UIRAM_START     (uintptr_t)&__uiram_start
+#define UIRAM_SIZE      (uintptr_t)&__uiram_size
+#define UIRAM_END       (uintptr_t)&__uiram_end
+#define UDRAM_START     (uintptr_t)&__udram_start
+#define UDRAM_SIZE      (uintptr_t)&__udram_size
+#define UDRAM_END       (uintptr_t)&__udram_end
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* Kernel ROM (RX)  */
+
+extern uintptr_t        __kirom_start;
+extern uintptr_t        __kirom_size;
+extern uintptr_t        __kdrom_start;
+extern uintptr_t        __kdrom_size;
+
+/* Kernel RAM (RW) */
+
+extern uintptr_t        __kiram_start;
+extern uintptr_t        __kiram_size;
+extern uintptr_t        __kiram_end;
+extern uintptr_t        __kdram_start;
+extern uintptr_t        __kdram_size;
+extern uintptr_t        __kdram_end;
+
+/* Exception vectors */
+
+extern uintptr_t        __vectors_start;
+extern uintptr_t        __vectors_end;
+
+/* User ROM (RX) */
+
+extern uintptr_t        __uirom_start;
+extern uintptr_t        __uirom_size;
+extern uintptr_t        __uirom_end;
+extern uintptr_t        __udrom_start;
+extern uintptr_t        __udrom_size;
+extern uintptr_t        __udrom_end;
+
+/* User RAM (RW) */
+
+extern uintptr_t        __uiram_start;
+extern uintptr_t        __uiram_size;
+extern uintptr_t        __uiram_end;
+extern uintptr_t        __udram_start;
+extern uintptr_t        __udram_size;
+extern uintptr_t        __udram_end;
+
+#endif /* __BOARDS_RISCV_ESP32C3_ESP32C3_DEVKIT_INCLUDE_BOARD_MEMORYMAP_H */
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/kernel/Makefile b/boards/risc-v/esp32c3/esp32c3-devkit/kernel/Makefile
new file mode 100755
index 0000000000..2b6b056e1f
--- /dev/null
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/kernel/Makefile
@@ -0,0 +1,98 @@
+############################################################################
+# boards/risc-v/esp32c3/esp32c3-devkit/kernel/Makefile
+#
+# 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.
+#
+############################################################################
+
+include $(TOPDIR)/Make.defs
+
+# The entry point name (if none is provided in the .config file)
+
+CONFIG_INIT_ENTRYPOINT ?= user_start
+ENTRYPT = $(patsubst "%",%,$(CONFIG_INIT_ENTRYPOINT))
+
+# Get the paths to the libraries and the links script path in format that
+# is appropriate for the host OS
+
+USER_LIBPATHS = $(addprefix -L,$(call CONVERT_PATH,$(addprefix $(TOPDIR)$(DELIM),$(dir $(USERLIBS)))))
+USER_LDSCRIPT = -T $(call CONVERT_PATH,$(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3_out.ld)
+USER_LDSCRIPT += -T $(call CONVERT_PATH,$(BOARD_DIR)$(DELIM)scripts$(DELIM)user-space.ld)
+USER_LDSCRIPT += -T $(call CONVERT_PATH,$(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3_rom.ld)
+USER_HEXFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.hex)
+USER_BINFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.bin)
+
+USER_LDFLAGS = --undefined=$(ENTRYPT) --entry=$(ENTRYPT) $(USER_LDSCRIPT) -melf32lriscv
+
+ifeq ($(CONFIG_DEBUG_LINK_MAP),y)
+USER_LDFLAGS += --cref -Map="$(TOPDIR)$(DELIM)User.map"
+endif
+
+USER_LDLIBS = $(patsubst lib%,-l%,$(basename $(notdir $(USERLIBS))))
+USER_LIBGCC = "${shell "$(CC)" $(ARCHCPUFLAGS) -print-libgcc-file-name}"
+
+# Source files
+
+CSRCS = esp32c3_userspace.c
+COBJS = $(CSRCS:.c=$(OBJEXT))
+OBJS  = $(COBJS)
+
+ifeq ($(LD),$(CC))
+  LDSTARTGROUP ?= -Wl,--start-group
+  LDENDGROUP   ?= -Wl,--end-group
+  USER_LDFLAGS := $(addprefix -Xlinker ,$(USER_LDFLAGS))
+  USER_LDFLAGS += $(CFLAGS)
+else
+  LDSTARTGROUP ?= --start-group
+  LDENDGROUP   ?= --end-group
+endif
+
+# Targets:
+
+all: $(TOPDIR)$(DELIM)nuttx_user.elf
+.PHONY: nuttx_user.elf depend clean distclean
+
+$(COBJS): %$(OBJEXT): %.c
+	$(call COMPILE, $<, $@)
+
+# Create the nuttx_user.elf file containing all of the user-mode code
+
+nuttx_user.elf: $(OBJS)
+	$(Q) $(LD) -o $@ $(USER_LDFLAGS) $(USER_LIBPATHS) $(OBJS) $(LDSTARTGROUP) $(USER_LDLIBS) $(LDENDGROUP) $(USER_LIBGCC)
+
+$(TOPDIR)$(DELIM)nuttx_user.elf: nuttx_user.elf
+	$(Q) echo "LD: nuttx_user.elf"
+	$(Q) cp -a nuttx_user.elf $(TOPDIR)$(DELIM)nuttx_user.elf
+ifeq ($(CONFIG_INTELHEX_BINARY),y)
+	$(Q) echo "CP: nuttx_user.hex"
+	$(Q) $(OBJCOPY) $(OBJCOPYARGS) -O ihex nuttx_user.elf $(USER_HEXFILE)
+endif
+ifeq ($(CONFIG_RAW_BINARY),y)
+	$(Q) echo "CP: nuttx_user.bin"
+	$(Q) $(OBJCOPY) $(OBJCOPYARGS) -O binary nuttx_user.elf $(USER_BINFILE)
+endif
+
+.depend:
+
+depend: .depend
+
+clean:
+	$(call DELFILE, nuttx_user.elf)
+	$(call DELFILE, "$(TOPDIR)$(DELIM)nuttx_user.*")
+	$(call DELFILE, "$(TOPDIR)$(DELIM)User.map")
+	$(call CLEAN)
+
+distclean: clean
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/kernel/esp32c3_userspace.c b/boards/risc-v/esp32c3/esp32c3-devkit/kernel/esp32c3_userspace.c
new file mode 100755
index 0000000000..82fa9907be
--- /dev/null
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/kernel/esp32c3_userspace.c
@@ -0,0 +1,114 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/esp32c3-devkit/kernel/esp32c3_userspace.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/mm/mm.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/userspace.h>
+
+#if defined(CONFIG_BUILD_PROTECTED) && !defined(__KERNEL__)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_NUTTX_USERSPACE
+#  error "CONFIG_NUTTX_USERSPACE not defined"
+#endif
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* These 'addresses' of these values are setup by the linker script.
+ * They are not actual uint32_t storage locations!
+ * They are only used meaningfully in the following way:
+ *
+ *  - The linker script defines, for example, the symbol_sdata.
+ *  - The declaration extern uint32_t _sdata; makes C happy.  C will believe
+ *    that the value _sdata is the address of a uint32_t variable _data
+ *    (it is not!).
+ *  - We can recover the linker value then by simply taking the address of
+ *    of _data.  like:  uint32_t *pdata = &_sdata;
+ */
+
+extern uint32_t _stext;           /* Start of .text */
+extern uint32_t _etext;           /* End+1 of .text + .rodata */
+extern const uint32_t _eronly;    /* End+1 of read only section */
+extern uint32_t _sdata;           /* Start of .data */
+extern uint32_t _edata;           /* End+1 of .data */
+extern uint32_t _sbss;            /* Start of .bss */
+extern uint32_t _ebss;            /* End+1 of .bss */
+
+extern uintptr_t *__ld_udram_end; /* End+1 of user ram section */
+
+/* This is the user space entry point */
+
+int CONFIG_INIT_ENTRYPOINT(int argc, char *argv[]);
+
+const struct userspace_s userspace locate_data(".userspace") =
+{
+  /* General memory map */
+
+  .us_entrypoint    = (main_t)CONFIG_INIT_ENTRYPOINT,
+  .us_textstart     = (uintptr_t)&_stext,
+  .us_textend       = (uintptr_t)&_etext,
+  .us_datasource    = (uintptr_t)&_eronly,
+  .us_datastart     = (uintptr_t)&_sdata,
+  .us_dataend       = (uintptr_t)&_edata,
+  .us_bssstart      = (uintptr_t)&_sbss,
+  .us_bssend        = (uintptr_t)&_ebss,
+
+  .us_heapend       = (uintptr_t)&__ld_udram_end,
+
+  /* Memory manager heap structure */
+
+  .us_heap          = &g_mmheap,
+
+  /* Task/thread startup routines */
+
+  .task_startup     = nxtask_startup,
+
+  /* Signal handler trampoline */
+
+  .signal_handler   = up_signal_handler,
+
+  /* Userspace work queue support (declared in include/nuttx/wqueue.h) */
+
+#ifdef CONFIG_LIBC_USRWORK
+  .work_usrstart    = work_usrstart,
+#endif
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#endif /* CONFIG_BUILD_PROTECTED && !__KERNEL__ */
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/Make.defs b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/Make.defs
index 393bda1470..7d6789f6bb 100644
--- a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/Make.defs
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/Make.defs
@@ -25,10 +25,14 @@ include $(TOPDIR)/arch/risc-v/src/common/Toolchain.defs
 
 ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3_out.ld
 
-ifeq ($(CONFIG_ESP32C3_APP_FORMAT_MCUBOOT),y)
-  ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3_mcuboot.ld
+ifeq ($(CONFIG_BUILD_PROTECTED),y)
+  ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)kernel-space.ld
 else
-  ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3.ld
+  ifeq ($(CONFIG_ESP32C3_APP_FORMAT_MCUBOOT),y)
+    ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3_mcuboot.ld
+  else
+    ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3.ld
+  endif
 endif
 
 ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)esp32c3_rom.ld
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/kernel-space.ld b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/kernel-space.ld
new file mode 100755
index 0000000000..87c0c99c0c
--- /dev/null
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/kernel-space.ld
@@ -0,0 +1,230 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/esp32c3-devkit/scripts/kernel-space.ld
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* Provide these so there is no need for using config files for this */
+
+__uirom_start = ORIGIN(UIROM);
+__uirom_size = LENGTH(UIROM);
+__uirom_end = ORIGIN(UIROM) + LENGTH(UIROM);
+__udrom_start = ORIGIN(UDROM);
+__udrom_size = LENGTH(UDROM);
+__udrom_end = ORIGIN(UDROM) + LENGTH(UDROM);
+__uiram_start = ORIGIN(UIRAM);
+__uiram_size = LENGTH(UIRAM);
+__uiram_end = ORIGIN(UIRAM) + LENGTH(UIRAM);
+__udram_start = ORIGIN(UDRAM);
+__udram_size = LENGTH(UDRAM);
+__udram_end = ORIGIN(UDRAM) + LENGTH(UDRAM);
+
+/* Provide the kernel boundaries as well */
+
+__kirom_start = ORIGIN(KIROM);
+__kirom_size = LENGTH(KIROM);
+__kdrom_start = ORIGIN(KDROM);
+__kdrom_size = LENGTH(KDROM);
+__kiram_start = ORIGIN(KIRAM);
+__kiram_size = LENGTH(KIRAM);
+__kiram_end = ORIGIN(KIRAM) + LENGTH(KIRAM);
+__kdram_start = ORIGIN(KDRAM);
+__kdram_size = LENGTH(KDRAM);
+__kdram_end = ORIGIN(KDRAM) + LENGTH(KDRAM);
+
+ENTRY(_stext)
+
+SECTIONS
+{
+  .iram0.text :
+  {
+    _iram_start = ABSOLUTE(.);
+
+    __vectors_start = ABSOLUTE(.);
+
+    /* Vectors go to start of IRAM */
+
+    KEEP(*(.exception_vectors.text));
+    . = ALIGN(4);
+
+    __vectors_end = ABSOLUTE(.);
+
+    *(.iram1)
+    *(.iram1.*)
+
+    *libsched.a:irq_dispatch.*(.text .text.* .literal .literal.*)
+
+    *(.wifi0iram .wifi0iram.*)
+    *(.wifirxiram .wifirxiram.*)
+    *(.wifislpiram .wifislpiram.*)
+    *(.wifislprxiram .wifislprxiram.*)
+
+    _iram_end = ABSOLUTE(.);
+  } >KIRAM
+
+  /* This section is required to skip .iram0.text area because iram0_0_seg
+   * and dram0_0_seg reflect the same address space on different buses.
+   */
+
+  .dram0.dummy (NOLOAD):
+  {
+    . = ORIGIN(KDRAM) + _iram_end - _iram_start;
+  } >KDRAM
+
+  /* Shared RAM */
+
+  .dram0.bss (NOLOAD) :
+  {
+    . = ALIGN (8);
+    _sbss = ABSOLUTE(.);
+    *(.dynsbss)
+    *(.sbss)
+    *(.sbss.*)
+    *(.gnu.linkonce.sb.*)
+    *(.scommon)
+    *(.sbss2)
+    *(.sbss2.*)
+    *(.gnu.linkonce.sb2.*)
+    *(.dynbss)
+    *(.bss)
+    *(.bss.*)
+    *(.share.mem)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+
+    . = ALIGN (8);
+    _ebss = ABSOLUTE(.);
+  } >KDRAM
+
+  .noinit (NOLOAD):
+  {
+    /* This section contains data that is not initialized during load,
+     * or during the application's initialization sequence.
+     */
+
+    *(.noinit)
+    *(.noinit.*)
+  } >KDRAM
+
+  .dram0.data :
+  {
+    _sdata = ABSOLUTE(.);
+    *(.data)
+    *(.data.*)
+    *(.gnu.linkonce.d.*)
+    *(.data1)
+    __global_pointer$ = . + 0x800;
+    *(.sdata)
+    *(.sdata.*)
+    *(.gnu.linkonce.s.*)
+    *(.sdata2)
+    *(.sdata2.*)
+    *(.gnu.linkonce.s2.*)
+    *(.jcr)
+    *(.dram1)
+    *(.dram1.*)
+    . = ALIGN(4);
+    _edata = ABSOLUTE(.);
+
+    /* Heap starts at the end of .data */
+
+    _sheap = ABSOLUTE(.);
+  } >KDRAM
+
+  .flash.text :
+  {
+    _stext = .;
+
+    *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
+    *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */
+    *(.fini.literal)
+    *(.fini)
+    *(.gnu.version)
+    _etext = .;
+
+    /* Similar to _iram_start, this symbol goes here so it is
+     * resolved by addr2line in preference to the first symbol in
+     * the flash.text segment.
+     */
+
+    _flash_cache_start = ABSOLUTE(0);
+  } >KIROM
+
+  .flash_rodata_dummy (NOLOAD):
+  {
+    . = ALIGN(ALIGNOF(.flash.text));
+    . = . + SIZEOF(.flash.text);
+    . = ALIGN(0x10000) + 0x20;
+  } >KDROM
+
+  .flash.rodata : ALIGN(0x10)
+  {
+    _srodata = ABSOLUTE(.);
+
+    *(.rodata)
+    *(.rodata.*)
+
+    *(.srodata.*)
+
+    *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
+    *(.gnu.linkonce.r.*)
+    *(.rodata1)
+    __XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
+    *(.xt_except_table)
+    *(.gcc_except_table .gcc_except_table.*)
+    *(.gnu.linkonce.e.*)
+    *(.gnu.version_r)
+    . = (. + 3) & ~ 3;
+    __eh_frame = ABSOLUTE(.);
+    KEEP(*(.eh_frame))
+    . = (. + 7) & ~ 3;
+
+    /* C++ constructor and destructor tables:
+     * RISC-V GCC is configured with --enable-initfini-array so it emits an
+     * .init_array section instead.
+     */
+
+    _sinit = ABSOLUTE(.);
+    KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))
+    KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array))
+    _einit = ABSOLUTE(.);
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+
+    /* C++ exception handlers table: */
+
+    __XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
+    *(.xt_except_desc)
+    *(.gnu.linkonce.h.*)
+    __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
+    *(.xt_except_desc_end)
+    *(.dynamic)
+    *(.gnu.version_d)
+    _erodata = ABSOLUTE(.);
+
+    /* Literals are also RO data. */
+
+    _lit4_start = ABSOLUTE(.);
+    *(*.lit4)
+    *(.lit4.*)
+    *(.gnu.linkonce.lit4.*)
+    _lit4_end = ABSOLUTE(.);
+    . = ALIGN(4);
+  } >KDROM
+}
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/protected.template.ld b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/protected.template.ld
new file mode 100644
index 0000000000..6e0e33ab6b
--- /dev/null
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/protected.template.ld
@@ -0,0 +1,95 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/esp32c3-devkit/scripts/protected.template.ld
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * This file describes the memory layout (memory blocks) as virtual
+ * memory addresses.
+ *
+ * NOTE: That this is not the actual linker script but rather a "template"
+ * for the esp32c3_out.ld script.  This template script is passed through
+ * the C preprocessor to include selected configuration options.
+ *
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "esp32c3_aliases.ld"
+
+#define SRAM_IRAM_START     0x4037c000
+#define SRAM_DRAM_START     0x3fc7c000
+
+/* ICache size is fixed to 16KB on ESP32-C3 */
+
+#define ICACHE_SIZE         0x4000
+#define I_D_SRAM_OFFSET     (SRAM_IRAM_START - SRAM_DRAM_START)
+
+/* 2nd stage bootloader iram_loader_seg start address */
+
+#define SRAM_IRAM_END       0x403d0000
+#define SRAM_DRAM_END       SRAM_IRAM_END - I_D_SRAM_OFFSET
+
+#define SRAM_IRAM_ORG       (SRAM_IRAM_START + ICACHE_SIZE)
+#define SRAM_DRAM_ORG       (SRAM_DRAM_START + ICACHE_SIZE)
+
+#define I_D_SRAM_SIZE       SRAM_DRAM_END - SRAM_DRAM_ORG
+
+MEMORY
+{
+  metadata (RX) :   org = 0x0, len = 0x18
+  ROM (RX) :        org = 0x18, len = 0x100000
+
+  /* Below values assume the flash cache is on, and have the blocks this
+   * uses subtracted from the length of the various regions. The 'data access
+   * port' dram/drom regions map to the same iram/irom regions but are
+   * connected to the data port of the CPU and e.g. allow bytewise access.
+   */
+
+  KIRAM (RWX) :     org = SRAM_IRAM_ORG, len = 64K
+  UIRAM (RWX) :     org = SRAM_IRAM_ORG + 64K, len = 256K
+
+  /* Flash mapped instruction data. */
+
+  /* The 0x20 offset is a convenience for the app binary image generation.
+   * Flash cache has 64KB pages. The .bin file which is flashed to the chip
+   * has a 0x18 byte file header, and each segment has a 0x08 byte segment
+   * header. Setting this offset makes it simple to meet the flash cache MMU's
+   * constraint that (paddr % 64KB == vaddr % 64KB).
+   */
+
+  KIROM (RX) :      org = 0x42000020, len = 0x80000 - 0x20
+  UIROM (RX) :      org = 0x42080000, len = 0x180000
+
+  /* Shared data RAM, excluding memory reserved for ROM bss/data/stack. */
+
+  KDRAM (RW) :      org = SRAM_DRAM_ORG, len = 64K
+  UDRAM (RW) :      org = SRAM_DRAM_ORG + 64K, len = 256K
+
+  /* Flash mapped constant data */
+
+  /* The 0x20 offset is a convenience for the app binary image generation.
+   * Flash cache has 64KB pages. The .bin file which is flashed to the chip
+   * has a 0x18 byte file header, and each segment has a 0x08 byte segment
+   * header. Setting this offset makes it simple to meet the flash cache MMU's
+   * constraint that (paddr % 64KB == vaddr % 64KB).
+   */
+
+  KDROM (R)  :      org = 0x3c000020, len = 0x80000 - 0x20
+  UDROM (R)  :      org = 0x3c080018, len = 0x180000 - 0x18
+}
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/scripts/user-space.ld b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/user-space.ld
new file mode 100755
index 0000000000..717c77efd9
--- /dev/null
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/scripts/user-space.ld
@@ -0,0 +1,214 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/esp32c3-devkit/scripts/user-space.ld
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+SECTIONS
+{
+  .metadata :
+  {
+    /* DROM metadata:
+     * - Destination address (VMA) for DROM region
+     * - Flash offset (LMA) for start of DROM region
+     * - Size of DROM region
+     */
+
+    LONG(ADDR(.userspace))
+    LONG(LOADADDR(.userspace))
+    LONG(SIZEOF(.userspace) + SIZEOF(.flash.rodata))
+
+    /* IROM metadata:
+     * - Destination address (VMA) for IROM region
+     * - Flash offset (LMA) for start of IROM region
+     * - Size of IROM region
+     */
+
+    LONG(ADDR(.flash.text))
+    LONG(LOADADDR(.flash.text))
+    LONG(SIZEOF(.flash.text))
+  } >metadata
+
+  /* section info */
+
+  __ld_uirom_start = ORIGIN(UIROM);
+  __ld_uirom_size = LENGTH(UIROM);
+  __ld_uirom_end = ORIGIN(UIROM) + LENGTH(UIROM);
+  __ld_udrom_start = ORIGIN(UDROM);
+  __ld_udrom_size = LENGTH(UDROM);
+  __ld_udrom_end = ORIGIN(UDROM) + LENGTH(UDROM);
+  __ld_uiram_start = ORIGIN(UIRAM);
+  __ld_uiram_size = LENGTH(UIRAM);
+  __ld_uiram_end = ORIGIN(UIRAM) + LENGTH(UIRAM);
+  __ld_udram_start = ORIGIN(UDRAM);
+  __ld_udram_size = LENGTH(UDRAM);
+  __ld_udram_end = ORIGIN(UDRAM) + LENGTH(UDRAM);
+
+  _eronly = LOADADDR(.dram0.data);
+
+  .userspace : {
+    *(.userspace)
+  } >UDROM AT>ROM
+
+  .flash.rodata :
+  {
+    _srodata = ABSOLUTE(.);
+
+    *(.rodata)
+    *(.rodata.*)
+
+    *(.srodata.*)
+
+    *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
+    *(.gnu.linkonce.r.*)
+    *(.rodata1)
+    __XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
+    *(.xt_except_table)
+    *(.gcc_except_table .gcc_except_table.*)
+    *(.gnu.linkonce.e.*)
+    *(.gnu.version_r)
+    . = (. + 3) & ~ 3;
+    __eh_frame = ABSOLUTE(.);
+    KEEP(*(.eh_frame))
+    . = (. + 7) & ~ 3;
+
+    /* C++ constructor and destructor tables:
+     * RISC-V GCC is configured with --enable-initfini-array so it emits an
+     * .init_array section instead.
+     */
+
+    _sinit = ABSOLUTE(.);
+    KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))
+    KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array))
+    _einit = ABSOLUTE(.);
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+
+    /* C++ exception handlers table: */
+
+    __XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
+    *(.xt_except_desc)
+    *(.gnu.linkonce.h.*)
+    __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
+    *(.xt_except_desc_end)
+    *(.dynamic)
+    *(.gnu.version_d)
+    _erodata = ABSOLUTE(.);
+
+    /* Literals are also RO data. */
+
+    _lit4_start = ABSOLUTE(.);
+    *(*.lit4)
+    *(.lit4.*)
+    *(.gnu.linkonce.lit4.*)
+    _lit4_end = ABSOLUTE(.);
+    . = ALIGN(4);
+  } >UDROM AT>ROM
+
+  .iram0.text :
+  {
+    _iram_start = ABSOLUTE(.);
+
+    *(.iram1)
+    *(.iram1.*)
+
+    _iram_end = ABSOLUTE(.);
+  } >UIRAM AT>ROM
+
+  /* This section is required to skip .iram0.text area because iram0_0_seg
+   * and dram0_0_seg reflect the same address space on different buses.
+   */
+
+  .dram0.dummy (NOLOAD):
+  {
+    . = ORIGIN(UDRAM) + _iram_end - _iram_start;
+  } >UDRAM
+
+  /* Shared RAM */
+
+  .dram0.bss (NOLOAD) :
+  {
+    . = ALIGN (8);
+    _sbss = ABSOLUTE(.);
+    *(.dynsbss)
+    *(.sbss)
+    *(.sbss.*)
+    *(.gnu.linkonce.sb.*)
+    *(.scommon)
+    *(.sbss2)
+    *(.sbss2.*)
+    *(.gnu.linkonce.sb2.*)
+    *(.dynbss)
+    *(.bss)
+    *(.bss.*)
+    *(.share.mem)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+
+    . = ALIGN (8);
+    _ebss = ABSOLUTE(.);
+  } >UDRAM
+
+  .noinit (NOLOAD):
+  {
+    /* This section contains data that is not initialized during load,
+     * or during the application's initialization sequence.
+     */
+
+    *(.noinit)
+    *(.noinit.*)
+  } >UDRAM
+
+  .dram0.data :
+  {
+    _sdata = ABSOLUTE(.);
+    *(.data)
+    *(.data.*)
+    *(.gnu.linkonce.d.*)
+    *(.data1)
+    *(.sdata)
+    *(.sdata.*)
+    *(.gnu.linkonce.s.*)
+    *(.sdata2)
+    *(.sdata2.*)
+    *(.gnu.linkonce.s2.*)
+    *(.jcr)
+    *(.dram1)
+    *(.dram1.*)
+    . = ALIGN(4);
+    _edata = ABSOLUTE(.);
+  } >UDRAM AT>ROM
+
+  .flash_text_dummy (NOLOAD) : ALIGN(0x00010000)
+  {
+    . = SIZEOF(.userspace) + SIZEOF(.flash.rodata);
+  } >UIROM
+
+  .flash.text : ALIGN(0x00010000)
+  {
+    _stext = .;
+
+    *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
+    *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */
+    *(.fini.literal)
+    *(.fini)
+    *(.gnu.version)
+    _etext = .;
+  } >UIROM AT>ROM
+}
diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/src/Makefile b/boards/risc-v/esp32c3/esp32c3-devkit/src/Makefile
index 8b0e0bbf40..3bbfad7aa6 100644
--- a/boards/risc-v/esp32c3/esp32c3-devkit/src/Makefile
+++ b/boards/risc-v/esp32c3/esp32c3-devkit/src/Makefile
@@ -113,7 +113,11 @@ ifneq ($(CONFIG_NSH_CUSTOMROMFS),y)
 endif
 endif
 
+ifeq ($(CONFIG_BUILD_PROTECTED),y)
+SCRIPTIN = $(SCRIPTDIR)$(DELIM)protected.template.ld
+else
 SCRIPTIN = $(SCRIPTDIR)$(DELIM)esp32c3.template.ld
+endif
 SCRIPTOUT = $(SCRIPTDIR)$(DELIM)esp32c3_out.ld
 
 .PHONY = context distclean
diff --git a/tools/esp32c3/Config.mk b/tools/esp32c3/Config.mk
index f48b2c4e18..3fcdc1c11d 100644
--- a/tools/esp32c3/Config.mk
+++ b/tools/esp32c3/Config.mk
@@ -128,6 +128,10 @@ endif
 
 ESPTOOL_BINS += $(FLASH_APP)
 
+ifeq ($(CONFIG_BUILD_PROTECTED),y)
+	ESPTOOL_BINS += $(CONFIG_ESP32C3_USER_IMAGE_OFFSET) nuttx_user.bin
+endif
+
 # Commands for colored and formatted output
 
 RED    = \033[1;31m