From c7194760cd30b21531ab28399e8fcbdf717d5d97 Mon Sep 17 00:00:00 2001 From: Mark Stevens Date: Sat, 12 Sep 2026 12:41:42 +0100 Subject: [PATCH 1/5] risc-v/esp32p4: Add BUILD_PROTECTED support. Add CONFIG_BUILD_PROTECTED for the ESP32-P4, linking the kernel and the user applications as two separate images: the kernel runs in machine mode, user code in user mode, and the PMP enforces the split. Adds an esp32p4-tab5:knsh configuration that exercises it. The P4 uses a CLIC, where mcause is not only a cause register. It carries mpp[29:28], mpie[27], minhv[30] and mpil[23:16], and mret restores privilege from mpp and mintstatus.mil from mpil. Upstream reads mcause for dispatch and then discards it, which is correct on a CLINT part and lossy here: whatever the last trap left in the CSR is what the next mret consumes. Two changes follow. * mcause is saved and restored with the trap frame. REG_MCAUSE_NDX is 33, so INT_XCPT_REGS becomes 34. This is an ABI change to the trap frame and is therefore gated to ARCH_CHIP_ESP32P4 && !BUILD_FLAT; every other RISC-V port keeps 33 and an unchanged frame layout. It uses the existing ARCH_RISCV_INTXCPT_EXTREGS extension slot, so REG_INT_CTX and everything below it keep their offsets. It is restored before mstatus: mstatus.MPP/MPIE are aliased into mcause[29:28]/[27], and synthesised frames leave the slot zero, so writing mcause after mstatus would drop kernel threads to U-mode and fault on the first instruction fetch of kernel text. * On a return to U-mode, mcause.interrupt (31) and minhv (30) are cleared. The frame's mcause is the value latched for the trap that saved the frame, but after a context switch the frame is restored by a different trap, so interrupt = 1 tells the CLIC it is returning from an interrupt that is not in flight. Kernel returns are left alone. Both changes are required; with either one alone the port does not reach NSH. There is no impact on other RISC-V ports. Every line added to the shared files sits inside CONFIG_RISCV_FRAME_TRACE, REG_MCAUSE or CONFIG_ARCH_CHIP_ESP32P4, all of which are false elsewhere. Two new Kconfig options, both default n and fully compiled out when off: * RISCV_FRAME_TRACE - a ring of trap frames recorded where the kernel chooses which frame to resume. Generic rather than Espressif-local because the hooks are in shared files. * ESPRESSIF_P4DBG - counters in the IRQ, idle and timer paths plus bring-up markers via ROM printf. Tested on an M5Stack Tab5 (ESP32-P4 rev v1.0), ostest run from NSH on hardware: esp32p4-tab5:knsh 224,280 B kernel + 144,544 B user ostest status 0, 154 sections, 99.5 s knsh + both debug options 225,176 B kernel ostest status 0, 154 sections, 99.3 s esp32p4-tab5:nsh (flat) ostest status 0, 162 sections, 125.5 s The flat configuration is unchanged by this commit. TESTING_OSTEST is not in its shipped defconfig and was enabled for that run only. Known limitation: the USB Serial/JTAG console does not come up in a protected build, so knsh uses UART0 at 115200. The flat nsh over USB is unaffected. This is under investigation and is not a regression. Assisted-by: Claude:claude-opus-5 Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Mark Stevens --- .../esp32p4/boards/esp32p4-tab5/index.rst | 30 ++ arch/risc-v/Kconfig | 19 + arch/risc-v/include/irq.h | 27 +- .../src/common/espressif/CMakeLists.txt | 8 + arch/risc-v/src/common/espressif/Kconfig | 91 ++++ arch/risc-v/src/common/espressif/Make.defs | 8 + .../src/common/espressif/esp_allocateheap.c | 23 +- arch/risc-v/src/common/espressif/esp_idle.c | 61 +++ arch/risc-v/src/common/espressif/esp_irq.c | 51 +++ arch/risc-v/src/common/espressif/esp_p4dbg.h | 99 +++++ .../src/common/espressif/esp_region_protect.c | 107 +++++ arch/risc-v/src/common/espressif/esp_start.c | 134 ++++++ .../src/common/espressif/esp_timerisr.c | 47 ++ .../src/common/espressif/esp_userspace.c | 410 ++++++++++++++++++ .../src/common/espressif/esp_userspace.h | 65 +++ arch/risc-v/src/common/riscv_doirq.c | 8 + .../src/common/riscv_exception_common.S | 85 ++++ arch/risc-v/src/common/riscv_internal.h | 35 ++ .../src/common/riscv_schedulesigaction.c | 9 + arch/risc-v/src/common/riscv_swint.c | 194 +++++++++ arch/risc-v/src/esp32p4/hal_esp32p4.cmake | 10 + arch/risc-v/src/esp32p4/hal_esp32p4.mk | 2 + boards/risc-v/esp32p4/common/kernel/Makefile | 125 ++++++ .../esp32p4/common/kernel/esp_userspace.c | 111 +++++ .../scripts/esp32p4_protected_memory.ld | 183 ++++++++ .../common/scripts/esp32p4_sections.ld | 380 ++++++++-------- .../common/scripts/esp32p4_sections.rev3.ld | 389 ++++++++--------- .../esp32p4/common/scripts/kernel-space.ld | 76 ++++ .../esp32p4/common/scripts/user-space.ld | 221 ++++++++++ .../esp32p4-tab5/configs/knsh/defconfig | 70 +++ .../esp32p4-tab5/include/board_memorymap.h | 118 +++++ .../esp32p4/esp32p4-tab5/scripts/Make.defs | 19 +- .../esp32p4-tab5/src/esp32p4_bringup.c | 60 +++ tools/espressif/Config.mk | 10 + 34 files changed, 2898 insertions(+), 387 deletions(-) create mode 100644 arch/risc-v/src/common/espressif/esp_p4dbg.h create mode 100644 arch/risc-v/src/common/espressif/esp_region_protect.c create mode 100644 arch/risc-v/src/common/espressif/esp_userspace.c create mode 100644 arch/risc-v/src/common/espressif/esp_userspace.h create mode 100644 boards/risc-v/esp32p4/common/kernel/Makefile create mode 100644 boards/risc-v/esp32p4/common/kernel/esp_userspace.c create mode 100644 boards/risc-v/esp32p4/common/scripts/esp32p4_protected_memory.ld create mode 100644 boards/risc-v/esp32p4/common/scripts/kernel-space.ld create mode 100644 boards/risc-v/esp32p4/common/scripts/user-space.ld create mode 100644 boards/risc-v/esp32p4/esp32p4-tab5/configs/knsh/defconfig create mode 100644 boards/risc-v/esp32p4/esp32p4-tab5/include/board_memorymap.h diff --git a/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst b/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst index 60710556b7d2e..a981726117a2f 100644 --- a/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst +++ b/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst @@ -200,6 +200,20 @@ We can use the interrupt pin to send a signal when the interrupt fires:: The pin is configured as a rising edge interrupt, so after issuing the above command, connect it to 3.3V. +knsh +---- + +This is identical to the ``nsh`` configuration below except that NuttX is +built in protected mode (``CONFIG_BUILD_PROTECTED``): the kernel and the user +applications are linked as two separate images, the kernel runs in machine +mode and user code in user mode, and the PMP enforces the split. + +The console is UART0 rather than the USB Serial/JTAG port, so connect to the +board's UART adapter rather than ``/dev/ttyACM0``. + +The build produces two images, ``nuttx.bin`` and ``nuttx_user.bin``; see +`Building and flashing`_ for the offsets. + lvgl_demo --------- @@ -301,3 +315,19 @@ Then open the console: $ picocom -b 115200 /dev/ttyACM0 nsh> + +Protected build +--------------- + +The ``knsh`` configuration produces a second image for user space, which is +flashed at ``CONFIG_ESPRESSIF_USER_IMAGE_OFFSET`` (``0x110000`` by default): + +.. code-block:: console + + $ ./tools/configure.sh esp32p4-tab5:knsh + $ make -j + $ esptool.py -c esp32p4 -p /dev/ttyACM0 -b 921600 write_flash \ + 0x2000 nuttx.bin 0x110000 nuttx_user.bin + +``make flash ESPTOOL_PORT=`` does both in one step. The console for this +configuration is UART0 at 115200, not the USB Serial/JTAG port. diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index 8ca236430636e..672a7907b4d6b 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -732,6 +732,25 @@ config RISCV_MISALIGNED_HANDLER depends on ARCH_HAVE_MISALIGN_EXCEPTION default y +config RISCV_FRAME_TRACE + bool "Trap frame trace (debug)" + default n + depends on !BUILD_FLAT + ---help--- + Record a ring of trap frames at the points where the kernel chooses + which frame to resume: interrupt dispatch, context-switch + syscalls, syscall return and the signal paths. Each entry holds the + frame pointer, EPC, the saved status word and, where the + architecture carries it, mcause. + + Intended too help debugging a protected build, where a frame restored + may be with the wrong privilege or interrupt level + Nothing is printed inline; the ring is read out + of RAM with a debugger, or dumped from the panic path. + + This adds a call on every trap dispatch and a static ring buffer + and is not intended fro production builds. + config RISCV_PERCPU_SCRATCH bool "Enable Scratch-based Per-CPU storage" default y if LIB_SYSCALL diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h index 77ef18eca0719..24e466103c65a 100644 --- a/arch/risc-v/include/irq.h +++ b/arch/risc-v/include/irq.h @@ -201,7 +201,26 @@ #define REG_INT_CTX_NDX 32 -#ifdef CONFIG_ARCH_RISCV_INTXCPT_EXTREGS +/* On a CLIC part, mcause carries mpp / mpie / mpil / interrupt -- state that + * mret consults -- so it must be saved and restored with the frame, not just + * read for dispatch. Uses the ARCH_RISCV_INTXCPT_EXTREGS extension slot, + * so REG_INT_CTX and everything below it keep their existing offsets. + */ + +#if defined(CONFIG_ARCH_CHIP_ESP32P4) && !defined(CONFIG_BUILD_FLAT) +# define REG_MCAUSE_NDX 33 +#endif + +#ifdef REG_MCAUSE_NDX + +/* The frame carries mcause as well; keep it sized to match. */ + +# ifdef CONFIG_ARCH_RISCV_INTXCPT_EXTREGS +# define INT_XCPT_REGS (34 + CONFIG_ARCH_RISCV_INTXCPT_EXTREGS) +# else +# define INT_XCPT_REGS 34 +# endif +#elif defined(CONFIG_ARCH_RISCV_INTXCPT_EXTREGS) # define INT_XCPT_REGS (33 + CONFIG_ARCH_RISCV_INTXCPT_EXTREGS) #else # define INT_XCPT_REGS 33 @@ -347,6 +366,9 @@ # define REG_X30 (INT_REG_SIZE*REG_X30_NDX) # define REG_X31 (INT_REG_SIZE*REG_X31_NDX) # define REG_INT_CTX (INT_REG_SIZE*REG_INT_CTX_NDX) +#ifdef REG_MCAUSE_NDX +# define REG_MCAUSE (INT_REG_SIZE*REG_MCAUSE_NDX) +#endif #ifdef CONFIG_ARCH_FPU # define REG_F0 (INT_REG_SIZE*REG_F0_NDX) @@ -426,6 +448,9 @@ # define REG_X30 REG_X30_NDX # define REG_X31 REG_X31_NDX # define REG_INT_CTX REG_INT_CTX_NDX +#ifdef REG_MCAUSE_NDX +# define REG_MCAUSE REG_MCAUSE_NDX +#endif #ifdef CONFIG_ARCH_FPU # define REG_F0 REG_F0_NDX diff --git a/arch/risc-v/src/common/espressif/CMakeLists.txt b/arch/risc-v/src/common/espressif/CMakeLists.txt index 350a7beede9bc..2a9db6c62e7b9 100644 --- a/arch/risc-v/src/common/espressif/CMakeLists.txt +++ b/arch/risc-v/src/common/espressif/CMakeLists.txt @@ -23,6 +23,14 @@ set(SRCS) # Head/startup file +if(CONFIG_ESPRESSIF_KERNEL_OWNS_PMP) + list(APPEND SRCS esp_region_protect.c) +endif() + +if(CONFIG_BUILD_PROTECTED) + list(APPEND SRCS esp_userspace.c) +endif() + list(APPEND SRCS esp_head.S) # Custom vector table (skip common RISC-V vector table) diff --git a/arch/risc-v/src/common/espressif/Kconfig b/arch/risc-v/src/common/espressif/Kconfig index 5cb80562ed0bf..b74fe0ef46879 100644 --- a/arch/risc-v/src/common/espressif/Kconfig +++ b/arch/risc-v/src/common/espressif/Kconfig @@ -34,6 +34,19 @@ config ESPRESSIF_FLASH_32M endchoice # ESPRESSIF_FLASH +config ESPRESSIF_P4DBG + bool "ESP32-P4 protected-build debug counters" + default n + depends on ARCH_CHIP_ESP32P4 && !BUILD_FLAT + ---help--- + Maintain counters and CLIC state snapshots in the interrupt, idle and + timer paths. Emit progress markers from board bring-up using the + ROM printf rather than syslog. + + The counters should be read with a debugger. + + Debug aid, do not activate in a production build. + config ESPRESSIF_DONT_USE_ROM_LIBC bool "Don't use ROM libc functions" default n @@ -238,6 +251,84 @@ config ESPRESSIF_REGION_PROTECTION ---help--- Configure the MPU to disable access to invalid memory regions. + Must be disabled in a protected build; esp_start.c fails the build + if it is not. It only adds a second, redundant call to + esp_cpu_configure_region_protection() late in esp_start() -- the + regions have already been programmed from bootloader_init() by then + -- and in a protected build the kernel owns the PMP and re-describes + it during userspace initialisation, so the extra call is pointless + at best and racy against that setup at worst. + + This is enforced with a compile-time check rather than + "depends on !BUILD_PROTECTED". This symbol selects ARCH_USE_MPU and + BUILD_PROTECTED depends on ARCH_USE_MPU, so a dependency on the + build type closes a loop that Kconfig resolves by making + BUILD_PROTECTED unsatisfiable -- which silently collapses the whole + "Memory organization" choice for every board in the tree. + +config ESPRESSIF_KERNEL_OWNS_PMP + bool "Kernel owns the PMP configuration" + depends on ARCH_CHIP_ESP32P4 + default n + select ARCH_USE_MPU + ---help--- + Drop the HAL's esp_cpu_configure_region_protection() from the build + and supply a NuttX build of the same code with the PMP lock bit + cleared. The region layout, and the PMA setup the SoC needs in + order to run at all, are unchanged; only the lock bit differs. + + The HAL version sets the lock bit on every entry it writes, and runs + from bootloader_init() before NuttX can intervene. PMP lock bits + are irreversible without the Smepmp extension, which the ESP32-P4 + does not implement, so a protected build has to prevent the locking + rather than undo it. + + A protected build requires this and must set it explicitly in its + defconfig; esp_start.c fails the build if the two disagree. It is + deliberately not "default y if BUILD_PROTECTED": this symbol selects + ARCH_USE_MPU, BUILD_PROTECTED depends on ARCH_USE_MPU, and a default + conditioned on BUILD_PROTECTED closes that loop. Kconfig resolves + the circularity by making BUILD_PROTECTED unsatisfiable, which + silently collapses the whole "Memory organization" choice for every + board in the tree. + + Enabling it on its own is legitimate only for bring-up: unlocked + entries do not constrain machine mode, so a flat build ends up with + less protection than it would otherwise have. + +if BUILD_PROTECTED + +config ESPRESSIF_USER_IMAGE_OFFSET + hex "User image offset" + default 0x110000 + ---help--- + Offset in SPI Flash for flashing the User application firmware + image (nuttx_user.bin). + + Must be aligned to the flash MMU page size (64 KB on ESP32-P4) so + that the cache MMU constraint paddr % 64KB == vaddr % 64KB can be + met, and must be beyond the end of the kernel image. + +endif # BUILD_PROTECTED + +config ESPRESSIF_PMP_EARLY_SNAPSHOT + bool "Dump PMP state during early boot (diagnostic)" + default n + ---help--- + Bring-up diagnostic. Prints the raw PMP configuration via the ROM + printf immediately before and after the bootloader_init() call in + esp_start(), long before the console driver exists. + + Use it to determine whether PMP entries are already locked when + NuttX gains control, or whether the lock bits are set by + bootloader_init() -> bootloader_init_mem() -> + esp_cpu_configure_region_protection(). PMP lock bits cannot be + cleared without the Smepmp extension, so a protected-mode port has + to prevent the locking rather than undo it, and that requires + knowing which code sets it. + + This is a debug aid only; leave it disabled in normal builds. + config ESPRESSIF_RUN_IRAM bool "Run from IRAM" default n diff --git a/arch/risc-v/src/common/espressif/Make.defs b/arch/risc-v/src/common/espressif/Make.defs index 5216b98a9eebe..6f9c3f68c0873 100644 --- a/arch/risc-v/src/common/espressif/Make.defs +++ b/arch/risc-v/src/common/espressif/Make.defs @@ -39,6 +39,14 @@ CHIP_CSRCS += esp_irq.c esp_gpio.c esp_rtc_gpio.c esp_libc_stubs.c CHIP_CSRCS += esp_lowputc.c esp_serial.c CHIP_CSRCS += esp_systemreset.c +ifeq ($(CONFIG_ESPRESSIF_KERNEL_OWNS_PMP),y) + CHIP_CSRCS += esp_region_protect.c +endif + +ifeq ($(CONFIG_BUILD_PROTECTED),y) + CHIP_CSRCS += esp_userspace.c +endif + ifeq ($(CONFIG_ARCH_HAVE_EXTRA_HEAPS),y) CHIP_CSRCS += esp_extraheaps.c ifeq ($(CONFIG_ESPRESSIF_RETENTION_HEAP),y) diff --git a/arch/risc-v/src/common/espressif/esp_allocateheap.c b/arch/risc-v/src/common/espressif/esp_allocateheap.c index 5e562aedf49e7..f9b268916e262 100644 --- a/arch/risc-v/src/common/espressif/esp_allocateheap.c +++ b/arch/risc-v/src/common/espressif/esp_allocateheap.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -103,7 +104,20 @@ void up_allocate_heap(void **heap_start, size_t *heap_size) board_autoled_on(LED_HEAPALLOCATE); -#if defined(CONFIG_MM_KERNEL_HEAP) && \ +#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP) + /* In a protected build this call describes the USER heap, not the + * kernel's. It runs from the end of the user image's .bss to the top of + * the user RAM region, both of which the user image published in its + * userspace structure. esp_userspace() has already granted user mode + * read/write over that span in the PMP. + * + * Using the kernel's own SRAM here -- as the flat path below does -- would + * hand user mode memory it cannot touch and would overlap the kernel heap. + */ + + *heap_start = (void *)USERSPACE->us_bssend; + *heap_size = USERSPACE->us_heapend - USERSPACE->us_bssend; +#elif defined(CONFIG_MM_KERNEL_HEAP) && \ defined(CONFIG_ESPRESSIF_SPIRAM) && \ defined(CONFIG_ESPRESSIF_SPIRAM_USER_HEAP) DEBUGASSERT(esp_psram_is_initialized()); @@ -182,9 +196,14 @@ void up_allocate_kheap(void **heap_start, size_t *heap_size) #if CONFIG_MM_REGIONS > 1 void riscv_addregion(void) { -#if defined(CONFIG_ESP32P4_SELECTS_REV_LESS_V3) +#if defined(CONFIG_ESP32P4_SELECTS_REV_LESS_V3) && \ + !defined(CONFIG_BUILD_PROTECTED) /* ESP32-P4 rev < v3 has non-contiguous SRAM: sram_low + sram_high. * The primary heap is in sram_low. Add sram_high as a second region. + * + * Not in a protected build: there sram_high is the user RAM region + * (see esp32p4_protected_memory.ld), so adding it to the kernel heap + * would hand the kernel memory that belongs to user space. */ extern uint8_t _sram_high_heap_start[]; diff --git a/arch/risc-v/src/common/espressif/esp_idle.c b/arch/risc-v/src/common/espressif/esp_idle.c index 1d1384ab7d3ae..9bd4fba88bab8 100644 --- a/arch/risc-v/src/common/espressif/esp_idle.c +++ b/arch/risc-v/src/common/espressif/esp_idle.c @@ -37,6 +37,7 @@ #include #include "riscv_internal.h" +#include "esp_p4dbg.h" #include "esp_pm.h" #ifdef CONFIG_ESPRESSIF_HR_TIMER @@ -236,6 +237,66 @@ void up_idle(void) * sleep in a reduced power mode until an interrupt occurs to save power */ +#ifdef P4DBG + /* If this counter advances while g_p4dbg_irq_n does not, the + * core is leaving WFI without taking an interrupt -- which on RISC-V means + * an interrupt is PENDING BUT MASKED, and mintstatus.mil below says why. + */ + + { + uint32_t v; + + g_p4dbg_idle_n++; + __asm__ __volatile__ ("csrr %0, 0x346" : "=r"(v)); + + if (v != g_p4dbg_idle_mint && g_p4dbg_mintlog_n < P4DBG_MINTLOG_N) + { + g_p4dbg_mintlog[g_p4dbg_mintlog_n][0] = g_p4dbg_idle_n; + g_p4dbg_mintlog[g_p4dbg_mintlog_n][1] = v; + g_p4dbg_mintlog_n++; + } + + g_p4dbg_idle_mint = v; + + /* Is the stuck CLIC level the blocker? Write it down to canonical + * level 0 (0x1f, NLBITS = 3) and record whether the CSR took the + * write. If it did and interrupts start flowing again, the level is + * the blocker and any fix must make it unwind; if the write is + * ignored, mintstatus is read-only here and the level is a symptom of + * something else. + */ + + if (g_p4dbg_force_mil0 != 0 && (v >> 24) != 0x1f) + { + uint32_t after; + + __asm__ __volatile__ ("csrw 0x346, %0" :: "r"(0x1f000000u)); + __asm__ __volatile__ ("csrr %0, 0x346" : "=r"(after)); + + g_p4dbg_mil_before = v; + g_p4dbg_mil_after = after; + } + + __asm__ __volatile__ ("csrr %0, mstatus" : "=r"(v)); + g_p4dbg_idle_mstatus = v; + + /* Snapshot the CLIC occasionally rather than every pass: this loop spins + * at millions of iterations a second once delivery has stopped. + */ + + if ((g_p4dbg_idle_n & 0xffff) == 0) + { + g_p4dbg_idle_thresh = *(volatile uint32_t *)(P4DBG_CLIC_BASE + 8); + + for (v = 0; v < P4DBG_CLIC_N; v++) + { + g_p4dbg_idle_clic[v] = + *(volatile uint32_t *)(P4DBG_CLIC_CTRL + v * 4); + } + } + } +#endif + esp_pm_impl_idle_hook(); esp_pm_impl_waiti(); diff --git a/arch/risc-v/src/common/espressif/esp_irq.c b/arch/risc-v/src/common/espressif/esp_irq.c index 991ac89e47250..9ac7b11f5809a 100644 --- a/arch/risc-v/src/common/espressif/esp_irq.c +++ b/arch/risc-v/src/common/espressif/esp_irq.c @@ -41,6 +41,7 @@ #include "esp_gpio.h" #include "esp_irq.h" +#include "esp_p4dbg.h" #include "esp_rtc_gpio.h" #include "esp_attr.h" @@ -251,6 +252,44 @@ IRAM_ATTR static int esp_isr_demultiplexing(int irq, void *context, * Public Functions ****************************************************************************/ +/**************************************************************************** + * Temporary instrumentation. + * + * After the SCHED_RR pthreads exit, a usleep() never wakes: the + * nxsig_timeout watchdog sits on g_wdactivelist unserviced while the idle + * task runs. These counters separate "the tick stopped" from "the tick + * runs but the watchdog arithmetic is wrong", and record mintstatus.mil, + * which can stick at a level that masks every interrupt. + * + * Read them with an observe-only halt, twice a few seconds apart: whichever + * counters advance is the answer. + ****************************************************************************/ + +#ifdef P4DBG +volatile uint32_t g_p4dbg_irq_n; /* interrupts dispatched */ +volatile uint32_t g_p4dbg_exc_n; /* exceptions dispatched */ +volatile uint32_t g_p4dbg_last_mcause; /* mcause of the last interrupt */ +volatile uint32_t g_p4dbg_tick_n; /* systimer_irq_handler entries */ +volatile uint32_t g_p4dbg_idle_n; /* up_idle() passes */ +volatile uint32_t g_p4dbg_idle_mint; /* mintstatus sampled in up_idle */ +volatile uint32_t g_p4dbg_idle_mstatus; /* mstatus sampled in up_idle */ +volatile uint32_t g_p4dbg_mil_first_tick; +volatile uint32_t g_p4dbg_mil_first_mcause; +volatile uint32_t g_p4dbg_mil_first_epc; +volatile uint32_t g_p4dbg_mil_ticks; +volatile uint32_t g_p4dbg_mil_last_zero_tick; +volatile uint32_t g_p4dbg_tick_thresh; +volatile uint32_t g_p4dbg_tick_mint; +volatile uint32_t g_p4dbg_tick_clic[P4DBG_CLIC_N]; +volatile uint32_t g_p4dbg_idle_thresh; +volatile uint32_t g_p4dbg_idle_clic[P4DBG_CLIC_N]; +volatile uint32_t g_p4dbg_mintlog[P4DBG_MINTLOG_N][2]; +volatile uint32_t g_p4dbg_mintlog_n; +volatile uint32_t g_p4dbg_force_mil0; /* 0: answered, see 36.21 */ +volatile uint32_t g_p4dbg_mil_before; +volatile uint32_t g_p4dbg_mil_after; +#endif + /**************************************************************************** * Name: up_irq_to_ndx * @@ -564,6 +603,18 @@ IRAM_ATTR void *riscv_dispatch_irq(uintreg_t mcause, uintreg_t *regs) bool is_edge = false; int cpu = this_cpu(); +#ifdef P4DBG + if (is_irq) + { + g_p4dbg_irq_n++; + g_p4dbg_last_mcause = (uint32_t)mcause; + } + else + { + g_p4dbg_exc_n++; + } +#endif + if (is_irq) { uint8_t cpuint = (mcause & VECTORS_MCAUSE_REASON_MASK) - diff --git a/arch/risc-v/src/common/espressif/esp_p4dbg.h b/arch/risc-v/src/common/espressif/esp_p4dbg.h new file mode 100644 index 0000000000000..a781de2d8db6e --- /dev/null +++ b/arch/risc-v/src/common/espressif/esp_p4dbg.h @@ -0,0 +1,99 @@ +/**************************************************************************** + * arch/risc-v/src/common/espressif/esp_p4dbg.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Debug counters for the protected build, CONFIG_ESPRESSIF_P4DBG. + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_P4DBG_H +#define __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_P4DBG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifdef CONFIG_ESPRESSIF_P4DBG +# define P4DBG 1 + +extern volatile uint32_t g_p4dbg_irq_n; +extern volatile uint32_t g_p4dbg_exc_n; +extern volatile uint32_t g_p4dbg_last_mcause; +extern volatile uint32_t g_p4dbg_tick_n; +extern volatile uint32_t g_p4dbg_idle_n; +extern volatile uint32_t g_p4dbg_idle_mint; +extern volatile uint32_t g_p4dbg_idle_mstatus; + +/* Onset detector for the stuck mintstatus.mil. mcause.mpil sampled at + * tick entry is the CLIC level of the context the tick INTERRUPTED, which + * for task context must be 0. The first tick that sees it non-zero is + * where the level started sticking. + */ + +extern volatile uint32_t g_p4dbg_mil_first_tick; +extern volatile uint32_t g_p4dbg_mil_first_mcause; +extern volatile uint32_t g_p4dbg_mil_first_epc; +extern volatile uint32_t g_p4dbg_mil_ticks; +extern volatile uint32_t g_p4dbg_mil_last_zero_tick; + +/* The pre-rev3 ESP32-P4 gates interrupt delivery on a MEMORY-MAPPED CLIC + * threshold (INTTHRESH_STANDARD = 0), not on a CSR, and the whole CLIC + * block reads back as zero over the JTAG debug bus -- so it has to be + * sampled by the target itself. Snapshot it from the tick handler (last + * healthy state) and from up_idle (hung state) and diff the two. + */ + +#define P4DBG_CLIC_BASE 0x20800000 /* CLIC_INT_CONFIG / INFO / THRESH */ +#define P4DBG_CLIC_CTRL 0x20801000 /* per-source IP/IE/ATTR/CTL, 1 word */ +#define P4DBG_CLIC_N 48 + +extern volatile uint32_t g_p4dbg_tick_thresh; +extern volatile uint32_t g_p4dbg_tick_mint; +extern volatile uint32_t g_p4dbg_tick_clic[P4DBG_CLIC_N]; +extern volatile uint32_t g_p4dbg_idle_thresh; +extern volatile uint32_t g_p4dbg_idle_clic[P4DBG_CLIC_N]; + +/* mintstatus sampled from up_idle -- TASK context, not a handler -- every + * time it changes. g_p4dbg_tick_mint is sampled inside the tick handler, + * where mil is legitimately raised, so it cannot answer "was mil ever 0 in + * task context". This can. + */ + +#define P4DBG_MINTLOG_N 12 + +extern volatile uint32_t g_p4dbg_mintlog[P4DBG_MINTLOG_N][2]; /* n, mint */ +extern volatile uint32_t g_p4dbg_mintlog_n; + +/* DIAGNOSTIC, not a fix: try writing mintstatus.mil down to canonical + * level 0 from the idle loop and see (a) whether the CSR is writable and + * (b) whether interrupt delivery resumes. Answers "is the stuck level the + * blocker" directly, instead of inferring it from another failed fix. + */ + +extern volatile uint32_t g_p4dbg_force_mil0; /* 1 = attempt the write */ +extern volatile uint32_t g_p4dbg_mil_before; +extern volatile uint32_t g_p4dbg_mil_after; +#endif + +#endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_P4DBG_H */ diff --git a/arch/risc-v/src/common/espressif/esp_region_protect.c b/arch/risc-v/src/common/espressif/esp_region_protect.c new file mode 100644 index 0000000000000..011bbf3f8cf0a --- /dev/null +++ b/arch/risc-v/src/common/espressif/esp_region_protect.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * arch/risc-v/src/common/espressif/esp_region_protect.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Unlocked build of the HAL's esp_cpu_configure_region_protection(). + * + * The HAL implementation programs every PMP entry with the lock bit set. It + * runs very early, from esp_start() -> bootloader_init() -> + * bootloader_init_mem(), and that path is not gated by + * CONFIG_ESPRESSIF_REGION_PROTECTION -- that option guards only a second, + * redundant call later in esp_start(). + * + * PMP lock bits cannot be cleared without the Smepmp extension, which the + * ESP32-P4 does not implement (reading mseccfg raises an illegal + * instruction). Once the HAL has run, 14 of the 16 entries are dead for the + * remainder of the boot, and one of the survivors grants U-mode read/write + * across the whole kernel data region. A protected build therefore has to + * stop the entries being locked in the first place. + * + * The same function also programs the 16 PMA entries that mark the invalid + * address ranges and make external flash/RAM, ROM and L2MEM cacheable. That + * work is required for the SoC to run at all: replacing this function with + * an empty stub boot-loops inside bootloader_init(). + * + * So rather than reimplement any of it, the HAL translation unit is dropped + * from the build (see hal_.mk / hal_.cmake) and its source is + * included below with PMP_L defined to zero. Including "riscv/csr.h" first + * means its include guard is already set when the HAL source includes it + * again, so the redefinition survives. Everything else -- the PMA setup, + * the chip-revision variants, the PSRAM handling -- stays byte for byte + * identical to the vendored source and tracks it when the HAL is updated. + * + * The result is the HAL's own region layout with every PMP entry left + * unlocked, so the kernel can re-describe them for a kernel/user split. + * + * NOTE: unlocked PMP entries do not constrain machine mode, so this reduces + * the protection a flat build gets. It is meant to be paired with a + * protected build, whose userspace initialisation re-establishes the + * boundaries. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/* Pulled in first so that its include guard is already set when the HAL + * source below includes it again, keeping the redefinition that follows. + */ + +#include "riscv/csr.h" + +#undef PMP_L +#define PMP_L 0 + +/* The HAL implementation itself, compiled with the lock bit cleared. The + * chip directory is spelled out rather than derived from + * CONFIG_ESPRESSIF_CHIP_SERIES because an #include directive cannot + * concatenate string literals; CONFIG_ESPRESSIF_KERNEL_OWNS_PMP depends on + * ARCH_CHIP_ESP32P4, so this file is only ever built for that chip. + */ + +#include "../../chip/esp-hal-3rdparty/components/esp_hw_support/port/esp32p4/cpu_region_protect.c" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The whole point of this file is that the HAL body above was compiled with + * the lock bit cleared. If the HAL ever reorganises its includes so that + * "riscv/csr.h" is no longer guarded by the time it is reached, the + * redefinition would be silently undone and every PMP entry would be locked + * again -- which would not fail the build, and would not show up until the + * kernel tried to reprogram an entry at run time. Fail loudly instead. + */ + +#if PMP_L != 0 +# error "PMP lock bit was not neutralised" +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* esp_cpu_configure_region_protection() is defined by the HAL source + * included above, and is the only symbol this translation unit exports. + */ diff --git a/arch/risc-v/src/common/espressif/esp_start.c b/arch/risc-v/src/common/espressif/esp_start.c index debc53e5eb2c9..0324a5ade3b1d 100644 --- a/arch/risc-v/src/common/espressif/esp_start.c +++ b/arch/risc-v/src/common/espressif/esp_start.c @@ -33,6 +33,9 @@ #include #include "riscv_internal.h" +#ifdef CONFIG_ESPRESSIF_PMP_EARLY_SNAPSHOT +# include +#endif #include "esp_irq.h" #include "esp_libc_stubs.h" @@ -65,6 +68,9 @@ #include "soc/rtc.h" #include "bootloader_init.h" +#ifdef CONFIG_BUILD_PROTECTED +# include "esp_userspace.h" +#endif #include "bootloader_sha.h" #ifdef CONFIG_ESPRESSIF_SIMPLE_BOOT @@ -89,6 +95,33 @@ * Pre-processor Definitions ****************************************************************************/ +/* A protected build must own the PMP outright. Without + * CONFIG_ESPRESSIF_KERNEL_OWNS_PMP the HAL programs every entry with the + * lock bit set, from bootloader_init() and before any NuttX code can + * intervene; the ESP32-P4 has no Smepmp, so those entries can never be + * re-described. The build would succeed, boot, run NSH in user mode and + * enforce nothing -- which is worse than a flat build, because it looks + * protected. Refuse to build it instead. + */ + +#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_ARCH_CHIP_ESP32P4) && \ + !defined(CONFIG_ESPRESSIF_KERNEL_OWNS_PMP) +# error "BUILD_PROTECTED needs ESPRESSIF_KERNEL_OWNS_PMP; the HAL locks every PMP entry" +#endif + +/* Region protection would re-run esp_cpu_configure_region_protection() + * late in esp_start(), after bootloader_init() has already programmed the + * regions, racing the userspace PMP setup. Enforced here rather than with + * a Kconfig dependency: both symbols select ARCH_USE_MPU, which + * BUILD_PROTECTED depends on, so a Kconfig dependency on the build type + * would be circular. + */ + +#if defined(CONFIG_BUILD_PROTECTED) && \ + defined(CONFIG_ESPRESSIF_REGION_PROTECTION) +# error "BUILD_PROTECTED needs ESPRESSIF_REGION_PROTECTION disabled" +#endif + #ifdef CONFIG_DEBUG_FEATURES # define showprogress(c) esp_rom_printf(c) #else @@ -474,6 +507,89 @@ void sys_startup_fn(void) SYS_STARTUP_FN(); } +#ifdef CONFIG_ESPRESSIF_PMP_EARLY_SNAPSHOT + +/**************************************************************************** + * Name: esp_pmp_early_snapshot + * + * Description: + * Bring-up diagnostic. Dumps the raw PMP configuration at a given point + * in early startup, before the console is available, using the ROM printf. + * + * Its purpose is to establish whether PMP entries are already locked when + * NuttX gains control, or whether the lock bits are set later by + * bootloader_init() -> bootloader_init_mem() -> + * esp_cpu_configure_region_protection(). Lock bits are irreversible + * without Smepmp, so this distinction decides whether a protected build is + * possible on a given part. + * + * Input Parameters: + * tag - Short label identifying the sample point. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void esp_pmp_early_snapshot(const char *tag) +{ + uintptr_t cfg[4]; + uintptr_t addr[16]; + int locked = 0; + int active = 0; + int i; + + cfg[0] = READ_CSR(pmpcfg0); + cfg[1] = READ_CSR(pmpcfg1); + cfg[2] = READ_CSR(pmpcfg2); + cfg[3] = READ_CSR(pmpcfg3); + + addr[0] = READ_CSR(pmpaddr0); + addr[1] = READ_CSR(pmpaddr1); + addr[2] = READ_CSR(pmpaddr2); + addr[3] = READ_CSR(pmpaddr3); + addr[4] = READ_CSR(pmpaddr4); + addr[5] = READ_CSR(pmpaddr5); + addr[6] = READ_CSR(pmpaddr6); + addr[7] = READ_CSR(pmpaddr7); + addr[8] = READ_CSR(pmpaddr8); + addr[9] = READ_CSR(pmpaddr9); + addr[10] = READ_CSR(pmpaddr10); + addr[11] = READ_CSR(pmpaddr11); + addr[12] = READ_CSR(pmpaddr12); + addr[13] = READ_CSR(pmpaddr13); + addr[14] = READ_CSR(pmpaddr14); + addr[15] = READ_CSR(pmpaddr15); + + for (i = 0; i < 16; i++) + { + uint8_t b = (uint8_t)((cfg[i / 4] >> ((i % 4) * 8)) & 0xff); + + if ((b & PMPCFG_L) != 0) + { + locked++; + } + + if ((b & PMPCFG_A_MASK) != PMPCFG_A_OFF) + { + active++; + } + } + + ets_printf("PMP[%s]: cfg %08x %08x %08x %08x active=%d locked=%d\n", + tag, (unsigned int)cfg[0], (unsigned int)cfg[1], + (unsigned int)cfg[2], (unsigned int)cfg[3], active, locked); + + for (i = 0; i < 16; i += 4) + { + ets_printf("PMP[%s]: addr%-2d %08x %08x %08x %08x\n", tag, i, + (unsigned int)addr[i], (unsigned int)addr[i + 1], + (unsigned int)addr[i + 2], (unsigned int)addr[i + 3]); + } +} + +#endif /* CONFIG_ESPRESSIF_PMP_EARLY_SNAPSHOT */ + /**************************************************************************** * Name: __esp_start ****************************************************************************/ @@ -499,6 +615,10 @@ void __esp_start(void) bootloader_clear_bss_section(); +#ifdef CONFIG_ESPRESSIF_PMP_EARLY_SNAPSHOT + esp_pmp_early_snapshot("pre-bl"); +#endif + #ifdef CONFIG_ESPRESSIF_SIMPLE_BOOT if (bootloader_init() != 0) { @@ -507,6 +627,10 @@ void __esp_start(void) } #endif +#ifdef CONFIG_ESPRESSIF_PMP_EARLY_SNAPSHOT + esp_pmp_early_snapshot("post-bl"); +#endif + /* Initialize the per CPU areas */ #ifdef CONFIG_RISCV_PERCPU_SCRATCH @@ -659,6 +783,16 @@ void __esp_start(void) showprogress("D"); +#ifdef CONFIG_BUILD_PROTECTED + /* Initialise the user-space image and put the PMP boundaries in place + * before any user code becomes reachable. + */ + + esp_userspace(); + + showprogress("E"); +#endif + nx_start(); UNUSED(ret); diff --git a/arch/risc-v/src/common/espressif/esp_timerisr.c b/arch/risc-v/src/common/espressif/esp_timerisr.c index b0b0945cc0779..6a51e1b5b9ccd 100644 --- a/arch/risc-v/src/common/espressif/esp_timerisr.c +++ b/arch/risc-v/src/common/espressif/esp_timerisr.c @@ -34,6 +34,7 @@ #include #include "chip.h" +#include "esp_p4dbg.h" #include "esp_irq.h" #include "hal/systimer_hal.h" @@ -88,6 +89,52 @@ static systimer_hal_context_t systimer_hal; static int systimer_irq_handler(int irq, void *context, void *arg) { +#ifdef P4DBG + { + uint32_t c; + + g_p4dbg_tick_n++; + + /* mcause.mpil here is the CLIC level of the context this tick + * interrupted. Task context must be level 0; anything else means the + * level was left raised by an earlier return. + */ + + __asm__ __volatile__ ("csrr %0, mcause" : "=r"(c)); + + if ((c & 0x00ff0000) != 0) + { + g_p4dbg_mil_ticks++; + + if (g_p4dbg_mil_first_tick == 0) + { + g_p4dbg_mil_first_tick = g_p4dbg_tick_n; + g_p4dbg_mil_first_mcause = c; + g_p4dbg_mil_first_epc = + (uint32_t)((uintreg_t *)context)[REG_EPC]; + } + } + else + { + g_p4dbg_mil_last_zero_tick = g_p4dbg_tick_n; + } + + /* Last healthy CLIC snapshot: this handler running IS the proof that + * delivery still works at this instant. + */ + + __asm__ __volatile__ ("csrr %0, 0x346" : "=r"(c)); + g_p4dbg_tick_mint = c; + g_p4dbg_tick_thresh = *(volatile uint32_t *)(P4DBG_CLIC_BASE + 8); + + for (c = 0; c < P4DBG_CLIC_N; c++) + { + g_p4dbg_tick_clic[c] = + *(volatile uint32_t *)(P4DBG_CLIC_CTRL + c * 4); + } + } +#endif + systimer_ll_clear_alarm_int(systimer_hal.dev, SYSTIMER_ALARM_OS_TICK_CORE0); diff --git a/arch/risc-v/src/common/espressif/esp_userspace.c b/arch/risc-v/src/common/espressif/esp_userspace.c new file mode 100644 index 0000000000000..6ce0bd7837d2a --- /dev/null +++ b/arch/risc-v/src/common/espressif/esp_userspace.c @@ -0,0 +1,410 @@ +/**************************************************************************** + * arch/risc-v/src/common/espressif/esp_userspace.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + +#include +#include + +#include + +#include "riscv_internal.h" + +#include "esp_userspace.h" + +#include "esp_rom_sys.h" +#include "soc/soc.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#include "hal/mmu_hal.h" +#include "hal/mmu_types.h" +#include "spi_flash_mmap.h" +#include "bootloader_flash_priv.h" + +#ifdef CONFIG_BUILD_PROTECTED + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define USER_IMAGE_OFFSET CONFIG_ESPRESSIF_USER_IMAGE_OFFSET + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Emitted at the start of the user image by user-space.ld. It tells the + * kernel where the user image expects its flash-mapped regions to live, so + * that the flash MMU can be programmed before any user code is reachable. + */ + +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 */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct user_image_load_header_s g_header; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: load_header + * + * Description: + * Read the user image load header out of flash. + * + * Unlike the ESP32-C3 protected port, which temporarily mapped a scratch + * flash window to reach the header, this reads it directly. The SPI flash + * driver is already initialised by the time esp_userspace() runs, and + * esp_start() uses the same call to parse the kernel image header, so no + * scratch mapping is needed. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void load_header(void) +{ + int ret = bootloader_flash_read(USER_IMAGE_OFFSET, &g_header, + sizeof(g_header), true); + + if (ret != 0) + { + esp_rom_printf("ERROR: user image header read failed: rc=%d at 0x%x\n", + ret, (unsigned int)USER_IMAGE_OFFSET); + PANIC(); + } +} + +/**************************************************************************** + * Name: configure_mmu + * + * Description: + * Map the user image's flash-resident code and read-only data into the + * virtual address space. + * + * This is deliberately additive. esp_start()'s map_rom_segments() calls + * mmu_hal_unmap_all() before installing the kernel's own mappings; doing + * that here would unmap the kernel while it is executing. Only the two + * user regions are added. + * + * The cache is disabled across the update, so this function -- and + * everything it calls -- must be resident in IRAM. The linker script + * places this object there by name. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void noinline_function configure_mmu(void) +{ + uint32_t actual_mapped_len = 0; + uint32_t drom_lma = USER_IMAGE_OFFSET + g_header.drom_lma; + uint32_t irom_lma = USER_IMAGE_OFFSET + g_header.irom_lma; + uint32_t drom_lma_aligned = drom_lma & MMU_FLASH_MASK; + uint32_t drom_vma_aligned = g_header.drom_vma & MMU_FLASH_MASK; + uint32_t irom_lma_aligned = irom_lma & MMU_FLASH_MASK; + uint32_t irom_vma_aligned = g_header.irom_vma & MMU_FLASH_MASK; + cache_bus_mask_t bus_mask; + + cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); + + mmu_hal_map_region(0, MMU_TARGET_FLASH0, + drom_vma_aligned, drom_lma_aligned, + g_header.drom_size, &actual_mapped_len); + + mmu_hal_map_region(0, MMU_TARGET_FLASH0, + irom_vma_aligned, irom_lma_aligned, + g_header.irom_size, &actual_mapped_len); + + bus_mask = cache_ll_l1_get_bus(0, drom_vma_aligned, g_header.drom_size); + cache_ll_l1_enable_bus(0, bus_mask); + bus_mask = cache_ll_l1_get_bus(0, irom_vma_aligned, g_header.irom_size); + cache_ll_l1_enable_bus(0, bus_mask); + +#if CONFIG_ESPRESSIF_NUM_CPUS > 1 + bus_mask = cache_ll_l1_get_bus(1, drom_vma_aligned, g_header.drom_size); + cache_ll_l1_enable_bus(1, bus_mask); + bus_mask = cache_ll_l1_get_bus(1, irom_vma_aligned, g_header.irom_size); + cache_ll_l1_enable_bus(1, bus_mask); +#endif + +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, + CACHE_LL_ID_ALL, irom_vma_aligned, + actual_mapped_len); +#endif + + cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); +} + +/**************************************************************************** + * Name: initialize_data + * + * Description: + * Copy the user image's initialised data from flash into user RAM. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void initialize_data(void) +{ + size_t length = USERSPACE->us_dataend - USERSPACE->us_datastart; + int ret; + + uintptr_t src = USER_IMAGE_OFFSET + USERSPACE->us_datasource; + + ret = bootloader_flash_read(src, (void *)USERSPACE->us_datastart, + length, true); + if (ret != 0) + { + /* The usual cause is alignment: this read wants its flash offset and + * length aligned, and .data's load address is whatever the end of + * .rodata left it at. user-space.ld pads both to 16 for that reason. + */ + + esp_rom_printf("ERROR: user .data read failed: rc=%d src=0x%x " + "dst=0x%x len=0x%x\n", + ret, (unsigned int)src, + (unsigned int)USERSPACE->us_datastart, + (unsigned int)length); + PANIC(); + } +} + +/**************************************************************************** + * Name: configure_mpu + * + * Description: + * Establish the PMP regions that separate kernel from user. + * + * Every entry is reset first. By the time this runs the HAL has already + * programmed eleven regions from bootloader_init(), several of which would + * grant user mode access to kernel memory -- entry 5 in particular covers + * the whole of SRAM as read/write. They are only reprogrammable because + * CONFIG_ESPRESSIF_KERNEL_OWNS_PMP built them without the lock bit. + * + * Only user-accessible regions are then described. Per the RISC-V + * privileged specification an access matching no PMP entry is permitted in + * machine mode and denied in user mode, so the kernel needs no entries of + * its own and everything not listed below is automatically inaccessible to + * user code. + * + * Regions are expressed as TOR pairs because the linker-defined bounds are + * not naturally aligned powers of two. Every boundary must respect the + * 128-byte PMP granularity of this SoC; user-space.ld is responsible for + * that alignment. + * + * 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; + + /* Drop everything the HAL left behind. Machine mode is unaffected: an + * unlocked entry never constrains it, and an address matching no entry is + * permitted in machine mode. + */ + + riscv_config_pmp_region(0, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(1, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(2, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(3, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(4, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(5, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(6, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(7, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(8, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(9, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(10, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(11, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(12, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(13, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(14, PMPCFG_A_OFF, 0, 0); + riscv_config_pmp_region(15, PMPCFG_A_OFF, 0, 0); + + /* TOR entries take their lower bound from the preceding entry's address, + * so the regions must be programmed in ascending address order. Each pair + * is an unmatched gap followed by the region proper: + * + * UIROM 0x40200000 - 0x40300000 user code, execute in place + * UDROM 0x40300080 - 0x40380000 user rodata (0x80 metadata gap below) + * ROM SOC_IROM_MASK_* ROM routines the user image calls + * UDRAM 0x4ff40000 - 0x4ff80000 user data, bss and heap + */ + + /* User code, executed in place from flash */ + + riscv_config_pmp_region(0, PMPCFG_A_TOR, UIROM_START, 0); + riscv_config_pmp_region(1, PMPCFG_A_TOR | rx, UIROM_END, 0); + + /* User read-only data, mapped from flash */ + + riscv_config_pmp_region(2, PMPCFG_A_TOR, UDROM_START, 0); + riscv_config_pmp_region(3, PMPCFG_A_TOR | r, UDROM_END, 0); + + /* Internal ROM. CONFIG_LIBC_ARCH_* is selected for this chip, so libc + * omits its generic memcpy(), strcmp() and friends and the user image is + * linked against the ROM implementations instead (see the ROM linker + * scripts in common/kernel/Makefile). Without this grant the first such + * call from user mode takes an instruction access fault. + */ + + riscv_config_pmp_region(4, PMPCFG_A_TOR, SOC_IROM_MASK_LOW, 0); + riscv_config_pmp_region(5, PMPCFG_A_TOR | rx, SOC_IROM_MASK_HIGH, 0); + + /* User data, bss and heap in internal SRAM */ + + riscv_config_pmp_region(6, PMPCFG_A_TOR, UDRAM_START, 0); + riscv_config_pmp_region(7, PMPCFG_A_TOR | rw, UDRAM_END, 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_userspace + * + * Description: + * See esp_userspace.h. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_userspace(void) +{ + uint8_t *dest; + uint8_t *end; + + /* Where does the user image expect to be mapped? */ + + load_header(); + + /* Make its code and rodata reachable before anything touches them. The + * header values are echoed first: if the metadata block and + * struct user_image_load_header_s ever disagree, this is where it shows. + */ + + esp_rom_printf("userspace: drom vma=0x%x lma=0x%x size=0x%x\n", + (unsigned int)g_header.drom_vma, + (unsigned int)g_header.drom_lma, + (unsigned int)g_header.drom_size); + esp_rom_printf("userspace: irom vma=0x%x lma=0x%x size=0x%x\n", + (unsigned int)g_header.irom_vma, + (unsigned int)g_header.irom_lma, + (unsigned int)g_header.irom_size); + + 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(); + + /* Finally, take ownership of the PMP and fence the two worlds apart */ + + configure_mpu(); + + /* Not showprogress(): that expands to nothing unless + * CONFIG_DEBUG_FEATURES is set, which would make a hang here + * indistinguishable from one inside nx_start(). + */ + + /* Echo what the kernel will actually act on. us_entrypoint should be an + * address inside UIROM and the heap bounds should lie inside UDRAM; if the + * user image's .userspace structure were mislinked or not loaded, this is + * where it becomes visible rather than showing up later as a silent + * failure to start the initial task. + */ + + esp_rom_printf("userspace: entry=0x%x heap=0x%x..0x%x bss=0x%x..0x%x\n", + (unsigned int)USERSPACE->us_entrypoint, + (unsigned int)USERSPACE->us_bssend, + (unsigned int)USERSPACE->us_heapend, + (unsigned int)USERSPACE->us_bssstart, + (unsigned int)USERSPACE->us_bssend); + esp_rom_printf("userspace: ready\n"); +} + +#endif /* CONFIG_BUILD_PROTECTED */ diff --git a/arch/risc-v/src/common/espressif/esp_userspace.h b/arch/risc-v/src/common/espressif/esp_userspace.h new file mode 100644 index 0000000000000..46b47fd6c68fc --- /dev/null +++ b/arch/risc-v/src/common/espressif/esp_userspace.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * arch/risc-v/src/common/espressif/esp_userspace.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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_COMMON_ESPRESSIF_ESP_USERSPACE_H +#define __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_USERSPACE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_BUILD_PROTECTED + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Name: esp_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, but on this SoC it also means mapping the user image out of + * external flash and establishing the PMP regions that separate the two + * worlds. + * + * Must be called from esp_start() immediately before nx_start(). + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_userspace(void); + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_BUILD_PROTECTED */ +#endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_USERSPACE_H */ diff --git a/arch/risc-v/src/common/riscv_doirq.c b/arch/risc-v/src/common/riscv_doirq.c index ee74b12f7ecbb..ac9e464f15bb3 100644 --- a/arch/risc-v/src/common/riscv_doirq.c +++ b/arch/risc-v/src/common/riscv_doirq.c @@ -148,6 +148,14 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs) regs = tcb->xcp.regs; +#ifdef CONFIG_RISCV_FRAME_TRACE + /* This is the single point where every trap decides which frame to + * restore. + */ + + riscv_trace_frame(RISCV_TRACE_TAG_IRQ(irq), tcb, regs); +#endif + /* (*running_task)->xcp.regs is about to become invalid * and will be marked as NULL to avoid misusage. */ diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/riscv_exception_common.S index 11570b3d69fae..4d3615131c2aa 100644 --- a/arch/risc-v/src/common/riscv_exception_common.S +++ b/arch/risc-v/src/common/riscv_exception_common.S @@ -148,6 +148,7 @@ exception_common: csrr s1, CSR_EPC /* s1=exception PC */ csrr s2, CSR_CAUSE /* s2=cause */ + #ifdef CONFIG_ARCH_KERNEL_STACK csrr s3, CSR_SCRATCH REGLOAD s3, RISCV_PERCPU_USP(s3) @@ -159,6 +160,12 @@ exception_common: REGSTORE s1, REG_EPC(sp) REGSTORE s3, REG_SP(sp) +#ifdef REG_MCAUSE + /* s2 still holds the RAW mcause here, before it is masked for dispatch. */ + + REGSTORE s2, REG_MCAUSE(sp) +#endif + #ifdef CONFIG_LIB_SYSCALL csrr tp, CSR_SCRATCH /* Load kernel TP */ REGLOAD tp, RISCV_PERCPU_TCB(tp) @@ -204,6 +211,17 @@ return_from_syscall: /* Clean up after system call */ REGSTORE a0, REG_A0(sp) /* Syscall return value to user context */ + +#ifdef CONFIG_RISCV_FRAME_TRACE + /* Frame trace. Safe here: the return value is already stored to the frame + * and everything is restored from sp immediately below, so clobbering + * caller-saved registers costs nothing. + */ + + mv a0, sp + call x1, riscv_trace_syscall_ret +#endif + mv a0, sp /* Return to same context */ tail return_from_exception @@ -279,9 +297,75 @@ return_from_exception: REGLOAD s0, REG_EPC(sp) /* restore sepc */ csrw CSR_EPC, s0 +#ifdef REG_MCAUSE + /* Restore mcause with the frame. On a CLIC part mcause holds mpp, mpie and + * mpil; mret restores privilege from mpp and mintstatus.mil from mpil. + * Leaving it as whatever the last trap wrote makes mret restore the wrong + * privilege or the wrong interrupt level -- mil stuck at 63 + * masks every interrupt and deadlocks the system. The frame's + * value is by construction what the hardware latched for this trap, so it is + * correct at any nesting depth. + * + * Restored BEFORE mstatus, deliberately. mstatus.MPP/MPIE are aliased into + * mcause[29:28]/[27], so whichever is written last wins for those fields. + * Synthesised frames -- up_initial_state(), riscv_jump_to_user() -- leave + * this slot zero, and writing that after mstatus dropped kernel threads to + * U-mode and faulted on the first instruction fetch of kernel text. Writing + * mcause first lets mstatus stay authoritative for privilege while mcause + * still supplies mpil, which lives nowhere else. + */ + + REGLOAD s1, REG_MCAUSE(sp) + + /* On a return to U-MODE, clear mcause.interrupt (31) and mcause.minhv (30) + * while keeping mpp/mpie/mpil. An mret to U-mode whose mcause has bit 31 + * set breaks the next trap this core takes: the trap latches + * mepc/mcause/mstatus and raises privilege, but the pc never reaches + * mtvec.base. The frame's mcause is the value the hardware latched for the + * trap that SAVED the frame, so after a context switch it is restored by a + * different trap -- SYS_restore_context, an ECALLM -- and interrupt = 1 then + * tells the CLIC it is returning from an interrupt that is not in flight. + * + * mpil (23:16) is deliberately NOT cleared: doing so was measured to change + * nothing, so the raised level does not come from this path. + * + * Kernel returns are left alone. s0 is reloaded from the frame immediately + * below; s2 is reloaded by load_ctx further down. + */ + + REGLOAD s0, REG_INT_CTX(sp) + li s2, STATUS_PPP + and s0, s0, s2 + bnez s0, 1f /* kernel return: leave mcause alone */ + li s2, 0x3fffffff /* clear interrupt (31) and minhv (30) */ + and s1, s1, s2 +1: + csrw mcause, s1 +#endif + REGLOAD s0, REG_INT_CTX(sp) /* restore status */ csrw CSR_STATUS, s0 +#ifdef CONFIG_RISCV_FRAME_TRACE + /* Capture what this mret will actually + * consume, after every CSR write and before the register reloads. t0/t1 are + * reloaded from the frame further down this epilogue, so clobbering them here + * is safe; no argument register is touched. Read the globals with an + * observe-only halt. + */ + + la t0, g_mret_epc + csrr t1, CSR_EPC + REGSTORE t1, 0(t0) + la t0, g_mret_status + csrr t1, CSR_STATUS + REGSTORE t1, 0(t0) + la t0, g_mret_cause + csrr t1, mcause + REGSTORE t1, 0(t0) +#endif + + #ifdef CONFIG_LIB_SYSCALL /* Store tcb to scratch register */ @@ -354,6 +438,7 @@ riscv_jump_to_user: li a1, ~STATUS_PPP and a0, a0, a1 REGSTORE a0, REG_INT_CTX(sp) + mv a0, sp tail return_from_exception diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h index d8a1e969afdb2..e80a43ebb571b 100644 --- a/arch/risc-v/src/common/riscv_internal.h +++ b/arch/risc-v/src/common/riscv_internal.h @@ -102,6 +102,32 @@ #define PMP_ACCESS_DENIED (-1) /* Access set and denied */ #define PMP_ACCESS_FULL (1) /* Access set and allowed */ +#ifdef CONFIG_RISCV_FRAME_TRACE + +/* Trap frame trace tags, the "tag" argument of riscv_trace_frame(). Each + * one names the place in the trap path that recorded the frame; they are + * printed verbatim by riscv_trace_dump(). The tag occupies the low 8 bits + * of the argument, bits 8 and up carry the IRQ number (see + * RISCV_TRACE_TAG_IRQ). + */ + +#define RISCV_TRACE_TAG_DOIRQ 0 /* riscv_doirq() frame selection */ +#define RISCV_TRACE_TAG_RESTORE_CTX 1 /* SYS_restore_context */ +#define RISCV_TRACE_TAG_SWITCH_CTX 2 /* SYS_switch_context */ +#define RISCV_TRACE_TAG_SYSCALL_RET 3 /* return_from_syscall */ +#define RISCV_TRACE_TAG_TRAP_ENTRY 4 /* exception_common, every trap */ +#define RISCV_TRACE_TAG_SIG_SCHED 5 /* frame built for signal delivery */ +#define RISCV_TRACE_TAG_SIG_HANDLER 6 /* SYS_signal_handler */ +#define RISCV_TRACE_TAG_SIG_RETURN 7 /* SYS_signal_handler_return */ +#define RISCV_TRACE_TAG_MRET 8 /* what the last mret consumed */ +#define RISCV_TRACE_TAG_PANIC 9 /* the panicking frame */ + +/* Tag for a frame recorded on behalf of a given IRQ */ + +#define RISCV_TRACE_TAG_IRQ(irq) (RISCV_TRACE_TAG_DOIRQ | ((irq) << 8)) + +#endif /* CONFIG_RISCV_FRAME_TRACE */ + #ifndef __ASSEMBLY__ /* Use ASM as rv64ilp32 compiler generated address is limited */ @@ -202,6 +228,15 @@ void riscv_ack_irq(int irq); void riscv_sigdeliver(void); int riscv_swint(int irq, void *context, void *arg); + +/* Trap frame trace, CONFIG_RISCV_FRAME_TRACE. See the option's help text. */ + +#ifdef CONFIG_RISCV_FRAME_TRACE +void riscv_trace_frame(int tag, struct tcb_s *tcb, uintreg_t *regs); +void riscv_trace_dump(uintreg_t *regs); +void riscv_trace_syscall_ret(uintreg_t *regs); +void riscv_trace_trap_entry(uintreg_t *regs, uintreg_t mcause); +#endif uintptr_t riscv_get_newintctx(void); void riscv_set_idleintctx(void); void riscv_exception_attach(void); diff --git a/arch/risc-v/src/common/riscv_schedulesigaction.c b/arch/risc-v/src/common/riscv_schedulesigaction.c index af492350aa670..65fbc6aab1b0f 100644 --- a/arch/risc-v/src/common/riscv_schedulesigaction.c +++ b/arch/risc-v/src/common/riscv_schedulesigaction.c @@ -121,4 +121,13 @@ void up_schedule_sigaction(struct tcb_s *tcb) #endif tcb->xcp.regs[REG_INT_CTX] = int_ctx; + +#ifdef CONFIG_RISCV_FRAME_TRACE + /* Record the frame this built. It deliberately sets MPP=M so the + * trampoline runs privileged, and leaves REG_MCAUSE as the copied user + * value. + */ + + riscv_trace_frame(RISCV_TRACE_TAG_SIG_SCHED, tcb, tcb->xcp.regs); +#endif } diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c index b5dc855484f42..75cafde229d61 100644 --- a/arch/risc-v/src/common/riscv_swint.c +++ b/arch/risc-v/src/common/riscv_swint.c @@ -28,6 +28,9 @@ #include #include +#ifdef CONFIG_RISCV_FRAME_TRACE +# include +#endif #include #include #include @@ -137,6 +140,170 @@ uintptr_t dispatch_syscall(unsigned int nbr, uintptr_t parm1, } #endif +#ifdef CONFIG_RISCV_FRAME_TRACE + +/**************************************************************************** + * Trap frame trace, CONFIG_RISCV_FRAME_TRACE. + * + * The question: when a user task blocks inside a syscall and is later + * resumed, which frame does the kernel restore on the way back out, and does + * its REG_INT_CTX carry MPP=M? riscv_doirq() ends with + * "regs = tcb->xcp.regs", so that is the single point where every trap + * decides what to restore -- RISCV_TRACE_TAG_DOIRQ records it. The + * RISCV_TRACE_TAG_RESTORE_CTX and RISCV_TRACE_TAG_SWITCH_CTX tags record the + * two context-switch cases below. + * + * Nothing is printed inline: on the polled UART console each character costs + * ~87 us, and printing from inside the switch path would perturb the timing + * under test. The ring buffer is dumped from the "default" case instead -- + * i.e. exactly when the flip has produced its panic. + ****************************************************************************/ + +#define TRACE_ENTRIES 64 +#define TRACE_USER_LO 0x40200000 /* user image text window */ +#define TRACE_USER_HI 0x40300000 + +struct riscv_trace_s +{ + uintreg_t *regs; + uintreg_t epc; + uintreg_t int_ctx; + uintreg_t mcause; + int16_t irq; + uint8_t tag; /* RISCV_TRACE_TAG_* */ + pid_t pid; +}; + +static struct riscv_trace_s g_trace[TRACE_ENTRIES]; +static unsigned int g_trace_ndx; + +/* Written by the asm probe in return_from_exception + * (riscv_exception_common.S) immediately after the mepc/mstatus restores: + * what the mret will actually consume, as opposed to what the frame holds. + */ + +uintreg_t g_mret_epc; +uintreg_t g_mret_status; +uintreg_t g_mret_cause; + +void riscv_trace_frame(int tag, struct tcb_s *tcb, uintreg_t *regs) +{ + struct riscv_trace_s *e = &g_trace[g_trace_ndx % TRACE_ENTRIES]; + + e->tag = (uint8_t)(tag & 0xff); + e->irq = (int16_t)(tag >> 8); + e->pid = tcb != NULL ? tcb->pid : -1; + e->regs = regs; + + if (regs != NULL) + { + e->epc = regs[REG_EPC]; + e->int_ctx = regs[REG_INT_CTX]; +#ifdef REG_MCAUSE + /* The frame's mcause, so mpil (23:16) can be tracked: mil pinned at 63 + * is what deadlocks the interrupt system. + */ + + e->mcause = regs[REG_MCAUSE]; +#endif + } + else + { + e->epc = 0; + e->int_ctx = 0; + e->mcause = 0; + } + + g_trace_ndx++; +} + +/* Called from return_from_syscall (riscv_exception_common.S). User + * syscall returns bypass riscv_doirq() entirely -- they restore the frame + * at sp -- so this is the only place they can be observed. + */ + +void riscv_trace_syscall_ret(uintreg_t *regs) +{ + riscv_trace_frame(RISCV_TRACE_TAG_SYSCALL_RET, this_task(), regs); +} + +/* Called from exception_common (riscv_exception_common.S) on EVERY trap + * entry, once the frame is fully formed. This is the mirror of the + * exit records: it shows the privilege the CPU was in when the trap was + * taken, straight from the hardware, plus the raw mcause. + */ + +void riscv_trace_trap_entry(uintreg_t *regs, uintreg_t mcause) +{ + struct riscv_trace_s *e = &g_trace[g_trace_ndx % TRACE_ENTRIES]; + + riscv_trace_frame(RISCV_TRACE_TAG_TRAP_ENTRY, this_task(), regs); + + /* riscv_trace_frame() may have skipped the entry; only stamp mcause if it + * actually recorded one. + */ + + if (e->tag == RISCV_TRACE_TAG_TRAP_ENTRY) + { + e->mcause = mcause; + } +} + +void riscv_trace_dump(uintreg_t *regs) +{ + unsigned int total; + + /* Record the panicking frame itself, so that its REG_INT_CTX can be + * read out of RAM with an observe-only halt. The _alert() output below is + * unreliable on this board at panic time; the ring buffer is not. + */ + + /* Stamp what the last mret consumed, from the asm probe, so that it + * comes out of the same ring-buffer read. + */ + + { + struct riscv_trace_s *m = &g_trace[g_trace_ndx % TRACE_ENTRIES]; + + m->tag = RISCV_TRACE_TAG_MRET; + m->pid = -1; + m->irq = 0; + m->regs = NULL; + m->epc = g_mret_epc; + m->int_ctx = g_mret_status; + m->mcause = g_mret_cause; + g_trace_ndx++; + } + + riscv_trace_frame(RISCV_TRACE_TAG_PANIC, this_task(), regs); + + total = g_trace_ndx; + unsigned int n = total < TRACE_ENTRIES ? total : TRACE_ENTRIES; + unsigned int i; + + _alert("TRACE: panic cmd=%" PRIxREG " frame=%p epc=%" PRIxREG + " int_ctx=%" PRIxREG "\n", + regs[REG_A0], regs, regs[REG_EPC], regs[REG_INT_CTX]); + _alert("TRACE: %u events, last %u shown; tag %u=doirq %u=restore " + "%u=switch\n", + total, n, RISCV_TRACE_TAG_DOIRQ, RISCV_TRACE_TAG_RESTORE_CTX, + RISCV_TRACE_TAG_SWITCH_CTX); + + for (i = total - n; i < total; i++) + { + struct riscv_trace_s *e = &g_trace[i % TRACE_ENTRIES]; + bool user = e->epc >= TRACE_USER_LO && e->epc < TRACE_USER_HI; + bool mpp = (e->int_ctx & STATUS_PPP) != 0; + + _alert(" [%2u] tag=%u irq=%d pid=%d frame=%p epc=%" PRIxREG + " int_ctx=%" PRIxREG " %s%s\n", + i, e->tag, e->irq, e->pid, e->regs, e->epc, e->int_ctx, + user ? "[user]" : "[kern]", + (user && mpp) ? " <<< USER FRAME WITH MPP=M" : ""); + } +} +#endif /* CONFIG_RISCV_FRAME_TRACE */ + /**************************************************************************** * Name: riscv_swint * @@ -168,6 +335,10 @@ int riscv_swint(int irq, void *context, void *arg) { case SYS_restore_context: { +#ifdef CONFIG_RISCV_FRAME_TRACE + riscv_trace_frame(RISCV_TRACE_TAG_RESTORE_CTX, tcb, + tcb->xcp.regs); +#endif riscv_restorecontext(tcb); restore_critical_section(tcb, cpu); } @@ -175,6 +346,10 @@ int riscv_swint(int irq, void *context, void *arg) case SYS_switch_context: { +#ifdef CONFIG_RISCV_FRAME_TRACE + riscv_trace_frame(RISCV_TRACE_TAG_SWITCH_CTX, tcb, + tcb->xcp.regs); +#endif riscv_savecontext(g_running_tasks[cpu]); riscv_restorecontext(tcb); restore_critical_section(tcb, cpu); @@ -198,6 +373,10 @@ int riscv_swint(int irq, void *context, void *arg) #if !defined(CONFIG_BUILD_FLAT) && defined(CONFIG_ENABLE_ALL_SIGNALS) case SYS_signal_handler: { +#ifdef CONFIG_RISCV_FRAME_TRACE + riscv_trace_frame(RISCV_TRACE_TAG_SIG_HANDLER, this_task(), + regs); +#endif struct tcb_s *rtcb = this_task(); /* Remember the caller's return address */ @@ -275,6 +454,10 @@ int riscv_swint(int irq, void *context, void *arg) #if !defined(CONFIG_BUILD_FLAT) && defined(CONFIG_ENABLE_ALL_SIGNALS) case SYS_signal_handler_return: { +#ifdef CONFIG_RISCV_FRAME_TRACE + riscv_trace_frame(RISCV_TRACE_TAG_SIG_RETURN, this_task(), + regs); +#endif struct tcb_s *rtcb = this_task(); /* Set up to return to the kernel-mode signal dispatching logic. */ @@ -303,6 +486,17 @@ int riscv_swint(int irq, void *context, void *arg) #endif default: +#ifdef CONFIG_RISCV_FRAME_TRACE + /* Record the panicking frame but do NOT print the ring here. + * riscv_trace_dump() pushes 64 syslog lines through the polled + * console from inside a trap with interrupts disabled; under an + * ostest-scale failure that takes minutes and buries the assert + * output. Read the ring out of RAM with an observe-only halt + * instead. + */ + + riscv_trace_frame(RISCV_TRACE_TAG_PANIC, this_task(), regs); +#endif DEBUGPANIC(); break; } diff --git a/arch/risc-v/src/esp32p4/hal_esp32p4.cmake b/arch/risc-v/src/esp32p4/hal_esp32p4.cmake index 04b130a95d6b1..0311be237137b 100644 --- a/arch/risc-v/src/esp32p4/hal_esp32p4.cmake +++ b/arch/risc-v/src/esp32p4/hal_esp32p4.cmake @@ -456,6 +456,16 @@ list( ${ESP_HAL_3RDPARTY_REPO}/nuttx/src/heap_caps.c ${ESP_HAL_3RDPARTY_REPO}/nuttx/src/platform/os.c) +# The kernel takes ownership of the PMP: drop the HAL implementation, which +# locks every entry it programs. See esp_region_protect.c. + +if(CONFIG_ESPRESSIF_KERNEL_OWNS_PMP) + list( + REMOVE_ITEM HAL_SRCS + ${ESP_HAL_3RDPARTY_REPO}/components/esp_hw_support/port/${CHIP_SERIES}/cpu_region_protect.c + ) +endif() + if(CONFIG_ESPRESSIF_WIFI OR CONFIG_ESPRESSIF_EMAC) list(APPEND HAL_SRCS ${ESP_HAL_3RDPARTY_REPO}/nuttx/src/esp_event.c) endif() diff --git a/arch/risc-v/src/esp32p4/hal_esp32p4.mk b/arch/risc-v/src/esp32p4/hal_esp32p4.mk index 0899e2c2fcb94..be14b4b9b54e7 100644 --- a/arch/risc-v/src/esp32p4/hal_esp32p4.mk +++ b/arch/risc-v/src/esp32p4/hal_esp32p4.mk @@ -294,7 +294,9 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)esp_ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)esp_hw_support$(DELIM)lowpower$(DELIM)port$(DELIM)$(CHIP_SERIES)$(DELIM)sleep_cpu_static.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)esp_hw_support$(DELIM)lowpower$(DELIM)port$(DELIM)$(CHIP_SERIES)$(DELIM)sleep_clock.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)esp_hw_support$(DELIM)port$(DELIM)regdma_link.c +ifneq ($(CONFIG_ESPRESSIF_KERNEL_OWNS_PMP),y) CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)esp_hw_support$(DELIM)port$(DELIM)$(CHIP_SERIES)$(DELIM)cpu_region_protect.c +endif CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)esp_hw_support$(DELIM)port$(DELIM)$(CHIP_SERIES)$(DELIM)esp_clk_tree.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)esp_hw_support$(DELIM)port$(DELIM)$(CHIP_SERIES)$(DELIM)esp_cpu_intr.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)esp_hw_support$(DELIM)port$(DELIM)$(CHIP_SERIES)$(DELIM)io_mux.c diff --git a/boards/risc-v/esp32p4/common/kernel/Makefile b/boards/risc-v/esp32p4/common/kernel/Makefile new file mode 100644 index 0000000000000..7dafb5fb7fddb --- /dev/null +++ b/boards/risc-v/esp32p4/common/kernel/Makefile @@ -0,0 +1,125 @@ +############################################################################ +# boards/risc-v/esp32p4/common/kernel/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# 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 = $(call CONVERT_PATH,$(BOARD_COMMON_DIR)$(DELIM)scripts$(DELIM)esp32p4_protected_memory.ld) +USER_LDSCRIPT += $(call CONVERT_PATH,$(BOARD_COMMON_DIR)$(DELIM)scripts$(DELIM)user-space.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) $(addprefix -T,$(addsuffix .tmp,$(USER_LDSCRIPT))) -melf32lriscv + +# The user image resolves memcpy(), strlen() and friends from ROM, exactly as +# the kernel does. CONFIG_LIBC_ARCH_* is selected by ARCH_CHIP_ESP32P4, so +# libc omits its generic implementations and expects the architecture to +# supply them; on this SoC they live in ROM and are named by these scripts. +# Without them the user link fails with undefined references to the whole +# string and memory family. + +ESP_ROM_LD_DIR = $(TOPDIR)$(DELIM)arch$(DELIM)risc-v$(DELIM)src$(DELIM)chip$(DELIM)esp-hal-3rdparty$(DELIM)components$(DELIM)esp_rom$(DELIM)esp32p4$(DELIM)ld + +USER_LDFLAGS += -T$(call CONVERT_PATH,$(ESP_ROM_LD_DIR)$(DELIM)esp32p4.rom.ld) +USER_LDFLAGS += -T$(call CONVERT_PATH,$(ESP_ROM_LD_DIR)$(DELIM)esp32p4.rom.libc.ld) + +# Deliberately NOT esp32p4.rom.newlib.ld. That script defines newlib's stdio +# symbols absolutely -- fflush = 0x4fc00370 among them -- which beats NuttX's +# own libc to the symbol. User mode then jumps into ROM, where it has no PMP +# grant and where ROM newlib's private state does not exist, and faults. It +# showed up as exit() -> fflush(NULL) faulting the moment a user task first ran +# to completion. NuttX supplies fflush itself; user space must use it. +USER_LDFLAGS += -T$(call CONVERT_PATH,$(ESP_ROM_LD_DIR)$(DELIM)esp32p4.rom.libc-suboptimal_for_misaligned_mem.ld) +USER_LDFLAGS += -T$(call CONVERT_PATH,$(ESP_ROM_LD_DIR)$(DELIM)esp32p4.rom.libgcc.ld) + +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 = esp_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, $<, $@) + +$(addsuffix .tmp,$(USER_LDSCRIPT)): $(USER_LDSCRIPT) + $(call PREPROCESS,$(patsubst %.tmp,%,$@),$@) + +# Create the nuttx_user.elf file containing all of the user-mode code + +nuttx_user.elf: $(OBJS) $(addsuffix .tmp,$(USER_LDSCRIPT)) + $(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 + $(Q) $(call DELFILE,$(addsuffix .tmp,$(USER_LDSCRIPT))) + +.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/esp32p4/common/kernel/esp_userspace.c b/boards/risc-v/esp32p4/common/kernel/esp_userspace.c new file mode 100644 index 0000000000000..41aeef74ba08e --- /dev/null +++ b/boards/risc-v/esp32p4/common/kernel/esp_userspace.c @@ -0,0 +1,111 @@ +/**************************************************************************** + * boards/risc-v/esp32p4/common/kernel/esp_userspace.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 +#include +#include + +#if defined(CONFIG_BUILD_PROTECTED) && !defined(__KERNEL__) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_NUTTX_USERSPACE +# error "CONFIG_NUTTX_USERSPACE not defined" +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct userspace_data_s g_userspace_data = +{ + .us_heap = &g_mmheap, +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* These 'addresses' of these values are setup by the linker script. */ + +extern uint8_t _stext[]; /* Start of .text */ +extern uint8_t _etext[]; /* End_1 of .text + .rodata */ +extern const uint8_t _eronly[]; /* End+1 of read only section (.text + .rodata) */ +extern uint8_t _sdata[]; /* Start of .data */ +extern uint8_t _edata[]; /* End+1 of .data */ +extern uint8_t _sbss[]; /* Start of .bss */ +extern uint8_t _ebss[]; /* End+1 of .bss */ + +extern uint8_t __ld_udram_end[]; /* End+1 of user ram section */ + +const struct userspace_s userspace locate_data(".userspace") = +{ + /* General memory map */ + + .us_entrypoint = 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, + + /* User data memory structure */ + + .us_data = &g_userspace_data, + + /* 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/esp32p4/common/scripts/esp32p4_protected_memory.ld b/boards/risc-v/esp32p4/common/scripts/esp32p4_protected_memory.ld new file mode 100644 index 0000000000000..3c51b2c09b3e6 --- /dev/null +++ b/boards/risc-v/esp32p4/common/scripts/esp32p4_protected_memory.ld @@ -0,0 +1,183 @@ +/**************************************************************************** + * boards/risc-v/esp32p4/common/scripts/esp32p4_protected_memory.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * ESP32-P4 memory layout for the protected build. + * + * kernel-space.ld and user-space.ld link the kernel and user images into + * these blocks respectively. + * + * Three properties of this SoC shape the layout: + * + * 1. Instruction and data share one virtual window for external flash + * (SOC_MMU_DI_VADDR_SHARED). Unlike parts with separate IROM and DROM + * windows, all four flash regions are carved out of 0x40000000 upwards + * and are distinguished only by address range. + * + * 2. On silicon older than v3.0 the internal SRAM is two banks with a + * hardware gap. That maps neatly onto the kernel/user split: the kernel + * takes sram_low, user data takes sram_high, and the boundary needs no + * artificial alignment because the banks are already far apart. + * + * 3. PMP granularity is 128 bytes, so every region boundary that the PMP + * describes must be 128-byte aligned. This is why the metadata block + * below is 0x80 rather than the 0x18 used by parts with 4-byte + * granularity: UDROM starts immediately after it, and that start address + * becomes a PMP TOR boundary. + * + * Flash offsets must also satisfy the cache MMU constraint + * paddr % 64KB == vaddr % 64KB. All four flash regions are placed on 64 KB + * boundaries, with the metadata offset applied on top for UDROM. + ****************************************************************************/ + +#include + +/* common.ld would supply RESERVE_RTC_MEM and MSPI_WORKAROUND_SIZE, but it + * also pulls in the HAL's sdkconfig.h, which is not on the include path when + * the user image is linked in pass 1. This file is shared by both links, so + * the two constants are reproduced here instead. Values are the ESP32-P4 + * ones: 24 bytes of RTC timer retention, and no MSPI workaround because that + * applies to revision v3 silicon only. + */ + +#ifndef RESERVE_RTC_MEM +# define RESERVE_RTC_MEM 24 +#endif + +#ifndef MSPI_WORKAROUND_SIZE +# define MSPI_WORKAROUND_SIZE 0x0 +#endif + +/* Internal SRAM. Bank boundaries come from the flat layout so that the two + * stay in step; see esp32p4_flat_memory.ld. + */ + +#define SRAM_LOW_START 0x4ff00000 +#define SRAM_LOW_END 0x4ff2cbd0 /* 2nd stage bootloader iram_loader_seg */ +#define SRAM_LOW_SIZE (SRAM_LOW_END - SRAM_LOW_START) + +#define SRAM_HIGH_START 0x4ff40000 +/* CONFIG_CACHE_L2_CACHE_SIZE is a HAL sdkconfig alias that is not visible + * here; the NuttX-side symbol it is derived from is used directly instead. + */ + +#define SRAM_HIGH_SIZE (0x80000 - CONFIG_ESPRESSIF_CACHE_L2_CACHE_SIZE) + +/* Flash, mapped into the shared instruction/data window. The 0x20 offset on + * KIROM is the usual Espressif convenience: the image has a 0x18 byte file + * header and each segment an 0x08 byte header, so starting 0x20 in keeps + * paddr % 64KB == vaddr % 64KB satisfied for the first segment. + */ + +#define IDROM_SEG_SIZE (CONFIG_MMU_PAGE_SIZE << 10) + +#define FLASH_WINDOW 0x40000000 + +#define KIROM_ORG (FLASH_WINDOW + 0x20) +#define KIROM_LEN (0x180000 - 0x20) + +#define KDROM_ORG (FLASH_WINDOW + 0x180000) +#define KDROM_LEN 0x080000 + +#define UIROM_ORG (FLASH_WINDOW + 0x200000) +#define UIROM_LEN 0x100000 + +/* The user image begins with a metadata block that the kernel reads to learn + * where this image expects to be mapped. UDROM starts just past it, and + * that address is a PMP boundary, hence the 128-byte size. + */ + +#define UDROM_METADATA_LEN 0x80 +#define UDROM_ORG (FLASH_WINDOW + 0x300000 + UDROM_METADATA_LEN) +#define UDROM_LEN (0x080000 - UDROM_METADATA_LEN) + +MEMORY +{ + /* Load-only block carrying the user image metadata. It is emitted at the + * start of the user image file, not mapped at run time. + */ + + metadata (RX) : org = 0x0, len = UDROM_METADATA_LEN + ROM (RX) : org = ORIGIN(metadata) + LENGTH(metadata), + len = 0x400000 - ORIGIN(ROM) + + /* TCM, kernel only */ + + tcm_idram_seg (RX) : org = 0x30100000, len = 0x2000 + + /* Kernel internal SRAM: code, data, bss and the kernel heap. This is one + * region rather than separate IRAM and DRAM blocks because SRAM is + * unified on this SoC -- there is no second view of it at another + * address, as there is on the ESP32-C3. + */ + + KRAM (RWX) : org = SRAM_LOW_START, len = SRAM_LOW_SIZE + + /* User internal SRAM: data, bss and the user heap. User code executes in + * place from flash, so there is no UIRAM region. + */ + + UDRAM (RW) : org = SRAM_HIGH_START, len = SRAM_HIGH_SIZE + + /* Flash-mapped kernel code and read-only data */ + + KIROM (RX) : org = KIROM_ORG, len = KIROM_LEN + KDROM (R) : org = KDROM_ORG, len = KDROM_LEN + + /* Flash-mapped user code and read-only data */ + + UIROM (RX) : org = UIROM_ORG, len = UIROM_LEN + UDROM (R) : org = UDROM_ORG, len = UDROM_LEN + + /* PSRAM */ + + extern_ram_seg (RWX) : org = 0x48000000, len = IDROM_SEG_SIZE + + /* LP/RTC memory, kernel only */ + + rev3_mspi_workaround_seg (RWX) : org = 0x50108000, len = MSPI_WORKAROUND_SIZE + lp_reserved_seg (RW) : org = 0x50108000 + MSPI_WORKAROUND_SIZE, + len = RESERVE_RTC_MEM + lp_ram_seg (RW) : org = 0x50108000 + MSPI_WORKAROUND_SIZE + RESERVE_RTC_MEM, + len = 0x8000 - RESERVE_RTC_MEM - MSPI_WORKAROUND_SIZE +} + +/* The flat layout's alias names are reused so that the kernel sections can + * be taken from esp32p4_sections.ld unchanged. + * + * Both sram_low and sram_high alias the single kernel RAM region: the flat + * script spills some sections into sram_high, and with both names pointing + * at KRAM those sections simply flow on sequentially instead of landing in + * memory that now belongs to user space. + */ + +REGION_ALIAS("rtc_iram_seg", lp_ram_seg); +REGION_ALIAS("rtc_data_seg", rtc_iram_seg); +REGION_ALIAS("rtc_slow_seg", rtc_iram_seg); +REGION_ALIAS("rtc_data_location", rtc_iram_seg); +REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg); +REGION_ALIAS("ext_ram_seg", extern_ram_seg); + +REGION_ALIAS("sram_low", KRAM); +REGION_ALIAS("sram_high", KRAM); +REGION_ALIAS("text_seg_low", KIROM); +REGION_ALIAS("rodata_seg_low", KDROM); diff --git a/boards/risc-v/esp32p4/common/scripts/esp32p4_sections.ld b/boards/risc-v/esp32p4/common/scripts/esp32p4_sections.ld index 85acf24527b1e..0580a39513390 100644 --- a/boards/risc-v/esp32p4/common/scripts/esp32p4_sections.ld +++ b/boards/risc-v/esp32p4/common/scripts/esp32p4_sections.ld @@ -202,100 +202,102 @@ SECTIONS *libsched.a:sched_lock.*(.text .text.* .literal .literal.*) *libsched.a:sched_unlock.*(.text .text.* .literal .literal.*) - *libarch.a:*(.text.esprv_intc_int_get_type .literal.esprv_intc_int_get_type) - *libarch.a:*riscv_doirq.*(.text .text.* .literal .literal.*) - *libarch.a:*brownout.*(.text .text.* .literal .literal.*) - *libarch.a:*cpu.*(.text .text.* .literal .literal.*) - *libarch.a:*gpio_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*periph_ctrl.*(.text .text.* .literal .literal.*) - *libarch.a:*clk.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_clk.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_clk_tree.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_clk_tree_common.*(.text .text.* .literal .literal.*) - *libarch.a:*clk_tree_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*pmu_init.*(.text .text.* .literal .literal.*) - *libarch.a:*modem_clock.*(.text .text.* .literal .literal.*) - *libarch.a:*regi2c_ctrl.*(.text .text.* .literal .literal.*) - *libarch.a:*gpio_periph.*(.text .text.* .literal .literal.*) - *libarch.a:*modem_clock_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_systimer.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_wdt.*(.text .text.* .literal .literal.*) - *libarch.a:*ocode_init.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_regi2c_esp32p4.*(.text .text.* .literal .literal.*) - *libarch.a:*rtc_clk.*(.text .text.* .literal .literal.*) - *libarch.a:*rtc_clk_init.*(.text .text.* .literal .literal.*) - *libarch.a:*pmu_sleep.*(.text .text.* .literal .literal.*) - *libarch.a:*pmu_param.*(.text .text.* .literal .literal.*) - *libarch.a:*rtc_time.*(.text .text.* .literal .literal.*) - *libarch.a:*systimer.*(.text .text.* .literal .literal.*) - *libarch.a:*systimer_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*uart_hal_iram.*(.text .text.* .literal .literal.*) - *libarch.a:*wdt_hal_iram.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_banner_wrap.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_init.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_common.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_common_loader.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_console.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_console_loader.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_esp32p4.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_flash.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_flash_config_esp32p4.*(.text .text.* .literal .literal.*) - *libarch.a:*flash_qio_mode.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_clock_init.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_clock_loader.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_efuse.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_panic.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_mem.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_random.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_random_esp32p4.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_image_format.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_soc.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_sha.*(.text .text.* .literal .literal.*) - *libarch.a:*flash_encrypt.*(.text .text.* .literal .literal.*) - *libarch.a:*cache_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*uart_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*mpu_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*mmu_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*uart_periph.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_uart.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_sys.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_spiflash.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_efuse_fields.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_efuse_api_key.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_efuse_utility.*(.text .text.* .literal .literal.*) - *libarch.a:*efuse_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*apm_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*log.*(.text .text.* .literal .literal.*) - *libarch.a:*cpu_region_protect.*(.text .text.* .literal .literal.*) - *libarch.a:*log_lock.*(.literal .literal.* .text .text.*) - *libarch.a:*log_print.*(.literal .literal.* .text .text.*) - *libarch.a:*log_timestamp.*(.literal.esp_log_early_timestamp .text.esp_log_early_timestamp) - *libarch.a:*log_timestamp.*(.literal.esp_log_timestamp .text.esp_log_timestamp) - *libarch.a:*log_timestamp_common.*(.literal .literal.* .text .text.*) - *libarch.a:*log_write.*(.literal.esp_log_write .text.esp_log_write) - *libarch.a:*log_write.*(.literal.esp_log_writev .text.esp_log_writev) - *libarch.a:*rv_utils.*(.literal .literal.* .text .text.*) - *libarch.a:*libarch.*(.literal .literal.* .text .text.*) - *libarch.a:*riscv_modifyreg32.*(.literal .literal.* .text .text.*) - *libarch.a:critical_section.*(.literal .literal.* .text .text.*) - *libarch.a:os.*(.literal.nuttx_enter_critical .text.nuttx_enter_critical) - *libarch.a:os.*(.literal.nuttx_exit_critical .text.nuttx_exit_critical) - *libarch.a:spi_flash_hpm_enable.*(.literal .literal.* .text .text.*) - *libarch.a:*sleep_modes.*(.literal.esp_sleep_pd_config* .text.esp_sleep_pd_config*) - *libarch.a:esp_spiflash.*(.literal .text .literal.* .text.*) - *libarch.a:esp_flash_api.*(.text .text.* .literal .literal.*) - *libarch.a:esp_flash_spi_init.*(.text .text.* .literal .literal.*) - *libarch.a:spi_flash_hal_iram.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_encrypt_hal_iram.*(.text .text.* .literal .literal.*) - *libarch.a:spi_flash_hal_gpspi.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_chip*.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_wrap.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_os_func_noos.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_os_func_app.*(.literal .literal.* .text .text.*) - *libarch.a:flash_brownout_hook.*(.literal .literal.* .text .text.*) - *libarch.a:esp_cache.*(.literal .literal.* .text .text.*) - *libarch.a:cache_utils.*(.literal .literal.* .text .text.*) - *libarch.a:memspi_host_driver.*(.literal .literal.* .text .text.*) + *arch.a:*(.text.esprv_intc_int_get_type .literal.esprv_intc_int_get_type) + *arch.a:*riscv_doirq.*(.text .text.* .literal .literal.*) + *arch.a:*brownout.*(.text .text.* .literal .literal.*) + *arch.a:*cpu.*(.text .text.* .literal .literal.*) + *arch.a:*gpio_hal.*(.text .text.* .literal .literal.*) + *arch.a:*periph_ctrl.*(.text .text.* .literal .literal.*) + *arch.a:*clk.*(.text .text.* .literal .literal.*) + *arch.a:*esp_clk.*(.text .text.* .literal .literal.*) + *arch.a:*esp_clk_tree.*(.text .text.* .literal .literal.*) + *arch.a:*esp_clk_tree_common.*(.text .text.* .literal .literal.*) + *arch.a:*clk_tree_hal.*(.text .text.* .literal .literal.*) + *arch.a:*pmu_init.*(.text .text.* .literal .literal.*) + *arch.a:*modem_clock.*(.text .text.* .literal .literal.*) + *arch.a:*regi2c_ctrl.*(.text .text.* .literal .literal.*) + *arch.a:*gpio_periph.*(.text .text.* .literal .literal.*) + *arch.a:*modem_clock_hal.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_systimer.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_wdt.*(.text .text.* .literal .literal.*) + *arch.a:*ocode_init.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_regi2c_esp32p4.*(.text .text.* .literal .literal.*) + *arch.a:*rtc_clk.*(.text .text.* .literal .literal.*) + *arch.a:*rtc_clk_init.*(.text .text.* .literal .literal.*) + *arch.a:*pmu_sleep.*(.text .text.* .literal .literal.*) + *arch.a:*pmu_param.*(.text .text.* .literal .literal.*) + *arch.a:*rtc_time.*(.text .text.* .literal .literal.*) + *arch.a:*systimer.*(.text .text.* .literal .literal.*) + *arch.a:*systimer_hal.*(.text .text.* .literal .literal.*) + *arch.a:*uart_hal_iram.*(.text .text.* .literal .literal.*) + *arch.a:*wdt_hal_iram.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_banner_wrap.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_init.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_common.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_common_loader.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_console.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_console_loader.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_esp32p4.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_flash.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_flash_config_esp32p4.*(.text .text.* .literal .literal.*) + *arch.a:*flash_qio_mode.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_clock_init.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_clock_loader.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_efuse.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_panic.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_mem.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_random.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_random_esp32p4.*(.text .text.* .literal .literal.*) + *arch.a:*esp_image_format.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_soc.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_sha.*(.text .text.* .literal .literal.*) + *arch.a:*flash_encrypt.*(.text .text.* .literal .literal.*) + *arch.a:*cache_hal.*(.text .text.* .literal .literal.*) + *arch.a:*uart_hal.*(.text .text.* .literal .literal.*) + *arch.a:*mpu_hal.*(.text .text.* .literal .literal.*) + *arch.a:*mmu_hal.*(.text .text.* .literal .literal.*) + *arch.a:*uart_periph.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_uart.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_sys.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_spiflash.*(.text .text.* .literal .literal.*) + *arch.a:*esp_efuse_fields.*(.text .text.* .literal .literal.*) + *arch.a:*esp_efuse_api_key.*(.text .text.* .literal .literal.*) + *arch.a:*esp_efuse_utility.*(.text .text.* .literal .literal.*) + *arch.a:*efuse_hal.*(.text .text.* .literal .literal.*) + *arch.a:*apm_hal.*(.text .text.* .literal .literal.*) + *arch.a:*log.*(.text .text.* .literal .literal.*) + *arch.a:*cpu_region_protect.*(.text .text.* .literal .literal.*) + *arch.a:*esp_region_protect.*(.text .text.* .literal .literal.*) + *arch.a:*esp_userspace.*(.text .text.* .literal .literal.*) + *arch.a:*log_lock.*(.literal .literal.* .text .text.*) + *arch.a:*log_print.*(.literal .literal.* .text .text.*) + *arch.a:*log_timestamp.*(.literal.esp_log_early_timestamp .text.esp_log_early_timestamp) + *arch.a:*log_timestamp.*(.literal.esp_log_timestamp .text.esp_log_timestamp) + *arch.a:*log_timestamp_common.*(.literal .literal.* .text .text.*) + *arch.a:*log_write.*(.literal.esp_log_write .text.esp_log_write) + *arch.a:*log_write.*(.literal.esp_log_writev .text.esp_log_writev) + *arch.a:*rv_utils.*(.literal .literal.* .text .text.*) + *arch.a:*libarch.*(.literal .literal.* .text .text.*) + *arch.a:*riscv_modifyreg32.*(.literal .literal.* .text .text.*) + *arch.a:critical_section.*(.literal .literal.* .text .text.*) + *arch.a:os.*(.literal.nuttx_enter_critical .text.nuttx_enter_critical) + *arch.a:os.*(.literal.nuttx_exit_critical .text.nuttx_exit_critical) + *arch.a:spi_flash_hpm_enable.*(.literal .literal.* .text .text.*) + *arch.a:*sleep_modes.*(.literal.esp_sleep_pd_config* .text.esp_sleep_pd_config*) + *arch.a:esp_spiflash.*(.literal .text .literal.* .text.*) + *arch.a:esp_flash_api.*(.text .text.* .literal .literal.*) + *arch.a:esp_flash_spi_init.*(.text .text.* .literal .literal.*) + *arch.a:spi_flash_hal_iram.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_encrypt_hal_iram.*(.text .text.* .literal .literal.*) + *arch.a:spi_flash_hal_gpspi.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_chip*.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_wrap.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_os_func_noos.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_os_func_app.*(.literal .literal.* .text .text.*) + *arch.a:flash_brownout_hook.*(.literal .literal.* .text .text.*) + *arch.a:esp_cache.*(.literal .literal.* .text .text.*) + *arch.a:cache_utils.*(.literal .literal.* .text .text.*) + *arch.a:memspi_host_driver.*(.literal .literal.* .text .text.*) *libc.a:sq_remlast.*(.literal .text .literal.* .text.*) @@ -353,106 +355,106 @@ SECTIONS *(.dram1) *(.dram1.*) - *libarch.a:brownout.*(.rodata .rodata.*) - *libarch.a:cpu.*(.rodata .rodata.*) - *libarch.a:gpio_hal.*(.rodata .rodata.*) - *libarch.a:interrupt.*(.rodata .rodata.*) - *libarch.a:periph_ctrl.*(.rodata .rodata.*) - *libarch.a:rtc_clk.*(.rodata .rodata.*) - *libarch.a:rtc_sleep.*(.rodata .rodata.*) - *libarch.a:rtc_time.*(.rodata .rodata.*) - *libarch.a:systimer.*(.rodata .rodata.*) - *libarch.a:systimer_hal.*(.rodata .rodata.*) - *libarch.a:uart_hal_iram.*(.rodata .rodata.*) - *libarch.a:wdt_hal_iram.*(.rodata .rodata.*) + *arch.a:brownout.*(.rodata .rodata.*) + *arch.a:cpu.*(.rodata .rodata.*) + *arch.a:gpio_hal.*(.rodata .rodata.*) + *arch.a:interrupt.*(.rodata .rodata.*) + *arch.a:periph_ctrl.*(.rodata .rodata.*) + *arch.a:rtc_clk.*(.rodata .rodata.*) + *arch.a:rtc_sleep.*(.rodata .rodata.*) + *arch.a:rtc_time.*(.rodata .rodata.*) + *arch.a:systimer.*(.rodata .rodata.*) + *arch.a:systimer_hal.*(.rodata .rodata.*) + *arch.a:uart_hal_iram.*(.rodata .rodata.*) + *arch.a:wdt_hal_iram.*(.rodata .rodata.*) *libsched.a:irq_dispatch.*(.rodata .rodata.*) *libsched.a:irq_dispatch.*(.rodata .rodata.*) *libsched.a:sched_lock.*(.rodata .rodata.*) *libsched.a:sched_unlock.*(.rodata .rodata.*) - *libarch.a:*(.rodata.esprv_intc_int_get_type) - *libarch.a:*riscv_doirq.*(.rodata .rodata.*) - *libarch.a:*brownout.*(.rodata .rodata.*) - *libarch.a:*cpu.*(.rodata .rodata.*) - *libarch.a:*gpio_hal.*(.rodata .rodata.*) - *libarch.a:*periph_ctrl.*(.rodata .rodata.*) - *libarch.a:*clk.*(.rodata .rodata.*) - *libarch.a:*esp_clk.*(.rodata .rodata.*) - *libarch.a:*esp_clk_tree.*(.rodata .rodata.*) - *libarch.a:*esp_clk_tree_common.*(.rodata .rodata.*) - *libarch.a:*clk_tree_hal.*(.rodata .rodata.*) - *libarch.a:*pmu_init.*(.rodata .rodata.*) - *libarch.a:*modem_clock.*(.rodata .rodata.*) - *libarch.a:*modem_clock_hal.*(.rodata .rodata.*) - *libarch.a:*regi2c_ctrl.*(.rodata .rodata.*) - *libarch.a:*gpio_periph.*(.rodata .rodata.*) - *libarch.a:*esp_rom_systimer.*(.rodata .rodata.*) - *libarch.a:*esp_rom_wdt.*(.rodata .rodata.*) - *libarch.a:*ocode_init.*(.rodata .rodata.*) - *libarch.a:*esp_rom_regi2c_esp32p4.*(.rodata .rodata.*) - *libarch.a:*rtc_clk.*(.rodata .rodata.*) - *libarch.a:*rtc_clk_init.*(.rodata .rodata.*) - *libarch.a:*pmu_param.*(.rodata .rodata.*) - *libarch.a:*pmu_sleep.*(.rodata .rodata.*) - *libarch.a:*rtc_time.*(.rodata .rodata.*) - *libarch.a:*systimer.*(.rodata .rodata.*) - *libarch.a:*systimer_hal.*(.rodata .rodata.*) - *libarch.a:*uart_hal_iram.*(.rodata .rodata.*) - *libarch.a:*wdt_hal_iram.*(.rodata .rodata.*) - *libarch.a:*bootloader_banner_wrap.*(.rodata .rodata.*) - *libarch.a:*bootloader_init.*(.rodata .rodata.*) - *libarch.a:*bootloader_common.*(.rodata .rodata.*) - *libarch.a:*bootloader_common_loader.*(.rodata .rodata.*) - *libarch.a:*bootloader_console.*(.rodata .rodata.*) - *libarch.a:*bootloader_console_loader.*(.rodata .rodata.*) - *libarch.a:*bootloader_esp32p4.*(.rodata .rodata.*) - *libarch.a:*bootloader_flash.*(.rodata .rodata.*) - *libarch.a:*bootloader_flash_config_esp32p4.*(.rodata .rodata.*) - *libarch.a:*flash_qio_mode.*(.rodata .rodata.*) - *libarch.a:*bootloader_clock_init.*(.rodata .rodata.*) - *libarch.a:*bootloader_clock_loader.*(.rodata .rodata.*) - *libarch.a:*bootloader_efuse.*(.rodata .rodata.*) - *libarch.a:*bootloader_panic.*(.rodata .rodata.*) - *libarch.a:*bootloader_mem.*(.rodata .rodata.*) - *libarch.a:*bootloader_random.*(.rodata .rodata.*) - *libarch.a:*bootloader_random_esp32p4.*(.rodata .rodata.*) - *libarch.a:*esp_image_format.*(.rodata .rodata.*) - *libarch.a:*bootloader_soc.*(.rodata .rodata.*) - *libarch.a:*bootloader_sha.*(.rodata .rodata.*) - *libarch.a:*flash_encrypt.*(.rodata .rodata.*) - *libarch.a:*cache_hal.*(.rodata .rodata.*) - *libarch.a:*uart_hal.*(.rodata .rodata.*) - *libarch.a:*mpu_hal.*(.rodata .rodata.*) - *libarch.a:*mmu_hal.*(.rodata .rodata.*) - *libarch.a:*uart_periph.*(.rodata .rodata.*) - *libarch.a:*esp_rom_uart.*(.rodata .rodata.*) - *libarch.a:*esp_rom_sys.*(.rodata .rodata.*) - *libarch.a:*esp_rom_spiflash.*(.rodata .rodata.*) - *libarch.a:*esp_efuse_fields.*(.rodata .rodata.*) - *libarch.a:*esp_efuse_api_key.*(.rodata .rodata.*) - *libarch.a:*esp_efuse_utility.*(.rodata .rodata.*) - *libarch.a:*efuse_hal.*(.rodata .rodata.*) - *libarch.a:*log.*(.rodata .rodata.*) - *libarch.a:*log_noos.*(.rodata .rodata.*) - *libarch.a:esp_spiflash.*(.rodata .rodata.*) - *libarch.a:esp_chip_rev.*(.rodata .rodata.*) - *libarch.a:critical_section.*(.rodata .rodata.*) - *libarch.a:os.*(.rodata.g_int_flags_count .rodata.g_int_flags) - *libarch.a:spi_flash_hpm_enable.*(.rodata .rodata.*) - *libarch.a:*sleep_modes.*(.rodata.esp_sleep_pd_config*) - *libarch.a:esp_flash_api.*(.rodata .rodata.*) - *libarch.a:esp_flash_spi_init.*(.rodata .rodata.*) - *libarch.a:spi_flash_hal_iram.*(.rodata .rodata.*) - *libarch.a:spi_flash_encrypt_hal_iram.*(.rodata .rodata.*) - *libarch.a:spi_flash_hal_gpspi.*(.rodata .rodata.*) - *libarch.a:spi_flash_chip*.*(.rodata .rodata.*) - *libarch.a:spi_flash_wrap.*(.rodata .rodata.*) - *libarch.a:spi_flash_os_func_noos.*(.rodata .rodata.*) - *libarch.a:spi_flash_os_func_app.*(.rodata .rodata.*) - *libarch.a:flash_brownout_hook.*(.rodata .rodata.*) - *libarch.a:esp_cache.*(.rodata .rodata.*) - *libarch.a:cache_utils.*(.rodata .rodata.*) - *libarch.a:memspi_host_driver.*(.rodata .rodata.*) + *arch.a:*(.rodata.esprv_intc_int_get_type) + *arch.a:*riscv_doirq.*(.rodata .rodata.*) + *arch.a:*brownout.*(.rodata .rodata.*) + *arch.a:*cpu.*(.rodata .rodata.*) + *arch.a:*gpio_hal.*(.rodata .rodata.*) + *arch.a:*periph_ctrl.*(.rodata .rodata.*) + *arch.a:*clk.*(.rodata .rodata.*) + *arch.a:*esp_clk.*(.rodata .rodata.*) + *arch.a:*esp_clk_tree.*(.rodata .rodata.*) + *arch.a:*esp_clk_tree_common.*(.rodata .rodata.*) + *arch.a:*clk_tree_hal.*(.rodata .rodata.*) + *arch.a:*pmu_init.*(.rodata .rodata.*) + *arch.a:*modem_clock.*(.rodata .rodata.*) + *arch.a:*modem_clock_hal.*(.rodata .rodata.*) + *arch.a:*regi2c_ctrl.*(.rodata .rodata.*) + *arch.a:*gpio_periph.*(.rodata .rodata.*) + *arch.a:*esp_rom_systimer.*(.rodata .rodata.*) + *arch.a:*esp_rom_wdt.*(.rodata .rodata.*) + *arch.a:*ocode_init.*(.rodata .rodata.*) + *arch.a:*esp_rom_regi2c_esp32p4.*(.rodata .rodata.*) + *arch.a:*rtc_clk.*(.rodata .rodata.*) + *arch.a:*rtc_clk_init.*(.rodata .rodata.*) + *arch.a:*pmu_param.*(.rodata .rodata.*) + *arch.a:*pmu_sleep.*(.rodata .rodata.*) + *arch.a:*rtc_time.*(.rodata .rodata.*) + *arch.a:*systimer.*(.rodata .rodata.*) + *arch.a:*systimer_hal.*(.rodata .rodata.*) + *arch.a:*uart_hal_iram.*(.rodata .rodata.*) + *arch.a:*wdt_hal_iram.*(.rodata .rodata.*) + *arch.a:*bootloader_banner_wrap.*(.rodata .rodata.*) + *arch.a:*bootloader_init.*(.rodata .rodata.*) + *arch.a:*bootloader_common.*(.rodata .rodata.*) + *arch.a:*bootloader_common_loader.*(.rodata .rodata.*) + *arch.a:*bootloader_console.*(.rodata .rodata.*) + *arch.a:*bootloader_console_loader.*(.rodata .rodata.*) + *arch.a:*bootloader_esp32p4.*(.rodata .rodata.*) + *arch.a:*bootloader_flash.*(.rodata .rodata.*) + *arch.a:*bootloader_flash_config_esp32p4.*(.rodata .rodata.*) + *arch.a:*flash_qio_mode.*(.rodata .rodata.*) + *arch.a:*bootloader_clock_init.*(.rodata .rodata.*) + *arch.a:*bootloader_clock_loader.*(.rodata .rodata.*) + *arch.a:*bootloader_efuse.*(.rodata .rodata.*) + *arch.a:*bootloader_panic.*(.rodata .rodata.*) + *arch.a:*bootloader_mem.*(.rodata .rodata.*) + *arch.a:*bootloader_random.*(.rodata .rodata.*) + *arch.a:*bootloader_random_esp32p4.*(.rodata .rodata.*) + *arch.a:*esp_image_format.*(.rodata .rodata.*) + *arch.a:*bootloader_soc.*(.rodata .rodata.*) + *arch.a:*bootloader_sha.*(.rodata .rodata.*) + *arch.a:*flash_encrypt.*(.rodata .rodata.*) + *arch.a:*cache_hal.*(.rodata .rodata.*) + *arch.a:*uart_hal.*(.rodata .rodata.*) + *arch.a:*mpu_hal.*(.rodata .rodata.*) + *arch.a:*mmu_hal.*(.rodata .rodata.*) + *arch.a:*uart_periph.*(.rodata .rodata.*) + *arch.a:*esp_rom_uart.*(.rodata .rodata.*) + *arch.a:*esp_rom_sys.*(.rodata .rodata.*) + *arch.a:*esp_rom_spiflash.*(.rodata .rodata.*) + *arch.a:*esp_efuse_fields.*(.rodata .rodata.*) + *arch.a:*esp_efuse_api_key.*(.rodata .rodata.*) + *arch.a:*esp_efuse_utility.*(.rodata .rodata.*) + *arch.a:*efuse_hal.*(.rodata .rodata.*) + *arch.a:*log.*(.rodata .rodata.*) + *arch.a:*log_noos.*(.rodata .rodata.*) + *arch.a:esp_spiflash.*(.rodata .rodata.*) + *arch.a:esp_chip_rev.*(.rodata .rodata.*) + *arch.a:critical_section.*(.rodata .rodata.*) + *arch.a:os.*(.rodata.g_int_flags_count .rodata.g_int_flags) + *arch.a:spi_flash_hpm_enable.*(.rodata .rodata.*) + *arch.a:*sleep_modes.*(.rodata.esp_sleep_pd_config*) + *arch.a:esp_flash_api.*(.rodata .rodata.*) + *arch.a:esp_flash_spi_init.*(.rodata .rodata.*) + *arch.a:spi_flash_hal_iram.*(.rodata .rodata.*) + *arch.a:spi_flash_encrypt_hal_iram.*(.rodata .rodata.*) + *arch.a:spi_flash_hal_gpspi.*(.rodata .rodata.*) + *arch.a:spi_flash_chip*.*(.rodata .rodata.*) + *arch.a:spi_flash_wrap.*(.rodata .rodata.*) + *arch.a:spi_flash_os_func_noos.*(.rodata .rodata.*) + *arch.a:spi_flash_os_func_app.*(.rodata .rodata.*) + *arch.a:flash_brownout_hook.*(.rodata .rodata.*) + *arch.a:esp_cache.*(.rodata .rodata.*) + *arch.a:cache_utils.*(.rodata .rodata.*) + *arch.a:memspi_host_driver.*(.rodata .rodata.*) esp_head.*(.rodata .rodata.*) esp_start.*(.rodata .rodata.*) diff --git a/boards/risc-v/esp32p4/common/scripts/esp32p4_sections.rev3.ld b/boards/risc-v/esp32p4/common/scripts/esp32p4_sections.rev3.ld index 8afb4d1e0cdd0..12c9d0b235bc1 100644 --- a/boards/risc-v/esp32p4/common/scripts/esp32p4_sections.rev3.ld +++ b/boards/risc-v/esp32p4/common/scripts/esp32p4_sections.rev3.ld @@ -211,102 +211,104 @@ SECTIONS *libsched.a:sched_lock.*(.text .text.* .literal .literal.*) *libsched.a:sched_unlock.*(.text .text.* .literal .literal.*) - *libarch.a:*(.text.esprv_intc_int_get_type .literal.esprv_intc_int_get_type) - *libarch.a:*riscv_doirq.*(.text .text.* .literal .literal.*) - *libarch.a:*brownout.*(.text .text.* .literal .literal.*) - *libarch.a:*cpu.*(.text .text.* .literal .literal.*) - *libarch.a:*gpio_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*periph_ctrl.*(.text .text.* .literal .literal.*) - *libarch.a:*clk.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_clk.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_clk_tree.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_clk_tree_common.*(.text .text.* .literal .literal.*) - *libarch.a:*clk_tree_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*pmu_init.*(.text .text.* .literal .literal.*) - *libarch.a:*modem_clock.*(.text .text.* .literal .literal.*) - *libarch.a:*regi2c_ctrl.*(.text .text.* .literal .literal.*) - *libarch.a:*gpio_periph.*(.text .text.* .literal .literal.*) - *libarch.a:*modem_clock_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_systimer.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_wdt.*(.text .text.* .literal .literal.*) - *libarch.a:*ocode_init.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_regi2c_esp32p4.*(.text .text.* .literal .literal.*) - *libarch.a:*rtc_clk.*(.text .text.* .literal .literal.*) - *libarch.a:*rtc_clk_init.*(.text .text.* .literal .literal.*) - *libarch.a:*pmu_sleep.*(.text .text.* .literal .literal.*) - *libarch.a:*pmu_param.*(.text .text.* .literal .literal.*) - *libarch.a:*rtc_time.*(.text .text.* .literal .literal.*) - *libarch.a:*systimer.*(.text .text.* .literal .literal.*) - *libarch.a:*systimer_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*uart_hal_iram.*(.text .text.* .literal .literal.*) - *libarch.a:*wdt_hal_iram.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_banner_wrap.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_init.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_common.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_common_loader.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_console.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_console_loader.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_esp32p4.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_flash.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_flash_config_esp32p4.*(.text .text.* .literal .literal.*) - *libarch.a:*flash_qio_mode.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_clock_init.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_clock_loader.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_efuse.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_panic.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_mem.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_random.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_random_esp32p4.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_image_format.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_soc.*(.text .text.* .literal .literal.*) - *libarch.a:*bootloader_sha.*(.text .text.* .literal .literal.*) - *libarch.a:*flash_encrypt.*(.text .text.* .literal .literal.*) - *libarch.a:*cache_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*uart_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*mpu_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*mmu_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*uart_periph.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_uart.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_sys.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_rom_spiflash.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_efuse_fields.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_efuse_api_key.*(.text .text.* .literal .literal.*) - *libarch.a:*esp_efuse_utility.*(.text .text.* .literal .literal.*) - *libarch.a:*efuse_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*apm_hal.*(.text .text.* .literal .literal.*) - *libarch.a:*log.*(.text .text.* .literal .literal.*) - *libarch.a:*cpu_region_protect.*(.text .text.* .literal .literal.*) - *libarch.a:*log_lock.*(.literal .literal.* .text .text.*) - *libarch.a:*log_print.*(.literal .literal.* .text .text.*) - *libarch.a:*log_timestamp.*(.literal.esp_log_early_timestamp .text.esp_log_early_timestamp) - *libarch.a:*log_timestamp.*(.literal.esp_log_timestamp .text.esp_log_timestamp) - *libarch.a:*log_timestamp_common.*(.literal .literal.* .text .text.*) - *libarch.a:*log_write.*(.literal.esp_log_write .text.esp_log_write) - *libarch.a:*log_write.*(.literal.esp_log_writev .text.esp_log_writev) - *libarch.a:*rv_utils.*(.literal .literal.* .text .text.*) - *libarch.a:*libarch.*(.literal .literal.* .text .text.*) - *libarch.a:*riscv_modifyreg32.*(.literal .literal.* .text .text.*) - *libarch.a:critical_section.*(.literal .literal.* .text .text.*) - *libarch.a:os.*(.literal.nuttx_enter_critical .text.nuttx_enter_critical) - *libarch.a:os.*(.literal.nuttx_exit_critical .text.nuttx_exit_critical) - *libarch.a:spi_flash_hpm_enable.*(.literal .literal.* .text .text.*) - *libarch.a:*sleep_modes.*(.literal.esp_sleep_pd_config* .text.esp_sleep_pd_config*) - *libarch.a:esp_spiflash.*(.literal .text .literal.* .text.*) - *libarch.a:esp_flash_api.*(.text .text.* .literal .literal.*) - *libarch.a:esp_flash_spi_init.*(.text .text.* .literal .literal.*) - *libarch.a:spi_flash_hal_iram.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_encrypt_hal_iram.*(.text .text.* .literal .literal.*) - *libarch.a:spi_flash_hal_gpspi.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_chip*.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_wrap.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_os_func_noos.*(.literal .literal.* .text .text.*) - *libarch.a:spi_flash_os_func_app.*(.literal .literal.* .text .text.*) - *libarch.a:flash_brownout_hook.*(.literal .literal.* .text .text.*) - *libarch.a:esp_cache.*(.literal .literal.* .text .text.*) - *libarch.a:cache_utils.*(.literal .literal.* .text .text.*) - *libarch.a:memspi_host_driver.*(.literal .literal.* .text .text.*) - *libarch.a:esp_psram_impl_ap_hex.*(.literal .literal.* .text .text.*) - *libarch.a:esp_psram.*(.literal.esp_psram_get_heap_size_to_protect .text.esp_psram_get_heap_size_to_protect) + *arch.a:*(.text.esprv_intc_int_get_type .literal.esprv_intc_int_get_type) + *arch.a:*riscv_doirq.*(.text .text.* .literal .literal.*) + *arch.a:*brownout.*(.text .text.* .literal .literal.*) + *arch.a:*cpu.*(.text .text.* .literal .literal.*) + *arch.a:*gpio_hal.*(.text .text.* .literal .literal.*) + *arch.a:*periph_ctrl.*(.text .text.* .literal .literal.*) + *arch.a:*clk.*(.text .text.* .literal .literal.*) + *arch.a:*esp_clk.*(.text .text.* .literal .literal.*) + *arch.a:*esp_clk_tree.*(.text .text.* .literal .literal.*) + *arch.a:*esp_clk_tree_common.*(.text .text.* .literal .literal.*) + *arch.a:*clk_tree_hal.*(.text .text.* .literal .literal.*) + *arch.a:*pmu_init.*(.text .text.* .literal .literal.*) + *arch.a:*modem_clock.*(.text .text.* .literal .literal.*) + *arch.a:*regi2c_ctrl.*(.text .text.* .literal .literal.*) + *arch.a:*gpio_periph.*(.text .text.* .literal .literal.*) + *arch.a:*modem_clock_hal.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_systimer.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_wdt.*(.text .text.* .literal .literal.*) + *arch.a:*ocode_init.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_regi2c_esp32p4.*(.text .text.* .literal .literal.*) + *arch.a:*rtc_clk.*(.text .text.* .literal .literal.*) + *arch.a:*rtc_clk_init.*(.text .text.* .literal .literal.*) + *arch.a:*pmu_sleep.*(.text .text.* .literal .literal.*) + *arch.a:*pmu_param.*(.text .text.* .literal .literal.*) + *arch.a:*rtc_time.*(.text .text.* .literal .literal.*) + *arch.a:*systimer.*(.text .text.* .literal .literal.*) + *arch.a:*systimer_hal.*(.text .text.* .literal .literal.*) + *arch.a:*uart_hal_iram.*(.text .text.* .literal .literal.*) + *arch.a:*wdt_hal_iram.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_banner_wrap.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_init.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_common.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_common_loader.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_console.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_console_loader.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_esp32p4.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_flash.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_flash_config_esp32p4.*(.text .text.* .literal .literal.*) + *arch.a:*flash_qio_mode.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_clock_init.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_clock_loader.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_efuse.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_panic.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_mem.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_random.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_random_esp32p4.*(.text .text.* .literal .literal.*) + *arch.a:*esp_image_format.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_soc.*(.text .text.* .literal .literal.*) + *arch.a:*bootloader_sha.*(.text .text.* .literal .literal.*) + *arch.a:*flash_encrypt.*(.text .text.* .literal .literal.*) + *arch.a:*cache_hal.*(.text .text.* .literal .literal.*) + *arch.a:*uart_hal.*(.text .text.* .literal .literal.*) + *arch.a:*mpu_hal.*(.text .text.* .literal .literal.*) + *arch.a:*mmu_hal.*(.text .text.* .literal .literal.*) + *arch.a:*uart_periph.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_uart.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_sys.*(.text .text.* .literal .literal.*) + *arch.a:*esp_rom_spiflash.*(.text .text.* .literal .literal.*) + *arch.a:*esp_efuse_fields.*(.text .text.* .literal .literal.*) + *arch.a:*esp_efuse_api_key.*(.text .text.* .literal .literal.*) + *arch.a:*esp_efuse_utility.*(.text .text.* .literal .literal.*) + *arch.a:*efuse_hal.*(.text .text.* .literal .literal.*) + *arch.a:*apm_hal.*(.text .text.* .literal .literal.*) + *arch.a:*log.*(.text .text.* .literal .literal.*) + *arch.a:*cpu_region_protect.*(.text .text.* .literal .literal.*) + *arch.a:*esp_region_protect.*(.text .text.* .literal .literal.*) + *arch.a:*esp_userspace.*(.text .text.* .literal .literal.*) + *arch.a:*log_lock.*(.literal .literal.* .text .text.*) + *arch.a:*log_print.*(.literal .literal.* .text .text.*) + *arch.a:*log_timestamp.*(.literal.esp_log_early_timestamp .text.esp_log_early_timestamp) + *arch.a:*log_timestamp.*(.literal.esp_log_timestamp .text.esp_log_timestamp) + *arch.a:*log_timestamp_common.*(.literal .literal.* .text .text.*) + *arch.a:*log_write.*(.literal.esp_log_write .text.esp_log_write) + *arch.a:*log_write.*(.literal.esp_log_writev .text.esp_log_writev) + *arch.a:*rv_utils.*(.literal .literal.* .text .text.*) + *arch.a:*libarch.*(.literal .literal.* .text .text.*) + *arch.a:*riscv_modifyreg32.*(.literal .literal.* .text .text.*) + *arch.a:critical_section.*(.literal .literal.* .text .text.*) + *arch.a:os.*(.literal.nuttx_enter_critical .text.nuttx_enter_critical) + *arch.a:os.*(.literal.nuttx_exit_critical .text.nuttx_exit_critical) + *arch.a:spi_flash_hpm_enable.*(.literal .literal.* .text .text.*) + *arch.a:*sleep_modes.*(.literal.esp_sleep_pd_config* .text.esp_sleep_pd_config*) + *arch.a:esp_spiflash.*(.literal .text .literal.* .text.*) + *arch.a:esp_flash_api.*(.text .text.* .literal .literal.*) + *arch.a:esp_flash_spi_init.*(.text .text.* .literal .literal.*) + *arch.a:spi_flash_hal_iram.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_encrypt_hal_iram.*(.text .text.* .literal .literal.*) + *arch.a:spi_flash_hal_gpspi.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_chip*.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_wrap.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_os_func_noos.*(.literal .literal.* .text .text.*) + *arch.a:spi_flash_os_func_app.*(.literal .literal.* .text .text.*) + *arch.a:flash_brownout_hook.*(.literal .literal.* .text .text.*) + *arch.a:esp_cache.*(.literal .literal.* .text .text.*) + *arch.a:cache_utils.*(.literal .literal.* .text .text.*) + *arch.a:memspi_host_driver.*(.literal .literal.* .text .text.*) + *arch.a:esp_psram_impl_ap_hex.*(.literal .literal.* .text .text.*) + *arch.a:esp_psram.*(.literal.esp_psram_get_heap_size_to_protect .text.esp_psram_get_heap_size_to_protect) *libc.a:sq_remlast.*(.literal .text .literal.* .text.*) @@ -374,108 +376,109 @@ SECTIONS *(.dram1) *(.dram1.*) - *libarch.a:brownout.*(.rodata .rodata.*) - *libarch.a:cpu.*(.rodata .rodata.*) - *libarch.a:gpio_hal.*(.rodata .rodata.*) - *libarch.a:interrupt.*(.rodata .rodata.*) - *libarch.a:periph_ctrl.*(.rodata .rodata.*) - *libarch.a:rtc_clk.*(.rodata .rodata.*) - *libarch.a:rtc_sleep.*(.rodata .rodata.*) - *libarch.a:rtc_time.*(.rodata .rodata.*) - *libarch.a:systimer.*(.rodata .rodata.*) - *libarch.a:systimer_hal.*(.rodata .rodata.*) - *libarch.a:uart_hal_iram.*(.rodata .rodata.*) - *libarch.a:wdt_hal_iram.*(.rodata .rodata.*) + *arch.a:brownout.*(.rodata .rodata.*) + *arch.a:cpu.*(.rodata .rodata.*) + *arch.a:gpio_hal.*(.rodata .rodata.*) + *arch.a:interrupt.*(.rodata .rodata.*) + *arch.a:periph_ctrl.*(.rodata .rodata.*) + *arch.a:rtc_clk.*(.rodata .rodata.*) + *arch.a:rtc_sleep.*(.rodata .rodata.*) + *arch.a:rtc_time.*(.rodata .rodata.*) + *arch.a:systimer.*(.rodata .rodata.*) + *arch.a:systimer_hal.*(.rodata .rodata.*) + *arch.a:uart_hal_iram.*(.rodata .rodata.*) + *arch.a:wdt_hal_iram.*(.rodata .rodata.*) *libsched.a:irq_dispatch.*(.rodata .rodata.*) *libsched.a:irq_dispatch.*(.rodata .rodata.*) *libsched.a:sched_lock.*(.rodata .rodata.*) *libsched.a:sched_unlock.*(.rodata .rodata.*) - *libarch.a:*(.rodata.esprv_intc_int_get_type) - *libarch.a:*riscv_doirq.*(.rodata .rodata.*) - *libarch.a:*brownout.*(.rodata .rodata.*) - *libarch.a:*cpu.*(.rodata .rodata.*) - *libarch.a:*gpio_hal.*(.rodata .rodata.*) - *libarch.a:*periph_ctrl.*(.rodata .rodata.*) - *libarch.a:*clk.*(.rodata .rodata.*) - *libarch.a:*esp_clk.*(.rodata .rodata.*) - *libarch.a:*esp_clk_tree.*(.rodata .rodata.*) - *libarch.a:*esp_clk_tree_common.*(.rodata .rodata.*) - *libarch.a:*clk_tree_hal.*(.rodata .rodata.*) - *libarch.a:*pmu_init.*(.rodata .rodata.*) - *libarch.a:*modem_clock.*(.rodata .rodata.*) - *libarch.a:*modem_clock_hal.*(.rodata .rodata.*) - *libarch.a:*regi2c_ctrl.*(.rodata .rodata.*) - *libarch.a:*gpio_periph.*(.rodata .rodata.*) - *libarch.a:*esp_rom_systimer.*(.rodata .rodata.*) - *libarch.a:*esp_rom_wdt.*(.rodata .rodata.*) - *libarch.a:*ocode_init.*(.rodata .rodata.*) - *libarch.a:*esp_rom_regi2c_esp32p4.*(.rodata .rodata.*) - *libarch.a:*rtc_clk.*(.rodata .rodata.*) - *libarch.a:*rtc_clk_init.*(.rodata .rodata.*) - *libarch.a:*pmu_param.*(.rodata .rodata.*) - *libarch.a:*pmu_sleep.*(.rodata .rodata.*) - *libarch.a:*rtc_time.*(.rodata .rodata.*) - *libarch.a:*systimer.*(.rodata .rodata.*) - *libarch.a:*systimer_hal.*(.rodata .rodata.*) - *libarch.a:*uart_hal_iram.*(.rodata .rodata.*) - *libarch.a:*wdt_hal_iram.*(.rodata .rodata.*) - *libarch.a:*bootloader_banner_wrap.*(.rodata .rodata.*) - *libarch.a:*bootloader_init.*(.rodata .rodata.*) - *libarch.a:*bootloader_common.*(.rodata .rodata.*) - *libarch.a:*bootloader_common_loader.*(.rodata .rodata.*) - *libarch.a:*bootloader_console.*(.rodata .rodata.*) - *libarch.a:*bootloader_console_loader.*(.rodata .rodata.*) - *libarch.a:*bootloader_esp32p4.*(.rodata .rodata.*) - *libarch.a:*bootloader_flash.*(.rodata .rodata.*) - *libarch.a:*bootloader_flash_config_esp32p4.*(.rodata .rodata.*) - *libarch.a:*flash_qio_mode.*(.rodata .rodata.*) - *libarch.a:*bootloader_clock_init.*(.rodata .rodata.*) - *libarch.a:*bootloader_clock_loader.*(.rodata .rodata.*) - *libarch.a:*bootloader_efuse.*(.rodata .rodata.*) - *libarch.a:*bootloader_panic.*(.rodata .rodata.*) - *libarch.a:*bootloader_mem.*(.rodata .rodata.*) - *libarch.a:*bootloader_random.*(.rodata .rodata.*) - *libarch.a:*bootloader_random_esp32p4.*(.rodata .rodata.*) - *libarch.a:*esp_image_format.*(.rodata .rodata.*) - *libarch.a:*bootloader_soc.*(.rodata .rodata.*) - *libarch.a:*bootloader_sha.*(.rodata .rodata.*) - *libarch.a:*flash_encrypt.*(.rodata .rodata.*) - *libarch.a:*cache_hal.*(.rodata .rodata.*) - *libarch.a:*uart_hal.*(.rodata .rodata.*) - *libarch.a:*mpu_hal.*(.rodata .rodata.*) - *libarch.a:*mmu_hal.*(.rodata .rodata.*) - *libarch.a:*uart_periph.*(.rodata .rodata.*) - *libarch.a:*esp_rom_uart.*(.rodata .rodata.*) - *libarch.a:*esp_rom_sys.*(.rodata .rodata.*) - *libarch.a:*esp_rom_spiflash.*(.rodata .rodata.*) - *libarch.a:*esp_efuse_fields.*(.rodata .rodata.*) - *libarch.a:*esp_efuse_api_key.*(.rodata .rodata.*) - *libarch.a:*esp_efuse_utility.*(.rodata .rodata.*) - *libarch.a:*efuse_hal.*(.rodata .rodata.*) - *libarch.a:*log.*(.rodata .rodata.*) - *libarch.a:*log_noos.*(.rodata .rodata.*) - *libarch.a:esp_spiflash.*(.rodata .rodata.*) - *libarch.a:esp_chip_rev.*(.rodata .rodata.*) - *libarch.a:critical_section.*(.rodata .rodata.*) - *libarch.a:os.*(.rodata.g_int_flags_count .rodata.g_int_flags) - *libarch.a:spi_flash_hpm_enable.*(.rodata .rodata.*) - *libarch.a:*sleep_modes.*(.rodata.esp_sleep_pd_config*) - *libarch.a:esp_flash_api.*(.rodata .rodata.*) - *libarch.a:esp_flash_spi_init.*(.rodata .rodata.*) - *libarch.a:spi_flash_hal_iram.*(.rodata .rodata.*) - *libarch.a:spi_flash_encrypt_hal_iram.*(.rodata .rodata.*) - *libarch.a:spi_flash_hal_gpspi.*(.rodata .rodata.*) - *libarch.a:spi_flash_chip*.*(.rodata .rodata.*) - *libarch.a:spi_flash_wrap.*(.rodata .rodata.*) - *libarch.a:spi_flash_os_func_noos.*(.rodata .rodata.*) - *libarch.a:spi_flash_os_func_app.*(.rodata .rodata.*) - *libarch.a:flash_brownout_hook.*(.rodata .rodata.*) - *libarch.a:esp_cache.*(.rodata .rodata.*) - *libarch.a:cache_utils.*(.rodata .rodata.*) - *libarch.a:memspi_host_driver.*(.rodata .rodata.*) - *libarch.a:esp_psram_impl_ap_hex.*(.rodata .rodata.*) - *libarch.a:cpu_region_protect.*(.rodata .rodata.*) + *arch.a:*(.rodata.esprv_intc_int_get_type) + *arch.a:*riscv_doirq.*(.rodata .rodata.*) + *arch.a:*brownout.*(.rodata .rodata.*) + *arch.a:*cpu.*(.rodata .rodata.*) + *arch.a:*gpio_hal.*(.rodata .rodata.*) + *arch.a:*periph_ctrl.*(.rodata .rodata.*) + *arch.a:*clk.*(.rodata .rodata.*) + *arch.a:*esp_clk.*(.rodata .rodata.*) + *arch.a:*esp_clk_tree.*(.rodata .rodata.*) + *arch.a:*esp_clk_tree_common.*(.rodata .rodata.*) + *arch.a:*clk_tree_hal.*(.rodata .rodata.*) + *arch.a:*pmu_init.*(.rodata .rodata.*) + *arch.a:*modem_clock.*(.rodata .rodata.*) + *arch.a:*modem_clock_hal.*(.rodata .rodata.*) + *arch.a:*regi2c_ctrl.*(.rodata .rodata.*) + *arch.a:*gpio_periph.*(.rodata .rodata.*) + *arch.a:*esp_rom_systimer.*(.rodata .rodata.*) + *arch.a:*esp_rom_wdt.*(.rodata .rodata.*) + *arch.a:*ocode_init.*(.rodata .rodata.*) + *arch.a:*esp_rom_regi2c_esp32p4.*(.rodata .rodata.*) + *arch.a:*rtc_clk.*(.rodata .rodata.*) + *arch.a:*rtc_clk_init.*(.rodata .rodata.*) + *arch.a:*pmu_param.*(.rodata .rodata.*) + *arch.a:*pmu_sleep.*(.rodata .rodata.*) + *arch.a:*rtc_time.*(.rodata .rodata.*) + *arch.a:*systimer.*(.rodata .rodata.*) + *arch.a:*systimer_hal.*(.rodata .rodata.*) + *arch.a:*uart_hal_iram.*(.rodata .rodata.*) + *arch.a:*wdt_hal_iram.*(.rodata .rodata.*) + *arch.a:*bootloader_banner_wrap.*(.rodata .rodata.*) + *arch.a:*bootloader_init.*(.rodata .rodata.*) + *arch.a:*bootloader_common.*(.rodata .rodata.*) + *arch.a:*bootloader_common_loader.*(.rodata .rodata.*) + *arch.a:*bootloader_console.*(.rodata .rodata.*) + *arch.a:*bootloader_console_loader.*(.rodata .rodata.*) + *arch.a:*bootloader_esp32p4.*(.rodata .rodata.*) + *arch.a:*bootloader_flash.*(.rodata .rodata.*) + *arch.a:*bootloader_flash_config_esp32p4.*(.rodata .rodata.*) + *arch.a:*flash_qio_mode.*(.rodata .rodata.*) + *arch.a:*bootloader_clock_init.*(.rodata .rodata.*) + *arch.a:*bootloader_clock_loader.*(.rodata .rodata.*) + *arch.a:*bootloader_efuse.*(.rodata .rodata.*) + *arch.a:*bootloader_panic.*(.rodata .rodata.*) + *arch.a:*bootloader_mem.*(.rodata .rodata.*) + *arch.a:*bootloader_random.*(.rodata .rodata.*) + *arch.a:*bootloader_random_esp32p4.*(.rodata .rodata.*) + *arch.a:*esp_image_format.*(.rodata .rodata.*) + *arch.a:*bootloader_soc.*(.rodata .rodata.*) + *arch.a:*bootloader_sha.*(.rodata .rodata.*) + *arch.a:*flash_encrypt.*(.rodata .rodata.*) + *arch.a:*cache_hal.*(.rodata .rodata.*) + *arch.a:*uart_hal.*(.rodata .rodata.*) + *arch.a:*mpu_hal.*(.rodata .rodata.*) + *arch.a:*mmu_hal.*(.rodata .rodata.*) + *arch.a:*uart_periph.*(.rodata .rodata.*) + *arch.a:*esp_rom_uart.*(.rodata .rodata.*) + *arch.a:*esp_rom_sys.*(.rodata .rodata.*) + *arch.a:*esp_rom_spiflash.*(.rodata .rodata.*) + *arch.a:*esp_efuse_fields.*(.rodata .rodata.*) + *arch.a:*esp_efuse_api_key.*(.rodata .rodata.*) + *arch.a:*esp_efuse_utility.*(.rodata .rodata.*) + *arch.a:*efuse_hal.*(.rodata .rodata.*) + *arch.a:*log.*(.rodata .rodata.*) + *arch.a:*log_noos.*(.rodata .rodata.*) + *arch.a:esp_spiflash.*(.rodata .rodata.*) + *arch.a:esp_chip_rev.*(.rodata .rodata.*) + *arch.a:critical_section.*(.rodata .rodata.*) + *arch.a:os.*(.rodata.g_int_flags_count .rodata.g_int_flags) + *arch.a:spi_flash_hpm_enable.*(.rodata .rodata.*) + *arch.a:*sleep_modes.*(.rodata.esp_sleep_pd_config*) + *arch.a:esp_flash_api.*(.rodata .rodata.*) + *arch.a:esp_flash_spi_init.*(.rodata .rodata.*) + *arch.a:spi_flash_hal_iram.*(.rodata .rodata.*) + *arch.a:spi_flash_encrypt_hal_iram.*(.rodata .rodata.*) + *arch.a:spi_flash_hal_gpspi.*(.rodata .rodata.*) + *arch.a:spi_flash_chip*.*(.rodata .rodata.*) + *arch.a:spi_flash_wrap.*(.rodata .rodata.*) + *arch.a:spi_flash_os_func_noos.*(.rodata .rodata.*) + *arch.a:spi_flash_os_func_app.*(.rodata .rodata.*) + *arch.a:flash_brownout_hook.*(.rodata .rodata.*) + *arch.a:esp_cache.*(.rodata .rodata.*) + *arch.a:cache_utils.*(.rodata .rodata.*) + *arch.a:memspi_host_driver.*(.rodata .rodata.*) + *arch.a:esp_psram_impl_ap_hex.*(.rodata .rodata.*) + *arch.a:cpu_region_protect.*(.rodata .rodata.*) + *arch.a:esp_region_protect.*(.rodata .rodata.*) esp_head.*(.rodata .rodata.*) esp_start.*(.rodata .rodata.*) diff --git a/boards/risc-v/esp32p4/common/scripts/kernel-space.ld b/boards/risc-v/esp32p4/common/scripts/kernel-space.ld new file mode 100644 index 0000000000000..089e02672a374 --- /dev/null +++ b/boards/risc-v/esp32p4/common/scripts/kernel-space.ld @@ -0,0 +1,76 @@ +/**************************************************************************** + * boards/risc-v/esp32p4/common/scripts/kernel-space.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Kernel image layout for the protected build. + * + * The kernel's own output sections are identical to the flat build's, so + * rather than maintaining a second copy of a 700-line script this exports + * the region boundaries and then includes esp32p4_sections.ld verbatim. + * The split between kernel and user is expressed entirely in + * esp32p4_protected_memory.ld, whose REGION_ALIAS definitions point the + * flat script's region names at the kernel's half of the map. + * + * The symbols below are what the kernel needs at run time. The __u* ones + * are consumed by esp_userspace.c to program the flash MMU and the PMP; the + * __k* ones are exported for debugging and for board_memorymap.h. + ****************************************************************************/ + +#include + +/* User regions. esp_userspace.c uses these to describe what user mode may + * reach; everything not covered is denied to user mode by default. + */ + +__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); +__udram_start = ORIGIN(UDRAM); +__udram_size = LENGTH(UDRAM); +__udram_end = ORIGIN(UDRAM) + LENGTH(UDRAM); + +/* There is no UIRAM region: user code executes in place from flash. The + * symbols are still defined, pointing at an empty span at the base of + * UDRAM, so that board_memorymap.h can declare them unconditionally. + */ + +__uiram_start = ORIGIN(UDRAM); +__uiram_size = 0; +__uiram_end = ORIGIN(UDRAM); + +/* Kernel regions */ + +__kirom_start = ORIGIN(KIROM); +__kirom_size = LENGTH(KIROM); +__kdrom_start = ORIGIN(KDROM); +__kdrom_size = LENGTH(KDROM); +__kiram_start = ORIGIN(KRAM); +__kiram_size = LENGTH(KRAM); +__kiram_end = ORIGIN(KRAM) + LENGTH(KRAM); +__kdram_start = ORIGIN(KRAM); +__kdram_size = LENGTH(KRAM); +__kdram_end = ORIGIN(KRAM) + LENGTH(KRAM); + +#include "esp32p4_sections.ld" diff --git a/boards/risc-v/esp32p4/common/scripts/user-space.ld b/boards/risc-v/esp32p4/common/scripts/user-space.ld new file mode 100644 index 0000000000000..27c59e5989566 --- /dev/null +++ b/boards/risc-v/esp32p4/common/scripts/user-space.ld @@ -0,0 +1,221 @@ +/**************************************************************************** + * boards/risc-v/esp32p4/common/scripts/user-space.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * User image layout for the protected build. + * + * Two differences from the equivalent ESP32-C3 script are worth noting: + * + * 1. There is no UIRAM region. On the C3, IRAM and DRAM are two views of + * the same internal SRAM at different addresses, so the user image needs + * an .iram0.text section and a .dram0.dummy section to skip past it. + * SRAM is unified here, and user code executes in place from flash, so + * .iram1 input sections are collected into the flash text output section + * and neither the IRAM output section nor the dummy is required. + * + * 2. The metadata block is 0x80 bytes rather than 0x18. UDROM starts + * immediately after it and that address becomes a PMP TOR boundary, so + * it has to respect this SoC's 128-byte PMP granularity. + ****************************************************************************/ + +#include + +SECTIONS +{ + /* Consumed by esp_userspace.c in the kernel before any user code is + * reachable. The layout must match struct user_image_load_header_s. + */ + + .metadata : + { + /* DROM: destination address, flash offset, size */ + + LONG(ADDR(.userspace)) + LONG(LOADADDR(.userspace)) + LONG(SIZEOF(.userspace) + SIZEOF(.rodata)) + + /* IROM: destination address, flash offset, size */ + + LONG(ADDR(.text)) + LONG(LOADADDR(.text)) + LONG(SIZEOF(.text)) + } >metadata + + /* Region boundaries, for the user image's own use */ + + __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_udram_start = ORIGIN(UDRAM); + __ld_udram_size = LENGTH(UDRAM); + __ld_udram_end = ORIGIN(UDRAM) + LENGTH(UDRAM); + + _eronly = LOADADDR(.data); + + .userspace : { + *(.userspace) + } >UDROM AT>ROM + + /* Output sections carry standard names rather than the Espressif-usual + * ".flash.text" so that GDB's "add-symbol-file" can find a .text section + * when symbols from both images are loaded together. + */ + + .rodata : + { + _srodata = ABSOLUTE(.); + + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + + /* Collect the small read-only sections here too. Left to themselves the + * linker emits them as orphan output sections after .rodata, and their + * unaligned sizes then push the load address of .data to an odd offset. + */ + + *(.srodata) + *(.srodata.*) + *(.sdata2) + *(.sdata2.*) + __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: classes would be sorted by + * init priority, but NuttX does not use priorities here. + */ + + _sinit = ABSOLUTE(.); + KEEP (*(.init_array .init_array.*)) + _einit = ABSOLUTE(.); + + KEEP (*(.fini_array .fini_array.*)) + + *(.lit4) + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + + /* esp_userspace() copies .data out of flash with bootloader_flash_read(), + * which requires an aligned source address; .data's load address follows + * the end of this section, so pad to 16 here and again at the end of + * .data so that both the offset and the length are aligned. + */ + + . = ALIGN(16); + _erodata = ABSOLUTE(.); + } >UDROM AT>ROM + + .noinit (NOLOAD): + { + /* Data that is neither loaded nor initialised at startup */ + + *(.noinit) + *(.noinit.*) + } >UDRAM + + .data : + { + _sdata = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + *(.dram1) + *(.dram1.*) + . = ALIGN(16); + _edata = ABSOLUTE(.); + } >UDRAM AT>ROM + + .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 (32); + _ebss = ABSOLUTE(.); + } >UDRAM + + /* Skip the flash space already consumed by .userspace and .rodata so that + * the text output section's load address follows them in the image while + * its virtual address sits in UIROM. + */ + + .flash_text_dummy (NOLOAD) : ALIGN(0x00010000) + { + . = SIZEOF(.userspace) + SIZEOF(.rodata); + } >UIROM + + .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 */ + + /* No UIRAM region on this SoC: anything the user image marked for + * internal instruction RAM is executed in place from flash instead. + */ + + *(.iram1) + *(.iram1.*) + + *(.fini.literal) + *(.fini) + *(.gnu.version) + _etext = .; + } >UIROM AT>ROM +} diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/configs/knsh/defconfig b/boards/risc-v/esp32p4/esp32p4-tab5/configs/knsh/defconfig new file mode 100644 index 0000000000000..331461b6155df --- /dev/null +++ b/boards/risc-v/esp32p4/esp32p4-tab5/configs/knsh/defconfig @@ -0,0 +1,70 @@ +# +# 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_ESPRESSIF_REGION_PROTECTION is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="esp32p4-tab5" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ESP32P4_TAB5=y +CONFIG_ARCH_CHIP="esp32p4" +CONFIG_ARCH_CHIP_ESP32P4=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_IRQ_TO_NDX=y +CONFIG_ARCH_MINIMAL_VECTORTABLE_DYNAMIC=y +CONFIG_ARCH_NUSER_INTERRUPTS=17 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=15000 +CONFIG_BUILD_PROTECTED=y +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_BINFMT=y +CONFIG_DEBUG_BINFMT_ERROR=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SCHED=y +CONFIG_DEBUG_SCHED_ERROR=y +CONFIG_DEBUG_SCHED_WARN=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_SYSCALL=y +CONFIG_DEBUG_SYSCALL_ERROR=y +CONFIG_DEBUG_SYSCALL_WARN=y +CONFIG_ESP32P4_REV_MIN_100=y +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESPRESSIF_FLASH_16M=y +CONFIG_ESPRESSIF_KERNEL_OWNS_PMP=y +CONFIG_EXPERIMENTAL=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_MM_REGIONS=2 +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_NSH_STRERROR=y +CONFIG_NUTTX_USERSPACE=0x40300080 +CONFIG_PASS1_BUILDIR="boards/risc-v/esp32p4/common/kernel" +CONFIG_PREALLOC_TIMERS=0 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_BACKTRACE=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=18 +CONFIG_START_MONTH=3 +CONFIG_START_YEAR=2026 +CONFIG_SYSTEM_DUMPSTACK=y +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART0_SERIAL_CONSOLE=y diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/include/board_memorymap.h b/boards/risc-v/esp32p4/esp32p4-tab5/include/board_memorymap.h new file mode 100644 index 0000000000000..4019a9a01fe2c --- /dev/null +++ b/boards/risc-v/esp32p4/esp32p4-tab5/include/board_memorymap.h @@ -0,0 +1,118 @@ +/**************************************************************************** + * boards/risc-v/esp32p4/esp32p4-tab5/include/board_memorymap.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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_ESP32P4_ESP32P4_TAB5_INCLUDE_BOARD_MEMORYMAP_H +#define __BOARDS_RISCV_ESP32P4_ESP32P4_TAB5_INCLUDE_BOARD_MEMORYMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * 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 uint8_t __kirom_start[]; +extern uint8_t __kirom_size[]; +extern uint8_t __kdrom_start[]; +extern uint8_t __kdrom_size[]; + +/* Kernel RAM (RW) */ + +extern uint8_t __kiram_start[]; +extern uint8_t __kiram_size[]; +extern uint8_t __kiram_end[]; +extern uint8_t __kdram_start[]; +extern uint8_t __kdram_size[]; +extern uint8_t __kdram_end[]; + +/* Exception vectors */ + +extern uint8_t __vectors_start[]; +extern uint8_t __vectors_end[]; + +/* User ROM (RX) */ + +extern uint8_t __uirom_start[]; +extern uint8_t __uirom_size[]; +extern uint8_t __uirom_end[]; +extern uint8_t __udrom_start[]; +extern uint8_t __udrom_size[]; +extern uint8_t __udrom_end[]; + +/* User RAM (RW) */ + +extern uint8_t __uiram_start[]; +extern uint8_t __uiram_size[]; +extern uint8_t __uiram_end[]; +extern uint8_t __udram_start[]; +extern uint8_t __udram_size[]; +extern uint8_t __udram_end[]; + +#endif /* __BOARDS_RISCV_ESP32P4_ESP32P4_TAB5_INCLUDE_BOARD_MEMORYMAP_H */ diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/scripts/Make.defs b/boards/risc-v/esp32p4/esp32p4-tab5/scripts/Make.defs index 51e5bbbf46c55..27c5fe5c3ba02 100644 --- a/boards/risc-v/esp32p4/esp32p4-tab5/scripts/Make.defs +++ b/boards/risc-v/esp32p4/esp32p4-tab5/scripts/Make.defs @@ -34,18 +34,33 @@ CHIP_SERIES = $(patsubst "%",%,$(CONFIG_ESPRESSIF_CHIP_SERIES)) ARCHSCRIPT += $(BOARD_COMMON_DIR)/scripts/$(CHIP_SERIES)_aliases.ld -ARCHSCRIPT += $(call FINDSCRIPT,$(CHIP_SERIES)_flat_memory.ld) - ifneq ($(CONFIG_ESP32P4_SELECTS_REV_LESS_V3),y) BOARD_REV = .rev3 endif +ifeq ($(CONFIG_BUILD_PROTECTED),y) + +# Protected build: the kernel image is linked against its own half of the +# memory map. kernel-space.ld exports the region boundaries and then pulls +# in the flat sections script, so the two stay in step -- the sections script +# must NOT also be added here, or .flash.text is defined twice. + +ARCHSCRIPT += $(call FINDSCRIPT,$(CHIP_SERIES)_protected_memory.ld) +ARCHSCRIPT += $(call FINDSCRIPT,kernel-space.ld) + +else + +ARCHSCRIPT += $(call FINDSCRIPT,$(CHIP_SERIES)_flat_memory.ld) + ifeq ($(CONFIG_ESPRESSIF_BOOTLOADER_MCUBOOT),y) ARCHSCRIPT += $(call FINDSCRIPT,$(CHIP_SERIES)_sections$(BOARD_REV).ld) else ifeq ($(CONFIG_ESPRESSIF_SIMPLE_BOOT),y) ARCHSCRIPT += $(call FINDSCRIPT,$(CHIP_SERIES)_sections$(BOARD_REV).ld) endif +endif + +ARCHPICFLAGS = -fpic CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -Werror=return-type CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_bringup.c b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_bringup.c index 850ea1e3b62bf..d5c9997a436c8 100644 --- a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_bringup.c +++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_bringup.c @@ -34,6 +34,12 @@ #include "espressif/esp_start.h" +#ifdef CONFIG_ESPRESSIF_P4DBG +# include +# include +# include "riscv_internal.h" +#endif + #ifdef CONFIG_ESPRESSIF_SPIFLASH # include "esp_board_spiflash.h" #endif @@ -77,10 +83,47 @@ * ****************************************************************************/ +#ifdef CONFIG_ESPRESSIF_P4DBG +/* Declared locally: the HAL header that provides this is not on the include + * path for board sources. esp_start.c declares ets_printf() the same way. + */ + +extern int esp_rom_printf(const char *fmt, ...) printf_like(1, 2); + +/**************************************************************************** + * Name: protected_fault_handler + * + * Description: + * Bring-up scaffolding. Reports a CPU exception using the ROM printf + * rather than syslog(), which needs a working scheduler and console. + * + ****************************************************************************/ + +static int protected_fault_handler(int irq, void *context, void *arg) +{ + uintreg_t *regs = (uintreg_t *)context; + + esp_rom_printf("FAULT: irq=%d epc=0x%x sp=0x%x ra=0x%x mstatus=0x%x\n", + irq, (unsigned int)regs[REG_EPC], + (unsigned int)regs[REG_SP], (unsigned int)regs[REG_RA], + (unsigned int)regs[REG_INT_CTX]); + + for (; ; ) + { + } + + return OK; +} +#endif + int esp_bringup(void) { int ret = OK; +#ifdef CONFIG_ESPRESSIF_P4DBG + esp_rom_printf("bringup: enter\n"); +#endif + #ifdef CONFIG_FS_PROCFS /* Mount the procfs file system */ @@ -253,5 +296,22 @@ int esp_bringup(void) * capabilities. */ +#ifdef CONFIG_ESPRESSIF_P4DBG + esp_rom_printf("bringup: done ret=%d\n", ret); + syslog(LOG_ERR, "bringup: syslog reaches the console\n"); + + /* Take over the fault vectors for the remainder of bring-up, so that a + * fault entering user mode announces itself. + */ + + irq_attach(RISCV_IRQ_IAFAULT, protected_fault_handler, NULL); + irq_attach(RISCV_IRQ_LAFAULT, protected_fault_handler, NULL); + irq_attach(RISCV_IRQ_SAFAULT, protected_fault_handler, NULL); + irq_attach(RISCV_IRQ_IINSTRUCTION, protected_fault_handler, NULL); + irq_attach(RISCV_IRQ_IAMISALIGNED, protected_fault_handler, NULL); + irq_attach(RISCV_IRQ_LAMISALIGNED, protected_fault_handler, NULL); + irq_attach(RISCV_IRQ_SAMISALIGNED, protected_fault_handler, NULL); +#endif + return ret; } diff --git a/tools/espressif/Config.mk b/tools/espressif/Config.mk index 1c705c294a5f5..9fd2a243ea92b 100644 --- a/tools/espressif/Config.mk +++ b/tools/espressif/Config.mk @@ -144,6 +144,16 @@ endif ESPTOOL_BINS += $(FLASH_APP) $(ENC_APP) +# A protected build produces a second image. nuttx_user.bin is a raw binary +# whose first bytes are the metadata block that esp_userspace() reads to learn +# where the user image expects its flash-mapped regions; it is not an +# Espressif application image and is written at its own offset rather than +# being merged into nuttx.bin. + +ifeq ($(CONFIG_BUILD_PROTECTED),y) + ESPTOOL_BINS += $(CONFIG_ESPRESSIF_USER_IMAGE_OFFSET) nuttx_user.bin +endif + # Commands for colored and formatted output RED = \033[1;31m From 1459084cb130b64895ba57457554f37d8c43d2ca Mon Sep 17 00:00:00 2001 From: Mark Stevens Date: Sat, 12 Sep 2026 14:01:46 +0100 Subject: [PATCH 2/5] risc-v/esp32p4: Add PSRAM to the user heap in a protected build. Enable external PSRAM for esp32p4-tab5:knsh and place all 32 MB of it in the user heap. The user heap grows from 259,740 to 33,814,172 bytes; the kernel heap stays in internal SRAM and is unchanged. The flat build has had PSRAM for some time, but three separate things kept it out of a protected build, and all three had to be addressed: * riscv_addregion() guarded its PSRAM block with !defined(CONFIG_MM_KERNEL_HEAP), which is never true in a protected build. The guard is widened to cover BUILD_PROTECTED as well. kumm_addregion() resolves to mm_addregion(USR_HEAP, ...), and USR_HEAP is the single heap in a flat build and (*USERSPACE->us_data->us_heap) in the kernel phase of a protected one, so the same call reaches user-accessible memory in both. A flat build that keeps a separate kernel heap is deliberately left as it was. * configure_mpu() described UIROM, UDROM, ROM and UDRAM only, so PSRAM matched no PMP entry and user access to it faulted. A read/write TOR pair now covers the window, bounded by the HAL's runtime esp_psram_extram_vaddr_start() and _end(). * knsh/defconfig did not enable CONFIG_ESPRESSIF_SPIRAM, and its CONFIG_MM_REGIONS of 2 left no room for a second user region. Ordering of the PMP entries matters more than it first appears, and the region table is now in ascending address order rather than having the new pair appended. PMP resolves an access to the lowest-numbered entry that matches it, so a low-numbered gap silently shadows any grant above it: appending PSRAM after UDRAM leaves the gap at entry 4, which spans UDROM_END (0x40380000) up to SOC_IROM_MASK_LOW (0x4fc00000), swallowing 0x48000000 and denying user access however the higher entries are programmed. It presents as a store access fault on the first user-mode touch of PSRAM, with the heap none the wiser. The comment in configure_mpu() records this so the ordering is not "tidied" later. Enabling SPIRAM selects ESPRESSIF_SPIRAM_USER_HEAP, which in turn selects ESPRESSIF_DONT_USE_ROM_LIBC and drops esp32p4.rom.newlib.ld from the kernel link. The user image already omits that script deliberately, so this aligns the two links rather than diverging them. No impact on the flat build: it comes out byte for byte identical in size with identical free(1) output, because the widened guard evaluates exactly as before when CONFIG_MM_KERNEL_HEAP is unset. Tested on an M5Stack Tab5 (ESP32-P4 rev v1.0), on hardware: esp32p4-tab5:knsh 233,240 B kernel + 146,098 B user Kmem 217,908 B Umem 33,814,172 B, maxfree 33,554,416 B, 3 regions ostest status 0, 154 sections, 99.3 s esp32p4-tab5:nsh text 183,906 B, Umem 34,039,356 B unchanged by this commit ostest alone does not prove the PMP grant, so the window was also exercised directly from user mode with ramtest at its base, middle and top (0x48000000, 0x49000000, 0x49ff0000): marching ones, marching zeroes, three pattern tests and address-in-address, all passing. The same three runs pass identically on the flat build as a control. TESTING_RAMTEST is enabled in the knsh defconfig so the grant can be checked on the board; it is not in the flat nsh defconfig and was enabled there only for that control run. Note for anyone repeating this: ramtest writes over whatever occupies the addresses it is given, so running it against the base of a heap-backed region destroys the allocator's region header. It is sound as an access-permission probe, but the board wants a reset afterwards. Assisted-by: Claude:claude-opus-5 Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Mark Stevens --- .../src/common/espressif/esp_allocateheap.c | 19 +++++- .../src/common/espressif/esp_userspace.c | 68 ++++++++++++++++--- .../esp32p4-tab5/configs/knsh/defconfig | 4 +- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/arch/risc-v/src/common/espressif/esp_allocateheap.c b/arch/risc-v/src/common/espressif/esp_allocateheap.c index f9b268916e262..5adbd1c2293d0 100644 --- a/arch/risc-v/src/common/espressif/esp_allocateheap.c +++ b/arch/risc-v/src/common/espressif/esp_allocateheap.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -221,8 +222,21 @@ void riscv_addregion(void) } #endif -#if !defined(CONFIG_MM_KERNEL_HEAP) -# if defined(CONFIG_ESPRESSIF_SPIRAM_USER_HEAP) + /* External PSRAM is user memory. kumm_addregion() resolves to + * mm_addregion(USR_HEAP, ...), and USR_HEAP is the single heap in a flat + * build and (*USERSPACE->us_data->us_heap) in the kernel phase of a + * protected one, so the same call reaches user-accessible memory in both. + * + * configure_mpu() has already granted user mode read/write over this + * span. The two must agree: a region added here without the grant is in + * the heap but faults on first touch from user code. + * + * A flat build that keeps a separate kernel heap is deliberately left as + * it was; changing where PSRAM lands there is not part of this change. + */ + +#if defined(CONFIG_ESPRESSIF_SPIRAM_USER_HEAP) && \ + (defined(CONFIG_BUILD_PROTECTED) || !defined(CONFIG_MM_KERNEL_HEAP)) if (esp_psram_is_initialized()) { uintptr_t start = esp_psram_extram_vaddr_start(); @@ -233,7 +247,6 @@ void riscv_addregion(void) kumm_addregion((void *)start, end - start); } } -# endif #endif } #endif diff --git a/arch/risc-v/src/common/espressif/esp_userspace.c b/arch/risc-v/src/common/espressif/esp_userspace.c index 6ce0bd7837d2a..563ae4d829d83 100644 --- a/arch/risc-v/src/common/espressif/esp_userspace.c +++ b/arch/risc-v/src/common/espressif/esp_userspace.c @@ -48,6 +48,12 @@ #include "spi_flash_mmap.h" #include "bootloader_flash_priv.h" +#if defined(CONFIG_ESPRESSIF_SPIRAM) && \ + defined(CONFIG_ESPRESSIF_SPIRAM_USER_HEAP) +# include "esp_psram.h" +# include "esp_private/esp_psram_extram.h" +#endif + #ifdef CONFIG_BUILD_PROTECTED /**************************************************************************** @@ -283,13 +289,22 @@ static void configure_mpu(void) riscv_config_pmp_region(15, PMPCFG_A_OFF, 0, 0); /* TOR entries take their lower bound from the preceding entry's address, - * so the regions must be programmed in ascending address order. Each pair - * is an unmatched gap followed by the region proper: + * so each pair is an unmatched gap followed by the region proper. * - * UIROM 0x40200000 - 0x40300000 user code, execute in place - * UDROM 0x40300080 - 0x40380000 user rodata (0x80 metadata gap below) - * ROM SOC_IROM_MASK_* ROM routines the user image calls - * UDRAM 0x4ff40000 - 0x4ff80000 user data, bss and heap + * 0/1 UIROM 0x40200000 - 0x40300000 user code, execute in place + * 2/3 UDROM 0x40300080 - 0x40380000 user rodata (0x80 metadata gap) + * 4/5 PSRAM runtime bounds external RAM, in the user heap + * 6/7 ROM SOC_IROM_MASK_* ROM routines the user image calls + * 8/9 UDRAM 0x4ff40000 - 0x4ff80000 user data, bss and heap + * + * The whole table must be in ascending address order, not merely each pair + * internally. PMP resolves an access to the LOWEST-numbered entry that + * matches it, so a low-numbered gap silently shadows any grant above it. + * Appending PSRAM after UDRAM does not work for exactly that reason: the + * gap at entry 4 spans UDROM_END up to SOC_IROM_MASK_LOW (0x40380000 to + * 0x4fc00000) and swallows 0x48000000, denying user access however the + * higher entries are programmed. It presents as a load/store access fault + * on the first user-mode touch of PSRAM, with the heap none the wiser. */ /* User code, executed in place from flash */ @@ -302,6 +317,39 @@ static void configure_mpu(void) riscv_config_pmp_region(2, PMPCFG_A_TOR, UDROM_START, 0); riscv_config_pmp_region(3, PMPCFG_A_TOR | r, UDROM_END, 0); +#if defined(CONFIG_ESPRESSIF_SPIRAM) && \ + defined(CONFIG_ESPRESSIF_SPIRAM_USER_HEAP) + /* External PSRAM. riscv_addregion() adds this same span to the user heap; + * without the grant here it would be in the heap but would fault on the + * first touch from user code. Read/write only: it is a data heap, and + * user code executes in place from flash. + * + * If PSRAM did not initialise, entries 4 and 5 are left off by the reset + * above and entry 6 simply takes its base from a zero pmpaddr5, which + * widens the following gap harmlessly. + */ + + if (esp_psram_is_initialized()) + { + uintptr_t pstart = esp_psram_extram_vaddr_start(); + uintptr_t pend = esp_psram_extram_vaddr_end(); + + /* Both bounds come from the HAL's mapping of a 64 KB-aligned window, + * so they already satisfy the 128-byte PMP granularity. Assert it + * rather than assume it: a misaligned bound silently rounds and would + * grant a different region than the heap is handed. + */ + + DEBUGASSERT((pstart & 0x7f) == 0 && (pend & 0x7f) == 0); + + if (pend > pstart) + { + riscv_config_pmp_region(4, PMPCFG_A_TOR, pstart, 0); + riscv_config_pmp_region(5, PMPCFG_A_TOR | rw, pend, 0); + } + } +#endif + /* Internal ROM. CONFIG_LIBC_ARCH_* is selected for this chip, so libc * omits its generic memcpy(), strcmp() and friends and the user image is * linked against the ROM implementations instead (see the ROM linker @@ -309,13 +357,13 @@ static void configure_mpu(void) * call from user mode takes an instruction access fault. */ - riscv_config_pmp_region(4, PMPCFG_A_TOR, SOC_IROM_MASK_LOW, 0); - riscv_config_pmp_region(5, PMPCFG_A_TOR | rx, SOC_IROM_MASK_HIGH, 0); + riscv_config_pmp_region(6, PMPCFG_A_TOR, SOC_IROM_MASK_LOW, 0); + riscv_config_pmp_region(7, PMPCFG_A_TOR | rx, SOC_IROM_MASK_HIGH, 0); /* User data, bss and heap in internal SRAM */ - riscv_config_pmp_region(6, PMPCFG_A_TOR, UDRAM_START, 0); - riscv_config_pmp_region(7, PMPCFG_A_TOR | rw, UDRAM_END, 0); + riscv_config_pmp_region(8, PMPCFG_A_TOR, UDRAM_START, 0); + riscv_config_pmp_region(9, PMPCFG_A_TOR | rw, UDRAM_END, 0); } /**************************************************************************** diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/configs/knsh/defconfig b/boards/risc-v/esp32p4/esp32p4-tab5/configs/knsh/defconfig index 331461b6155df..9024fc3183647 100644 --- a/boards/risc-v/esp32p4/esp32p4-tab5/configs/knsh/defconfig +++ b/boards/risc-v/esp32p4/esp32p4-tab5/configs/knsh/defconfig @@ -40,6 +40,7 @@ CONFIG_ESP32P4_REV_MIN_100=y CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y CONFIG_ESPRESSIF_FLASH_16M=y CONFIG_ESPRESSIF_KERNEL_OWNS_PMP=y +CONFIG_ESPRESSIF_SPIRAM=y CONFIG_EXPERIMENTAL=y CONFIG_FS_PROCFS=y CONFIG_IDLETHREAD_STACKSIZE=2048 @@ -47,7 +48,7 @@ CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INTELHEX_BINARY=y CONFIG_LIBC_PERROR_STDOUT=y CONFIG_LIBC_STRERROR=y -CONFIG_MM_REGIONS=2 +CONFIG_MM_REGIONS=3 CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 CONFIG_NSH_BUILTIN_APPS=y CONFIG_NSH_FILEIOSIZE=512 @@ -67,4 +68,5 @@ CONFIG_SYSTEM_DUMPSTACK=y CONFIG_SYSTEM_NSH=y CONFIG_TESTING_GETPRIME=y CONFIG_TESTING_OSTEST=y +CONFIG_TESTING_RAMTEST=y CONFIG_UART0_SERIAL_CONSOLE=y From bba70e5ce7890763213b03d8ddacae1cb8fb8cae Mon Sep 17 00:00:00 2001 From: Mark Stevens Date: Sun, 13 Sep 2026 10:38:39 +0100 Subject: [PATCH 3/5] arch/risc-v: Fix a cmake-format style issue this PR introduced. The list(REMOVE_ITEM ...) added to hal_esp32p4.cmake for CONFIG_ESPRESSIF_KERNEL_OWNS_PMP did not match the layout cmake-format produces, which failed the Check job in CI. Put REMOVE_ITEM and HAL_SRCS on separate lines. Assisted-by: Claude:claude-opus-5 Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Mark Stevens --- arch/risc-v/src/esp32p4/hal_esp32p4.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/src/esp32p4/hal_esp32p4.cmake b/arch/risc-v/src/esp32p4/hal_esp32p4.cmake index 0311be237137b..5a7d19db61273 100644 --- a/arch/risc-v/src/esp32p4/hal_esp32p4.cmake +++ b/arch/risc-v/src/esp32p4/hal_esp32p4.cmake @@ -461,7 +461,8 @@ list( if(CONFIG_ESPRESSIF_KERNEL_OWNS_PMP) list( - REMOVE_ITEM HAL_SRCS + REMOVE_ITEM + HAL_SRCS ${ESP_HAL_3RDPARTY_REPO}/components/esp_hw_support/port/${CHIP_SERIES}/cpu_region_protect.c ) endif() From d13c527fbcd1d8443181a5bd252ac40a185596e9 Mon Sep 17 00:00:00 2001 From: Mark Stevens Date: Sun, 13 Sep 2026 10:39:38 +0100 Subject: [PATCH 4/5] arch/risc-v: Use generic name (same name as PR #20126) for enabling CLIC. Change configuration variable name. Signed-off-by: Mark Stevens --- arch/risc-v/Kconfig | 10 ++++++++++ arch/risc-v/include/irq.h | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index 672a7907b4d6b..abfe5f0f36969 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -222,6 +222,7 @@ config ARCH_CHIP_ESP32P4 select ARCH_RV_ISA_M select ARCH_RV_ISA_A select ARCH_RV_ISA_C + select ARCH_RV_HAVE_CLIC select ARCH_VECNOTIRQ select ARCH_HAVE_BOOTLOADER if !ESPRESSIF_SIMPLE_BOOT select ARCH_HAVE_I2CRESET @@ -795,6 +796,15 @@ config ARCH_RV_HAVE_APLIC Controller (APLIC) to provide flexible interrupt control. This device is not backward compatible with PLIC. +config ARCH_RV_HAVE_CLIC + bool + default n + ---help--- + RISC-V defines Core-Level Interrupt Controller (CLIC) to provide + flexible interrupt control. When enabled, CLIC uses interrupt + threshold (MINTTHRESH/SINTTHRESH) CSRs for interrupt control + instead of the standard IE bit in STATUS register. + config ARCH_RV_EXT_AIA bool "Enable RISC-V SxAIA support" default n diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h index 24e466103c65a..55c399e5f5daa 100644 --- a/arch/risc-v/include/irq.h +++ b/arch/risc-v/include/irq.h @@ -205,9 +205,13 @@ * mret consults -- so it must be saved and restored with the frame, not just * read for dispatch. Uses the ARCH_RISCV_INTXCPT_EXTREGS extension slot, * so REG_INT_CTX and everything below it keep their existing offsets. + * + * Only a protected build needs this: a flat build never returns to a lower + * privilege level, so nothing consumes the saved mpp. Keeping the frame at + * its original size there leaves every flat RISC-V target untouched. */ -#if defined(CONFIG_ARCH_CHIP_ESP32P4) && !defined(CONFIG_BUILD_FLAT) +#if defined(CONFIG_ARCH_RV_HAVE_CLIC) && !defined(CONFIG_BUILD_FLAT) # define REG_MCAUSE_NDX 33 #endif From a3cd6f5cf11bd71164daa4122b7ea1b7365315bd Mon Sep 17 00:00:00 2001 From: Mark Stevens Date: Sun, 13 Sep 2026 11:08:15 +0100 Subject: [PATCH 5/5] arch/risc-v: Remove the trap frame trace from this change. Drops CONFIG_RISCV_FRAME_TRACE and its five hook sites. The feature will be submitted as its own pull request, as requested in review. Removed, 295 lines: arch/risc-v/Kconfig config RISCV_FRAME_TRACE arch/risc-v/src/common/riscv_swint.c ring buffer and dump arch/risc-v/src/common/riscv_internal.h prototypes and tags arch/risc-v/src/common/riscv_exception_common.S syscall-return probe and the mret capture arch/risc-v/src/common/riscv_schedulesigaction.c signal-path hook arch/risc-v/src/common/riscv_doirq.c dispatch hook Nothing else in this pull request depends on it. The option was default n and compiled out entirely when off, so no shipping configuration changes: esp32p4-tab5:knsh builds byte for byte identical to the same tree with the trace still present. With the trace gone, the only remaining lines this pull request adds to generic RISC-V code are the REG_MCAUSE frame slot in irq.h and the code guarded by it, all gated on ARCH_RV_HAVE_CLIC && !BUILD_FLAT. Tested on an M5Stack Tab5 (ESP32-P4 rev v1.0), on hardware: esp32p4-tab5:knsh 233,240 B kernel + 146,098 B user Kmem 217,908 B, Umem 33,814,172 B ostest status 0, 154 sections, 99.4 s esp32p4-tab5:knsh + P4DBG 156,298 B text bring-up markers emitted ostest status 0, 154 sections, 99.4 s esp32p4-tab5:nsh (flat) 183,906 B text, builds clean All builds clean with zero compiler warnings, and the four modified C and header files pass nxstyle. Assisted-by: Claude:claude-opus-5 Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Mark Stevens --- arch/risc-v/Kconfig | 19 -- arch/risc-v/src/common/riscv_doirq.c | 8 - .../src/common/riscv_exception_common.S | 31 --- arch/risc-v/src/common/riscv_internal.h | 34 --- .../src/common/riscv_schedulesigaction.c | 9 - arch/risc-v/src/common/riscv_swint.c | 194 ------------------ 6 files changed, 295 deletions(-) diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index abfe5f0f36969..aad6b6ec4f808 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -733,25 +733,6 @@ config RISCV_MISALIGNED_HANDLER depends on ARCH_HAVE_MISALIGN_EXCEPTION default y -config RISCV_FRAME_TRACE - bool "Trap frame trace (debug)" - default n - depends on !BUILD_FLAT - ---help--- - Record a ring of trap frames at the points where the kernel chooses - which frame to resume: interrupt dispatch, context-switch - syscalls, syscall return and the signal paths. Each entry holds the - frame pointer, EPC, the saved status word and, where the - architecture carries it, mcause. - - Intended too help debugging a protected build, where a frame restored - may be with the wrong privilege or interrupt level - Nothing is printed inline; the ring is read out - of RAM with a debugger, or dumped from the panic path. - - This adds a call on every trap dispatch and a static ring buffer - and is not intended fro production builds. - config RISCV_PERCPU_SCRATCH bool "Enable Scratch-based Per-CPU storage" default y if LIB_SYSCALL diff --git a/arch/risc-v/src/common/riscv_doirq.c b/arch/risc-v/src/common/riscv_doirq.c index ac9e464f15bb3..ee74b12f7ecbb 100644 --- a/arch/risc-v/src/common/riscv_doirq.c +++ b/arch/risc-v/src/common/riscv_doirq.c @@ -148,14 +148,6 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs) regs = tcb->xcp.regs; -#ifdef CONFIG_RISCV_FRAME_TRACE - /* This is the single point where every trap decides which frame to - * restore. - */ - - riscv_trace_frame(RISCV_TRACE_TAG_IRQ(irq), tcb, regs); -#endif - /* (*running_task)->xcp.regs is about to become invalid * and will be marked as NULL to avoid misusage. */ diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/riscv_exception_common.S index 4d3615131c2aa..e318b4489c38e 100644 --- a/arch/risc-v/src/common/riscv_exception_common.S +++ b/arch/risc-v/src/common/riscv_exception_common.S @@ -148,7 +148,6 @@ exception_common: csrr s1, CSR_EPC /* s1=exception PC */ csrr s2, CSR_CAUSE /* s2=cause */ - #ifdef CONFIG_ARCH_KERNEL_STACK csrr s3, CSR_SCRATCH REGLOAD s3, RISCV_PERCPU_USP(s3) @@ -212,16 +211,6 @@ return_from_syscall: REGSTORE a0, REG_A0(sp) /* Syscall return value to user context */ -#ifdef CONFIG_RISCV_FRAME_TRACE - /* Frame trace. Safe here: the return value is already stored to the frame - * and everything is restored from sp immediately below, so clobbering - * caller-saved registers costs nothing. - */ - - mv a0, sp - call x1, riscv_trace_syscall_ret -#endif - mv a0, sp /* Return to same context */ tail return_from_exception @@ -346,26 +335,6 @@ return_from_exception: REGLOAD s0, REG_INT_CTX(sp) /* restore status */ csrw CSR_STATUS, s0 -#ifdef CONFIG_RISCV_FRAME_TRACE - /* Capture what this mret will actually - * consume, after every CSR write and before the register reloads. t0/t1 are - * reloaded from the frame further down this epilogue, so clobbering them here - * is safe; no argument register is touched. Read the globals with an - * observe-only halt. - */ - - la t0, g_mret_epc - csrr t1, CSR_EPC - REGSTORE t1, 0(t0) - la t0, g_mret_status - csrr t1, CSR_STATUS - REGSTORE t1, 0(t0) - la t0, g_mret_cause - csrr t1, mcause - REGSTORE t1, 0(t0) -#endif - - #ifdef CONFIG_LIB_SYSCALL /* Store tcb to scratch register */ diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h index e80a43ebb571b..da0814aea628b 100644 --- a/arch/risc-v/src/common/riscv_internal.h +++ b/arch/risc-v/src/common/riscv_internal.h @@ -102,32 +102,6 @@ #define PMP_ACCESS_DENIED (-1) /* Access set and denied */ #define PMP_ACCESS_FULL (1) /* Access set and allowed */ -#ifdef CONFIG_RISCV_FRAME_TRACE - -/* Trap frame trace tags, the "tag" argument of riscv_trace_frame(). Each - * one names the place in the trap path that recorded the frame; they are - * printed verbatim by riscv_trace_dump(). The tag occupies the low 8 bits - * of the argument, bits 8 and up carry the IRQ number (see - * RISCV_TRACE_TAG_IRQ). - */ - -#define RISCV_TRACE_TAG_DOIRQ 0 /* riscv_doirq() frame selection */ -#define RISCV_TRACE_TAG_RESTORE_CTX 1 /* SYS_restore_context */ -#define RISCV_TRACE_TAG_SWITCH_CTX 2 /* SYS_switch_context */ -#define RISCV_TRACE_TAG_SYSCALL_RET 3 /* return_from_syscall */ -#define RISCV_TRACE_TAG_TRAP_ENTRY 4 /* exception_common, every trap */ -#define RISCV_TRACE_TAG_SIG_SCHED 5 /* frame built for signal delivery */ -#define RISCV_TRACE_TAG_SIG_HANDLER 6 /* SYS_signal_handler */ -#define RISCV_TRACE_TAG_SIG_RETURN 7 /* SYS_signal_handler_return */ -#define RISCV_TRACE_TAG_MRET 8 /* what the last mret consumed */ -#define RISCV_TRACE_TAG_PANIC 9 /* the panicking frame */ - -/* Tag for a frame recorded on behalf of a given IRQ */ - -#define RISCV_TRACE_TAG_IRQ(irq) (RISCV_TRACE_TAG_DOIRQ | ((irq) << 8)) - -#endif /* CONFIG_RISCV_FRAME_TRACE */ - #ifndef __ASSEMBLY__ /* Use ASM as rv64ilp32 compiler generated address is limited */ @@ -229,14 +203,6 @@ void riscv_ack_irq(int irq); void riscv_sigdeliver(void); int riscv_swint(int irq, void *context, void *arg); -/* Trap frame trace, CONFIG_RISCV_FRAME_TRACE. See the option's help text. */ - -#ifdef CONFIG_RISCV_FRAME_TRACE -void riscv_trace_frame(int tag, struct tcb_s *tcb, uintreg_t *regs); -void riscv_trace_dump(uintreg_t *regs); -void riscv_trace_syscall_ret(uintreg_t *regs); -void riscv_trace_trap_entry(uintreg_t *regs, uintreg_t mcause); -#endif uintptr_t riscv_get_newintctx(void); void riscv_set_idleintctx(void); void riscv_exception_attach(void); diff --git a/arch/risc-v/src/common/riscv_schedulesigaction.c b/arch/risc-v/src/common/riscv_schedulesigaction.c index 65fbc6aab1b0f..af492350aa670 100644 --- a/arch/risc-v/src/common/riscv_schedulesigaction.c +++ b/arch/risc-v/src/common/riscv_schedulesigaction.c @@ -121,13 +121,4 @@ void up_schedule_sigaction(struct tcb_s *tcb) #endif tcb->xcp.regs[REG_INT_CTX] = int_ctx; - -#ifdef CONFIG_RISCV_FRAME_TRACE - /* Record the frame this built. It deliberately sets MPP=M so the - * trampoline runs privileged, and leaves REG_MCAUSE as the copied user - * value. - */ - - riscv_trace_frame(RISCV_TRACE_TAG_SIG_SCHED, tcb, tcb->xcp.regs); -#endif } diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c index 75cafde229d61..b5dc855484f42 100644 --- a/arch/risc-v/src/common/riscv_swint.c +++ b/arch/risc-v/src/common/riscv_swint.c @@ -28,9 +28,6 @@ #include #include -#ifdef CONFIG_RISCV_FRAME_TRACE -# include -#endif #include #include #include @@ -140,170 +137,6 @@ uintptr_t dispatch_syscall(unsigned int nbr, uintptr_t parm1, } #endif -#ifdef CONFIG_RISCV_FRAME_TRACE - -/**************************************************************************** - * Trap frame trace, CONFIG_RISCV_FRAME_TRACE. - * - * The question: when a user task blocks inside a syscall and is later - * resumed, which frame does the kernel restore on the way back out, and does - * its REG_INT_CTX carry MPP=M? riscv_doirq() ends with - * "regs = tcb->xcp.regs", so that is the single point where every trap - * decides what to restore -- RISCV_TRACE_TAG_DOIRQ records it. The - * RISCV_TRACE_TAG_RESTORE_CTX and RISCV_TRACE_TAG_SWITCH_CTX tags record the - * two context-switch cases below. - * - * Nothing is printed inline: on the polled UART console each character costs - * ~87 us, and printing from inside the switch path would perturb the timing - * under test. The ring buffer is dumped from the "default" case instead -- - * i.e. exactly when the flip has produced its panic. - ****************************************************************************/ - -#define TRACE_ENTRIES 64 -#define TRACE_USER_LO 0x40200000 /* user image text window */ -#define TRACE_USER_HI 0x40300000 - -struct riscv_trace_s -{ - uintreg_t *regs; - uintreg_t epc; - uintreg_t int_ctx; - uintreg_t mcause; - int16_t irq; - uint8_t tag; /* RISCV_TRACE_TAG_* */ - pid_t pid; -}; - -static struct riscv_trace_s g_trace[TRACE_ENTRIES]; -static unsigned int g_trace_ndx; - -/* Written by the asm probe in return_from_exception - * (riscv_exception_common.S) immediately after the mepc/mstatus restores: - * what the mret will actually consume, as opposed to what the frame holds. - */ - -uintreg_t g_mret_epc; -uintreg_t g_mret_status; -uintreg_t g_mret_cause; - -void riscv_trace_frame(int tag, struct tcb_s *tcb, uintreg_t *regs) -{ - struct riscv_trace_s *e = &g_trace[g_trace_ndx % TRACE_ENTRIES]; - - e->tag = (uint8_t)(tag & 0xff); - e->irq = (int16_t)(tag >> 8); - e->pid = tcb != NULL ? tcb->pid : -1; - e->regs = regs; - - if (regs != NULL) - { - e->epc = regs[REG_EPC]; - e->int_ctx = regs[REG_INT_CTX]; -#ifdef REG_MCAUSE - /* The frame's mcause, so mpil (23:16) can be tracked: mil pinned at 63 - * is what deadlocks the interrupt system. - */ - - e->mcause = regs[REG_MCAUSE]; -#endif - } - else - { - e->epc = 0; - e->int_ctx = 0; - e->mcause = 0; - } - - g_trace_ndx++; -} - -/* Called from return_from_syscall (riscv_exception_common.S). User - * syscall returns bypass riscv_doirq() entirely -- they restore the frame - * at sp -- so this is the only place they can be observed. - */ - -void riscv_trace_syscall_ret(uintreg_t *regs) -{ - riscv_trace_frame(RISCV_TRACE_TAG_SYSCALL_RET, this_task(), regs); -} - -/* Called from exception_common (riscv_exception_common.S) on EVERY trap - * entry, once the frame is fully formed. This is the mirror of the - * exit records: it shows the privilege the CPU was in when the trap was - * taken, straight from the hardware, plus the raw mcause. - */ - -void riscv_trace_trap_entry(uintreg_t *regs, uintreg_t mcause) -{ - struct riscv_trace_s *e = &g_trace[g_trace_ndx % TRACE_ENTRIES]; - - riscv_trace_frame(RISCV_TRACE_TAG_TRAP_ENTRY, this_task(), regs); - - /* riscv_trace_frame() may have skipped the entry; only stamp mcause if it - * actually recorded one. - */ - - if (e->tag == RISCV_TRACE_TAG_TRAP_ENTRY) - { - e->mcause = mcause; - } -} - -void riscv_trace_dump(uintreg_t *regs) -{ - unsigned int total; - - /* Record the panicking frame itself, so that its REG_INT_CTX can be - * read out of RAM with an observe-only halt. The _alert() output below is - * unreliable on this board at panic time; the ring buffer is not. - */ - - /* Stamp what the last mret consumed, from the asm probe, so that it - * comes out of the same ring-buffer read. - */ - - { - struct riscv_trace_s *m = &g_trace[g_trace_ndx % TRACE_ENTRIES]; - - m->tag = RISCV_TRACE_TAG_MRET; - m->pid = -1; - m->irq = 0; - m->regs = NULL; - m->epc = g_mret_epc; - m->int_ctx = g_mret_status; - m->mcause = g_mret_cause; - g_trace_ndx++; - } - - riscv_trace_frame(RISCV_TRACE_TAG_PANIC, this_task(), regs); - - total = g_trace_ndx; - unsigned int n = total < TRACE_ENTRIES ? total : TRACE_ENTRIES; - unsigned int i; - - _alert("TRACE: panic cmd=%" PRIxREG " frame=%p epc=%" PRIxREG - " int_ctx=%" PRIxREG "\n", - regs[REG_A0], regs, regs[REG_EPC], regs[REG_INT_CTX]); - _alert("TRACE: %u events, last %u shown; tag %u=doirq %u=restore " - "%u=switch\n", - total, n, RISCV_TRACE_TAG_DOIRQ, RISCV_TRACE_TAG_RESTORE_CTX, - RISCV_TRACE_TAG_SWITCH_CTX); - - for (i = total - n; i < total; i++) - { - struct riscv_trace_s *e = &g_trace[i % TRACE_ENTRIES]; - bool user = e->epc >= TRACE_USER_LO && e->epc < TRACE_USER_HI; - bool mpp = (e->int_ctx & STATUS_PPP) != 0; - - _alert(" [%2u] tag=%u irq=%d pid=%d frame=%p epc=%" PRIxREG - " int_ctx=%" PRIxREG " %s%s\n", - i, e->tag, e->irq, e->pid, e->regs, e->epc, e->int_ctx, - user ? "[user]" : "[kern]", - (user && mpp) ? " <<< USER FRAME WITH MPP=M" : ""); - } -} -#endif /* CONFIG_RISCV_FRAME_TRACE */ - /**************************************************************************** * Name: riscv_swint * @@ -335,10 +168,6 @@ int riscv_swint(int irq, void *context, void *arg) { case SYS_restore_context: { -#ifdef CONFIG_RISCV_FRAME_TRACE - riscv_trace_frame(RISCV_TRACE_TAG_RESTORE_CTX, tcb, - tcb->xcp.regs); -#endif riscv_restorecontext(tcb); restore_critical_section(tcb, cpu); } @@ -346,10 +175,6 @@ int riscv_swint(int irq, void *context, void *arg) case SYS_switch_context: { -#ifdef CONFIG_RISCV_FRAME_TRACE - riscv_trace_frame(RISCV_TRACE_TAG_SWITCH_CTX, tcb, - tcb->xcp.regs); -#endif riscv_savecontext(g_running_tasks[cpu]); riscv_restorecontext(tcb); restore_critical_section(tcb, cpu); @@ -373,10 +198,6 @@ int riscv_swint(int irq, void *context, void *arg) #if !defined(CONFIG_BUILD_FLAT) && defined(CONFIG_ENABLE_ALL_SIGNALS) case SYS_signal_handler: { -#ifdef CONFIG_RISCV_FRAME_TRACE - riscv_trace_frame(RISCV_TRACE_TAG_SIG_HANDLER, this_task(), - regs); -#endif struct tcb_s *rtcb = this_task(); /* Remember the caller's return address */ @@ -454,10 +275,6 @@ int riscv_swint(int irq, void *context, void *arg) #if !defined(CONFIG_BUILD_FLAT) && defined(CONFIG_ENABLE_ALL_SIGNALS) case SYS_signal_handler_return: { -#ifdef CONFIG_RISCV_FRAME_TRACE - riscv_trace_frame(RISCV_TRACE_TAG_SIG_RETURN, this_task(), - regs); -#endif struct tcb_s *rtcb = this_task(); /* Set up to return to the kernel-mode signal dispatching logic. */ @@ -486,17 +303,6 @@ int riscv_swint(int irq, void *context, void *arg) #endif default: -#ifdef CONFIG_RISCV_FRAME_TRACE - /* Record the panicking frame but do NOT print the ring here. - * riscv_trace_dump() pushes 64 syslog lines through the polled - * console from inside a trap with interrupts disabled; under an - * ostest-scale failure that takes minutes and buries the assert - * output. Read the ring out of RAM with an observe-only halt - * instead. - */ - - riscv_trace_frame(RISCV_TRACE_TAG_PANIC, this_task(), regs); -#endif DEBUGPANIC(); break; }