Skip to content

xtensa/esp32s3: Let a protected build boot from simple boot - #19764

Merged
xiaoxiang781216 merged 1 commit into
apache:masterfrom
casaroli:esp32s3-protected-simpleboot
Aug 11, 2026
Merged

xtensa/esp32s3: Let a protected build boot from simple boot#19764
xiaoxiang781216 merged 1 commit into
apache:masterfrom
casaroli:esp32s3-protected-simpleboot

Conversation

@casaroli

@casaroli casaroli commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

A protected build on the ESP32-S3 always used the ESP-IDF second-stage bootloader. ESP32S3_APP_FORMAT_LEGACY has default y if BUILD_PROTECTED. Simple boot was not possible.

The protected layout does not need that bootloader. ESP32S3_KERNEL_OFFSET, ESP32S3_KERNEL_IMAGE_SIZE and ESP32S3_KERNEL_RAM_SIZE give the layout of the two images. esp32s3_userspace() maps the user image itself.

Three problems prevented simple boot.

The three configuration symbols were available only with ESP32S3_APP_FORMAT_LEGACY. protected_memory.ld uses them for the KIROM, KDROM, UIROM, UDROM, KDRAM and UDRAM regions. Without them the region lengths underflow to 2^64-1. The kernel and user RAM split is then invalid. The hardware reports a DRAM0 PMS monitor violation when the first user process runs. This patch makes the symbols available for all protected builds. The kernel offset is 0x0 for simple boot, because the image starts at the beginning of the device.

protected_memory.ld had no case for a 32 MB part. FLASH_SIZE was therefore undefined, and the ROM, UIROM and UDROM lengths underflowed. flat_memory.ld already has this case.

kernel-space.ld did not define the symbols that simple boot needs. These symbols are _image_irom_*, _image_drom_* and _bss_*. The script also kept no early code in RAM. __start() calls bootloader_init() and map_rom_segments() before a flash mapping exists. All code that these functions reach must stay in RAM. This includes map_rom_segments() itself, which unmaps the MMU that it runs from. It also includes nuttx_enter_critical(), which rtc_clk_init() reaches through the regi2c functions. esp32s3_sections.ld already does this for the flat build.

Impact

The change is specific to the ESP32-S3. It adds a configuration that was not available before.

Users of ESP32S3_APP_FORMAT_LEGACY see no change. The legacy path uses the same values as before. The default for a protected build is still the legacy format.

A protected build can now use ESPRESSIF_SIMPLE_BOOT. Disable ESP32S3_APP_FORMAT_LEGACY to select it. Write the kernel image to offset 0x0 and the user image to ESP32S3_KERNEL_IMAGE_SIZE. The ESP-IDF bootloader and the partition table are not necessary.

A 32 MB part now gives correct region lengths in a protected build.

Testing

Board: ESP32-S3-DevKitC with an ESP32-S3-WROOM-2 module, 32 MB octal flash. Host: macOS 15 on Apple Silicon, xtensa-esp32s3-elf-gcc 12.2.0.

Configuration: esp32s3-devkit:knsh, with ESP32S3_APP_FORMAT_LEGACY disabled. The module also needs ARCH_CHIP_ESP32S3WROOM2N32R8V, ESP32S3_FLASH_MODE_OCT and ESP32S3_SPI_FLASH_USE_32BIT_ADDRESS.

esptool.py -c esp32s3 write_flash 0x0 nuttx.bin 0x80000 nuttx_user.bin

The board boots to NSH and runs ostest to the end:

NuttShell (NSH) NuttX-12.2.1
nsh> ostest
...
ostest_main: Exiting with status 0

tools/checkpatch.sh -c -u -m -g gives no errors.

Before this change the same configuration does not build. ESP32S3_KERNEL_IMAGE_SIZE is not defined, and protected_memory.ld fails.

@github-actions github-actions Bot added Arch: xtensa Issues related to the Xtensa architecture Size: M The size of the change in this PR is medium Board: xtensa labels Aug 10, 2026
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@casaroli
casaroli force-pushed the esp32s3-protected-simpleboot branch from 3115f84 to 33273a6 Compare August 10, 2026 12:50
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>
@xiaoxiang781216
xiaoxiang781216 merged commit 46528ea into apache:master Aug 11, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: xtensa Issues related to the Xtensa architecture Board: xtensa Size: M The size of the change in this PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants