Skip to content

Commit

Permalink
esp32: add simple boot support
Browse files Browse the repository at this point in the history
The Simple Boot feature for Espressif chips is a method of booting
that doesn't depend on a 2nd stage bootloader. Its not the
intention to replace a 2nd stage bootloader such as MCUboot and
ESP-IDF bootloader, but to have a minimal and straight-forward way
of booting, and also simplify the building.

This commit also removes deprecated code and makes this bootloader
configuration as default for esp32 targets and removes the need
for running 'make bootloader' command for it.

Signed-off-by: Almir Okato <almir.okato@espressif.com>
  • Loading branch information
almir-okato committed Jul 3, 2024
1 parent cdcf6e5 commit ad2d660
Show file tree
Hide file tree
Showing 27 changed files with 861 additions and 236 deletions.
64 changes: 40 additions & 24 deletions Documentation/platforms/xtensa/esp32/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,48 @@ These steps are given in the setup guide in
Building and flashing NuttX
===========================

Firmware for ESP32 is flashed via the USB/UART interface using the ``esptool.py`` tool.
It's a two step process where the first converts the ELF file into a ESP32-compatible binary
and the second flashes it to the board. These steps are included into the build system and you can
flash your NuttX firmware simply by running::
Bootloader and partitions
-------------------------

NuttX can boot the ESP32 directly using the so-called "Simple Boot". An externally-built
2nd stage bootloader is not required in this case as all functions required to boot the device
are built within NuttX. Simple boot does not require any specific configuration (it is selectable
by default if no other 2nd stage bootloader is used).

If other features are required, an externally-built 2nd stage bootloader is needed. The bootloader
is built using the ``make bootloader`` command. This command generates the firmware in the
``nuttx`` folder. The ``ESPTOOL_BINDIR`` is used in the ``make flash`` command to specify the path
to the bootloader. For compatibility among other SoCs and future options of 2nd stage bootloaders,
the commands ``make bootloader`` and the ``ESPTOOL_BINDIR`` option (for the ``make flash``) can be
used even if no externally-built 2nd stage bootloader is being built (they will be ignored if
Simple Boot is used, for instance)::

$ make bootloader

.. note:: It is recommended that if this is the first time you are using the board with NuttX to
perform a complete SPI FLASH erase.

.. code-block:: console
$ esptool.py erase_flash
Building and Flashing
---------------------

First, make sure that ``esptool.py`` is installed. This tool is used to convert the ELF to a
compatible ESP32 image and to flash the image into the board.
It can be installed with: ``pip install esptool==4.8.dev4``.

It's a two-step process where the first converts the ELF file into an ESP32 compatible binary
and the second flashes it to the board. These steps are included in the build system and it is
possible to build and flash the NuttX firmware simply by running::

$ make flash ESPTOOL_PORT=<port>
$ make flash ESPTOOL_PORT=<port> ESPTOOL_BINDIR=./

where ``<port>`` is typically ``/dev/ttyUSB0`` or similar. You can change the baudrate by passing ``ESPTOOL_BAUD``.
where ``<port>`` is typically ``/dev/ttyUSB0`` or similar. ``ESPTOOL_BINDIR=./`` is the path of the
externally-built 2nd stage bootloader and the partition table (if applicable): when built using the
``make bootloader``, these files are placed into ``nuttx`` folder. ``ESPTOOL_BAUD`` is able to
change the flash baud rate if desired.

Debugging with OpenOCD
======================
Expand Down Expand Up @@ -135,24 +169,6 @@ OpenOCD can then be used::

openocd -c 'set ESP_RTOS hwthread; set ESP_FLASH_SIZE 0' -f board/esp32-wrover-kit-1.8v.cfg

Bootloader and partitions
-------------------------

ESP32 requires a bootloader to be flashed as well as a set of FLASH partitions. This is only needed the first time
(or any time you which to modify either of these). An easy way is to use prebuilt binaries for NuttX `from here <https://github.com/espressif/esp-nuttx-bootloader>`__. In there you will find instructions to rebuild these if necessary.
Once you downloaded both binaries, you can flash them by adding an ``ESPTOOL_BINDIR`` parameter, pointing to the directory where these binaries were downloaded:

.. code-block:: console
$ make flash ESPTOOL_PORT=<port> ESPTOOL_BINDIR=<dir>
.. note:: It is recommended that if this is the first time you are using the board with NuttX that you perform a complete
SPI FLASH erase.

.. code-block:: console
$ esptool.py erase_flash
Peripheral Support
==================

Expand Down
1 change: 1 addition & 0 deletions arch/xtensa/src/common/espressif/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ CHIP_CSRCS += esp_mcpwm.c
endif

