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/nuttx.git
commit c6b23e3e21ead6de128717e06c60e53e04ba750c Author: Marco Casaroli <[email protected]> AuthorDate: Thu Jul 30 14:16:04 2026 +0200 xtensa/esp32s3: Isolate the unprivileged world. Separate the world split from the protected user image, give WORLD1 its own vector table and its own PMS permissions -- including the PSRAM -- clean up the user cache-MMU windows, and stop keeping the page pool mapped. Folds in: xtensa/esp32s3: separate the world split from the protected user image xtensa/esp32s3: give the unprivileged world its own vector table xtensa/esp32s3: give the unprivileged world its permissions xtensa/esp32s3: clean up the user cache-MMU windows xtensa/esp32s3: stop keeping the page pool mapped xtensa/esp32s3: give the PSRAM its own PMS permissions Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- arch/xtensa/src/common/espressif/esp_irq.c | 4 +- arch/xtensa/src/esp32s3/Make.defs | 11 + arch/xtensa/src/esp32s3/esp32s3_isolation.c | 628 +++++++++++++++++++++ .../{esp32s3_userspace.h => esp32s3_isolation.h} | 73 ++- arch/xtensa/src/esp32s3/esp32s3_pms.c | 284 +++++++++- arch/xtensa/src/esp32s3/esp32s3_pms.h | 24 + arch/xtensa/src/esp32s3/esp32s3_start.c | 14 + arch/xtensa/src/esp32s3/esp32s3_userspace.c | 160 +----- arch/xtensa/src/esp32s3/esp32s3_userspace.h | 20 - arch/xtensa/src/esp32s3/esp32s3_wcl.c | 24 + arch/xtensa/src/esp32s3/esp32s3_world1_vectors.S | 221 ++++++++ .../esp32s3-devkit/configs/kernel_oct/defconfig | 1 + 12 files changed, 1251 insertions(+), 213 deletions(-) diff --git a/arch/xtensa/src/common/espressif/esp_irq.c b/arch/xtensa/src/common/espressif/esp_irq.c index 68f4ddb1c68..b7396d59b31 100644 --- a/arch/xtensa/src/common/espressif/esp_irq.c +++ b/arch/xtensa/src/common/espressif/esp_irq.c @@ -82,7 +82,7 @@ # include "hardware/esp32s3_soc.h" # include "esp_gpio.h" # include "esp32s3_rtc_gpio.h" -# include "esp32s3_userspace.h" +# include "esp32s3_isolation.h" # ifdef CONFIG_SMP # include "esp32s3_smp.h" # define ESP_FROMCPU1_PERIPH ESP32S3_PERIPH_INT_FROM_CPU1 @@ -107,7 +107,7 @@ # define ESP_NCPUS 1 #endif -#if defined(CONFIG_ARCH_CHIP_ESP32S3) && defined(CONFIG_BUILD_PROTECTED) +#if defined(CONFIG_ARCH_CHIP_ESP32S3) && !defined(CONFIG_BUILD_FLAT) # define esp_pmsirqinitialize() esp32s3_pmsirqinitialize() #else # define esp_pmsirqinitialize() diff --git a/arch/xtensa/src/esp32s3/Make.defs b/arch/xtensa/src/esp32s3/Make.defs index 6fd8e8087fb..574a99a599f 100644 --- a/arch/xtensa/src/esp32s3/Make.defs +++ b/arch/xtensa/src/esp32s3/Make.defs @@ -43,6 +43,17 @@ ifeq ($(CONFIG_BUILD_PROTECTED),y) CHIP_CSRCS += esp32s3_userspace.c endif +# The privileged/unprivileged world split itself, shared by the protected +# user split and the kernel-build address environments. + +ifneq ($(CONFIG_BUILD_FLAT),y) +CHIP_CSRCS += esp32s3_isolation.c +endif + +ifeq ($(CONFIG_BUILD_KERNEL),y) +CHIP_ASRCS += esp32s3_world1_vectors.S +endif + # The MMU/PMS/WCL primitives back both the protected user split and the # BUILD_KERNEL address-environment remap. diff --git a/arch/xtensa/src/esp32s3/esp32s3_isolation.c b/arch/xtensa/src/esp32s3/esp32s3_isolation.c new file mode 100644 index 00000000000..9521ac2f42f --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_isolation.c @@ -0,0 +1,628 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_isolation.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. + * + ****************************************************************************/ + +/* Permission control that a protected build and a kernel build share: the + * violation interrupt, and the peripheral permissions. Everything here + * concerns the WORLD0 (privileged) / WORLD1 (unprivileged) split and is + * independent of how the user memory itself is laid out, which is what + * separates the two build models. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> + +#include <nuttx/irq.h> +#include <nuttx/nuttx.h> +#include <nuttx/sched.h> + +#ifdef CONFIG_ESP32S3_PAGEFAULT_ABORT +#include <signal.h> +#include <arch/irq.h> +#include <arch/xtensa/xtensa_corebits.h> +#endif + +#include <assert.h> +#include <debug.h> + +#include "chip.h" +#include "xtensa.h" +#include "esp_attr.h" +#include "esp_irq.h" +#include "esp32s3_isolation.h" +#include "esp32s3_addrenv.h" +#include "esp32s3_pms.h" +#include "esp32s3_spiram.h" +#include "esp32s3_wcl.h" +#include "hardware/esp32s3_rom_layout.h" +#include "hardware/esp32s3_sensitive.h" +#include "hardware/esp32s3_soc.h" + +#include "soc/extmem_reg.h" + +#ifdef CONFIG_ESP32S3_PAGEFAULT_ABORT +#include "sched/sched.h" +#include "signal/signal.h" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_BUILD_KERNEL +/* The WORLD1 vector table is one Xtensa vector table: 1 KB. */ + +# define WORLD1_VECTORS_SIZE 0x400 +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef CONFIG_BUILD_KERNEL + +/* The WORLD1 vector table (esp32s3_world1_vectors.S), which the linker + * script places at the 1 KB alignment a vector base requires. + */ + +extern uint8_t _world1_vectors[]; + +/* The end of the kernel's instruction memory, and so the line that divides + * Internal SRAM1 between the instruction and the data bus. The linker + * script aligns it to the 256 bytes a split line needs. + */ + +extern uint8_t _iram_end[]; + +/* Vectors in the kernel's own table. Fetching one of these switches the CPU + * to WORLD0 once it is registered as a World Controller entry address. + */ + +extern void _user_exception_vector(void); +extern void _xtensa_level3_vector(void); +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_PAGEFAULT_ABORT + +/**************************************************************************** + * Name: pms_clear_violations + * + * Description: + * Acknowledge and re-arm every PMS violation monitor. The monitors raise + * a level-triggered interrupt, so the latch must be cleared (pulse the CLR + * bit) before returning from the ISR or the interrupt re-fires forever. + * + ****************************************************************************/ + +static void IRAM_ATTR pms_clear_violations(void) +{ + /* IRAM0 / DRAM0 / PIF monitors: pulse VIOLATE_CLR (keeping VIOLATE_EN). */ + + modifyreg32(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, 0, + SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_CLR_M); + modifyreg32(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, + SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_CLR_M, 0); + + modifyreg32(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, 0, + SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_CLR_M); + modifyreg32(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, + SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_CLR_M, 0); + + modifyreg32(SENSITIVE_CORE_0_PIF_PMS_MONITOR_1_REG, 0, + SENSITIVE_CORE_0_PIF_PMS_MONITOR_VIOLATE_CLR_M); + modifyreg32(SENSITIVE_CORE_0_PIF_PMS_MONITOR_1_REG, + SENSITIVE_CORE_0_PIF_PMS_MONITOR_VIOLATE_CLR_M, 0); + + /* Flash instruction/data cache reject monitors. */ + + modifyreg32(EXTMEM_CORE0_ACS_CACHE_INT_CLR_REG, 0, + EXTMEM_CORE0_IBUS_REJECT_INT_CLR_M | + EXTMEM_CORE0_DBUS_REJECT_INT_CLR_M); + modifyreg32(EXTMEM_CORE0_ACS_CACHE_INT_CLR_REG, + EXTMEM_CORE0_IBUS_REJECT_INT_CLR_M | + EXTMEM_CORE0_DBUS_REJECT_INT_CLR_M, 0); +} +#endif + +/**************************************************************************** + * Name: pms_violation_isr + * + * Description: + * This is the common PMS interrupt handler. It will be invoked the PMS + * detects an access violation. + * + * Parameters: + * cpuint - CPU interrupt index + * context - Context data from the ISR + * arg - Opaque pointer to the internal driver state structure. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +static int IRAM_ATTR pms_violation_isr(int cpuint, void *context, void *arg) +{ +#ifdef CONFIG_ESP32S3_PAGEFAULT_ABORT + uint32_t *regs = (uint32_t *)context; + + /* Acknowledge and re-arm the monitors first so the level-triggered + * interrupt does not immediately re-fire while we handle it. + */ + + pms_clear_violations(); + + /* An ESP32-S3 PMS permission violation is asynchronous (unlike the precise + * cache-attribute faults). If the interruptee was an unprivileged (user) + * WORLD1 task -- its saved PS carries the User Mode bit -- terminate only + * that task with SIGSEGV instead of the whole system. The IRQ dispatch + * return path applies the up_schedule_sigaction() redirect. + */ + + if (regs != NULL && (regs[REG_PS] & PS_UM) != 0) + { + struct tcb_s *tcb = this_task(); + siginfo_t info; + + _alert("SIGSEGV (PMS) task %s: PC=%08x\n", + get_task_name(tcb), (unsigned)regs[REG_PC]); + + info.si_signo = SIGSEGV; + info.si_code = SI_USER; + info.si_errno = 0; + info.si_value.sival_ptr = NULL; + + nxsig_tcbdispatch(tcb, &info, false); + return OK; + } +#endif + + /* Privileged (WORLD0) violation, or abort disabled: not survivable. */ + + PANIC(); + + return OK; +} + +#ifdef CONFIG_BUILD_KERNEL +/**************************************************************************** + * Name: isolation_enable_interrupts + * + * Description: + * Arm the permission violation monitors. The handler itself is registered + * later, from up_irqinitialize(); until then a violation is a panic, which + * is what an early kernel violation should be anyway. + * + ****************************************************************************/ + +static void isolation_enable_interrupts(void) +{ + modifyreg32(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, + SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_CLR_M, + SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_EN); + + modifyreg32(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, + SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_CLR_M, + SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_EN); + + modifyreg32(SENSITIVE_CORE_0_PIF_PMS_MONITOR_1_REG, + SENSITIVE_CORE_0_PIF_PMS_MONITOR_VIOLATE_CLR_M, + SENSITIVE_CORE_0_PIF_PMS_MONITOR_VIOLATE_EN); + + /* Instruction and data cache reject monitors. */ + + modifyreg32(EXTMEM_CORE0_ACS_CACHE_INT_CLR_REG, + EXTMEM_CORE0_IBUS_REJECT_INT_CLR_M | + EXTMEM_CORE0_DBUS_REJECT_INT_CLR_M, 0); + modifyreg32(EXTMEM_CORE0_ACS_CACHE_INT_ENA_REG, + EXTMEM_CORE0_IBUS_REJECT_INT_ENA_M | + EXTMEM_CORE0_DBUS_REJECT_INT_ENA_M, + EXTMEM_CORE0_IBUS_REJECT_INT_ENA | + EXTMEM_CORE0_DBUS_REJECT_INT_ENA); +} + +/**************************************************************************** + * Name: isolation_configure_iram + * + * Description: + * Instruction memory. All of it belongs to the kernel except the WORLD1 + * vector table, which the unprivileged world must be able to fetch and + * nothing more. + * + ****************************************************************************/ + +static void isolation_configure_iram(void) +{ + uintptr_t vstart = (uintptr_t)_world1_vectors; + uintptr_t vend = vstart + WORLD1_VECTORS_SIZE; + + /* Internal SRAM0, the blocks not given to the instruction cache. They + * hold the kernel's own vector table and the start of its IRAM code, and + * the hardware can say nothing finer than a whole 16 KB block here, which + * is why the WORLD1 table is not among them. + */ + + esp32s3_pms_configure_icache(PMS_AREA_0, PMS_WORLD_0, PMS_ACCESS_ALL); + esp32s3_pms_configure_icache(PMS_AREA_1, PMS_WORLD_0, PMS_ACCESS_ALL); + esp32s3_pms_configure_icache(PMS_AREA_0, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_icache(PMS_AREA_1, PMS_WORLD_1, PMS_ACCESS_NONE); + + /* Internal SRAM1, split around the WORLD1 vector table: + * + * area 0 the kernel's IRAM code + * area 1 the WORLD1 vector table + * area 2 whatever IRAM follows it + * area 3 past the main split line, which is data memory + */ + + esp32s3_pms_set_iram_split_line(PMS_SPLIT_LINE_0, vstart); + esp32s3_pms_set_iram_split_line(PMS_SPLIT_LINE_1, vend); + + esp32s3_pms_configure_iram_region(PMS_AREA_0, PMS_WORLD_0, PMS_ACCESS_ALL); + esp32s3_pms_configure_iram_region(PMS_AREA_1, PMS_WORLD_0, PMS_ACCESS_ALL); + esp32s3_pms_configure_iram_region(PMS_AREA_2, PMS_WORLD_0, PMS_ACCESS_ALL); + esp32s3_pms_configure_iram_region(PMS_AREA_3, PMS_WORLD_0, + PMS_ACCESS_NONE); + + esp32s3_pms_configure_iram_region(PMS_AREA_0, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_iram_region(PMS_AREA_1, PMS_WORLD_1, PMS_ACCESS_X); + esp32s3_pms_configure_iram_region(PMS_AREA_2, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_iram_region(PMS_AREA_3, PMS_WORLD_1, + PMS_ACCESS_NONE); +} + +/**************************************************************************** + * Name: isolation_configure_dram + * + * Description: + * Data memory. A kernel build has none that belongs to the user: a + * process keeps its data, heap and stacks in PSRAM behind the cache MMU, + * so the unprivileged world has no business in internal RAM at all. + * + ****************************************************************************/ + +static void isolation_configure_dram(void) +{ + uintptr_t rom_reserved = + ALIGN_DOWN(ets_rom_layout_p->dram0_rtos_reserved_start, 256); + + /* Internal SRAM2, the blocks not given to the data cache. */ + + esp32s3_pms_configure_dcache(PMS_WORLD_0, PMS_ACCESS_ALL); + esp32s3_pms_configure_dcache(PMS_WORLD_1, PMS_ACCESS_NONE); + + /* Area 0 is what lies before the main split line -- instruction memory, + * which is not to be reached over the data bus by either world. The rest + * is the kernel's. + */ + + esp32s3_pms_set_dram_split_line(PMS_SPLIT_LINE_0, + MAP_IRAM_TO_DRAM((uintptr_t)_iram_end)); + esp32s3_pms_set_dram_split_line(PMS_SPLIT_LINE_1, rom_reserved); + + esp32s3_pms_configure_dram_region(PMS_AREA_0, PMS_WORLD_0, + PMS_ACCESS_NONE); + esp32s3_pms_configure_dram_region(PMS_AREA_1, PMS_WORLD_0, PMS_ACCESS_ALL); + esp32s3_pms_configure_dram_region(PMS_AREA_2, PMS_WORLD_0, PMS_ACCESS_ALL); + esp32s3_pms_configure_dram_region(PMS_AREA_3, PMS_WORLD_0, PMS_ACCESS_ALL); + + esp32s3_pms_configure_dram_region(PMS_AREA_0, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_dram_region(PMS_AREA_1, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_dram_region(PMS_AREA_2, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_dram_region(PMS_AREA_3, PMS_WORLD_1, + PMS_ACCESS_NONE); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s3_isolation_revoke_peripherals + * + * Description: + * Refuse World 1 every peripheral. A user process reaches a device + * through the kernel, so it needs none of them directly. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_isolation_revoke_peripherals(void) +{ + /* Revoke User access permission to every peripheral */ + + esp32s3_pms_configure_peripheral(PMS_UART1, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_I2C, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_MISC, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_IO_MUX, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_RTC, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_FE, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_FE2, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_GPIO, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_G0SPI_0, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_G0SPI_1, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_UART, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_SYSTIMER, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_TIMERGROUP1, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_TIMERGROUP, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_BB, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_LEDC, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_RMT, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_UHCI0, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_I2C_EXT0, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_BT, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_PWR, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_WIFIMAC, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_RWBT, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_I2S1, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_CAN, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_APB_CTRL, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_SPI_2, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_WORLD_CONTROLLER, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_DIO, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_AD, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_CACHE_CONFIG, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_DMA_COPY, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_INTERRUPT, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_SENSITIVE, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_SYSTEM, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_BT_PWR, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_APB_ADC, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_CRYPTO_DMA, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_CRYPTO_PERI, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_USB_WRAP, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_USB_DEVICE, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_I2S0, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_HINF, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_PWM0, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_BACKUP, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_SLC, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_PCNT, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_SLCHOST, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_UART2, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_PWM1, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_SDIO_HOST, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_I2C_EXT1, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_SPI_3, PMS_WORLD_1, PMS_ACCESS_NONE); + esp32s3_pms_configure_peripheral(PMS_USB, PMS_WORLD_1, PMS_ACCESS_NONE); +} + +#ifdef CONFIG_BUILD_KERNEL + +/**************************************************************************** + * Name: esp32s3_isolation_worlds + * + * Description: + * Give World 1 its own vector table and register the kernel entry points + * that return the CPU to World 0. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_isolation_worlds(void) +{ + /* Give each world its own vector table. The override applies to both + * worlds at once, so WORLD0 has to be pointed at the kernel table it has + * been using all along, the one __start() loaded into VECBASE. + */ + + esp32s3_wcl_set_vecbase(PMS_WORLD_0, (uintptr_t)_init_start); + esp32s3_wcl_set_vecbase(PMS_WORLD_1, (uintptr_t)_world1_vectors); + + /* Fetching one of these kernel vectors is what takes the CPU back to + * WORLD0. Only the level 1 and level 3 paths record the interruptee's + * world on the way in and restore it on the way out, so only those two + * may be reached from WORLD1; the WORLD1 table handles window spills + * itself and never leaves the world. + */ + + esp32s3_wcl_set_world0_entry(1, (uintptr_t)_user_exception_vector); + esp32s3_wcl_set_world0_entry(2, (uintptr_t)_xtensa_level3_vector); +} + +/**************************************************************************** + * Name: esp32s3_isolation_permissions + * + * Description: + * Give World 1 its permissions: its own pages of the page pool, and + * nothing else. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_isolation_permissions(void) +{ + size_t psram_size; + + /* The WORLD1 vector table has to be in Internal SRAM1 for any of this to + * mean anything (see isolation_configure_iram), and a mistake here would + * be silent: the split lines would land somewhere harmless and the + * unprivileged world would keep its access to instruction memory. + */ + + ASSERT((uintptr_t)_world1_vectors >= SOC_DIRAM_IRAM_LOW && + (uintptr_t)_world1_vectors + WORLD1_VECTORS_SIZE <= + (uintptr_t)_iram_end); + + isolation_enable_interrupts(); + + /* Divide Internal SRAM1 into its instruction and data halves. The kernel + * image is linked with its IRAM below _iram_end and its data above the + * corresponding data-bus address. + */ + + esp32s3_pms_set_sram_main_split_line((uintptr_t)_iram_end); + + esp32s3_pms_configure_irom_access(); + esp32s3_pms_configure_drom_access(); + + isolation_configure_iram(); + isolation_configure_dram(); + + /* Cached external PSRAM. Every page of a user process -- text, data and + * heap alike -- is a page of the pgalloc pool, and that pool is a + * contiguous physical window of the PSRAM device. Give WORLD1 exactly + * that window and nothing else, so the kernel's own PSRAM above and below + * it is out of reach. The ACE addresses are physical offsets into the + * device, which is the same space mm_pgalloc() hands out. + * + * These registers were never programmed before, which left PSRAM at its + * reset value -- open to both worlds -- while the whole of user space + * lived in it. + */ + + psram_size = esp_spiram_get_size(); + + DEBUGASSERT(ESP32S3_PGPOOL_PEND <= psram_size); + + esp32s3_pms_set_sram_split_line(PMS_SPLIT_LINE_0, 0, + ESP32S3_PGPOOL_PBASE); + esp32s3_pms_set_sram_split_line(PMS_SPLIT_LINE_1, ESP32S3_PGPOOL_PBASE, + ESP32S3_PGPOOL_SIZE); + esp32s3_pms_set_sram_split_line(PMS_SPLIT_LINE_2, ESP32S3_PGPOOL_PEND, + psram_size - ESP32S3_PGPOOL_PEND); + + /* Region 3 is unused. Park it at the end of the device with zero length: + * the TRM forbids overlapping regions, so it cannot be left at zero. + */ + + esp32s3_pms_set_sram_split_line(PMS_SPLIT_LINE_3, psram_size, 0); + + esp32s3_pms_configure_sram_region(PMS_AREA_0, PMS_WORLD_0, + PMS_ACCESS_ALL); + esp32s3_pms_configure_sram_region(PMS_AREA_1, PMS_WORLD_0, + PMS_ACCESS_ALL); + esp32s3_pms_configure_sram_region(PMS_AREA_2, PMS_WORLD_0, + PMS_ACCESS_ALL); + esp32s3_pms_configure_sram_region(PMS_AREA_3, PMS_WORLD_0, + PMS_ACCESS_ALL); + + /* The pool holds text and data pages interleaved, so the grant has to + * cover both; the ACE cannot separate them at page granularity and W^X + * within a process is not what this boundary is for. + */ + + esp32s3_pms_configure_sram_region(PMS_AREA_0, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_sram_region(PMS_AREA_1, PMS_WORLD_1, + PMS_ACCESS_ALL); + esp32s3_pms_configure_sram_region(PMS_AREA_2, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_sram_region(PMS_AREA_3, PMS_WORLD_1, + PMS_ACCESS_NONE); + + /* Cached external flash. A user process whose text was copied into PSRAM + * needs nothing from flash -- but one running XIP does, so this cannot + * simply deny every region. Until the XIP case carries its own split + * line between the kernel image and the mapped application, WORLD1 keeps + * no flash access and XIP is unsupported here. + */ + + esp32s3_pms_configure_flash_cache_region(PMS_AREA_0, PMS_WORLD_0, + PMS_ACCESS_ALL); + esp32s3_pms_configure_flash_cache_region(PMS_AREA_1, PMS_WORLD_0, + PMS_ACCESS_ALL); + esp32s3_pms_configure_flash_cache_region(PMS_AREA_2, PMS_WORLD_0, + PMS_ACCESS_ALL); + esp32s3_pms_configure_flash_cache_region(PMS_AREA_3, PMS_WORLD_0, + PMS_ACCESS_ALL); + + esp32s3_pms_configure_flash_cache_region(PMS_AREA_0, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_flash_cache_region(PMS_AREA_1, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_flash_cache_region(PMS_AREA_2, PMS_WORLD_1, + PMS_ACCESS_NONE); + esp32s3_pms_configure_flash_cache_region(PMS_AREA_3, PMS_WORLD_1, + PMS_ACCESS_NONE); + + esp32s3_isolation_revoke_peripherals(); +} +#endif + +/**************************************************************************** + * Name: esp32s3_pmsirqinitialize + * + * Description: + * Install the handler that reports a permission violation. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_pmsirqinitialize(void) +{ + VERIFY(esp_setup_irq(ESP32S3_PERIPH_CORE_0_IRAM0_PMS_MONITOR_VIOLATE, + 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); + VERIFY(esp_setup_irq(ESP32S3_PERIPH_CORE_0_DRAM0_PMS_MONITOR_VIOLATE, + 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); + VERIFY(esp_setup_irq(ESP32S3_PERIPH_CACHE_CORE0_ACS, + 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); + VERIFY(esp_setup_irq(ESP32S3_PERIPH_CORE_0_PIF_PMS_MONITOR_VIOLATE, + 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); + + up_enable_irq(ESP32S3_IRQ_CORE_0_IRAM0_PMS_MONITOR_VIOLATE); + up_enable_irq(ESP32S3_IRQ_CORE_0_DRAM0_PMS_MONITOR_VIOLATE); + up_enable_irq(ESP32S3_IRQ_CACHE_CORE0_ACS); + up_enable_irq(ESP32S3_IRQ_CORE_0_PIF_PMS_MONITOR_VIOLATE); +} diff --git a/arch/xtensa/src/esp32s3/esp32s3_userspace.h b/arch/xtensa/src/esp32s3/esp32s3_isolation.h similarity index 50% copy from arch/xtensa/src/esp32s3/esp32s3_userspace.h copy to arch/xtensa/src/esp32s3/esp32s3_isolation.h index 0deff1d0f5c..5b0be7abf7b 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_userspace.h +++ b/arch/xtensa/src/esp32s3/esp32s3_isolation.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/xtensa/src/esp32s3/esp32s3_userspace.h + * arch/xtensa/src/esp32s3/esp32s3_isolation.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_USERSPACE_H -#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_USERSPACE_H +#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_ISOLATION_H +#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_ISOLATION_H /**************************************************************************** * Included Files @@ -31,19 +31,66 @@ * Public Functions Prototypes ****************************************************************************/ +#ifndef CONFIG_BUILD_FLAT + +/**************************************************************************** + * Name: esp32s3_isolation_revoke_peripherals + * + * Description: + * Revoke the unprivileged world's access to every peripheral. A user + * task reaches a peripheral only through a system call, so WORLD1 has no + * business addressing one directly. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_isolation_revoke_peripherals(void); + +#ifdef CONFIG_BUILD_KERNEL + +/**************************************************************************** + * Name: esp32s3_isolation_worlds + * + * Description: + * Give the unprivileged world its own vector table and tell the World + * Controller which kernel vectors return the CPU to the privileged world. + * A protected build does the equivalent from esp32s3_userspace.c, where + * the table belongs to the user image instead. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s3_isolation_worlds(void); + /**************************************************************************** - * Name: esp32s3_userspace + * Name: esp32s3_isolation_permissions * * 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. + * Program the permission control for a kernel build: what the + * unprivileged world may reach, which is the WORLD1 vector table and + * nothing else in internal memory, and arm the violation monitors. This + * is the kernel-build counterpart to configure_mpu() in + * esp32s3_userspace.c, which serves the protected user image. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. * ****************************************************************************/ -#ifdef CONFIG_BUILD_PROTECTED -void esp32s3_userspace(void); +void esp32s3_isolation_permissions(void); #endif /**************************************************************************** @@ -60,10 +107,10 @@ void esp32s3_userspace(void); * ****************************************************************************/ -#ifdef CONFIG_BUILD_PROTECTED void esp32s3_pmsirqinitialize(void); + #else # define esp32s3_pmsirqinitialize() -#endif +#endif /* !CONFIG_BUILD_FLAT */ -#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_USERSPACE_H */ +#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_ISOLATION_H */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_pms.c b/arch/xtensa/src/esp32s3/esp32s3_pms.c index e68c284252a..776b805b63f 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_pms.c +++ b/arch/xtensa/src/esp32s3/esp32s3_pms.c @@ -205,6 +205,17 @@ static void set_dram_split_line(uintptr_t addr, const uint32_t sensitive_reg) /**************************************************************************** * Name: esp32s3_pms_set_sram_main_split_line + * + * Description: + * Set the boundary that divides Internal SRAM1 between the instruction + * bus and the data bus. + * + * Input Parameters: + * addr - The boundary address. It must be aligned to 256 bytes. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_set_sram_main_split_line(uintptr_t addr) @@ -215,6 +226,18 @@ void esp32s3_pms_set_sram_main_split_line(uintptr_t addr) /**************************************************************************** * Name: esp32s3_pms_set_iram_split_line + * + * Description: + * Set one of the boundaries that divide the instruction bus into the + * areas a permission is given to. + * + * Input Parameters: + * line - Which boundary to set. + * addr - The boundary address. It must be aligned to 256 bytes. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_set_iram_split_line(enum pms_split_line_e line, @@ -244,6 +267,18 @@ void esp32s3_pms_set_iram_split_line(enum pms_split_line_e line, /**************************************************************************** * Name: esp32s3_pms_set_dram_split_line + * + * Description: + * Set one of the boundaries that divide the data bus into the areas a + * permission is given to. + * + * Input Parameters: + * line - Which boundary to set. + * addr - The boundary address. It must be aligned to 256 bytes. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_set_dram_split_line(enum pms_split_line_e line, @@ -273,6 +308,19 @@ void esp32s3_pms_set_dram_split_line(enum pms_split_line_e line, /**************************************************************************** * Name: esp32s3_pms_set_flash_cache_split_line + * + * Description: + * Set one of the boundaries that divide cached external flash into the + * areas a permission is given to. + * + * Input Parameters: + * line - Which boundary to set. + * addr - The start of the area. + * length - The length of the area in bytes. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_set_flash_cache_split_line(enum pms_split_line_e line, @@ -346,6 +394,18 @@ void esp32s3_pms_set_flash_cache_split_line(enum pms_split_line_e line, /**************************************************************************** * Name: esp32s3_pms_configure_iram_region + * + * Description: + * Give a world its permission on one area of the instruction bus. + * + * Input Parameters: + * area - Which area, as named by the split lines. + * world - The world the permission applies to. + * flags - The access to allow. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_configure_iram_region(enum pms_area_e area, @@ -375,6 +435,18 @@ void esp32s3_pms_configure_iram_region(enum pms_area_e area, /**************************************************************************** * Name: esp32s3_pms_configure_icache + * + * Description: + * Give a world its permission on one area of the instruction cache. + * + * Input Parameters: + * area - Which area, as named by the split lines. + * world - The world the permission applies to. + * flags - The access to allow. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_configure_icache(enum pms_area_e area, @@ -404,6 +476,17 @@ void esp32s3_pms_configure_icache(enum pms_area_e area, /**************************************************************************** * Name: esp32s3_pms_configure_dcache + * + * Description: + * Give a world its permission on the data cache. + * + * Input Parameters: + * world - The world the permission applies to. + * flags - The access to allow. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_configure_dcache(enum esp32s3_pms_world_e world, @@ -443,6 +526,18 @@ void esp32s3_pms_configure_dcache(enum esp32s3_pms_world_e world, /**************************************************************************** * Name: esp32s3_pms_configure_dram_region + * + * Description: + * Give a world its permission on one area of the data bus. + * + * Input Parameters: + * area - Which area, as named by the split lines. + * world - The world the permission applies to. + * flags - The access to allow. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_configure_dram_region(enum pms_area_e area, @@ -469,34 +564,47 @@ void esp32s3_pms_configure_dram_region(enum pms_area_e area, /**************************************************************************** * Name: esp32s3_pms_configure_flash_cache_region + * + * Description: + * Give a world its permission on one area of cached external flash. + * + * Input Parameters: + * area - Which area, as named by the split lines. + * world - The world the permission applies to. + * flags - The access to allow. + * + * Returned Value: + * None. + * ****************************************************************************/ +/**************************************************************************** + * Name: pms_ace_attr + * + * Description: + * Convert PMS_ACCESS_* flags to the 3-bit field the external-memory ACE + * registers use. TRM Table 15.5-2 (p.697): the field is ordered W/R/X + * with X in the least significant bit, which is the reverse of the order + * in enum pms_flags_e, and the reverse again of the IRAM0/DRAM0 constraint + * fields. Footnote C settles it: 0b010 grants read and neither write nor + * execute. + * + ****************************************************************************/ + +static uint32_t pms_ace_attr(enum pms_flags_e flags) +{ + return (((flags & PMS_ACCESS_W) != 0) << 2) | + (((flags & PMS_ACCESS_R) != 0) << 1) | + (((flags & PMS_ACCESS_X) != 0) << 0); +} + void esp32s3_pms_configure_flash_cache_region(enum pms_area_e area, enum esp32s3_pms_world_e world, enum pms_flags_e flags) { const uint32_t shift = (FLASH_CACHE_S * world); const uint32_t mask = FLASH_CACHE_V << shift; - uint32_t attr; - - if (flags == PMS_ACCESS_ALL) - { - attr = 0b11; - } - else if ((flags & PMS_ACCESS_W) != 0) - { - PANIC(); - } - else if ((flags & PMS_ACCESS_X) != 0) - { - attr = flags | 0b1; - } - else - { - attr = flags; - } - - uint32_t val = 0x40 | (attr & FLASH_CACHE_V) << shift; + const uint32_t val = pms_ace_attr(flags) << shift; switch (area) { @@ -528,8 +636,128 @@ void esp32s3_pms_configure_flash_cache_region(enum pms_area_e area, } } +/**************************************************************************** + * Name: esp32s3_pms_set_sram_split_line + * + * Description: + * Place one of the four external-SRAM (PSRAM) split regions. Address and + * length are physical -- a zero-based offset into the PSRAM device, the + * same space mm_pgalloc() hands out -- and both must be 64 KB aligned + * (TRM 15.5.1 p.696). Regions must not overlap. + * + ****************************************************************************/ + +void esp32s3_pms_set_sram_split_line(enum pms_split_line_e line, + uintptr_t addr, size_t length) +{ + uintptr_t aligned_addr = ALIGN_DOWN(addr, MMU_PAGE_SIZE); + size_t length_pages = length / MMU_PAGE_SIZE; + + switch (line) + { + case PMS_SPLIT_LINE_0: + { + modifyreg32(APB_CTRL_SRAM_ACE0_ADDR_REG, + APB_CTRL_SRAM_ACE0_ADDR_S_M, + VALUE_TO_FIELD(aligned_addr, + APB_CTRL_SRAM_ACE0_ADDR_S)); + modifyreg32(APB_CTRL_SRAM_ACE0_SIZE_REG, + APB_CTRL_SRAM_ACE0_SIZE_M, + VALUE_TO_FIELD(length_pages, APB_CTRL_SRAM_ACE0_SIZE)); + } + break; + case PMS_SPLIT_LINE_1: + { + modifyreg32(APB_CTRL_SRAM_ACE1_ADDR_REG, + APB_CTRL_SRAM_ACE1_ADDR_S_M, + VALUE_TO_FIELD(aligned_addr, + APB_CTRL_SRAM_ACE1_ADDR_S)); + modifyreg32(APB_CTRL_SRAM_ACE1_SIZE_REG, + APB_CTRL_SRAM_ACE1_SIZE_M, + VALUE_TO_FIELD(length_pages, APB_CTRL_SRAM_ACE1_SIZE)); + } + break; + case PMS_SPLIT_LINE_2: + { + modifyreg32(APB_CTRL_SRAM_ACE2_ADDR_REG, + APB_CTRL_SRAM_ACE2_ADDR_S_M, + VALUE_TO_FIELD(aligned_addr, + APB_CTRL_SRAM_ACE2_ADDR_S)); + modifyreg32(APB_CTRL_SRAM_ACE2_SIZE_REG, + APB_CTRL_SRAM_ACE2_SIZE_M, + VALUE_TO_FIELD(length_pages, APB_CTRL_SRAM_ACE2_SIZE)); + } + break; + case PMS_SPLIT_LINE_3: + { + modifyreg32(APB_CTRL_SRAM_ACE3_ADDR_REG, + APB_CTRL_SRAM_ACE3_ADDR_S_M, + VALUE_TO_FIELD(aligned_addr, + APB_CTRL_SRAM_ACE3_ADDR_S)); + modifyreg32(APB_CTRL_SRAM_ACE3_SIZE_REG, + APB_CTRL_SRAM_ACE3_SIZE_M, + VALUE_TO_FIELD(length_pages, APB_CTRL_SRAM_ACE3_SIZE)); + } + break; + default: + { + PANIC(); + } + break; + } +} + +/**************************************************************************** + * Name: esp32s3_pms_configure_sram_region + * + * Description: + * Set a world's permissions on one external-SRAM split region. Same + * field layout as the flash regions, TRM Table 15.5-2. + * + ****************************************************************************/ + +void esp32s3_pms_configure_sram_region(enum pms_area_e area, + enum esp32s3_pms_world_e world, + enum pms_flags_e flags) +{ + const uint32_t shift = (FLASH_CACHE_S * world); + const uint32_t mask = FLASH_CACHE_V << shift; + const uint32_t val = pms_ace_attr(flags) << shift; + + switch (area) + { + case PMS_AREA_0: + modifyreg32(APB_CTRL_SRAM_ACE0_ATTR_REG, mask, val); + break; + case PMS_AREA_1: + modifyreg32(APB_CTRL_SRAM_ACE1_ATTR_REG, mask, val); + break; + case PMS_AREA_2: + modifyreg32(APB_CTRL_SRAM_ACE2_ATTR_REG, mask, val); + break; + case PMS_AREA_3: + modifyreg32(APB_CTRL_SRAM_ACE3_ATTR_REG, mask, val); + break; + default: + PANIC(); + break; + } +} + /**************************************************************************** * Name: esp32s3_pms_configure_peripheral + * + * Description: + * Give a world its permission on one peripheral. + * + * Input Parameters: + * periph - The peripheral. + * world - The world the permission applies to. + * flags - The access to allow. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_configure_peripheral(enum pms_peripheral_e periph, @@ -567,6 +795,14 @@ void esp32s3_pms_configure_peripheral(enum pms_peripheral_e periph, /**************************************************************************** * Name: esp32s3_pms_configure_irom_access + * + * Description: + * Allow both worlds to read the instruction ROM. The ROM holds code that + * a user process still calls, so neither world can be refused it. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_configure_irom_access(void) @@ -588,6 +824,14 @@ void esp32s3_pms_configure_irom_access(void) /**************************************************************************** * Name: esp32s3_pms_configure_drom_access + * + * Description: + * Allow both worlds to read the data ROM. The ROM holds constants that a + * user process still reads, so neither world can be refused it. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_pms_configure_drom_access(void) diff --git a/arch/xtensa/src/esp32s3/esp32s3_pms.h b/arch/xtensa/src/esp32s3/esp32s3_pms.h index fe4bb7cc787..2afec694c0b 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_pms.h +++ b/arch/xtensa/src/esp32s3/esp32s3_pms.h @@ -251,6 +251,30 @@ void esp32s3_pms_configure_flash_cache_region(enum pms_area_e area, enum esp32s3_pms_world_e world, enum pms_flags_e flags); +/**************************************************************************** + * Name: esp32s3_pms_set_sram_split_line + * + * Description: + * Place one of the four external-SRAM (PSRAM) split regions. Address and + * length are physical offsets into the PSRAM device, both 64 KB aligned. + * + ****************************************************************************/ + +void esp32s3_pms_set_sram_split_line(enum pms_split_line_e line, + uintptr_t addr, size_t length); + +/**************************************************************************** + * Name: esp32s3_pms_configure_sram_region + * + * Description: + * Configure a world's access permissions to one external-SRAM region. + * + ****************************************************************************/ + +void esp32s3_pms_configure_sram_region(enum pms_area_e area, + enum esp32s3_pms_world_e world, + enum pms_flags_e flags); + /**************************************************************************** * Name: esp32s3_pms_configure_peripheral * diff --git a/arch/xtensa/src/esp32s3/esp32s3_start.c b/arch/xtensa/src/esp32s3/esp32s3_start.c index ecf6d42bdce..4e99f628137 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_start.c +++ b/arch/xtensa/src/esp32s3/esp32s3_start.c @@ -51,6 +51,9 @@ #ifdef CONFIG_BUILD_PROTECTED # include "esp32s3_userspace.h" #endif +#ifdef CONFIG_BUILD_KERNEL +# include "esp32s3_isolation.h" +#endif #include "esp32s3_spi_timing.h" #include "hardware/esp32s3_cache_memory.h" #include "hardware/esp32s3_system.h" @@ -441,6 +444,17 @@ noinstrument_function void noreturn_function IRAM_ATTR __esp32s3_start(void) showprogress('C'); #endif +#ifdef CONFIG_BUILD_KERNEL + /* A kernel build has no user image to load, but the unprivileged world + * still needs its vector table and its permissions before the first user + * process runs. + */ + + esp32s3_isolation_worlds(); + esp32s3_isolation_permissions(); + showprogress('C'); +#endif + /* Bring up NuttX */ nx_start(); diff --git a/arch/xtensa/src/esp32s3/esp32s3_userspace.c b/arch/xtensa/src/esp32s3/esp32s3_userspace.c index b18267a3b91..4a8cce1b176 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_userspace.c +++ b/arch/xtensa/src/esp32s3/esp32s3_userspace.c @@ -38,7 +38,7 @@ #include "chip.h" #include "xtensa.h" #include "esp_attr.h" -#include "esp_irq.h" +#include "esp32s3_isolation.h" #include "esp32s3_userspace.h" #include "esp32s3_mmu.h" #include "esp32s3_pms.h" @@ -50,8 +50,6 @@ #include "soc/extmem_reg.h" -#ifdef CONFIG_BUILD_PROTECTED - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -295,31 +293,6 @@ static void initialize_iram(void) } } -/**************************************************************************** - * Name: pms_violation_isr - * - * Description: - * This is the common PMS interrupt handler. It will be invoked the PMS - * detects an access violation. - * - * Parameters: - * cpuint - CPU interrupt index - * context - Context data from the ISR - * arg - Opaque pointer to the internal driver state structure. - * - * Returned Value: - * Zero (OK) is returned on success. A negated errno value is returned on - * failure. - * - ****************************************************************************/ - -static int IRAM_ATTR pms_violation_isr(int cpuint, void *context, void *arg) -{ - PANIC(); - - return OK; -} - /**************************************************************************** * Name: pms_enable_interrupts * @@ -617,102 +590,6 @@ static IRAM_ATTR void pms_configure_flash_cache_access(void) esp32s3_dcache_resume(cache_state); } -/**************************************************************************** - * Name: pms_configure_peripheral_access - * - * Description: - * Configure Kernel and Userspace permissions for accessing the chip's - * peripherals. - * - * Input Parameters: - * None. - * - * Returned Value: - * None. - * - ****************************************************************************/ - -static void pms_configure_peripheral_access(void) -{ - /* Revoke User access permission to every peripheral */ - - esp32s3_pms_configure_peripheral(PMS_UART1, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_I2C, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_MISC, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_IO_MUX, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_RTC, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_FE, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_FE2, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_GPIO, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_G0SPI_0, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_G0SPI_1, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_UART, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_SYSTIMER, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_TIMERGROUP1, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_TIMERGROUP, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_BB, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_LEDC, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_RMT, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_UHCI0, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_I2C_EXT0, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_BT, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_PWR, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_WIFIMAC, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_RWBT, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_I2S1, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_CAN, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_APB_CTRL, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_SPI_2, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_WORLD_CONTROLLER, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_DIO, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_AD, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_CACHE_CONFIG, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_DMA_COPY, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_INTERRUPT, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_SENSITIVE, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_SYSTEM, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_BT_PWR, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_APB_ADC, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_CRYPTO_DMA, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_CRYPTO_PERI, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_USB_WRAP, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_USB_DEVICE, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_I2S0, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_HINF, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_PWM0, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_BACKUP, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_SLC, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_PCNT, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_SLCHOST, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_UART2, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_PWM1, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_SDIO_HOST, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_I2C_EXT1, PMS_WORLD_1, - PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_SPI_3, PMS_WORLD_1, PMS_ACCESS_NONE); - esp32s3_pms_configure_peripheral(PMS_USB, PMS_WORLD_1, PMS_ACCESS_NONE); -} - /**************************************************************************** * Name: configure_mpu * @@ -767,7 +644,7 @@ static void configure_mpu(void) * peripherals. */ - pms_configure_peripheral_access(); + esp32s3_isolation_revoke_peripherals(); } /**************************************************************************** @@ -813,36 +690,3 @@ void esp32s3_userspace(void) configure_mpu(); } - -/**************************************************************************** - * Name: esp32s3_pmsirqinitialize - * - * Description: - * Initialize interrupt handler for the PMS violation ISR. - * - * Input Parameters: - * None. - * - * Returned Value: - * None. - * - ****************************************************************************/ - -void esp32s3_pmsirqinitialize(void) -{ - VERIFY(esp_setup_irq(ESP32S3_PERIPH_CORE_0_IRAM0_PMS_MONITOR_VIOLATE, - 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); - VERIFY(esp_setup_irq(ESP32S3_PERIPH_CORE_0_DRAM0_PMS_MONITOR_VIOLATE, - 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); - VERIFY(esp_setup_irq(ESP32S3_PERIPH_CACHE_CORE0_ACS, - 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); - VERIFY(esp_setup_irq(ESP32S3_PERIPH_CORE_0_PIF_PMS_MONITOR_VIOLATE, - 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); - - up_enable_irq(ESP32S3_IRQ_CORE_0_IRAM0_PMS_MONITOR_VIOLATE); - up_enable_irq(ESP32S3_IRQ_CORE_0_DRAM0_PMS_MONITOR_VIOLATE); - up_enable_irq(ESP32S3_IRQ_CACHE_CORE0_ACS); - up_enable_irq(ESP32S3_IRQ_CORE_0_PIF_PMS_MONITOR_VIOLATE); -} - -#endif /* CONFIG_BUILD_PROTECTED */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_userspace.h b/arch/xtensa/src/esp32s3/esp32s3_userspace.h index 0deff1d0f5c..2496042ed2a 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_userspace.h +++ b/arch/xtensa/src/esp32s3/esp32s3_userspace.h @@ -46,24 +46,4 @@ void esp32s3_userspace(void); #endif -/**************************************************************************** - * Name: esp32s3_pmsirqinitialize - * - * Description: - * Initialize interrupt handler for the PMS violation ISR. - * - * Input Parameters: - * None. - * - * Returned Value: - * None. - * - ****************************************************************************/ - -#ifdef CONFIG_BUILD_PROTECTED -void esp32s3_pmsirqinitialize(void); -#else -# define esp32s3_pmsirqinitialize() -#endif - #endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_USERSPACE_H */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_wcl.c b/arch/xtensa/src/esp32s3/esp32s3_wcl.c index d66e836b321..f176f25d611 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_wcl.c +++ b/arch/xtensa/src/esp32s3/esp32s3_wcl.c @@ -57,6 +57,18 @@ /**************************************************************************** * Name: esp32s3_wcl_set_vecbase + * + * Description: + * Set the vector table a world uses, and make the World Controller take + * the value from these registers instead of the reset default. + * + * Input Parameters: + * world - The world the table belongs to. + * vecbase - The address of the table. It must be aligned to 1 KB. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_wcl_set_vecbase(enum esp32s3_pms_world_e world, @@ -97,6 +109,18 @@ void esp32s3_wcl_set_vecbase(enum esp32s3_pms_world_e world, /**************************************************************************** * Name: esp32s3_wcl_set_world0_entry + * + * Description: + * Register an address that returns the CPU to World 0 when it is fetched. + * This is how an exception taken in World 1 reaches a kernel handler. + * + * Input Parameters: + * entry - Which entry to set, from 1 to WCL_ENTRY_MAX. + * addr - The address that switches the world. + * + * Returned Value: + * None. + * ****************************************************************************/ void esp32s3_wcl_set_world0_entry(uint32_t entry, uintptr_t addr) diff --git a/arch/xtensa/src/esp32s3/esp32s3_world1_vectors.S b/arch/xtensa/src/esp32s3/esp32s3_world1_vectors.S new file mode 100644 index 00000000000..e6dcb31cc18 --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_world1_vectors.S @@ -0,0 +1,221 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_world1_vectors.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. + * + ****************************************************************************/ + +/* The vector table used while the CPU executes in WORLD1, the unprivileged + * world, in a kernel build. The World Controller gives each world its own + * vector table base, and this one exists so that WORLD1 needs no execute + * permission on the kernel's own vectors. + * + * Window overflow and underflow are handled here, in WORLD1, because they + * only ever touch the interrupted task's own stack and because there is no + * way back: entering the kernel table switches the CPU to WORLD0, and only + * the level 1 and level 3 exception paths restore the interruptee's world + * on the way out (see exception_exit_hook in chip_macros.h). A window spill + * returns with RFWO/RFWU, which would leave the task running privileged. + * + * Every other vector jumps to its counterpart in the kernel table. Those + * kernel entry points are registered with the World Controller as WORLD0 + * entry addresses, so fetching one is what switches the CPU to WORLD0 -- the + * jump instruction itself still executes in WORLD1, out of this table. + * + * The layout must match the kernel table in esp32s3_sections.ld, since the + * hardware picks the slot by exception type and vector base alone. + */ + + .file "esp32s3_world1_vectors.S" + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <arch/irq.h> +#include <arch/chip/core-isa.h> +#include <arch/xtensa/xtensa_abi.h> +#include <arch/xtensa/xtensa_specregs.h> + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + + .section .world1_vectors.text, "ax" + .global _world1_vectors + .type _world1_vectors, @function + .align 1024 + +_world1_vectors: + +/**************************************************************************** + * Window exception vectors + ****************************************************************************/ + +/**************************************************************************** + * Name: _world1_window_overflow4 + ****************************************************************************/ + + .org 0x0 + .global _world1_window_overflow4 +_world1_window_overflow4: + s32e a0, a5, -16 /* save a0 to call[j+1]'s stack frame */ + s32e a1, a5, -12 /* save a1 to call[j+1]'s stack frame */ + s32e a2, a5, -8 /* save a2 to call[j+1]'s stack frame */ + s32e a3, a5, -4 /* save a3 to call[j+1]'s stack frame */ + rfwo /* rotates back to call[i] position */ + +/**************************************************************************** + * Name: _world1_window_underflow4 + ****************************************************************************/ + + .org 0x40 + .global _world1_window_underflow4 +_world1_window_underflow4: + l32e a0, a5, -16 /* restore a0 from call[i+1]'s stack frame */ + l32e a1, a5, -12 /* restore a1 from call[i+1]'s stack frame */ + l32e a2, a5, -8 /* restore a2 from call[i+1]'s stack frame */ + l32e a3, a5, -4 /* restore a3 from call[i+1]'s stack frame */ + rfwu + +/**************************************************************************** + * Name: _world1_window_overflow8 + ****************************************************************************/ + + .org 0x80 + .global _world1_window_overflow8 +_world1_window_overflow8: + s32e a0, a9, -16 /* save a0 to call[j+1]'s stack frame */ + l32e a0, a1, -12 /* a0 <- call[j-1]'s sp + (used to find end of call[j]'s frame) */ + s32e a1, a9, -12 /* save a1 to call[j+1]'s stack frame */ + s32e a2, a9, -8 /* save a2 to call[j+1]'s stack frame */ + s32e a3, a9, -4 /* save a3 to call[j+1]'s stack frame */ + s32e a4, a0, -32 /* save a4 to call[j]'s stack frame */ + s32e a5, a0, -28 /* save a5 to call[j]'s stack frame */ + s32e a6, a0, -24 /* save a6 to call[j]'s stack frame */ + s32e a7, a0, -20 /* save a7 to call[j]'s stack frame */ + rfwo /* rotates back to call[i] position */ + +/**************************************************************************** + * Name: _world1_window_underflow8 + ****************************************************************************/ + + .org 0xc0 + .global _world1_window_underflow8 +_world1_window_underflow8: + l32e a0, a9, -16 /* restore a0 from call[i+1]'s stack frame */ + l32e a1, a9, -12 /* restore a1 from call[i+1]'s stack frame */ + l32e a2, a9, -8 /* restore a2 from call[i+1]'s stack frame */ + l32e a7, a1, -12 /* a7 <- call[i-1]'s sp + (used to find end of call[i]'s frame) */ + l32e a3, a9, -4 /* restore a3 from call[i+1]'s stack frame */ + l32e a4, a7, -32 /* restore a4 from call[i]'s stack frame */ + l32e a5, a7, -28 /* restore a5 from call[i]'s stack frame */ + l32e a6, a7, -24 /* restore a6 from call[i]'s stack frame */ + l32e a7, a7, -20 /* restore a7 from call[i]'s stack frame */ + rfwu + +/**************************************************************************** + * Name: _world1_window_overflow12 + ****************************************************************************/ + + .org 0x100 + .global _world1_window_overflow12 +_world1_window_overflow12: + s32e a0, a13, -16 /* save a0 to call[j+1]'s stack frame */ + l32e a0, a1, -12 /* a0 <- call[j-1]'s sp + (used to find end of call[j]'s frame) */ + s32e a1, a13, -12 /* save a1 to call[j+1]'s stack frame */ + s32e a2, a13, -8 /* save a2 to call[j+1]'s stack frame */ + s32e a3, a13, -4 /* save a3 to call[j+1]'s stack frame */ + s32e a4, a0, -48 /* save a4 to end of call[j]'s stack frame */ + s32e a5, a0, -44 /* save a5 to end of call[j]'s stack frame */ + s32e a6, a0, -40 /* save a6 to end of call[j]'s stack frame */ + s32e a7, a0, -36 /* save a7 to end of call[j]'s stack frame */ + s32e a8, a0, -32 /* save a8 to end of call[j]'s stack frame */ + s32e a9, a0, -28 /* save a9 to end of call[j]'s stack frame */ + s32e a10, a0, -24 /* save a10 to end of call[j]'s stack frame */ + s32e a11, a0, -20 /* save a11 to end of call[j]'s stack frame */ + rfwo /* rotates back to call[i] position */ + +/**************************************************************************** + * Name: _world1_window_underflow12 + ****************************************************************************/ + + .org 0x140 + .global _world1_window_underflow12 +_world1_window_underflow12: + l32e a0, a13, -16 /* restore a0 from call[i+1]'s stack frame */ + l32e a1, a13, -12 /* restore a1 from call[i+1]'s stack frame */ + l32e a2, a13, -8 /* restore a2 from call[i+1]'s stack frame */ + l32e a11, a1, -12 /* a11 <- call[i-1]'s sp + (used to find end of call[i]'s frame) */ + l32e a3, a13, -4 /* restore a3 from call[i+1]'s stack frame */ + l32e a4, a11, -48 /* restore a4 from end of call[i]'s stack frame */ + l32e a5, a11, -44 /* restore a5 from end of call[i]'s stack frame */ + l32e a6, a11, -40 /* restore a6 from end of call[i]'s stack frame */ + l32e a7, a11, -36 /* restore a7 from end of call[i]'s stack frame */ + l32e a8, a11, -32 /* restore a8 from end of call[i]'s stack frame */ + l32e a9, a11, -28 /* restore a9 from end of call[i]'s stack frame */ + l32e a10, a11, -24 /* restore a10 from end of call[i]'s stack frame */ + l32e a11, a11, -20 /* restore a11 from end of call[i]'s stack frame */ + rfwu + +/**************************************************************************** + * Medium-/High-priority interrupt vectors + ****************************************************************************/ + + .org 0x180 + j _xtensa_level2_vector + + .org 0x1c0 + j _xtensa_level3_vector + +/* 0x200 and 0x240 are the level 4 and level 5 vectors. This configuration + * has no interrupt above level 3, and the kernel table leaves those slots + * empty as well. + */ + + .org 0x280 + j _debug_exception_vector + + .org 0x2c0 + j _xtensa_nmi_vector + +/**************************************************************************** + * General exception vectors + ****************************************************************************/ + +/* A WORLD1 task always takes the user exception vector, since it runs with + * PS.UM set. The kernel slot is jumped to anyway, so that a table entry is + * never a hole. + */ + + .org 0x300 + j _kernel_exception_vector + + .org 0x340 + j _user_exception_vector + + .org 0x3c0 + j _double_exception_vector + + .org 0x400 + + .size _world1_vectors, . - _world1_vectors diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/configs/kernel_oct/defconfig b/boards/xtensa/esp32s3/esp32s3-devkit/configs/kernel_oct/defconfig index e7b65090a03..0e515654878 100644 --- a/boards/xtensa/esp32s3/esp32s3-devkit/configs/kernel_oct/defconfig +++ b/boards/xtensa/esp32s3/esp32s3-devkit/configs/kernel_oct/defconfig @@ -57,6 +57,7 @@ CONFIG_ESP32S3_SPIRAM=y CONFIG_ESP32S3_SPIRAM_MODE_OCT=y CONFIG_ESP32S3_UART0=y CONFIG_ESP32S3_WCL=y +CONFIG_EXAMPLES_PFFAULT=y CONFIG_FS_PROCFS=y CONFIG_FS_ROMFS=y CONFIG_HAVE_CXX=y
