xtensa/esp32s3: Let a protected build boot from simple boot.

BUILD_PROTECTED defaults ESP32S3_APP_FORMAT_LEGACY to y, so a protected build
has always needed the ESP-IDF second-stage bootloader.  Nothing about the
protected layout requires it:  the kernel and user images are described
entirely by ESP32S3_KERNEL_OFFSET, ESP32S3_KERNEL_IMAGE_SIZE and
ESP32S3_KERNEL_RAM_SIZE, and esp32s3_userspace() maps the user image itself.
Three obstacles stood in the way.

Those three symbols were gated on ESP32S3_APP_FORMAT_LEGACY, but
protected_memory.ld needs all of them for KIROM, KDROM, UIROM, UDROM, KDRAM
and UDRAM.  Without them the region lengths underflow to 2**64-1 and the
kernel/user RAM split lands nowhere, which the hardware reports as a DRAM0
PMS monitor violation once the first user process runs.  The offset becomes
0x0 for simple boot, where the image is flashed at the start of the device.

protected_memory.ld had no case for a 32 MB part, so FLASH_SIZE was
undefined there and ROM, UIROM and UDROM underflowed the same way.
flat_memory.ld has had the case all along.

kernel-space.ld defined none of the symbols simple boot needs
(_image_irom_*, _image_drom_*, _bss_*), and kept none of the early code
resident.  __start() runs bootloader_init() and map_rom_segments() before any
flash mapping exists, so everything they reach has to be in RAM -- including
map_rom_segments() itself, which unmaps the MMU it is running from, and
nuttx_enter_critical(), reached from rtc_clk_init() by way of regi2c.  These
mirror what esp32s3_sections.ld already does for the flat build.

Verified on an ESP32-S3-WROOM-2 (32 MB octal flash), esp32s3-devkit:knsh with
FLASH_MODE_OCT:  boots to NSH and runs ostest, where it reaches the same
timedmutex abort as every other target.  The legacy path is untouched.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
Marco Casaroli 2026-08-10 11:56:16 +02:00 committed by Xiang Xiao
parent 83e4b6065a
commit 46528ea5ee
3 changed files with 179 additions and 4 deletions

View file

@ -2901,15 +2901,15 @@ endif # !ESP32S3_CUSTOM_PARTITION_TABLE_OFFSET
config ESP32S3_KERNEL_OFFSET
hex
default 0x10000
depends on ESP32S3_APP_FORMAT_LEGACY
default 0x10000 if ESP32S3_APP_FORMAT_LEGACY
default 0x0
depends on ESP32S3_APP_FORMAT_LEGACY || BUILD_PROTECTED
if BUILD_PROTECTED
config ESP32S3_KERNEL_IMAGE_SIZE
hex "Kernel Image Size"
default 0x100000
depends on ESP32S3_APP_FORMAT_LEGACY
---help---
Max size of the kernel image. This parameter is used to 1) write to
the SPI flash, 2) calculate the offset for the user image and 3) set
@ -2921,7 +2921,6 @@ config ESP32S3_KERNEL_RAM_SIZE
hex "Kernel Allocated RAM"
default 0x30000
range 0x10000 0x54700
depends on ESP32S3_APP_FORMAT_LEGACY
---help---
Selects the amount of RAM available to the kernel from the total
available amount (337,75KiB). The rest of the memory will be

View file

@ -135,6 +135,104 @@ SECTIONS
*libkarch.a:cache_utils.*(.literal .literal.* .text .text.*)
*libkarch.a:memspi_host_driver.*(.literal .literal.* .text .text.*)
#ifdef CONFIG_ESPRESSIF_SIMPLE_BOOT
/* Simple boot runs bootloader_init() and map_rom_segments() before any
* flash mapping exists, so everything they reach has to be resident.
*/
*libkarch.a:*esp_loader.*(.literal .text .literal.* .text.*)
*libkarch.a:*brownout_hal.*(.text .text.* .literal .literal.*)
*libkarch.a:*cpu.*(.text .text.* .literal .literal.*)
*libkarch.a:*gpio_hal.*(.text .text.* .literal .literal.*)
*libkarch.a:*periph_ctrl.*(.text .text.* .literal .literal.*)
*libkarch.a:*clk.*(.text .text.* .literal .literal.*)
*libkarch.a:critical_section.*(.literal .literal.* .text .text.*)
*libkarch.a:os.*(.literal.nuttx_enter_critical .text.nuttx_enter_critical)
*libkarch.a:os.*(.literal.nuttx_exit_critical .text.nuttx_exit_critical)
*libkarch.a:*sleep_modes.*(.literal.esp_sleep_sub_mode_force_disable* .text.esp_sleep_sub_mode_force_disable*)
*libkarch.a:*efuse_hal.*(.literal.is_eco0 .text.is_eco0)
*libkarch.a:*efuse_utility.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_clk.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_clk_tree.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_clk_tree_common.*(.text .text.* .literal .literal.*)
*libkarch.a:*clk_tree_hal.*(.text .text.* .literal .literal.*)
*libkarch.a:*rtc_init.*(.text .text.* .literal .literal.*)
*libkarch.a:*rtc_clk.*(.text .text.* .literal .literal.*)
*libkarch.a:*rtc_clk_init.*(.text .text.* .literal .literal.*)
*libkarch.a:*rtc_sleep.*(.text .text.* .literal .literal.*)
*libkarch.a:*rtc_time.*(.text .text.* .literal .literal.*)
*libkarch.a:*regi2c_ctrl.*(.text .text.* .literal .literal.*)
*libkarch.a:*uart_hal_iram.*(.text .text.* .literal .literal.*)
*libkarch.a:*wdt_hal_iram.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_banner_wrap.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_init.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_common.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_common_loader.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_console.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_console_loader.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_esp32s3.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_flash.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_flash_config_esp32s3.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_clock_init.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_clock_loader.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_efuse.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_panic.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_mem.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_random.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_random*.*(.literal.bootloader_random_disable .text.bootloader_random_disable)
*libkarch.a:*bootloader_random*.*(.literal.bootloader_random_enable .text.bootloader_random_enable)
*libkarch.a:*bootloader_random_esp32s3.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_image_format.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_soc.*(.text .text.* .literal .literal.*)
*libkarch.a:*bootloader_sha.*(.text .text.* .literal .literal.*)
*libkarch.a:*flash_encrypt.*(.text .text.* .literal .literal.*)
*libkarch.a:*cache_hal.*(.text .text.* .literal .literal.*)
*libkarch.a:*uart_hal.*(.text .text.* .literal .literal.*)
*libkarch.a:*mpu_hal.*(.text .text.* .literal .literal.*)
*libkarch.a:*mmu_hal.*(.text .text.* .literal .literal.*)
*libkarch.a:*efuse_hal.*(.text .text.* .literal .literal.*)
*libkarch.a:*uart_periph.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_rom_uart.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_rom_sys.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_rom_spiflash.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_rom_cache_esp32s2_esp32s3.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_rom_wdt.*(.text .text.* .literal .literal.*)
*libkarch.a:*log.*(.text .text.* .literal .literal.*)
*libkarch.a:*log_lock.*(.literal .literal.* .text .text.*)
*libkarch.a:*log_print.*(.literal .literal.* .text .text.*)
*libkarch.a:*log_timestamp.*(.literal.esp_log_early_timestamp .text.esp_log_early_timestamp)
*libkarch.a:*log_timestamp.*(.literal.esp_log_timestamp .text.esp_log_timestamp)
*libkarch.a:*log_timestamp_common.*(.literal .literal.* .text .text.*)
*libkarch.a:*log_write.*(.literal.esp_log_write .text.esp_log_write)
*libkarch.a:*log_write.*(.literal.esp_log_writev .text.esp_log_writev)
*libkarch.a:*cpu_region_protect.*(.text .text.* .literal .literal.*)
*libkarch.a:*esp_rom_cache_esp32s2_esp32s3.*(.literal .text .literal.* .text.*)
*libkarch.a:*flash_qio_mode.*(.text .text.* .literal .literal.*)
*libkarch.a:*spi_flash_wrap.*(.text .text.* .literal .literal.*)
#ifdef CONFIG_ESP32S3_FLASH_MODE_OCT
/* Octal (OPI) bring-up only. A board with quad flash never runs these,
* and pinning them would cost it IRAM for nothing.
*/
*libkarch.a:*mspi_timing_tuning.*(.text .text.* .literal .literal.*)
*libkarch.a:*mspi_timing_config.*(.text .text.* .literal .literal.*)
*libkarch.a:*spi_flash_oct_flash_init.*(.text .text.* .literal .literal.*)
*libkarch.a:*spi_flash_hpm_enable.*(.text .text.* .literal .literal.*)
#endif
*libkarch.a:esp_spiflash.*(.literal .text .literal.* .text.*)
*libkarch.a:esp_flash_api.*(.text .text.* .literal .literal.*)
*libkarch.a:esp_flash_spi_init.*(.text .text.* .literal .literal.*)
*libkarch.a:spi_flash_hal_iram.*(.literal .literal.* .text .text.*)
*libkarch.a:spi_flash_encrypt_hal_iram.*(.text .text.* .literal .literal.*)
*libkarch.a:spi_flash_hal_gpspi.*(.literal .literal.* .text .text.*)
*libkarch.a:spi_flash_chip*.*(.literal .literal.* .text .text.*)
*libkarch.a:spi_flash_wrap.*(.literal .literal.* .text .text.*)
*libkarch.a:spi_flash_os_func_noos.*(.literal .literal.* .text .text.*)
*libkarch.a:spi_flash_os_func_app.*(.literal .literal.* .text .text.*)
#endif
*libsched.a:sched_suspendscheduler.*(.literal .text .literal.* .text.*)
*libsched.a:sched_note.*(.literal .text .literal.* .text.*)
*libsched.a:sched_thistask.*(.literal .text .literal.* .text.*)
@ -250,6 +348,63 @@ SECTIONS
*libkarch.a:esp_mmu_map.*(.rodata .rodata.*)
*libkarch.a:ext_mem_layout.*(.rodata .rodata.*)
#ifdef CONFIG_ESPRESSIF_SIMPLE_BOOT
*libkarch.a:*esp_loader.*(.rodata .rodata.*)
*libkarch.a:*brownout.*(.rodata .rodata.*)
*libkarch.a:*cpu.*(.rodata .rodata.*)
*libkarch.a:*gpio_hal.*(.rodata .rodata.*)
*libkarch.a:*periph_ctrl.*(.rodata .rodata.*)
*libkarch.a:*clk.*(.rodata .rodata.*)
*libkarch.a:*efuse_utility.*(.rodata .rodata.*)
*libkarch.a:critical_section.*(.rodata .rodata.*)
*libkarch.a:os.*(.rodata.g_int_flags_count .rodata.g_int_flags)
*libkarch.a:*sleep_modes.*(.rodata.esp_sleep_sub_mode_force_disable*)
*libkarch.a:*rtc_time.*(.rodata .rodata.*)
*libkarch.a:*regi2c_ctrl.*(.rodata .rodata.*)
*libkarch.a:*uart_hal_iram.*(.rodata .rodata.*)
*libkarch.a:*wdt_hal_iram.*(.rodata .rodata.*)
*libkarch.a:*bootloader_banner_wrap.*(.rodata .rodata.*)
*libkarch.a:*bootloader_init.*(.rodata .rodata.*)
*libkarch.a:*bootloader_common.*(.rodata .rodata.*)
*libkarch.a:*bootloader_common_loader.*(.rodata .rodata.*)
*libkarch.a:*bootloader_console.*(.rodata .rodata.*)
*libkarch.a:*bootloader_console_loader.*(.rodata .rodata.*)
*libkarch.a:*bootloader_esp32s3.*(.rodata .rodata.*)
*libkarch.a:*bootloader_flash.*(.rodata .rodata.*)
*libkarch.a:*bootloader_flash_config_esp32s3.*(.rodata .rodata.*)
*libkarch.a:*bootloader_clock_init.*(.rodata .rodata.*)
*libkarch.a:*bootloader_clock_loader.*(.rodata .rodata.*)
*libkarch.a:*bootloader_efuse.*(.rodata .rodata.*)
*libkarch.a:*bootloader_panic.*(.rodata .rodata.*)
*libkarch.a:*bootloader_mem.*(.rodata .rodata.*)
*libkarch.a:*bootloader_random.*(.rodata .rodata.*)
*libkarch.a:*bootloader_random_esp32s3.*(.rodata .rodata.*)
*libkarch.a:*esp_image_format.*(.rodata .rodata.*)
*libkarch.a:*bootloader_soc.*(.rodata .rodata.*)
*libkarch.a:*bootloader_sha.*(.rodata .rodata.*)
*libkarch.a:*flash_encrypt.*(.rodata .rodata.*)
*libkarch.a:*cache_hal.*(.rodata .rodata.*)
*libkarch.a:*uart_hal.*(.rodata .rodata.*)
*libkarch.a:*mpu_hal.*(.rodata .rodata.*)
*libkarch.a:*mmu_hal.*(.rodata .rodata.*)
*libkarch.a:*uart_periph.*(.rodata .rodata.*)
*libkarch.a:*esp_rom_uart.*(.rodata .rodata.*)
*libkarch.a:*esp_rom_sys.*(.rodata .rodata.*)
*libkarch.a:*esp_rom_spiflash.*(.rodata .rodata.*)
*libkarch.a:*esp_rom_cache_esp32s2_esp32s3.*(.rodata .rodata.*)
*libkarch.a:*esp_rom_wdt.*(.rodata .rodata.*)
*libkarch.a:*efuse_hal.*(.rodata .rodata.*)
*libkarch.a:*log.*(.rodata .rodata.*)
*libkarch.a:*log_noos.*(.rodata .rodata.*)
*libkarch.a:*cpu_region_protect.*(.rodata .rodata.*)
#ifdef CONFIG_ESP32S3_FLASH_MODE_OCT
*libkarch.a:*mspi_timing_tuning.*(.rodata .rodata.*)
*libkarch.a:*mspi_timing_config.*(.rodata .rodata.*)
#endif
*libkarch.a:esp32s3_psram_quad.*(.rodata .rodata.*)
*libkarch.a:esp32s3_psram_octal.*(.rodata .rodata.*)
#endif
*libsched.a:sched_suspendscheduler.*(.rodata .rodata.*)
*libsched.a:sched_thistask.*(.rodata .rodata.*)
*libsched.a:sched_note.*(.rodata .rodata.*)
@ -391,6 +546,25 @@ SECTIONS
. = ALIGN(4);
} >KDROM
#ifdef CONFIG_ESPRESSIF_SIMPLE_BOOT
/* Simple boot has no second-stage bootloader: __start() maps the flash
* itself, from these, and bootloader_init() clears the BSS.
*/
_image_irom_vma = ADDR(.flash.text);
_image_irom_lma = LOADADDR(.flash.text);
_image_irom_size = LOADADDR(.flash.text) + SIZEOF(.flash.text) -
_image_irom_lma;
_image_drom_vma = ADDR(.flash.rodata);
_image_drom_lma = LOADADDR(.flash.rodata);
_image_drom_size = LOADADDR(.flash.rodata) + SIZEOF(.flash.rodata) -
_image_drom_lma;
_bss_start = _sbss;
_bss_end = _ebss;
#endif
/*
* This section holds RTC data that should have fixed addresses.
* The data are not initialized at power-up and are retained during deep sleep.

View file

@ -69,6 +69,8 @@
# define FLASH_SIZE 0x800000
#elif defined (CONFIG_ESP32S3_FLASH_16M)
# define FLASH_SIZE 0x1000000
#elif defined (CONFIG_ESP32S3_FLASH_32M)
# define FLASH_SIZE 0x2000000
#endif
#define RESERVE_RTC_MEM 24