ifeq ($(filter $(CONFIG_ESPRESSIF_SIMPLE_BOOT) \
$(CONFIG_ESP32_APP_FORMAT_MCUBOOT) \
$(CONFIG_ESP32S2_APP_FORMAT_MCUBOOT) \
$(CONFIG_ESP32S3_APP_FORMAT_MCUBOOT),y),y)
CHIP_CSRCS += esp_loader.c
Expand Down
53 changes: 50 additions & 3 deletions arch/xtensa/src/common/espressif/esp_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,13 @@
#include "hal/cache_types.h"
#include "hal/cache_ll.h"
#include "hal/cache_hal.h"
#include "soc/extmem_reg.h"
#include "rom/cache.h"
#include "spi_flash_mmap.h"

#ifndef CONFIG_ARCH_CHIP_ESP32
# include "soc/extmem_reg.h"
#endif

# include "bootloader_flash_priv.h"
#ifdef CONFIG_ESPRESSIF_SIMPLE_BOOT
# include "bootloader_init.h"
Expand Down Expand Up @@ -107,6 +110,16 @@ extern uint8_t _image_drom_size[];

extern int ets_printf(const char *fmt, ...) printf_like(1, 2);

#ifdef CONFIG_ARCH_CHIP_ESP32
extern void cache_read_enable(int cpu);
extern void cache_read_disable(int cpu);
extern void cache_flush(int cpu);
extern unsigned int cache_flash_mmu_set(int cpu_no, int pid,
unsigned int vaddr,
unsigned int paddr,
int psize, int num);
#endif

