diff --git a/arch/risc-v/src/esp32c3/Kconfig b/arch/risc-v/src/esp32c3/Kconfig index b0ed2d9708..2535afed5b 100644 --- a/arch/risc-v/src/esp32c3/Kconfig +++ b/arch/risc-v/src/esp32c3/Kconfig @@ -156,6 +156,13 @@ config ESP32C3_CPU_FREQ_MHZ default 80 if ESP32C3_CPU_FREQ_80 default 160 if ESP32C3_CPU_FREQ_160 +config ESP32C3_REGION_PROTECTION + bool "Enable region protection" + default y + select ARCH_USE_MPU + ---help--- + Configure the MPU to disable access to invalid memory regions. + config ESP32C3_RT_TIMER bool "Real-time Timer" default n diff --git a/arch/risc-v/src/esp32c3/Make.defs b/arch/risc-v/src/esp32c3/Make.defs index fcf0ada929..f26aae8e90 100644 --- a/arch/risc-v/src/esp32c3/Make.defs +++ b/arch/risc-v/src/esp32c3/Make.defs @@ -41,6 +41,10 @@ CHIP_CSRCS += esp32c3_lowputc.c esp32c3_serial.c CHIP_CSRCS += esp32c3_systemreset.c esp32c3_resetcause.c CHIP_CSRCS += esp32c3_uid.c +ifeq ($(CONFIG_ESP32C3_REGION_PROTECTION),y) +CHIP_CSRCS += esp32c3_region.c +endif + ifeq ($(CONFIG_BUILD_PROTECTED),y) CHIP_CSRCS += esp32c3_userspace.c endif diff --git a/arch/risc-v/src/esp32c3/esp32c3_region.c b/arch/risc-v/src/esp32c3/esp32c3_region.c new file mode 100644 index 0000000000..ebad5821c1 --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_region.c @@ -0,0 +1,183 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_region.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 + +#include +#include + +#include "riscv_internal.h" +#include "hardware/esp32c3_soc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_BUILD_PROTECTED + /* BUILD_PROTECTED also makes use of the ESP32-C3 PMP (MPU) for isolating + * the Kernel from the Userspace. + */ + +# error "ESP32C3_REGION_PROTECTION shall not be enabled with Protected Mode" +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_region_protection + * + * Description: + * Configure the MPU to disable access to invalid memory regions. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + * Notes: + * 1) ESP32-C3 CPU doesn't support overlapping PMP regions. + * 2) Therefore, we use TOR (top of range) entries to map the whole address + * space, bottom to top. + * 3) There are not enough entries to describe all the memory regions 100% + * accurately. + * 4) This means some gaps (invalid memory) are accessible. Priority for + * extending regions to cover gaps is to extend read-only or read-execute + * regions or read-only regions only (executing unmapped addresses should + * always fault with invalid instruction, read-only means stores will + * correctly fault even if reads may return some invalid value). + * 5) Entries are grouped in order with some static asserts to try and verify + * everything is correct. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32C3_REGION_PROTECTION +void esp32c3_region_protection(void) +{ + const uintptr_t R = PMPCFG_L | PMPCFG_R; + const uintptr_t RW = PMPCFG_L | PMPCFG_R | PMPCFG_W; + const uintptr_t RX = PMPCFG_L | PMPCFG_R | PMPCFG_X; + const uintptr_t RWX = PMPCFG_L | PMPCFG_R | PMPCFG_W | PMPCFG_X; + + /* 1. Gap at bottom of address space */ + + riscv_config_pmp_region(0, PMPCFG_A_TOR, SOC_DEBUG_LOW, 0); + + /* 2. Debug region */ + + riscv_config_pmp_region(1, PMPCFG_A_TOR | RWX, SOC_DEBUG_HIGH, 0); + static_assert(SOC_DEBUG_LOW < SOC_DEBUG_HIGH, "Invalid CPU debug region"); + + /* 3. Gap between debug region & DROM (flash cache) */ + + riscv_config_pmp_region(2, PMPCFG_A_TOR, SOC_DROM_LOW, 0); + static_assert(SOC_DEBUG_HIGH < SOC_DROM_LOW, "Invalid PMP entry order"); + + /* 4. DROM (flash cache) + * 5. Gap between DROM & DRAM + * Note: To save PMP entries these two are merged into one read-only region + */ + + riscv_config_pmp_region(3, PMPCFG_A_TOR | R, SOC_DRAM_LOW, 0); + static_assert(SOC_DROM_LOW < SOC_DROM_HIGH, "Invalid DROM region"); + static_assert(SOC_DROM_HIGH < SOC_DRAM_LOW, "Invalid PMP entry order"); + + /* 6. DRAM */ + + riscv_config_pmp_region(4, PMPCFG_A_TOR | RW, SOC_DRAM_HIGH, 0); + static_assert(SOC_DRAM_LOW < SOC_DRAM_HIGH, "Invalid DRAM region"); + + /* 7. Gap between DRAM and Mask DROM + * 8. Mask DROM + * Note: to save PMP entries these two are merged into one read-only region + */ + + riscv_config_pmp_region(5, PMPCFG_A_TOR | R, SOC_DROM_MASK_HIGH, 0); + static_assert(SOC_DRAM_HIGH < SOC_DROM_MASK_LOW, + "Invalid PMP entry order"); + static_assert(SOC_DROM_MASK_LOW < SOC_DROM_MASK_HIGH, + "Invalid mask DROM region"); + + /* 9. Gap between mask DROM and mask IROM + * 10. Mask IROM + * Note: to save PMP entries these two are merged into one RX region + */ + + riscv_config_pmp_region(6, PMPCFG_A_TOR | RX, SOC_IROM_MASK_HIGH, 0); + static_assert(SOC_DROM_MASK_HIGH < SOC_IROM_MASK_LOW, + "Invalid PMP entry order"); + static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, + "Invalid mask IROM region"); + + /* 11. Gap between mask IROM & IRAM */ + + riscv_config_pmp_region(7, PMPCFG_A_TOR, SOC_IRAM_LOW, 0); + static_assert(SOC_IROM_MASK_HIGH < SOC_IRAM_LOW, + "Invalid PMP entry order"); + + /* 12. IRAM */ + + riscv_config_pmp_region(8, PMPCFG_A_TOR | RWX, SOC_IRAM_HIGH, 0); + static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid IRAM region"); + + /* 13. Gap between IRAM and IROM + * 14. IROM (flash cache) + * Note: to save PMP entries these two are merged into one RX region + */ + + riscv_config_pmp_region(9, PMPCFG_A_TOR | RX, SOC_IROM_HIGH, 0); + static_assert(SOC_IRAM_HIGH < SOC_IROM_LOW, "Invalid PMP entry order"); + static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid IROM region"); + + /* 15. Gap between IROM & RTC slow memory */ + + riscv_config_pmp_region(10, PMPCFG_A_TOR, SOC_RTC_RAM_LOW, 0); + static_assert(SOC_IROM_HIGH < SOC_RTC_RAM_LOW, "Invalid PMP entry order"); + + /* 16. RTC fast memory */ + + riscv_config_pmp_region(11, PMPCFG_A_TOR | RWX, SOC_RTC_RAM_HIGH, 0); + static_assert(SOC_RTC_RAM_LOW < SOC_RTC_RAM_HIGH, + "Invalid RTC IRAM region"); + + /* 17. Gap between RTC fast memory & peripheral addresses */ + + riscv_config_pmp_region(12, PMPCFG_A_TOR, SOC_PERIPHERAL_LOW, 0); + static_assert(SOC_RTC_RAM_HIGH < SOC_PERIPHERAL_LOW, + "Invalid PMP entry order"); + + /* 18. Peripheral addresses */ + + riscv_config_pmp_region(13, PMPCFG_A_TOR | RW, SOC_PERIPHERAL_HIGH, 0); + static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, + "Invalid peripheral region"); + + /* 19. End of address space */ + + riscv_config_pmp_region(14, PMPCFG_A_TOR, UINT32_MAX, 0); + riscv_config_pmp_region(15, PMPCFG_A_NA4, UINT32_MAX, 0); +} +#endif diff --git a/arch/risc-v/src/esp32c3/esp32c3_region.h b/arch/risc-v/src/esp32c3/esp32c3_region.h new file mode 100644 index 0000000000..a81e1b5ed4 --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_region.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_region.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_REGION_H +#define __ARCH_RISCV_SRC_ESP32C3_ESP32C3_REGION_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_region_protection + * + * Description: + * Configure the MPU to disable access to invalid memory regions. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32c3_region_protection(void); + +#if defined(__cplusplus) +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_RISCV_SRC_ESP32C3_ESP32C3_REGION_H */ diff --git a/arch/risc-v/src/esp32c3/esp32c3_start.c b/arch/risc-v/src/esp32c3/esp32c3_start.c index 2679cd6d15..ce92df4f86 100644 --- a/arch/risc-v/src/esp32c3/esp32c3_start.c +++ b/arch/risc-v/src/esp32c3/esp32c3_start.c @@ -36,6 +36,9 @@ #include "esp32c3_clockconfig.h" #include "esp32c3_irq.h" #include "esp32c3_lowputc.h" +#ifdef CONFIG_ESP32C3_REGION_PROTECTION +#include "esp32c3_region.h" +#endif #include "esp32c3_rtc.h" #include "esp32c3_start.h" #include "esp32c3_wdt.h" @@ -243,6 +246,12 @@ void __esp32c3_start(void) #endif +#ifdef CONFIG_ESP32C3_REGION_PROTECTION + /* Configure region protection */ + + esp32c3_region_protection(); +#endif + /* Initialize RTC parameters */ esp32c3_rtc_init(); diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/configs/knsh/defconfig b/boards/risc-v/esp32c3/esp32c3-devkit/configs/knsh/defconfig index 694a952499..85ae6a6af3 100644 --- a/boards/risc-v/esp32c3/esp32c3-devkit/configs/knsh/defconfig +++ b/boards/risc-v/esp32c3/esp32c3-devkit/configs/knsh/defconfig @@ -5,6 +5,7 @@ # You can then do "make savedefconfig" to generate a new defconfig file that includes your # modifications. # +# CONFIG_ESP32C3_REGION_PROTECTION is not set # CONFIG_NSH_ARGCAT is not set # CONFIG_NSH_CMDOPT_HEXDUMP is not set # CONFIG_NSH_CMDPARMS is not set