/****************************************************************************
* Private Functions
****************************************************************************/
Expand Down Expand Up @@ -140,6 +153,11 @@ int map_rom_segments(uint32_t app_drom_start, uint32_t app_drom_vaddr,
uint32_t app_drom_start_aligned = app_drom_start & MMU_FLASH_MASK;
uint32_t app_drom_vaddr_aligned = app_drom_vaddr & MMU_FLASH_MASK;

#ifdef CONFIG_ARCH_CHIP_ESP32
uint32_t drom_page_count = 0;
uint32_t irom_page_count = 0;
#endif

#ifdef CONFIG_ESPRESSIF_SIMPLE_BOOT
esp_image_header_t image_header; /* Header for entire image */
esp_image_segment_header_t WORD_ALIGNED_ATTR segment_hdr;
Expand Down Expand Up @@ -244,7 +262,8 @@ int map_rom_segments(uint32_t app_drom_start, uint32_t app_drom_vaddr,
#endif

#if defined (CONFIG_ESP32S2_APP_FORMAT_MCUBOOT) || \
defined (CONFIG_ESP32S3_APP_FORMAT_MCUBOOT)
defined (CONFIG_ESP32S3_APP_FORMAT_MCUBOOT) || \
defined (CONFIG_ESP32_APP_FORMAT_MCUBOOT)
ets_printf("IROM segment aligned lma 0x%08x vma 0x%08x len 0x%06x (%u)\n",
app_irom_start_aligned, app_irom_vaddr_aligned,
app_irom_size, app_irom_size);
Expand All @@ -253,21 +272,46 @@ int map_rom_segments(uint32_t app_drom_start, uint32_t app_drom_vaddr,
app_drom_size, app_drom_size);
#endif

#ifdef CONFIG_ARCH_CHIP_ESP32
cache_read_disable(0);
cache_flush(0);
#else
cache_hal_disable(CACHE_TYPE_ALL);
#endif

/* Clear the MMU entries that are already set up,
* so the new app only has the mappings it creates.
*/

mmu_hal_unmap_all();

#ifdef CONFIG_ARCH_CHIP_ESP32
drom_page_count = (app_drom_size + SPI_FLASH_MMU_PAGE_SIZE - 1) /
SPI_FLASH_MMU_PAGE_SIZE;
rc = cache_flash_mmu_set(0, 0, app_drom_vaddr_aligned,
app_drom_start_aligned, 64,
(int)drom_page_count);
rc |= cache_flash_mmu_set(1, 0, app_drom_vaddr_aligned,
app_drom_start_aligned, 64,
(int)drom_page_count);

irom_page_count = (app_irom_size + SPI_FLASH_MMU_PAGE_SIZE - 1) /
SPI_FLASH_MMU_PAGE_SIZE;
rc |= cache_flash_mmu_set(0, 0, app_irom_vaddr_aligned,
app_irom_start_aligned, 64,
(int)irom_page_count);
rc |= cache_flash_mmu_set(1, 0, app_irom_vaddr_aligned,
app_irom_start_aligned, 64,
(int)irom_page_count);
#else
mmu_hal_map_region(0, MMU_TARGET_FLASH0,
app_drom_vaddr_aligned, app_drom_start_aligned,
app_drom_size, &actual_mapped_len);

mmu_hal_map_region(0, MMU_TARGET_FLASH0,
app_irom_vaddr_aligned, app_irom_start_aligned,
app_irom_size, &actual_mapped_len);
#endif

/* ------------------Enable corresponding buses--------------------- */

Expand All @@ -285,7 +329,10 @@ int map_rom_segments(uint32_t app_drom_start, uint32_t app_drom_vaddr,

/* ------------------Enable Cache----------------------------------- */

#ifdef CONFIG_ARCH_CHIP_ESP32
cache_read_enable(0);
#else
cache_hal_enable(CACHE_TYPE_ALL);

#endif
return (int)rc;
}
28 changes: 7 additions & 21 deletions arch/xtensa/src/esp32/Bootloader.mk
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

.PHONY: bootloader clean_bootloader

ifeq ($(CONFIG_ESP32_BOOTLOADER_BUILD_FROM_SOURCE),y)
ifeq ($(CONFIG_ESPRESSIF_SIMPLE_BOOT),)

TOOLSDIR = $(TOPDIR)/tools/espressif
CHIPDIR = $(TOPDIR)/arch/xtensa/src/chip
Expand Down Expand Up @@ -112,8 +112,13 @@ else ifeq ($(CONFIG_ESP32_APP_FORMAT_LEGACY),y)
$(call cfg_val,CONFIG_PARTITION_TABLE_OFFSET,$(CONFIG_ESP32_PARTITION_TABLE_OFFSET)) \
} >> $(BOOTLOADER_CONFIG)
endif
endif

ifeq ($(CONFIG_ESP32_APP_FORMAT_MCUBOOT),y)
ifeq ($(CONFIG_ESPRESSIF_SIMPLE_BOOT),y)
bootloader:
$(Q) echo "Using direct bootloader to boot NuttX."

else ifeq ($(CONFIG_ESP32_APP_FORMAT_MCUBOOT),y)

BOOTLOADER_BIN = $(TOPDIR)/mcuboot-esp32.bin
BOOTLOADER_SIGNED_BIN = $(TOPDIR)/mcuboot-esp32.signed.bin
Expand Down Expand Up @@ -186,22 +191,3 @@ clean_bootloader:
$(call DELFILE,$(TOPDIR)/partition-table-esp32.bin)

endif

else ifeq ($(CONFIG_ESP32_BOOTLOADER_DOWNLOAD_PREBUILT),y)

BOOTLOADER_VERSION = latest
BOOTLOADER_URL = https://github.com/espressif/esp-nuttx-bootloader/releases/download/$(BOOTLOADER_VERSION)

ifeq ($(CONFIG_ESP32_APP_FORMAT_LEGACY),y)

bootloader:
$(call DOWNLOAD,$(BOOTLOADER_URL),bootloader-esp32.bin,$(TOPDIR)/bootloader-esp32.bin)
$(call DOWNLOAD,$(BOOTLOADER_URL),partition-table-esp32.bin,$(TOPDIR)/partition-table-esp32.bin)

clean_bootloader:
$(call DELFILE,$(TOPDIR)/bootloader-esp32.bin)
$(call DELFILE,$(TOPDIR)/partition-table-esp32.bin)

endif

endif
34 changes: 12 additions & 22 deletions arch/xtensa/src/esp32/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ config ESPRESSIF_CHIP_SERIES
string
default "esp32"

config ESPRESSIF_NUM_CPUS
int
default 1 if ESP32_SINGLE_CPU
default 2 if ESP32_DUAL_CPU

config ESP32_SINGLE_CPU
bool
default n
Expand Down Expand Up @@ -1890,7 +1895,6 @@ comment "Partition Table Configuration"
config ESP32_PARTITION_TABLE
bool "Create MTD partitions from Partition Table"
default n
select ESP32_BOOTLOADER_BUILD_FROM_SOURCE
---help---
Decode partition table and initialize partitions as MTD.

Expand Down Expand Up @@ -2560,39 +2564,26 @@ config ESP32_HAVE_OTA_PARTITION

menu "Bootloader and Image Configuration"

config ESPRESSIF_SIMPLE_BOOT
bool
depends on !ESP32_APP_FORMAT_MCUBOOT && !ESP32_APP_FORMAT_LEGACY
default y

config ESP32_APP_FORMAT_LEGACY
bool "Enable legacy IDF bootloader format"
default y if !ESP32_APP_FORMAT_MCUBOOT
depends on !ESP32_APP_FORMAT_MCUBOOT
default y if BUILD_PROTECTED
---help---
This is the legacy application image format, as supported by the ESP-IDF
2nd stage bootloader.

config ESP32_APP_FORMAT_MCUBOOT
bool "Enable MCUboot-bootable format"
depends on !MCUBOOT_BOOTLOADER
default n
select ESP32_HAVE_OTA_PARTITION
select ESP32_BOOTLOADER_BUILD_FROM_SOURCE
---help---
Enables the Espressif port of MCUboot to be used as 2nd stage bootloader.

config ESP32_BOOTLOADER_DOWNLOAD_PREBUILT
bool
default y if !ESP32_BOOTLOADER_BUILD_FROM_SOURCE
depends on !ESP32_BOOTLOADER_BUILD_FROM_SOURCE
---help---
The build system will download the prebuilt binaries from
https://github.com/espressif/esp-nuttx-bootloader according to the chosen
Application Image Format (ESP32_APP_FORMAT_LEGACY or ESP32_APP_FORMAT_MCUBOOT)

config ESP32_BOOTLOADER_BUILD_FROM_SOURCE
bool "Build binaries from source"
---help---
The build system will build all the required binaries from source. It will clone
the https://github.com/espressif/esp-nuttx-bootloader repository and build a
custom bootloader according to the chosen Application Image Format
(ESP32_APP_FORMAT_LEGACY or ESP32_APP_FORMAT_MCUBOOT) and partition information.

choice
prompt "Target slot for image flashing"
default ESP32_ESPTOOL_TARGET_PRIMARY
Expand Down Expand Up @@ -2637,7 +2628,6 @@ config ESP32_CUSTOM_PARTITION_TABLE_OFFSET
bool "Customize partition table offset"
default n
depends on ESP32_APP_FORMAT_LEGACY
select ESP32_BOOTLOADER_BUILD_FROM_SOURCE
---help---
Enable to select the offset of the partition table in the flash.

Expand Down
6 changes: 0 additions & 6 deletions arch/xtensa/src/esp32/Kconfig.security
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ config ESP32_SECURE_BOOT

if ESP32_SECURE_BOOT

comment "Secure Boot support requires building the bootloader from source (ESP32_BOOTLOADER_BUILD_FROM_SOURCE)"
depends on !ESP32_BOOTLOADER_BUILD_FROM_SOURCE

config ESP32_SECURE_BOOT_BUILD_SIGNED_BINARIES
bool "Sign binaries during build"
default y
Expand Down Expand Up @@ -117,9 +114,6 @@ config ESP32_SECURE_FLASH_ENC_ENABLED

if ESP32_SECURE_FLASH_ENC_ENABLED

comment "Flash Encryption support requires building the bootloader from source (ESP32_BOOTLOADER_BUILD_FROM_SOURCE)"
depends on !ESP32_BOOTLOADER_BUILD_FROM_SOURCE

choice ESP32_SECURE_FLASH_ENCRYPTION_MODE
bool "Enable usage mode"
default ESP32_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
Expand Down
9 changes: 5 additions & 4 deletions arch/xtensa/src/esp32/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ endif

ESP_HAL_3RDPARTY_REPO = esp-hal-3rdparty
ifndef ESP_HAL_3RDPARTY_VERSION
ESP_HAL_3RDPARTY_VERSION = 966f1bbf7d80d3fac9a43f414e864985cbcfd680
ESP_HAL_3RDPARTY_VERSION = 0e6895d4ce431ce95b156027e6e3af50f9b4df37
endif

ifndef ESP_HAL_3RDPARTY_URL
Expand All @@ -232,6 +232,10 @@ chip/$(ESP_HAL_3RDPARTY_REPO):

CFLAGS += -Wno-undef -Wno-unused-variable

# Enable strict volatile bitfield access

CFLAGS += -fstrict-volatile-bitfields

# Files that require the HAL recipe

CHIP_SERIES = $(patsubst "%",%,$(CONFIG_ESPRESSIF_CHIP_SERIES))
Expand All @@ -251,9 +255,6 @@ ifeq ($(CONFIG_ESP32_WIRELESS),y)
$(Q) cd chip/$(ESP_HAL_3RDPARTY_REPO)/components/mbedtls/mbedtls && git apply ../../../nuttx/patches/components/mbedtls/mbedtls/*.patch
endif

distclean::
$(call DELDIR, chip/$(ESP_HAL_3RDPARTY_REPO))

ifeq ($(CONFIG_ESP32_WIRELESS),y)
include chip/Wireless.mk
endif
Expand Down
Loading

0 comments on commit ad2d660

Please sign in to comment.