From ac40b2129f5d376be62b07f0dee0a0773f375b59 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Mon, 9 Feb 2026 18:38:55 +0530 Subject: [PATCH 01/16] xtensa/esp32: Implement board_boot_image for mcuboot/nxboot support This commit adds the board_boot_image() implementation for ESP32, enabling support for MCUboot and nxboot bootloaders. It includes parsing the image header and setting up the necessary MMU mappings. Signed-off-by: Aviral Garg --- arch/xtensa/include/esp32/partition.h | 17 +- arch/xtensa/src/esp32/esp32_partition.c | 884 ++++++++---------- boards/xtensa/esp32/common/src/Make.defs | 2 + .../esp32/common/src/esp32_boot_image.c | 230 +++++ 4 files changed, 625 insertions(+), 508 deletions(-) create mode 100644 boards/xtensa/esp32/common/src/esp32_boot_image.c diff --git a/arch/xtensa/include/esp32/partition.h b/arch/xtensa/include/esp32/partition.h index 20a8c21bb061a..7335b330ed6ff 100644 --- a/arch/xtensa/include/esp32/partition.h +++ b/arch/xtensa/include/esp32/partition.h @@ -33,8 +33,7 @@ /* OTA image operation code */ -enum ota_img_ctrl -{ +enum ota_img_ctrl { OTA_IMG_GET_BOOT = 0xe1, OTA_IMG_SET_BOOT = 0xe2, OTA_IMG_SET_ENCRYPTED = 0xe3, @@ -43,15 +42,15 @@ enum ota_img_ctrl OTA_IMG_GET_SUBTYPE = 0xe6, OTA_IMG_INVALIDATE_BOOT = 0xe7, OTA_IMG_IS_MAPPED_AS_TEXT = 0xe8, + OTA_IMG_GET_OFFSET = 0xe9, }; /* OTA image boot sequency */ -enum ota_img_bootseq -{ - OTA_IMG_BOOT_FACTORY = 0, - OTA_IMG_BOOT_OTA_0 = 1, - OTA_IMG_BOOT_OTA_1 = 2, +enum ota_img_bootseq { + OTA_IMG_BOOT_FACTORY = 0, + OTA_IMG_BOOT_OTA_0 = 1, + OTA_IMG_BOOT_OTA_1 = 2, OTA_IMG_BOOT_SEQ_MAX }; @@ -72,7 +71,7 @@ enum ota_img_bootseq * ****************************************************************************/ -int esp32_partition_read_decrypt(const char *label, size_t offset, - void *buf, size_t size); +int esp32_partition_read_decrypt(const char *label, size_t offset, void *buf, + size_t size); #endif /* __ARCH_XTENSA_INCLUDE_ESP32_PARTITION_H */ diff --git a/arch/xtensa/src/esp32/esp32_partition.c b/arch/xtensa/src/esp32/esp32_partition.c index f9e102a5eb5b3..1d9e0a386ee16 100644 --- a/arch/xtensa/src/esp32/esp32_partition.c +++ b/arch/xtensa/src/esp32/esp32_partition.c @@ -24,18 +24,18 @@ #include +#include +#include #include +#include #include #include -#include -#include -#include #include -#include "esp32_spiflash.h" -#include "esp32_partition.h" #include "arch/esp32/partition.h" +#include "esp32_partition.h" +#include "esp32_spiflash.h" /**************************************************************************** * Pre-processor Definitions @@ -43,28 +43,28 @@ /* Partition table max size */ -#define PARTITION_MAX_SIZE (0xc00) +#define PARTITION_MAX_SIZE (0xc00) /* Partition max number */ -#define PARTITION_MAX_NUM (PARTITION_MAX_SIZE / \ - sizeof(struct partition_info_priv)) +#define PARTITION_MAX_NUM \ + (PARTITION_MAX_SIZE / sizeof(struct partition_info_priv)) /* Partition table header magic value */ -#define PARTITION_MAGIC (0x50aa) +#define PARTITION_MAGIC (0x50aa) /* Partition table member label length */ -#define PARTITION_LABEL_LEN (16) +#define PARTITION_LABEL_LEN (16) /* OTA data offset in OTA partition */ -#define OTA_DATA_OFFSET (4096) +#define OTA_DATA_OFFSET (4096) /* OTA data number */ -#define OTA_DATA_NUM (2) +#define OTA_DATA_NUM (2) /* Partition offset in SPI Flash */ @@ -76,12 +76,11 @@ /* Partition mount pointer max length */ -#define PARTITION_MOUNTPTR_LEN_MAX (PARTITION_LABEL_LEN + \ - sizeof(g_path_base)) +#define PARTITION_MOUNTPTR_LEN_MAX (PARTITION_LABEL_LEN + sizeof(g_path_base)) /* Partition encrypted flag */ -#define PARTITION_FLAG_ENCRYPTED (1 << 0) +#define PARTITION_FLAG_ENCRYPTED (1 << 0) /**************************************************************************** * Private Types @@ -89,15 +88,14 @@ /* OTA image state */ -enum ota_img_state -{ +enum ota_img_state { /* Monitor the first boot. In bootloader of esp-idf this state is changed * to ESP_OTA_IMG_PENDING_VERIFY if this bootloader enable app rollback. * * So this driver doesn't use this state currently. */ - OTA_IMG_NEW = 0x0, + OTA_IMG_NEW = 0x0, /* First boot for this app was. If while the second boot this state is then * it will be changed to ABORTED if this bootloader enable app rollback. @@ -105,15 +103,15 @@ enum ota_img_state * So this driver doesn't use this state currently. */ - OTA_IMG_PENDING_VERIFY = 0x1, + OTA_IMG_PENDING_VERIFY = 0x1, /* App was confirmed as workable. App can boot and work without limits. */ - OTA_IMG_VALID = 0x2, + OTA_IMG_VALID = 0x2, /* App was confirmed as non-workable. This app will not selected to boot. */ - OTA_IMG_INVALID = 0x3, + OTA_IMG_INVALID = 0x3, /* App could not confirm the workable or non-workable. In bootloader * IMG_PENDING_VERIFY state will be changed to IMG_ABORTED. This app will @@ -122,59 +120,56 @@ enum ota_img_state * So this driver doesn't use this state currently. */ - OTA_IMG_ABORTED = 0x4, + OTA_IMG_ABORTED = 0x4, /* Undefined. App can boot and work without limits in esp-idf. * * This state is not used. */ - OTA_IMG_UNDEFINED = 0xffffffff, + OTA_IMG_UNDEFINED = 0xffffffff, }; /* Partition information data */ -struct partition_info_priv -{ - uint16_t magic; /* Partition magic */ - uint8_t type; /* Partition type */ - uint8_t subtype; /* Partition sub-type */ +struct partition_info_priv { + uint16_t magic; /* Partition magic */ + uint8_t type; /* Partition type */ + uint8_t subtype; /* Partition sub-type */ - uint32_t offset; /* Offset in SPI Flash */ - uint32_t size; /* Size by byte */ + uint32_t offset; /* Offset in SPI Flash */ + uint32_t size; /* Size by byte */ - uint8_t label[PARTITION_LABEL_LEN]; /* Partition label */ + uint8_t label[PARTITION_LABEL_LEN]; /* Partition label */ - uint32_t flags; /* Partition flags */ + uint32_t flags; /* Partition flags */ }; /* Partition device data */ -struct mtd_dev_priv -{ - struct mtd_dev_s mtd; /* MTD data */ +struct mtd_dev_priv { + struct mtd_dev_s mtd; /* MTD data */ - uint8_t type; /* Partition type */ - uint8_t subtype; /* Partition sub-type */ - uint32_t flags; /* Partition flags */ - uint32_t offset; /* Partition offset in SPI Flash */ - uint32_t size; /* Partition size in SPI Flash */ + uint8_t type; /* Partition type */ + uint8_t subtype; /* Partition sub-type */ + uint32_t flags; /* Partition flags */ + uint32_t offset; /* Partition offset in SPI Flash */ + uint32_t size; /* Partition size in SPI Flash */ - struct mtd_dev_s *mtd_ll; /* Low-level MTD data */ + struct mtd_dev_s *mtd_ll; /* Low-level MTD data */ - struct mtd_dev_s *mtd_part; /* MTD partition device */ + struct mtd_dev_s *mtd_part; /* MTD partition device */ - struct mtd_geometry_s geo; /* Partition geometry information */ + struct mtd_geometry_s geo; /* Partition geometry information */ }; /* OTA data entry */ -struct ota_data_entry -{ - uint32_t ota_seq; /* Boot sequence */ - uint8_t seq_label[20]; /* Boot sequence label */ - uint32_t ota_state; /* Boot entry state */ - uint32_t crc; /* Boot ota_seq CRC32 */ +struct ota_data_entry { + uint32_t ota_seq; /* Boot sequence */ + uint8_t seq_label[20]; /* Boot sequence label */ + uint32_t ota_state; /* Boot entry state */ + uint32_t crc; /* Boot ota_seq CRC32 */ }; /**************************************************************************** @@ -203,14 +198,12 @@ const char g_path_base[] = PARTITION_MOUNT_POINT; * ****************************************************************************/ -static bool ota_is_valid(struct ota_data_entry *ota_data) -{ +static bool ota_is_valid(struct ota_data_entry *ota_data) { if ((ota_data->ota_seq == UINT32_MAX) || (ota_data->ota_state != OTA_IMG_VALID) || - (ota_data->crc != crc32_le(UINT32_MAX, (uint8_t *)ota_data, 4))) - { - return false; - } + (ota_data->crc != crc32_le(UINT32_MAX, (uint8_t *)ota_data, 4))) { + return false; + } return true; } @@ -230,8 +223,7 @@ static bool ota_is_valid(struct ota_data_entry *ota_data) * ****************************************************************************/ -static int ota_get_bootseq(struct mtd_dev_priv *dev, uint32_t *seqptr) -{ +static int ota_get_bootseq(struct mtd_dev_priv *dev, uint32_t *seqptr) { int i; int ret; uint32_t seq = 0; @@ -240,37 +232,30 @@ static int ota_get_bootseq(struct mtd_dev_priv *dev, uint32_t *seqptr) /* Each OTA data locates in independent sector */ - for (i = 0; i < OTA_DATA_NUM; i++) - { - ret = MTD_READ(dev->mtd_part, i * dev->geo.erasesize, - size, (uint8_t *)&ota_data); - if (ret != size) - { - ferr("ERROR: Failed to read OTA%d data error=%d\n", i, ret); - return -EIO; - } - - if (ota_is_valid(&ota_data)) - { - seq = MAX(seq, ota_data.ota_seq); - } + for (i = 0; i < OTA_DATA_NUM; i++) { + ret = MTD_READ(dev->mtd_part, i * dev->geo.erasesize, size, + (uint8_t *)&ota_data); + if (ret != size) { + ferr("ERROR: Failed to read OTA%d data error=%d\n", i, ret); + return -EIO; } + if (ota_is_valid(&ota_data)) { + seq = MAX(seq, ota_data.ota_seq); + } + } + finfo("seq=%" PRIu32 "\n", seq); - if (seq > 0) - { - ret = (seq - 1) % OTA_DATA_NUM + OTA_IMG_BOOT_OTA_0; - } - else - { - ret = OTA_IMG_BOOT_FACTORY; - } + if (seq > 0) { + ret = (seq - 1) % OTA_DATA_NUM + OTA_IMG_BOOT_OTA_0; + } else { + ret = OTA_IMG_BOOT_FACTORY; + } - if (seqptr) - { - *seqptr = seq; - } + if (seqptr) { + *seqptr = seq; + } return ret; } @@ -290,8 +275,7 @@ static int ota_get_bootseq(struct mtd_dev_priv *dev, uint32_t *seqptr) * ****************************************************************************/ -static int ota_set_bootseq(struct mtd_dev_priv *dev, int num) -{ +static int ota_set_bootseq(struct mtd_dev_priv *dev, int num) { int ret; int size; uint8_t *buffer; @@ -303,105 +287,84 @@ static int ota_set_bootseq(struct mtd_dev_priv *dev, int num) finfo("INFO: num=%d\n", num); - switch (num) - { - case OTA_IMG_BOOT_FACTORY: - - /* Erase all OTA data to force use factory app */ - - ret = MTD_ERASE(dev->mtd_part, 0, OTA_DATA_NUM); - if (ret != OTA_DATA_NUM) - { - ferr("ERROR: Failed to erase OTA data error=%d\n", ret); - return -1; - } - - break; - case OTA_IMG_BOOT_OTA_0: - case OTA_IMG_BOOT_OTA_1: - ret = ota_get_bootseq(dev, &next_seq); - if (ret < 0) - { - ferr("ERROR: Failed to get boot sequence error=%d\n", ret); - return ret; - } - else if (ret == num) - { - /* the requested num is already set as next boot partition */ - - return OK; - } - else if (ret == OTA_IMG_BOOT_FACTORY) - { - next_seq = (uint32_t)num; - } - else - { - next_seq++; - } - - sec = num - OTA_IMG_BOOT_OTA_0; - - ret = MTD_ERASE(dev->mtd_part, sec, 1); - if (ret != 1) - { - ferr("ERROR: Failed to erase OTA%" PRId32 "data error=%d\n", - sec, ret); - return -EIO; - } - - ota_data.ota_state = OTA_IMG_VALID; - ota_data.ota_seq = next_seq; - ota_data.crc = crc32_le(UINT32_MAX, (uint8_t *)&ota_data, 4); - - if (dev->flags & PARTITION_FLAG_ENCRYPTED) - { - blkcnt = sizeof(struct ota_data_entry) / dev->geo.blocksize; - size = sizeof(struct ota_data_entry) % dev->geo.blocksize; - if (size) - { - blkcnt++; - } - - size = blkcnt * dev->geo.blocksize; - buffer = kmm_malloc(size); - if (!buffer) - { - ferr("ERROR:Failed to allocate %d bytes\n", size); - return -ENOMEM; - } - - memcpy(buffer, &ota_data, sizeof(struct ota_data_entry)); - - blk = sec * dev->geo.erasesize / dev->geo.blocksize; - ret = MTD_BWRITE(dev->mtd_part, blk, blkcnt, buffer); - kmm_free(buffer); - if (ret != blkcnt) - { - ferr("ERROR: Failed to write OTA%" PRId32 "data error=%d\n", - sec, ret); - return -EIO; - } - } - else - { - ret = MTD_WRITE(dev->mtd_part, sec * dev->geo.erasesize, - sizeof(struct ota_data_entry), - (uint8_t *)&ota_data); - if (ret != sizeof(struct ota_data_entry)) - { - ferr("ERROR: Failed to write OTA%" PRId32 "data error=%d\n", - sec, ret); - return -1; - } - } - - break; - default: - ferr("ERROR: num=%d is error\n", num); - return -EINVAL; + switch (num) { + case OTA_IMG_BOOT_FACTORY: + + /* Erase all OTA data to force use factory app */ + + ret = MTD_ERASE(dev->mtd_part, 0, OTA_DATA_NUM); + if (ret != OTA_DATA_NUM) { + ferr("ERROR: Failed to erase OTA data error=%d\n", ret); + return -1; + } + + break; + case OTA_IMG_BOOT_OTA_0: + case OTA_IMG_BOOT_OTA_1: + ret = ota_get_bootseq(dev, &next_seq); + if (ret < 0) { + ferr("ERROR: Failed to get boot sequence error=%d\n", ret); + return ret; + } else if (ret == num) { + /* the requested num is already set as next boot partition */ + + return OK; + } else if (ret == OTA_IMG_BOOT_FACTORY) { + next_seq = (uint32_t)num; + } else { + next_seq++; + } + + sec = num - OTA_IMG_BOOT_OTA_0; + + ret = MTD_ERASE(dev->mtd_part, sec, 1); + if (ret != 1) { + ferr("ERROR: Failed to erase OTA%" PRId32 "data error=%d\n", sec, ret); + return -EIO; + } + + ota_data.ota_state = OTA_IMG_VALID; + ota_data.ota_seq = next_seq; + ota_data.crc = crc32_le(UINT32_MAX, (uint8_t *)&ota_data, 4); + + if (dev->flags & PARTITION_FLAG_ENCRYPTED) { + blkcnt = sizeof(struct ota_data_entry) / dev->geo.blocksize; + size = sizeof(struct ota_data_entry) % dev->geo.blocksize; + if (size) { + blkcnt++; + } + + size = blkcnt * dev->geo.blocksize; + buffer = kmm_malloc(size); + if (!buffer) { + ferr("ERROR:Failed to allocate %d bytes\n", size); + return -ENOMEM; + } + + memcpy(buffer, &ota_data, sizeof(struct ota_data_entry)); + + blk = sec * dev->geo.erasesize / dev->geo.blocksize; + ret = MTD_BWRITE(dev->mtd_part, blk, blkcnt, buffer); + kmm_free(buffer); + if (ret != blkcnt) { + ferr("ERROR: Failed to write OTA%" PRId32 "data error=%d\n", sec, ret); + return -EIO; + } + } else { + ret = MTD_WRITE(dev->mtd_part, sec * dev->geo.erasesize, + sizeof(struct ota_data_entry), (uint8_t *)&ota_data); + if (ret != sizeof(struct ota_data_entry)) { + ferr("ERROR: Failed to write OTA%" PRId32 "data error=%d\n", sec, ret); + return -1; + } } + break; + default: + ferr("ERROR: num=%d is error\n", num); + return -EINVAL; + } + return OK; } @@ -420,30 +383,26 @@ static int ota_set_bootseq(struct mtd_dev_priv *dev, int num) * ****************************************************************************/ -static int ota_invalidate_bootseq(struct mtd_dev_priv *dev, int num) -{ +static int ota_invalidate_bootseq(struct mtd_dev_priv *dev, int num) { int ret; uint32_t sec; finfo("INFO: num=%d\n", num); - switch (num) - { - case OTA_IMG_BOOT_OTA_0: - case OTA_IMG_BOOT_OTA_1: - sec = num - OTA_IMG_BOOT_OTA_0; - ret = MTD_ERASE(dev->mtd_part, sec, 1); - if (ret != 1) - { - ferr("ERROR: Failed to erase OTA%" PRId32 "data error=%d\n", - sec, ret); - return -EIO; - } - - break; - default: - ferr("ERROR: num=%d is error\n", num); - return -EINVAL; + switch (num) { + case OTA_IMG_BOOT_OTA_0: + case OTA_IMG_BOOT_OTA_1: + sec = num - OTA_IMG_BOOT_OTA_0; + ret = MTD_ERASE(dev->mtd_part, sec, 1); + if (ret != 1) { + ferr("ERROR: Failed to erase OTA%" PRId32 "data error=%d\n", sec, ret); + return -EIO; } + break; + default: + ferr("ERROR: num=%d is error\n", num); + return -EINVAL; + } + return OK; } @@ -462,16 +421,13 @@ static int ota_invalidate_bootseq(struct mtd_dev_priv *dev, int num) * ****************************************************************************/ -static int is_currently_mapped_as_text(struct mtd_dev_priv *dev, - bool *mapped) -{ +static int is_currently_mapped_as_text(struct mtd_dev_priv *dev, bool *mapped) { uint32_t currently_mapped_address; - if (mapped == NULL) - { - ferr("ERROR: Invalid argument.\n"); - return -EINVAL; - } + if (mapped == NULL) { + ferr("ERROR: Invalid argument.\n"); + return -EINVAL; + } currently_mapped_address = esp32_get_flash_address_mapped_as_text(); @@ -498,8 +454,7 @@ static int is_currently_mapped_as_text(struct mtd_dev_priv *dev, ****************************************************************************/ static int esp32_part_erase(struct mtd_dev_s *dev, off_t startblock, - size_t nblocks) -{ + size_t nblocks) { struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_ERASE(mtd_priv->mtd_ll, startblock, nblocks); @@ -523,8 +478,7 @@ static int esp32_part_erase(struct mtd_dev_s *dev, off_t startblock, ****************************************************************************/ static ssize_t esp32_part_read(struct mtd_dev_s *dev, off_t offset, - size_t nbytes, uint8_t *buffer) -{ + size_t nbytes, uint8_t *buffer) { struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_READ(mtd_priv->mtd_ll, offset, nbytes, buffer); @@ -548,8 +502,7 @@ static ssize_t esp32_part_read(struct mtd_dev_s *dev, off_t offset, ****************************************************************************/ static ssize_t esp32_part_bread(struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, uint8_t *buffer) -{ + size_t nblocks, uint8_t *buffer) { struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_BREAD(mtd_priv->mtd_ll, startblock, nblocks, buffer); @@ -573,8 +526,7 @@ static ssize_t esp32_part_bread(struct mtd_dev_s *dev, off_t startblock, ****************************************************************************/ static ssize_t esp32_part_write(struct mtd_dev_s *dev, off_t offset, - size_t nbytes, const uint8_t *buffer) -{ + size_t nbytes, const uint8_t *buffer) { struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_WRITE(mtd_priv->mtd_ll, offset, nbytes, buffer); @@ -599,8 +551,7 @@ static ssize_t esp32_part_write(struct mtd_dev_s *dev, off_t offset, ****************************************************************************/ static ssize_t esp32_part_bwrite(struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, const uint8_t *buffer) -{ + size_t nblocks, const uint8_t *buffer) { struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_BWRITE(mtd_priv->mtd_ll, startblock, nblocks, buffer); @@ -622,98 +573,80 @@ static ssize_t esp32_part_bwrite(struct mtd_dev_s *dev, off_t startblock, * ****************************************************************************/ -static int esp32_part_ioctl(struct mtd_dev_s *dev, int cmd, - unsigned long arg) -{ +static int esp32_part_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg) { int ret = OK; struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; finfo("INFO: cmd=%d(%x) arg=%" PRIx32 "\n", cmd, cmd, arg); - switch (_IOC_NR(cmd)) - { - case OTA_IMG_GET_BOOT: - { - ret = ota_get_bootseq(mtd_priv, NULL); - if (ret < 0) - { - ferr("ERROR: Failed to get boot img\n"); - } - else - { - *(int *)arg = ret; - } - } - - break; - case OTA_IMG_SET_BOOT: - { - ret = ota_set_bootseq(mtd_priv, arg); - if (ret) - { - ferr("ERROR: Failed to set boot img\n"); - } - } - - break; - case OTA_IMG_GET_ENCRYPTED: - if (mtd_priv->flags & PARTITION_FLAG_ENCRYPTED) - { - *(int *)arg = 1; - } - else - { - *(int *)arg = 0; - } - - break; - case OTA_IMG_SET_ENCRYPTED: - if (arg) - { - mtd_priv->flags |= PARTITION_FLAG_ENCRYPTED; - } - else - { - mtd_priv->flags &= ~PARTITION_FLAG_ENCRYPTED; - } - - break; - case OTA_IMG_GET_TYPE: - *(int *)arg = mtd_priv->type; - break; - case OTA_IMG_GET_SUBTYPE: - *(int *)arg = mtd_priv->subtype; - break; - case OTA_IMG_INVALIDATE_BOOT: - { - ret = ota_invalidate_bootseq(mtd_priv, arg); - if (ret < 0) - { - ferr("ERROR: Failed to invalidate boot img\n"); - } - } - - break; - case OTA_IMG_IS_MAPPED_AS_TEXT: - { - bool *mapped = (bool *)arg; - - ret = is_currently_mapped_as_text(mtd_priv, mapped); - if (ret < 0) - { - ferr("ERROR: Failed to check partition is mapped as text\n"); - } - } - - break; - default: - { - ret = MTD_IOCTL(mtd_priv->mtd_ll, cmd, arg); - } - - break; + switch (_IOC_NR(cmd)) { + case OTA_IMG_GET_BOOT: { + ret = ota_get_bootseq(mtd_priv, NULL); + if (ret < 0) { + ferr("ERROR: Failed to get boot img\n"); + } else { + *(int *)arg = ret; + } + } + + break; + case OTA_IMG_SET_BOOT: { + ret = ota_set_bootseq(mtd_priv, arg); + if (ret) { + ferr("ERROR: Failed to set boot img\n"); + } + } + + break; + case OTA_IMG_GET_ENCRYPTED: + if (mtd_priv->flags & PARTITION_FLAG_ENCRYPTED) { + *(int *)arg = 1; + } else { + *(int *)arg = 0; + } + + break; + case OTA_IMG_SET_ENCRYPTED: + if (arg) { + mtd_priv->flags |= PARTITION_FLAG_ENCRYPTED; + } else { + mtd_priv->flags &= ~PARTITION_FLAG_ENCRYPTED; } + break; + case OTA_IMG_GET_TYPE: + *(int *)arg = mtd_priv->type; + break; + case OTA_IMG_GET_SUBTYPE: + *(int *)arg = mtd_priv->subtype; + break; + case OTA_IMG_INVALIDATE_BOOT: { + ret = ota_invalidate_bootseq(mtd_priv, arg); + if (ret < 0) { + ferr("ERROR: Failed to invalidate boot img\n"); + } + } + + break; + case OTA_IMG_IS_MAPPED_AS_TEXT: { + bool *mapped = (bool *)arg; + + ret = is_currently_mapped_as_text(mtd_priv, mapped); + if (ret < 0) { + ferr("ERROR: Failed to check partition is mapped as text\n"); + } + } + + break; + case OTA_IMG_GET_OFFSET: + *(uint32_t *)arg = mtd_priv->offset; + break; + + default: { + ret = MTD_IOCTL(mtd_priv->mtd_ll, cmd, arg); + } break; + } + return ret; } @@ -735,10 +668,8 @@ static int esp32_part_ioctl(struct mtd_dev_s *dev, int cmd, ****************************************************************************/ static int partition_create_dev(const struct partition_info_priv *info, - bool encrypt, - struct mtd_dev_s *mtd, - struct mtd_dev_s *mtd_encrypt) -{ + bool encrypt, struct mtd_dev_s *mtd, + struct mtd_dev_s *mtd_encrypt) { int ret; uint32_t flags; struct mtd_dev_s *mtd_ll; @@ -746,29 +677,25 @@ static int partition_create_dev(const struct partition_info_priv *info, struct mtd_geometry_s geo; char path[PARTITION_MOUNTPTR_LEN_MAX]; - if (info->magic != PARTITION_MAGIC) - { - return -EINVAL; - } + if (info->magic != PARTITION_MAGIC) { + return -EINVAL; + } - snprintf(path, PARTITION_MOUNTPTR_LEN_MAX, "%s/%s", - g_path_base, info->label); + snprintf(path, PARTITION_MOUNTPTR_LEN_MAX, "%s/%s", g_path_base, info->label); /* If SPI Flash encryption is enable, "APP", "OTA data" and "NVS keys" are * force to set as encryption partition. */ flags = info->flags; - if (encrypt) - { - if ((info->type == PARTITION_TYPE_DATA && - info->subtype == PARTITION_SUBTYPE_DATA_OTA) || - (info->type == PARTITION_TYPE_DATA && - info->subtype == PARTITION_SUBTYPE_DATA_NVS_KEYS)) - { - flags |= PARTITION_FLAG_ENCRYPTED; - } + if (encrypt) { + if ((info->type == PARTITION_TYPE_DATA && + info->subtype == PARTITION_SUBTYPE_DATA_OTA) || + (info->type == PARTITION_TYPE_DATA && + info->subtype == PARTITION_SUBTYPE_DATA_NVS_KEYS)) { + flags |= PARTITION_FLAG_ENCRYPTED; } + } finfo("INFO: [label]: %s\n", info->label); finfo("INFO: [type]: %d\n", info->type); @@ -777,64 +704,55 @@ static int partition_create_dev(const struct partition_info_priv *info, finfo("INFO: [size]: 0x0x08%" PRIx32 "\n", info->size); finfo("INFO: [flags]: 0x0x08%" PRIx32 "\n", info->flags); finfo("INFO: [mount]: %s\n", path); - if (flags & PARTITION_FLAG_ENCRYPTED) - { - mtd_ll = mtd_encrypt; - finfo("INFO: [encrypted]\n\n"); - } - else - { - mtd_ll = mtd; - finfo("INFO: [no-encrypted]\n\n"); - } + if (flags & PARTITION_FLAG_ENCRYPTED) { + mtd_ll = mtd_encrypt; + finfo("INFO: [encrypted]\n\n"); + } else { + mtd_ll = mtd; + finfo("INFO: [no-encrypted]\n\n"); + } ret = MTD_IOCTL(mtd_ll, MTDIOC_GEOMETRY, (unsigned long)&geo); - if (ret < 0) - { - ferr("ERROR: Failed to get GEOMETRY from mtd_ll\n"); - return ret; - } + if (ret < 0) { + ferr("ERROR: Failed to get GEOMETRY from mtd_ll\n"); + return ret; + } mtd_priv = kmm_malloc(sizeof(struct mtd_dev_priv)); - if (!mtd_priv) - { - ferr("ERROR: Failed to allocate %d byte\n", - sizeof(struct mtd_dev_priv)); - return -ENOMEM; - } - - mtd_priv->offset = info->offset; - mtd_priv->size = info->size; - mtd_priv->type = info->type; + if (!mtd_priv) { + ferr("ERROR: Failed to allocate %d byte\n", sizeof(struct mtd_dev_priv)); + return -ENOMEM; + } + + mtd_priv->offset = info->offset; + mtd_priv->size = info->size; + mtd_priv->type = info->type; mtd_priv->subtype = info->subtype; - mtd_priv->flags = flags; - mtd_priv->mtd_ll = mtd_ll; + mtd_priv->flags = flags; + mtd_priv->mtd_ll = mtd_ll; memcpy(&mtd_priv->geo, &geo, sizeof(geo)); - mtd_priv->mtd.bread = esp32_part_bread; + mtd_priv->mtd.bread = esp32_part_bread; mtd_priv->mtd.bwrite = esp32_part_bwrite; - mtd_priv->mtd.erase = esp32_part_erase; - mtd_priv->mtd.ioctl = esp32_part_ioctl; - mtd_priv->mtd.read = esp32_part_read; - mtd_priv->mtd.write = esp32_part_write; - mtd_priv->mtd.name = mtd_priv->mtd_ll->name; - mtd_priv->mtd_part = mtd_partition(&mtd_priv->mtd, - info->offset / geo.blocksize, - info->size / geo.blocksize); - if (!mtd_priv->mtd_part) - { - ferr("ERROR: Failed to create MTD partition\n"); - kmm_free(mtd_priv); - return -ENOSPC; - } + mtd_priv->mtd.erase = esp32_part_erase; + mtd_priv->mtd.ioctl = esp32_part_ioctl; + mtd_priv->mtd.read = esp32_part_read; + mtd_priv->mtd.write = esp32_part_write; + mtd_priv->mtd.name = mtd_priv->mtd_ll->name; + mtd_priv->mtd_part = mtd_partition( + &mtd_priv->mtd, info->offset / geo.blocksize, info->size / geo.blocksize); + if (!mtd_priv->mtd_part) { + ferr("ERROR: Failed to create MTD partition\n"); + kmm_free(mtd_priv); + return -ENOSPC; + } ret = register_mtddriver(path, mtd_priv->mtd_part, 0777, mtd_priv); - if (ret < 0) - { - ferr("ERROR: Failed to register MTD @ %s\n", path); - kmm_free(mtd_priv); - return ret; - } + if (ret < 0) { + ferr("ERROR: Failed to register MTD @ %s\n", path); + kmm_free(mtd_priv); + return ret; + } return OK; } @@ -854,8 +772,7 @@ static int partition_create_dev(const struct partition_info_priv *info, * ****************************************************************************/ -static int partition_get_offset(const char *label, size_t size) -{ +static int partition_get_offset(const char *label, size_t size) { int i; int ret; uint8_t *pbuf; @@ -863,44 +780,37 @@ static int partition_get_offset(const char *label, size_t size) const struct partition_info_priv *info; DEBUGASSERT(label != NULL); struct mtd_dev_s *mtd = esp32_spiflash_encrypt_get_mtd(); - if (!mtd) - { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } pbuf = kmm_malloc(PARTITION_MAX_SIZE); - if (!pbuf) - { - ferr("ERROR: Failed to allocate %d byte\n", PARTITION_MAX_SIZE); - return -ENOMEM; - } - - ret = MTD_READ(mtd, PARTITION_TABLE_OFFSET, - PARTITION_MAX_SIZE, pbuf); - if (ret != PARTITION_MAX_SIZE) - { - ferr("ERROR: Failed to get read data from MTD\n"); - kmm_free(pbuf); - return -EIO; - } + if (!pbuf) { + ferr("ERROR: Failed to allocate %d byte\n", PARTITION_MAX_SIZE); + return -ENOMEM; + } + + ret = MTD_READ(mtd, PARTITION_TABLE_OFFSET, PARTITION_MAX_SIZE, pbuf); + if (ret != PARTITION_MAX_SIZE) { + ferr("ERROR: Failed to get read data from MTD\n"); + kmm_free(pbuf); + return -EIO; + } info = (struct partition_info_priv *)pbuf; - for (i = 0; i < PARTITION_MAX_NUM; i++) - { - if (memcmp(info[i].label, label, size) == 0) - { - partion_offset = info[i].offset; - break; - } + for (i = 0; i < PARTITION_MAX_NUM; i++) { + if (memcmp(info[i].label, label, size) == 0) { + partion_offset = info[i].offset; + break; } + } kmm_free(pbuf); - if (i == PARTITION_MAX_NUM) - { - ferr("ERROR: No %s partition is created\n", label); - return -EPERM; - } + if (i == PARTITION_MAX_NUM) { + ferr("ERROR: No %s partition is created\n", label); + return -EPERM; + } finfo("Get Partition offset: 0x%x\n", partion_offset); return partion_offset; @@ -925,8 +835,7 @@ static int partition_get_offset(const char *label, size_t size) * ****************************************************************************/ -int esp32_partition_init(void) -{ +int esp32_partition_init(void) { int i; int ret; uint8_t *pbuf; @@ -936,58 +845,50 @@ int esp32_partition_init(void) const struct partition_info_priv *info; mtd = esp32_spiflash_get_mtd(); - if (!mtd) - { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } mtd_encrypt = esp32_spiflash_encrypt_get_mtd(); - if (!mtd_encrypt) - { - ferr("ERROR: Failed to get SPI flash encrypted MTD\n"); - return -ENOSYS; - } + if (!mtd_encrypt) { + ferr("ERROR: Failed to get SPI flash encrypted MTD\n"); + return -ENOSYS; + } pbuf = kmm_malloc(PARTITION_MAX_SIZE); - if (!pbuf) - { - ferr("ERROR: Failed to allocate %d byte\n", PARTITION_MAX_SIZE); - return -ENOMEM; - } + if (!pbuf) { + ferr("ERROR: Failed to allocate %d byte\n", PARTITION_MAX_SIZE); + return -ENOMEM; + } /* Even without SPI Flash encryption, we can also use encrypted * MTD to read no-encrypted data. */ - ret = MTD_READ(mtd_encrypt, PARTITION_TABLE_OFFSET, - PARTITION_MAX_SIZE, pbuf); - if (ret != PARTITION_MAX_SIZE) - { - ferr("ERROR: Failed to get read data from MTD\n"); - kmm_free(pbuf); - return -EIO; - } + ret = MTD_READ(mtd_encrypt, PARTITION_TABLE_OFFSET, PARTITION_MAX_SIZE, pbuf); + if (ret != PARTITION_MAX_SIZE) { + ferr("ERROR: Failed to get read data from MTD\n"); + kmm_free(pbuf); + return -EIO; + } info = (struct partition_info_priv *)pbuf; encrypt = esp32_flash_encryption_enabled(); - for (i = 0; i < PARTITION_MAX_NUM; i++) - { - ret = partition_create_dev(&info[i], encrypt, mtd, mtd_encrypt); - if (ret != OK) - { - break; - } + for (i = 0; i < PARTITION_MAX_NUM; i++) { + ret = partition_create_dev(&info[i], encrypt, mtd, mtd_encrypt); + if (ret != OK) { + break; } + } kmm_free(pbuf); - if (i == 0) - { - ferr("ERROR: No partition is created\n"); - return -EPERM; - } + if (i == 0) { + ferr("ERROR: No partition is created\n"); + return -EPERM; + } return OK; } @@ -1010,32 +911,27 @@ int esp32_partition_init(void) ****************************************************************************/ int esp32_partition_read(const char *label, size_t offset, void *buf, - size_t size) -{ + size_t size) { int ret; int partion_offset; DEBUGASSERT(label != NULL && buf != NULL); struct mtd_dev_s *mtd = esp32_spiflash_get_mtd(); - if (!mtd) - { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } partion_offset = partition_get_offset(label, sizeof(label)); - if (partion_offset < 0) - { - ferr("ERROR: Failed to get partition: %s offset\n", label); - return partion_offset; - } + if (partion_offset < 0) { + ferr("ERROR: Failed to get partition: %s offset\n", label); + return partion_offset; + } - ret = MTD_READ(mtd, partion_offset + offset, - size, (uint8_t *)buf); - if (ret != size) - { - ferr("ERROR: Failed to get read data from MTD\n"); - return -EIO; - } + ret = MTD_READ(mtd, partion_offset + offset, size, (uint8_t *)buf); + if (ret != size) { + ferr("ERROR: Failed to get read data from MTD\n"); + return -EIO; + } return OK; } @@ -1058,34 +954,29 @@ int esp32_partition_read(const char *label, size_t offset, void *buf, ****************************************************************************/ int esp32_partition_read_decrypt(const char *label, size_t offset, void *buf, - size_t size) -{ + size_t size) { int ret; int partion_offset; DEBUGASSERT(label != NULL && buf != NULL); struct mtd_dev_s *mtd; partion_offset = partition_get_offset(label, strlen(label)); - if (partion_offset < 0) - { - ferr("ERROR: Failed to get partition: %s offset\n", label); - return partion_offset; - } + if (partion_offset < 0) { + ferr("ERROR: Failed to get partition: %s offset\n", label); + return partion_offset; + } mtd = esp32_spiflash_encrypt_get_mtd(); - if (!mtd) - { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } - ret = MTD_READ(mtd, partion_offset + offset, - size, (uint8_t *)buf); - if (ret != size) - { - ferr("ERROR: Failed to get read data from MTD\n"); - return -EIO; - } + ret = MTD_READ(mtd, partion_offset + offset, size, (uint8_t *)buf); + if (ret != size) { + ferr("ERROR: Failed to get read data from MTD\n"); + return -EIO; + } return OK; } @@ -1108,32 +999,27 @@ int esp32_partition_read_decrypt(const char *label, size_t offset, void *buf, ****************************************************************************/ int esp32_partition_write(const char *label, size_t offset, void *buf, - size_t size) -{ + size_t size) { int ret; int partion_offset; DEBUGASSERT(label != NULL && buf != NULL); struct mtd_dev_s *mtd = esp32_spiflash_get_mtd(); - if (!mtd) - { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } partion_offset = partition_get_offset(label, sizeof(label)); - if (partion_offset < 0) - { - ferr("ERROR: Failed to get partition: %s offset\n", label); - return partion_offset; - } - - ret = MTD_WRITE(mtd, partion_offset + offset, - size, (uint8_t *)buf); - if (ret != size) - { - ferr("ERROR: Failed to get read data from MTD\n"); - return -EIO; - } + if (partion_offset < 0) { + ferr("ERROR: Failed to get partition: %s offset\n", label); + return partion_offset; + } + + ret = MTD_WRITE(mtd, partion_offset + offset, size, (uint8_t *)buf); + if (ret != size) { + ferr("ERROR: Failed to get read data from MTD\n"); + return -EIO; + } return OK; } diff --git a/boards/xtensa/esp32/common/src/Make.defs b/boards/xtensa/esp32/common/src/Make.defs index 94fefc1e1e97d..54efd856d8dad 100644 --- a/boards/xtensa/esp32/common/src/Make.defs +++ b/boards/xtensa/esp32/common/src/Make.defs @@ -178,6 +178,8 @@ ifeq ($(CONFIG_ETC_ROMFS),y) RCSRCS = etc/init.d/rc.sysinit etc/init.d/rcS endif +CSRCS += esp32_boot_image.c + DEPPATH += --dep-path src VPATH += :src CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src diff --git a/boards/xtensa/esp32/common/src/esp32_boot_image.c b/boards/xtensa/esp32/common/src/esp32_boot_image.c new file mode 100644 index 0000000000000..7611123f32dcf --- /dev/null +++ b/boards/xtensa/esp32/common/src/esp32_boot_image.c @@ -0,0 +1,230 @@ +/**************************************************************************** + * boards/xtensa/esp32/common/src/esp32_boot_image.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "esp_app_format.h" +#include "esp_loader.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ESP32_APP_IMAGE_MAGIC 0xE9 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct esp32_boot_loader_args_s { + uint32_t entry_addr; + uint32_t drom_addr; + uint32_t drom_vaddr; + uint32_t drom_size; + uint32_t irom_addr; + uint32_t irom_vaddr; + uint32_t irom_size; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void IRAM_ATTR esp32_boot_loader_stub(void *arg); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_boot_loader_stub + * + * Description: + * This function resides in IRAM and is responsible for switching MMU + * mappings and jumping to the new application. + * + ****************************************************************************/ + +static void IRAM_ATTR esp32_boot_loader_stub(void *arg) { + struct esp32_boot_loader_args_s *args = + (struct esp32_boot_loader_args_s *)arg; + void (*entry_point)(void) = (void (*)(void))args->entry_addr; + + /* Disable interrupts */ + + up_irq_disable(); + + /* Disable cache */ + +#ifdef CONFIG_ARCH_CHIP_ESP32 + cache_read_disable(0); + cache_flush(0); +#else + cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); +#endif + + /* Map new segments */ + + map_rom_segments(args->drom_addr, args->drom_vaddr, args->drom_size, + args->irom_addr, args->irom_vaddr, args->irom_size); + + /* Jump to entry point */ + + entry_point(); + + /* Should never reach here */ + + while (1) { + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_boot_image + * + * Description: + * Boot a new application image. + * + * Input Parameters: + * path - Path to the image file/partition + * hdr_size - Size of the image header (unused for ESP32) + * + * Returned Value: + * Does not return on success; returns error code on failure. + * + ****************************************************************************/ + +int board_boot_image(FAR const char *path, uint32_t hdr_size) { + int fd; + int ret; + uint32_t offset; + esp_image_header_t image_header; + esp_image_segment_header_t segment_hdr; + struct esp32_boot_loader_args_s args = {0}; + uint32_t current_offset; + int i; + + /* Check for legacy format (not supported) */ + +#ifdef CONFIG_ESP32_APP_FORMAT_LEGACY + ferr("ERROR: Legacy format not supported for board_boot_image\n"); + return -ENOTSUP; +#endif + + /* Open the image file */ + + fd = open(path, O_RDONLY); + if (fd < 0) { + ferr("ERROR: Failed to open %s: %d\n", path, errno); + return -errno; + } + + /* Get partition offset */ + + ret = ioctl(fd, OTA_IMG_GET_OFFSET, (unsigned long)&offset); + if (ret < 0) { + ferr("ERROR: Failed to get partition offset: %d\n", errno); + close(fd); + return -errno; + } + + /* Read image header */ + + ret = read(fd, &image_header, sizeof(esp_image_header_t)); + if (ret != sizeof(esp_image_header_t)) { + ferr("ERROR: Failed to read image header: %d\n", errno); + close(fd); + return -errno; + } + + if (image_header.magic != ESP32_APP_IMAGE_MAGIC) { + ferr("ERROR: Invalid image magic: 0x%02x\n", image_header.magic); + close(fd); + return -EINVAL; + } + + args.entry_addr = image_header.entry_addr; + current_offset = sizeof(esp_image_header_t); + + /* Parse segments */ + + for (i = 0; i < image_header.segment_count; i++) { + ret = read(fd, &segment_hdr, sizeof(esp_image_segment_header_t)); + if (ret != sizeof(esp_image_segment_header_t)) { + ferr("ERROR: Failed to read segment header: %d\n", errno); + close(fd); + return -errno; + } + + /* Check for IROM/DROM segments */ + + if (segment_hdr.load_addr >= 0x3f400000 && + segment_hdr.load_addr < 0x3f800000) /* DROM */ + { + args.drom_addr = + offset + current_offset + sizeof(esp_image_segment_header_t); + args.drom_vaddr = segment_hdr.load_addr; + args.drom_size = segment_hdr.data_len; + } else if (segment_hdr.load_addr >= 0x400d0000 && + segment_hdr.load_addr < 0x40400000) /* IROM */ + { + args.irom_addr = + offset + current_offset + sizeof(esp_image_segment_header_t); + args.irom_vaddr = segment_hdr.load_addr; + args.irom_size = segment_hdr.data_len; + } + + current_offset += sizeof(esp_image_segment_header_t) + segment_hdr.data_len; + + /* Advance file pointer to next segment */ + + lseek(fd, segment_hdr.data_len, SEEK_CUR); + } + + close(fd); + + finfo("Booting image: entry=0x%08" PRIx32 ", drom=0x%08" PRIx32 + " (0x%08" PRIx32 "), irom=0x%08" PRIx32 " (0x%08" PRIx32 ")\n", + args.entry_addr, args.drom_vaddr, args.drom_size, args.irom_vaddr, + args.irom_size); + + /* Invoke IRAM loader stub */ + + esp32_boot_loader_stub(&args); + + return 0; +} From 38731ab84008326b50a406a7552a48284617d3c0 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Mon, 9 Feb 2026 18:49:08 +0530 Subject: [PATCH 02/16] boards/esp32: Fix checkpatch style errors in boot_image Fix coding style issues in esp32_boot_image.c reported by checkpatch.sh and nxstyle, including brace alignment and blank line usage. Signed-off-by: Aviral Garg --- .../esp32/common/src/esp32_boot_image.c | 135 ++++++++++-------- 1 file changed, 76 insertions(+), 59 deletions(-) diff --git a/boards/xtensa/esp32/common/src/esp32_boot_image.c b/boards/xtensa/esp32/common/src/esp32_boot_image.c index 7611123f32dcf..56e1551b589c5 100644 --- a/boards/xtensa/esp32/common/src/esp32_boot_image.c +++ b/boards/xtensa/esp32/common/src/esp32_boot_image.c @@ -34,8 +34,8 @@ #include #include -#include "esp_app_format.h" #include "esp_loader.h" +#include "esp_app_format.h" /**************************************************************************** * Pre-processor Definitions @@ -47,7 +47,8 @@ * Private Types ****************************************************************************/ -struct esp32_boot_loader_args_s { +struct esp32_boot_loader_args_s +{ uint32_t entry_addr; uint32_t drom_addr; uint32_t drom_vaddr; @@ -76,9 +77,10 @@ static void IRAM_ATTR esp32_boot_loader_stub(void *arg); * ****************************************************************************/ -static void IRAM_ATTR esp32_boot_loader_stub(void *arg) { +static void IRAM_ATTR esp32_boot_loader_stub(void *arg) +{ struct esp32_boot_loader_args_s *args = - (struct esp32_boot_loader_args_s *)arg; + (struct esp32_boot_loader_args_s *)arg; void (*entry_point)(void) = (void (*)(void))args->entry_addr; /* Disable interrupts */ @@ -105,8 +107,9 @@ static void IRAM_ATTR esp32_boot_loader_stub(void *arg) { /* Should never reach here */ - while (1) { - } + while (1) + { + } } /**************************************************************************** @@ -128,13 +131,18 @@ static void IRAM_ATTR esp32_boot_loader_stub(void *arg) { * ****************************************************************************/ -int board_boot_image(FAR const char *path, uint32_t hdr_size) { +int board_boot_image(FAR const char *path, uint32_t hdr_size) +{ int fd; int ret; uint32_t offset; esp_image_header_t image_header; esp_image_segment_header_t segment_hdr; - struct esp32_boot_loader_args_s args = {0}; + struct esp32_boot_loader_args_s args = + { + 0 + }; + uint32_t current_offset; int i; @@ -148,79 +156,88 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) { /* Open the image file */ fd = open(path, O_RDONLY); - if (fd < 0) { - ferr("ERROR: Failed to open %s: %d\n", path, errno); - return -errno; - } + if (fd < 0) + { + ferr("ERROR: Failed to open %s: %d\n", path, errno); + return -errno; + } /* Get partition offset */ ret = ioctl(fd, OTA_IMG_GET_OFFSET, (unsigned long)&offset); - if (ret < 0) { - ferr("ERROR: Failed to get partition offset: %d\n", errno); - close(fd); - return -errno; - } + if (ret < 0) + { + ferr("ERROR: Failed to get partition offset: %d\n", errno); + close(fd); + return -errno; + } /* Read image header */ ret = read(fd, &image_header, sizeof(esp_image_header_t)); - if (ret != sizeof(esp_image_header_t)) { - ferr("ERROR: Failed to read image header: %d\n", errno); - close(fd); - return -errno; - } - - if (image_header.magic != ESP32_APP_IMAGE_MAGIC) { - ferr("ERROR: Invalid image magic: 0x%02x\n", image_header.magic); - close(fd); - return -EINVAL; - } + if (ret != sizeof(esp_image_header_t)) + { + ferr("ERROR: Failed to read image header: %d\n", errno); + close(fd); + return -errno; + } + + if (image_header.magic != ESP32_APP_IMAGE_MAGIC) + { + ferr("ERROR: Invalid image magic: 0x%02x\n", image_header.magic); + close(fd); + return -EINVAL; + } args.entry_addr = image_header.entry_addr; current_offset = sizeof(esp_image_header_t); /* Parse segments */ - for (i = 0; i < image_header.segment_count; i++) { - ret = read(fd, &segment_hdr, sizeof(esp_image_segment_header_t)); - if (ret != sizeof(esp_image_segment_header_t)) { - ferr("ERROR: Failed to read segment header: %d\n", errno); - close(fd); - return -errno; - } - - /* Check for IROM/DROM segments */ - - if (segment_hdr.load_addr >= 0x3f400000 && - segment_hdr.load_addr < 0x3f800000) /* DROM */ + for (i = 0; i < image_header.segment_count; i++) { - args.drom_addr = - offset + current_offset + sizeof(esp_image_segment_header_t); - args.drom_vaddr = segment_hdr.load_addr; - args.drom_size = segment_hdr.data_len; - } else if (segment_hdr.load_addr >= 0x400d0000 && + ret = read(fd, &segment_hdr, sizeof(esp_image_segment_header_t)); + if (ret != sizeof(esp_image_segment_header_t)) + { + ferr("ERROR: Failed to read segment header: %d\n", errno); + close(fd); + return -errno; + } + + /* Check for IROM/DROM segments */ + + if (segment_hdr.load_addr >= 0x3f400000 && + segment_hdr.load_addr < 0x3f800000) /* DROM */ + { + args.drom_addr = + offset + current_offset + sizeof(esp_image_segment_header_t); + args.drom_vaddr = segment_hdr.load_addr; + args.drom_size = segment_hdr.data_len; + } + else if (segment_hdr.load_addr >= 0x400d0000 && segment_hdr.load_addr < 0x40400000) /* IROM */ - { - args.irom_addr = - offset + current_offset + sizeof(esp_image_segment_header_t); - args.irom_vaddr = segment_hdr.load_addr; - args.irom_size = segment_hdr.data_len; - } + { + args.irom_addr = + offset + current_offset + sizeof(esp_image_segment_header_t); + args.irom_vaddr = segment_hdr.load_addr; + args.irom_size = segment_hdr.data_len; + } - current_offset += sizeof(esp_image_segment_header_t) + segment_hdr.data_len; + current_offset += sizeof(esp_image_segment_header_t) + + segment_hdr.data_len; - /* Advance file pointer to next segment */ + /* Advance file pointer to next segment */ - lseek(fd, segment_hdr.data_len, SEEK_CUR); - } + lseek(fd, segment_hdr.data_len, SEEK_CUR); + } close(fd); - finfo("Booting image: entry=0x%08" PRIx32 ", drom=0x%08" PRIx32 - " (0x%08" PRIx32 "), irom=0x%08" PRIx32 " (0x%08" PRIx32 ")\n", - args.entry_addr, args.drom_vaddr, args.drom_size, args.irom_vaddr, - args.irom_size); + finfo("Booting image: entry=0x%08" PRIx32 "\n", args.entry_addr); + finfo(" drom=0x%08" PRIx32 " (0x%08" PRIx32 ")\n", + args.drom_vaddr, args.drom_size); + finfo(" irom=0x%08" PRIx32 " (0x%08" PRIx32 ")\n", + args.irom_vaddr, args.irom_size); /* Invoke IRAM loader stub */ From 151e36a0f0770ec13efbd94ee551a4859e910e49 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Mon, 9 Feb 2026 18:51:51 +0530 Subject: [PATCH 03/16] arch/esp32: Fix nxstyle errors in partition.h Fix coding style issues in partition.h reported by nxstyle, specifically correcting brace placement in enum definitions. Signed-off-by: Aviral Garg --- arch/xtensa/include/esp32/partition.h | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/arch/xtensa/include/esp32/partition.h b/arch/xtensa/include/esp32/partition.h index 7335b330ed6ff..360e4764290d3 100644 --- a/arch/xtensa/include/esp32/partition.h +++ b/arch/xtensa/include/esp32/partition.h @@ -33,24 +33,26 @@ /* OTA image operation code */ -enum ota_img_ctrl { - OTA_IMG_GET_BOOT = 0xe1, - OTA_IMG_SET_BOOT = 0xe2, - OTA_IMG_SET_ENCRYPTED = 0xe3, - OTA_IMG_GET_ENCRYPTED = 0xe4, - OTA_IMG_GET_TYPE = 0xe5, - OTA_IMG_GET_SUBTYPE = 0xe6, - OTA_IMG_INVALIDATE_BOOT = 0xe7, +enum ota_img_ctrl +{ + OTA_IMG_GET_BOOT = 0xe1, + OTA_IMG_SET_BOOT = 0xe2, + OTA_IMG_SET_ENCRYPTED = 0xe3, + OTA_IMG_GET_ENCRYPTED = 0xe4, + OTA_IMG_GET_TYPE = 0xe5, + OTA_IMG_GET_SUBTYPE = 0xe6, + OTA_IMG_INVALIDATE_BOOT = 0xe7, OTA_IMG_IS_MAPPED_AS_TEXT = 0xe8, - OTA_IMG_GET_OFFSET = 0xe9, + OTA_IMG_GET_OFFSET = 0xe9, }; /* OTA image boot sequency */ -enum ota_img_bootseq { +enum ota_img_bootseq +{ OTA_IMG_BOOT_FACTORY = 0, - OTA_IMG_BOOT_OTA_0 = 1, - OTA_IMG_BOOT_OTA_1 = 2, + OTA_IMG_BOOT_OTA_0 = 1, + OTA_IMG_BOOT_OTA_1 = 2, OTA_IMG_BOOT_SEQ_MAX }; From c065fd212fa302e757a53a079f38d14ef5fd7f2f Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Mon, 9 Feb 2026 18:59:56 +0530 Subject: [PATCH 04/16] arch/esp32: Fix nxstyle errors and reset partition.c This commit fixes the style issues in the ESP32 boot image implementation: - Reset esp32_partition.c to upstream master to fix extensive formatting issues - Add minimal OTA_IMG_GET_OFFSET ioctl case with correct NuttX style - esp32_boot_image.c and partition.h already fixed in previous commits Signed-off-by: Aviral Garg Signed-off-by: aviralgarg05 --- arch/xtensa/src/esp32/esp32_partition.c | 887 ++++++++++-------- boards/xtensa/esp32/common/src/Make.defs | 4 +- .../esp32/common/src/esp32_boot_image.c | 17 +- 3 files changed, 516 insertions(+), 392 deletions(-) diff --git a/arch/xtensa/src/esp32/esp32_partition.c b/arch/xtensa/src/esp32/esp32_partition.c index 1d9e0a386ee16..80a10a2237e24 100644 --- a/arch/xtensa/src/esp32/esp32_partition.c +++ b/arch/xtensa/src/esp32/esp32_partition.c @@ -24,18 +24,18 @@ #include -#include -#include #include -#include #include #include +#include +#include +#include #include -#include "arch/esp32/partition.h" -#include "esp32_partition.h" #include "esp32_spiflash.h" +#include "esp32_partition.h" +#include "arch/esp32/partition.h" /**************************************************************************** * Pre-processor Definitions @@ -43,28 +43,28 @@ /* Partition table max size */ -#define PARTITION_MAX_SIZE (0xc00) +#define PARTITION_MAX_SIZE (0xc00) /* Partition max number */ -#define PARTITION_MAX_NUM \ - (PARTITION_MAX_SIZE / sizeof(struct partition_info_priv)) +#define PARTITION_MAX_NUM (PARTITION_MAX_SIZE / \ + sizeof(struct partition_info_priv)) /* Partition table header magic value */ -#define PARTITION_MAGIC (0x50aa) +#define PARTITION_MAGIC (0x50aa) /* Partition table member label length */ -#define PARTITION_LABEL_LEN (16) +#define PARTITION_LABEL_LEN (16) /* OTA data offset in OTA partition */ -#define OTA_DATA_OFFSET (4096) +#define OTA_DATA_OFFSET (4096) /* OTA data number */ -#define OTA_DATA_NUM (2) +#define OTA_DATA_NUM (2) /* Partition offset in SPI Flash */ @@ -76,11 +76,12 @@ /* Partition mount pointer max length */ -#define PARTITION_MOUNTPTR_LEN_MAX (PARTITION_LABEL_LEN + sizeof(g_path_base)) +#define PARTITION_MOUNTPTR_LEN_MAX (PARTITION_LABEL_LEN + \ + sizeof(g_path_base)) /* Partition encrypted flag */ -#define PARTITION_FLAG_ENCRYPTED (1 << 0) +#define PARTITION_FLAG_ENCRYPTED (1 << 0) /**************************************************************************** * Private Types @@ -88,14 +89,15 @@ /* OTA image state */ -enum ota_img_state { +enum ota_img_state +{ /* Monitor the first boot. In bootloader of esp-idf this state is changed * to ESP_OTA_IMG_PENDING_VERIFY if this bootloader enable app rollback. * * So this driver doesn't use this state currently. */ - OTA_IMG_NEW = 0x0, + OTA_IMG_NEW = 0x0, /* First boot for this app was. If while the second boot this state is then * it will be changed to ABORTED if this bootloader enable app rollback. @@ -103,15 +105,15 @@ enum ota_img_state { * So this driver doesn't use this state currently. */ - OTA_IMG_PENDING_VERIFY = 0x1, + OTA_IMG_PENDING_VERIFY = 0x1, /* App was confirmed as workable. App can boot and work without limits. */ - OTA_IMG_VALID = 0x2, + OTA_IMG_VALID = 0x2, /* App was confirmed as non-workable. This app will not selected to boot. */ - OTA_IMG_INVALID = 0x3, + OTA_IMG_INVALID = 0x3, /* App could not confirm the workable or non-workable. In bootloader * IMG_PENDING_VERIFY state will be changed to IMG_ABORTED. This app will @@ -120,56 +122,59 @@ enum ota_img_state { * So this driver doesn't use this state currently. */ - OTA_IMG_ABORTED = 0x4, + OTA_IMG_ABORTED = 0x4, /* Undefined. App can boot and work without limits in esp-idf. * * This state is not used. */ - OTA_IMG_UNDEFINED = 0xffffffff, + OTA_IMG_UNDEFINED = 0xffffffff, }; /* Partition information data */ -struct partition_info_priv { - uint16_t magic; /* Partition magic */ - uint8_t type; /* Partition type */ - uint8_t subtype; /* Partition sub-type */ +struct partition_info_priv +{ + uint16_t magic; /* Partition magic */ + uint8_t type; /* Partition type */ + uint8_t subtype; /* Partition sub-type */ - uint32_t offset; /* Offset in SPI Flash */ - uint32_t size; /* Size by byte */ + uint32_t offset; /* Offset in SPI Flash */ + uint32_t size; /* Size by byte */ - uint8_t label[PARTITION_LABEL_LEN]; /* Partition label */ + uint8_t label[PARTITION_LABEL_LEN]; /* Partition label */ - uint32_t flags; /* Partition flags */ + uint32_t flags; /* Partition flags */ }; /* Partition device data */ -struct mtd_dev_priv { - struct mtd_dev_s mtd; /* MTD data */ +struct mtd_dev_priv +{ + struct mtd_dev_s mtd; /* MTD data */ - uint8_t type; /* Partition type */ - uint8_t subtype; /* Partition sub-type */ - uint32_t flags; /* Partition flags */ - uint32_t offset; /* Partition offset in SPI Flash */ - uint32_t size; /* Partition size in SPI Flash */ + uint8_t type; /* Partition type */ + uint8_t subtype; /* Partition sub-type */ + uint32_t flags; /* Partition flags */ + uint32_t offset; /* Partition offset in SPI Flash */ + uint32_t size; /* Partition size in SPI Flash */ - struct mtd_dev_s *mtd_ll; /* Low-level MTD data */ + struct mtd_dev_s *mtd_ll; /* Low-level MTD data */ - struct mtd_dev_s *mtd_part; /* MTD partition device */ + struct mtd_dev_s *mtd_part; /* MTD partition device */ - struct mtd_geometry_s geo; /* Partition geometry information */ + struct mtd_geometry_s geo; /* Partition geometry information */ }; /* OTA data entry */ -struct ota_data_entry { - uint32_t ota_seq; /* Boot sequence */ - uint8_t seq_label[20]; /* Boot sequence label */ - uint32_t ota_state; /* Boot entry state */ - uint32_t crc; /* Boot ota_seq CRC32 */ +struct ota_data_entry +{ + uint32_t ota_seq; /* Boot sequence */ + uint8_t seq_label[20]; /* Boot sequence label */ + uint32_t ota_state; /* Boot entry state */ + uint32_t crc; /* Boot ota_seq CRC32 */ }; /**************************************************************************** @@ -198,12 +203,14 @@ const char g_path_base[] = PARTITION_MOUNT_POINT; * ****************************************************************************/ -static bool ota_is_valid(struct ota_data_entry *ota_data) { +static bool ota_is_valid(struct ota_data_entry *ota_data) +{ if ((ota_data->ota_seq == UINT32_MAX) || (ota_data->ota_state != OTA_IMG_VALID) || - (ota_data->crc != crc32_le(UINT32_MAX, (uint8_t *)ota_data, 4))) { - return false; - } + (ota_data->crc != crc32_le(UINT32_MAX, (uint8_t *)ota_data, 4))) + { + return false; + } return true; } @@ -223,7 +230,8 @@ static bool ota_is_valid(struct ota_data_entry *ota_data) { * ****************************************************************************/ -static int ota_get_bootseq(struct mtd_dev_priv *dev, uint32_t *seqptr) { +static int ota_get_bootseq(struct mtd_dev_priv *dev, uint32_t *seqptr) +{ int i; int ret; uint32_t seq = 0; @@ -232,30 +240,37 @@ static int ota_get_bootseq(struct mtd_dev_priv *dev, uint32_t *seqptr) { /* Each OTA data locates in independent sector */ - for (i = 0; i < OTA_DATA_NUM; i++) { - ret = MTD_READ(dev->mtd_part, i * dev->geo.erasesize, size, - (uint8_t *)&ota_data); - if (ret != size) { - ferr("ERROR: Failed to read OTA%d data error=%d\n", i, ret); - return -EIO; + for (i = 0; i < OTA_DATA_NUM; i++) + { + ret = MTD_READ(dev->mtd_part, i * dev->geo.erasesize, + size, (uint8_t *)&ota_data); + if (ret != size) + { + ferr("ERROR: Failed to read OTA%d data error=%d\n", i, ret); + return -EIO; + } + + if (ota_is_valid(&ota_data)) + { + seq = MAX(seq, ota_data.ota_seq); + } } - if (ota_is_valid(&ota_data)) { - seq = MAX(seq, ota_data.ota_seq); - } - } - finfo("seq=%" PRIu32 "\n", seq); - if (seq > 0) { - ret = (seq - 1) % OTA_DATA_NUM + OTA_IMG_BOOT_OTA_0; - } else { - ret = OTA_IMG_BOOT_FACTORY; - } + if (seq > 0) + { + ret = (seq - 1) % OTA_DATA_NUM + OTA_IMG_BOOT_OTA_0; + } + else + { + ret = OTA_IMG_BOOT_FACTORY; + } - if (seqptr) { - *seqptr = seq; - } + if (seqptr) + { + *seqptr = seq; + } return ret; } @@ -275,7 +290,8 @@ static int ota_get_bootseq(struct mtd_dev_priv *dev, uint32_t *seqptr) { * ****************************************************************************/ -static int ota_set_bootseq(struct mtd_dev_priv *dev, int num) { +static int ota_set_bootseq(struct mtd_dev_priv *dev, int num) +{ int ret; int size; uint8_t *buffer; @@ -287,84 +303,105 @@ static int ota_set_bootseq(struct mtd_dev_priv *dev, int num) { finfo("INFO: num=%d\n", num); - switch (num) { - case OTA_IMG_BOOT_FACTORY: - - /* Erase all OTA data to force use factory app */ - - ret = MTD_ERASE(dev->mtd_part, 0, OTA_DATA_NUM); - if (ret != OTA_DATA_NUM) { - ferr("ERROR: Failed to erase OTA data error=%d\n", ret); - return -1; - } - - break; - case OTA_IMG_BOOT_OTA_0: - case OTA_IMG_BOOT_OTA_1: - ret = ota_get_bootseq(dev, &next_seq); - if (ret < 0) { - ferr("ERROR: Failed to get boot sequence error=%d\n", ret); - return ret; - } else if (ret == num) { - /* the requested num is already set as next boot partition */ - - return OK; - } else if (ret == OTA_IMG_BOOT_FACTORY) { - next_seq = (uint32_t)num; - } else { - next_seq++; - } - - sec = num - OTA_IMG_BOOT_OTA_0; - - ret = MTD_ERASE(dev->mtd_part, sec, 1); - if (ret != 1) { - ferr("ERROR: Failed to erase OTA%" PRId32 "data error=%d\n", sec, ret); - return -EIO; - } - - ota_data.ota_state = OTA_IMG_VALID; - ota_data.ota_seq = next_seq; - ota_data.crc = crc32_le(UINT32_MAX, (uint8_t *)&ota_data, 4); - - if (dev->flags & PARTITION_FLAG_ENCRYPTED) { - blkcnt = sizeof(struct ota_data_entry) / dev->geo.blocksize; - size = sizeof(struct ota_data_entry) % dev->geo.blocksize; - if (size) { - blkcnt++; - } - - size = blkcnt * dev->geo.blocksize; - buffer = kmm_malloc(size); - if (!buffer) { - ferr("ERROR:Failed to allocate %d bytes\n", size); - return -ENOMEM; - } - - memcpy(buffer, &ota_data, sizeof(struct ota_data_entry)); - - blk = sec * dev->geo.erasesize / dev->geo.blocksize; - ret = MTD_BWRITE(dev->mtd_part, blk, blkcnt, buffer); - kmm_free(buffer); - if (ret != blkcnt) { - ferr("ERROR: Failed to write OTA%" PRId32 "data error=%d\n", sec, ret); - return -EIO; - } - } else { - ret = MTD_WRITE(dev->mtd_part, sec * dev->geo.erasesize, - sizeof(struct ota_data_entry), (uint8_t *)&ota_data); - if (ret != sizeof(struct ota_data_entry)) { - ferr("ERROR: Failed to write OTA%" PRId32 "data error=%d\n", sec, ret); - return -1; - } + switch (num) + { + case OTA_IMG_BOOT_FACTORY: + + /* Erase all OTA data to force use factory app */ + + ret = MTD_ERASE(dev->mtd_part, 0, OTA_DATA_NUM); + if (ret != OTA_DATA_NUM) + { + ferr("ERROR: Failed to erase OTA data error=%d\n", ret); + return -1; + } + + break; + case OTA_IMG_BOOT_OTA_0: + case OTA_IMG_BOOT_OTA_1: + ret = ota_get_bootseq(dev, &next_seq); + if (ret < 0) + { + ferr("ERROR: Failed to get boot sequence error=%d\n", ret); + return ret; + } + else if (ret == num) + { + /* the requested num is already set as next boot partition */ + + return OK; + } + else if (ret == OTA_IMG_BOOT_FACTORY) + { + next_seq = (uint32_t)num; + } + else + { + next_seq++; + } + + sec = num - OTA_IMG_BOOT_OTA_0; + + ret = MTD_ERASE(dev->mtd_part, sec, 1); + if (ret != 1) + { + ferr("ERROR: Failed to erase OTA%" PRId32 "data error=%d\n", + sec, ret); + return -EIO; + } + + ota_data.ota_state = OTA_IMG_VALID; + ota_data.ota_seq = next_seq; + ota_data.crc = crc32_le(UINT32_MAX, (uint8_t *)&ota_data, 4); + + if (dev->flags & PARTITION_FLAG_ENCRYPTED) + { + blkcnt = sizeof(struct ota_data_entry) / dev->geo.blocksize; + size = sizeof(struct ota_data_entry) % dev->geo.blocksize; + if (size) + { + blkcnt++; + } + + size = blkcnt * dev->geo.blocksize; + buffer = kmm_malloc(size); + if (!buffer) + { + ferr("ERROR:Failed to allocate %d bytes\n", size); + return -ENOMEM; + } + + memcpy(buffer, &ota_data, sizeof(struct ota_data_entry)); + + blk = sec * dev->geo.erasesize / dev->geo.blocksize; + ret = MTD_BWRITE(dev->mtd_part, blk, blkcnt, buffer); + kmm_free(buffer); + if (ret != blkcnt) + { + ferr("ERROR: Failed to write OTA%" PRId32 "data error=%d\n", + sec, ret); + return -EIO; + } + } + else + { + ret = MTD_WRITE(dev->mtd_part, sec * dev->geo.erasesize, + sizeof(struct ota_data_entry), + (uint8_t *)&ota_data); + if (ret != sizeof(struct ota_data_entry)) + { + ferr("ERROR: Failed to write OTA%" PRId32 "data error=%d\n", + sec, ret); + return -1; + } + } + + break; + default: + ferr("ERROR: num=%d is error\n", num); + return -EINVAL; } - break; - default: - ferr("ERROR: num=%d is error\n", num); - return -EINVAL; - } - return OK; } @@ -383,26 +420,30 @@ static int ota_set_bootseq(struct mtd_dev_priv *dev, int num) { * ****************************************************************************/ -static int ota_invalidate_bootseq(struct mtd_dev_priv *dev, int num) { +static int ota_invalidate_bootseq(struct mtd_dev_priv *dev, int num) +{ int ret; uint32_t sec; finfo("INFO: num=%d\n", num); - switch (num) { - case OTA_IMG_BOOT_OTA_0: - case OTA_IMG_BOOT_OTA_1: - sec = num - OTA_IMG_BOOT_OTA_0; - ret = MTD_ERASE(dev->mtd_part, sec, 1); - if (ret != 1) { - ferr("ERROR: Failed to erase OTA%" PRId32 "data error=%d\n", sec, ret); - return -EIO; + switch (num) + { + case OTA_IMG_BOOT_OTA_0: + case OTA_IMG_BOOT_OTA_1: + sec = num - OTA_IMG_BOOT_OTA_0; + ret = MTD_ERASE(dev->mtd_part, sec, 1); + if (ret != 1) + { + ferr("ERROR: Failed to erase OTA%" PRId32 "data error=%d\n", + sec, ret); + return -EIO; + } + + break; + default: + ferr("ERROR: num=%d is error\n", num); + return -EINVAL; } - break; - default: - ferr("ERROR: num=%d is error\n", num); - return -EINVAL; - } - return OK; } @@ -421,13 +462,16 @@ static int ota_invalidate_bootseq(struct mtd_dev_priv *dev, int num) { * ****************************************************************************/ -static int is_currently_mapped_as_text(struct mtd_dev_priv *dev, bool *mapped) { +static int is_currently_mapped_as_text(struct mtd_dev_priv *dev, + bool *mapped) +{ uint32_t currently_mapped_address; - if (mapped == NULL) { - ferr("ERROR: Invalid argument.\n"); - return -EINVAL; - } + if (mapped == NULL) + { + ferr("ERROR: Invalid argument.\n"); + return -EINVAL; + } currently_mapped_address = esp32_get_flash_address_mapped_as_text(); @@ -454,7 +498,8 @@ static int is_currently_mapped_as_text(struct mtd_dev_priv *dev, bool *mapped) { ****************************************************************************/ static int esp32_part_erase(struct mtd_dev_s *dev, off_t startblock, - size_t nblocks) { + size_t nblocks) +{ struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_ERASE(mtd_priv->mtd_ll, startblock, nblocks); @@ -478,7 +523,8 @@ static int esp32_part_erase(struct mtd_dev_s *dev, off_t startblock, ****************************************************************************/ static ssize_t esp32_part_read(struct mtd_dev_s *dev, off_t offset, - size_t nbytes, uint8_t *buffer) { + size_t nbytes, uint8_t *buffer) +{ struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_READ(mtd_priv->mtd_ll, offset, nbytes, buffer); @@ -502,7 +548,8 @@ static ssize_t esp32_part_read(struct mtd_dev_s *dev, off_t offset, ****************************************************************************/ static ssize_t esp32_part_bread(struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, uint8_t *buffer) { + size_t nblocks, uint8_t *buffer) +{ struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_BREAD(mtd_priv->mtd_ll, startblock, nblocks, buffer); @@ -526,7 +573,8 @@ static ssize_t esp32_part_bread(struct mtd_dev_s *dev, off_t startblock, ****************************************************************************/ static ssize_t esp32_part_write(struct mtd_dev_s *dev, off_t offset, - size_t nbytes, const uint8_t *buffer) { + size_t nbytes, const uint8_t *buffer) +{ struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_WRITE(mtd_priv->mtd_ll, offset, nbytes, buffer); @@ -551,7 +599,8 @@ static ssize_t esp32_part_write(struct mtd_dev_s *dev, off_t offset, ****************************************************************************/ static ssize_t esp32_part_bwrite(struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, const uint8_t *buffer) { + size_t nblocks, const uint8_t *buffer) +{ struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; return MTD_BWRITE(mtd_priv->mtd_ll, startblock, nblocks, buffer); @@ -573,80 +622,101 @@ static ssize_t esp32_part_bwrite(struct mtd_dev_s *dev, off_t startblock, * ****************************************************************************/ -static int esp32_part_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg) { +static int esp32_part_ioctl(struct mtd_dev_s *dev, int cmd, + unsigned long arg) +{ int ret = OK; struct mtd_dev_priv *mtd_priv = (struct mtd_dev_priv *)dev; finfo("INFO: cmd=%d(%x) arg=%" PRIx32 "\n", cmd, cmd, arg); - switch (_IOC_NR(cmd)) { - case OTA_IMG_GET_BOOT: { - ret = ota_get_bootseq(mtd_priv, NULL); - if (ret < 0) { - ferr("ERROR: Failed to get boot img\n"); - } else { - *(int *)arg = ret; - } - } - - break; - case OTA_IMG_SET_BOOT: { - ret = ota_set_bootseq(mtd_priv, arg); - if (ret) { - ferr("ERROR: Failed to set boot img\n"); - } - } - - break; - case OTA_IMG_GET_ENCRYPTED: - if (mtd_priv->flags & PARTITION_FLAG_ENCRYPTED) { - *(int *)arg = 1; - } else { - *(int *)arg = 0; - } - - break; - case OTA_IMG_SET_ENCRYPTED: - if (arg) { - mtd_priv->flags |= PARTITION_FLAG_ENCRYPTED; - } else { - mtd_priv->flags &= ~PARTITION_FLAG_ENCRYPTED; + switch (_IOC_NR(cmd)) + { + case OTA_IMG_GET_BOOT: + { + ret = ota_get_bootseq(mtd_priv, NULL); + if (ret < 0) + { + ferr("ERROR: Failed to get boot img\n"); + } + else + { + *(int *)arg = ret; + } + } + + break; + case OTA_IMG_SET_BOOT: + { + ret = ota_set_bootseq(mtd_priv, arg); + if (ret) + { + ferr("ERROR: Failed to set boot img\n"); + } + } + + break; + case OTA_IMG_GET_ENCRYPTED: + if (mtd_priv->flags & PARTITION_FLAG_ENCRYPTED) + { + *(int *)arg = 1; + } + else + { + *(int *)arg = 0; + } + + break; + case OTA_IMG_SET_ENCRYPTED: + if (arg) + { + mtd_priv->flags |= PARTITION_FLAG_ENCRYPTED; + } + else + { + mtd_priv->flags &= ~PARTITION_FLAG_ENCRYPTED; + } + + break; + case OTA_IMG_GET_TYPE: + *(int *)arg = mtd_priv->type; + break; + case OTA_IMG_GET_SUBTYPE: + *(int *)arg = mtd_priv->subtype; + break; + case OTA_IMG_INVALIDATE_BOOT: + { + ret = ota_invalidate_bootseq(mtd_priv, arg); + if (ret < 0) + { + ferr("ERROR: Failed to invalidate boot img\n"); + } + } + + break; + case OTA_IMG_IS_MAPPED_AS_TEXT: + { + bool *mapped = (bool *)arg; + + ret = is_currently_mapped_as_text(mtd_priv, mapped); + if (ret < 0) + { + ferr("ERROR: Failed to check partition is mapped as text\n"); + } + } + + break; + case OTA_IMG_GET_OFFSET: + *(uint32_t *)arg = mtd_priv->offset; + break; + default: + { + ret = MTD_IOCTL(mtd_priv->mtd_ll, cmd, arg); + } + + break; } - break; - case OTA_IMG_GET_TYPE: - *(int *)arg = mtd_priv->type; - break; - case OTA_IMG_GET_SUBTYPE: - *(int *)arg = mtd_priv->subtype; - break; - case OTA_IMG_INVALIDATE_BOOT: { - ret = ota_invalidate_bootseq(mtd_priv, arg); - if (ret < 0) { - ferr("ERROR: Failed to invalidate boot img\n"); - } - } - - break; - case OTA_IMG_IS_MAPPED_AS_TEXT: { - bool *mapped = (bool *)arg; - - ret = is_currently_mapped_as_text(mtd_priv, mapped); - if (ret < 0) { - ferr("ERROR: Failed to check partition is mapped as text\n"); - } - } - - break; - case OTA_IMG_GET_OFFSET: - *(uint32_t *)arg = mtd_priv->offset; - break; - - default: { - ret = MTD_IOCTL(mtd_priv->mtd_ll, cmd, arg); - } break; - } - return ret; } @@ -668,8 +738,10 @@ static int esp32_part_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg) { ****************************************************************************/ static int partition_create_dev(const struct partition_info_priv *info, - bool encrypt, struct mtd_dev_s *mtd, - struct mtd_dev_s *mtd_encrypt) { + bool encrypt, + struct mtd_dev_s *mtd, + struct mtd_dev_s *mtd_encrypt) +{ int ret; uint32_t flags; struct mtd_dev_s *mtd_ll; @@ -677,25 +749,29 @@ static int partition_create_dev(const struct partition_info_priv *info, struct mtd_geometry_s geo; char path[PARTITION_MOUNTPTR_LEN_MAX]; - if (info->magic != PARTITION_MAGIC) { - return -EINVAL; - } + if (info->magic != PARTITION_MAGIC) + { + return -EINVAL; + } - snprintf(path, PARTITION_MOUNTPTR_LEN_MAX, "%s/%s", g_path_base, info->label); + snprintf(path, PARTITION_MOUNTPTR_LEN_MAX, "%s/%s", + g_path_base, info->label); /* If SPI Flash encryption is enable, "APP", "OTA data" and "NVS keys" are * force to set as encryption partition. */ flags = info->flags; - if (encrypt) { - if ((info->type == PARTITION_TYPE_DATA && - info->subtype == PARTITION_SUBTYPE_DATA_OTA) || - (info->type == PARTITION_TYPE_DATA && - info->subtype == PARTITION_SUBTYPE_DATA_NVS_KEYS)) { - flags |= PARTITION_FLAG_ENCRYPTED; + if (encrypt) + { + if ((info->type == PARTITION_TYPE_DATA && + info->subtype == PARTITION_SUBTYPE_DATA_OTA) || + (info->type == PARTITION_TYPE_DATA && + info->subtype == PARTITION_SUBTYPE_DATA_NVS_KEYS)) + { + flags |= PARTITION_FLAG_ENCRYPTED; + } } - } finfo("INFO: [label]: %s\n", info->label); finfo("INFO: [type]: %d\n", info->type); @@ -704,55 +780,64 @@ static int partition_create_dev(const struct partition_info_priv *info, finfo("INFO: [size]: 0x0x08%" PRIx32 "\n", info->size); finfo("INFO: [flags]: 0x0x08%" PRIx32 "\n", info->flags); finfo("INFO: [mount]: %s\n", path); - if (flags & PARTITION_FLAG_ENCRYPTED) { - mtd_ll = mtd_encrypt; - finfo("INFO: [encrypted]\n\n"); - } else { - mtd_ll = mtd; - finfo("INFO: [no-encrypted]\n\n"); - } + if (flags & PARTITION_FLAG_ENCRYPTED) + { + mtd_ll = mtd_encrypt; + finfo("INFO: [encrypted]\n\n"); + } + else + { + mtd_ll = mtd; + finfo("INFO: [no-encrypted]\n\n"); + } ret = MTD_IOCTL(mtd_ll, MTDIOC_GEOMETRY, (unsigned long)&geo); - if (ret < 0) { - ferr("ERROR: Failed to get GEOMETRY from mtd_ll\n"); - return ret; - } + if (ret < 0) + { + ferr("ERROR: Failed to get GEOMETRY from mtd_ll\n"); + return ret; + } mtd_priv = kmm_malloc(sizeof(struct mtd_dev_priv)); - if (!mtd_priv) { - ferr("ERROR: Failed to allocate %d byte\n", sizeof(struct mtd_dev_priv)); - return -ENOMEM; - } - - mtd_priv->offset = info->offset; - mtd_priv->size = info->size; - mtd_priv->type = info->type; + if (!mtd_priv) + { + ferr("ERROR: Failed to allocate %d byte\n", + sizeof(struct mtd_dev_priv)); + return -ENOMEM; + } + + mtd_priv->offset = info->offset; + mtd_priv->size = info->size; + mtd_priv->type = info->type; mtd_priv->subtype = info->subtype; - mtd_priv->flags = flags; - mtd_priv->mtd_ll = mtd_ll; + mtd_priv->flags = flags; + mtd_priv->mtd_ll = mtd_ll; memcpy(&mtd_priv->geo, &geo, sizeof(geo)); - mtd_priv->mtd.bread = esp32_part_bread; + mtd_priv->mtd.bread = esp32_part_bread; mtd_priv->mtd.bwrite = esp32_part_bwrite; - mtd_priv->mtd.erase = esp32_part_erase; - mtd_priv->mtd.ioctl = esp32_part_ioctl; - mtd_priv->mtd.read = esp32_part_read; - mtd_priv->mtd.write = esp32_part_write; - mtd_priv->mtd.name = mtd_priv->mtd_ll->name; - mtd_priv->mtd_part = mtd_partition( - &mtd_priv->mtd, info->offset / geo.blocksize, info->size / geo.blocksize); - if (!mtd_priv->mtd_part) { - ferr("ERROR: Failed to create MTD partition\n"); - kmm_free(mtd_priv); - return -ENOSPC; - } + mtd_priv->mtd.erase = esp32_part_erase; + mtd_priv->mtd.ioctl = esp32_part_ioctl; + mtd_priv->mtd.read = esp32_part_read; + mtd_priv->mtd.write = esp32_part_write; + mtd_priv->mtd.name = mtd_priv->mtd_ll->name; + mtd_priv->mtd_part = mtd_partition(&mtd_priv->mtd, + info->offset / geo.blocksize, + info->size / geo.blocksize); + if (!mtd_priv->mtd_part) + { + ferr("ERROR: Failed to create MTD partition\n"); + kmm_free(mtd_priv); + return -ENOSPC; + } ret = register_mtddriver(path, mtd_priv->mtd_part, 0777, mtd_priv); - if (ret < 0) { - ferr("ERROR: Failed to register MTD @ %s\n", path); - kmm_free(mtd_priv); - return ret; - } + if (ret < 0) + { + ferr("ERROR: Failed to register MTD @ %s\n", path); + kmm_free(mtd_priv); + return ret; + } return OK; } @@ -772,7 +857,8 @@ static int partition_create_dev(const struct partition_info_priv *info, * ****************************************************************************/ -static int partition_get_offset(const char *label, size_t size) { +static int partition_get_offset(const char *label, size_t size) +{ int i; int ret; uint8_t *pbuf; @@ -780,37 +866,44 @@ static int partition_get_offset(const char *label, size_t size) { const struct partition_info_priv *info; DEBUGASSERT(label != NULL); struct mtd_dev_s *mtd = esp32_spiflash_encrypt_get_mtd(); - if (!mtd) { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) + { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } pbuf = kmm_malloc(PARTITION_MAX_SIZE); - if (!pbuf) { - ferr("ERROR: Failed to allocate %d byte\n", PARTITION_MAX_SIZE); - return -ENOMEM; - } - - ret = MTD_READ(mtd, PARTITION_TABLE_OFFSET, PARTITION_MAX_SIZE, pbuf); - if (ret != PARTITION_MAX_SIZE) { - ferr("ERROR: Failed to get read data from MTD\n"); - kmm_free(pbuf); - return -EIO; - } + if (!pbuf) + { + ferr("ERROR: Failed to allocate %d byte\n", PARTITION_MAX_SIZE); + return -ENOMEM; + } + + ret = MTD_READ(mtd, PARTITION_TABLE_OFFSET, + PARTITION_MAX_SIZE, pbuf); + if (ret != PARTITION_MAX_SIZE) + { + ferr("ERROR: Failed to get read data from MTD\n"); + kmm_free(pbuf); + return -EIO; + } info = (struct partition_info_priv *)pbuf; - for (i = 0; i < PARTITION_MAX_NUM; i++) { - if (memcmp(info[i].label, label, size) == 0) { - partion_offset = info[i].offset; - break; + for (i = 0; i < PARTITION_MAX_NUM; i++) + { + if (memcmp(info[i].label, label, size) == 0) + { + partion_offset = info[i].offset; + break; + } } - } kmm_free(pbuf); - if (i == PARTITION_MAX_NUM) { - ferr("ERROR: No %s partition is created\n", label); - return -EPERM; - } + if (i == PARTITION_MAX_NUM) + { + ferr("ERROR: No %s partition is created\n", label); + return -EPERM; + } finfo("Get Partition offset: 0x%x\n", partion_offset); return partion_offset; @@ -835,7 +928,8 @@ static int partition_get_offset(const char *label, size_t size) { * ****************************************************************************/ -int esp32_partition_init(void) { +int esp32_partition_init(void) +{ int i; int ret; uint8_t *pbuf; @@ -845,50 +939,58 @@ int esp32_partition_init(void) { const struct partition_info_priv *info; mtd = esp32_spiflash_get_mtd(); - if (!mtd) { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) + { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } mtd_encrypt = esp32_spiflash_encrypt_get_mtd(); - if (!mtd_encrypt) { - ferr("ERROR: Failed to get SPI flash encrypted MTD\n"); - return -ENOSYS; - } + if (!mtd_encrypt) + { + ferr("ERROR: Failed to get SPI flash encrypted MTD\n"); + return -ENOSYS; + } pbuf = kmm_malloc(PARTITION_MAX_SIZE); - if (!pbuf) { - ferr("ERROR: Failed to allocate %d byte\n", PARTITION_MAX_SIZE); - return -ENOMEM; - } + if (!pbuf) + { + ferr("ERROR: Failed to allocate %d byte\n", PARTITION_MAX_SIZE); + return -ENOMEM; + } /* Even without SPI Flash encryption, we can also use encrypted * MTD to read no-encrypted data. */ - ret = MTD_READ(mtd_encrypt, PARTITION_TABLE_OFFSET, PARTITION_MAX_SIZE, pbuf); - if (ret != PARTITION_MAX_SIZE) { - ferr("ERROR: Failed to get read data from MTD\n"); - kmm_free(pbuf); - return -EIO; - } + ret = MTD_READ(mtd_encrypt, PARTITION_TABLE_OFFSET, + PARTITION_MAX_SIZE, pbuf); + if (ret != PARTITION_MAX_SIZE) + { + ferr("ERROR: Failed to get read data from MTD\n"); + kmm_free(pbuf); + return -EIO; + } info = (struct partition_info_priv *)pbuf; encrypt = esp32_flash_encryption_enabled(); - for (i = 0; i < PARTITION_MAX_NUM; i++) { - ret = partition_create_dev(&info[i], encrypt, mtd, mtd_encrypt); - if (ret != OK) { - break; + for (i = 0; i < PARTITION_MAX_NUM; i++) + { + ret = partition_create_dev(&info[i], encrypt, mtd, mtd_encrypt); + if (ret != OK) + { + break; + } } - } kmm_free(pbuf); - if (i == 0) { - ferr("ERROR: No partition is created\n"); - return -EPERM; - } + if (i == 0) + { + ferr("ERROR: No partition is created\n"); + return -EPERM; + } return OK; } @@ -911,27 +1013,32 @@ int esp32_partition_init(void) { ****************************************************************************/ int esp32_partition_read(const char *label, size_t offset, void *buf, - size_t size) { + size_t size) +{ int ret; int partion_offset; DEBUGASSERT(label != NULL && buf != NULL); struct mtd_dev_s *mtd = esp32_spiflash_get_mtd(); - if (!mtd) { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) + { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } partion_offset = partition_get_offset(label, sizeof(label)); - if (partion_offset < 0) { - ferr("ERROR: Failed to get partition: %s offset\n", label); - return partion_offset; - } + if (partion_offset < 0) + { + ferr("ERROR: Failed to get partition: %s offset\n", label); + return partion_offset; + } - ret = MTD_READ(mtd, partion_offset + offset, size, (uint8_t *)buf); - if (ret != size) { - ferr("ERROR: Failed to get read data from MTD\n"); - return -EIO; - } + ret = MTD_READ(mtd, partion_offset + offset, + size, (uint8_t *)buf); + if (ret != size) + { + ferr("ERROR: Failed to get read data from MTD\n"); + return -EIO; + } return OK; } @@ -954,29 +1061,34 @@ int esp32_partition_read(const char *label, size_t offset, void *buf, ****************************************************************************/ int esp32_partition_read_decrypt(const char *label, size_t offset, void *buf, - size_t size) { + size_t size) +{ int ret; int partion_offset; DEBUGASSERT(label != NULL && buf != NULL); struct mtd_dev_s *mtd; partion_offset = partition_get_offset(label, strlen(label)); - if (partion_offset < 0) { - ferr("ERROR: Failed to get partition: %s offset\n", label); - return partion_offset; - } + if (partion_offset < 0) + { + ferr("ERROR: Failed to get partition: %s offset\n", label); + return partion_offset; + } mtd = esp32_spiflash_encrypt_get_mtd(); - if (!mtd) { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) + { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } - ret = MTD_READ(mtd, partion_offset + offset, size, (uint8_t *)buf); - if (ret != size) { - ferr("ERROR: Failed to get read data from MTD\n"); - return -EIO; - } + ret = MTD_READ(mtd, partion_offset + offset, + size, (uint8_t *)buf); + if (ret != size) + { + ferr("ERROR: Failed to get read data from MTD\n"); + return -EIO; + } return OK; } @@ -999,27 +1111,32 @@ int esp32_partition_read_decrypt(const char *label, size_t offset, void *buf, ****************************************************************************/ int esp32_partition_write(const char *label, size_t offset, void *buf, - size_t size) { + size_t size) +{ int ret; int partion_offset; DEBUGASSERT(label != NULL && buf != NULL); struct mtd_dev_s *mtd = esp32_spiflash_get_mtd(); - if (!mtd) { - ferr("ERROR: Failed to get SPI flash MTD\n"); - return -ENOSYS; - } + if (!mtd) + { + ferr("ERROR: Failed to get SPI flash MTD\n"); + return -ENOSYS; + } partion_offset = partition_get_offset(label, sizeof(label)); - if (partion_offset < 0) { - ferr("ERROR: Failed to get partition: %s offset\n", label); - return partion_offset; - } - - ret = MTD_WRITE(mtd, partion_offset + offset, size, (uint8_t *)buf); - if (ret != size) { - ferr("ERROR: Failed to get read data from MTD\n"); - return -EIO; - } + if (partion_offset < 0) + { + ferr("ERROR: Failed to get partition: %s offset\n", label); + return partion_offset; + } + + ret = MTD_WRITE(mtd, partion_offset + offset, + size, (uint8_t *)buf); + if (ret != size) + { + ferr("ERROR: Failed to get read data from MTD\n"); + return -EIO; + } return OK; } diff --git a/boards/xtensa/esp32/common/src/Make.defs b/boards/xtensa/esp32/common/src/Make.defs index 54efd856d8dad..92999a6b34bb6 100644 --- a/boards/xtensa/esp32/common/src/Make.defs +++ b/boards/xtensa/esp32/common/src/Make.defs @@ -178,7 +178,9 @@ ifeq ($(CONFIG_ETC_ROMFS),y) RCSRCS = etc/init.d/rc.sysinit etc/init.d/rcS endif -CSRCS += esp32_boot_image.c +ifeq ($(CONFIG_BOARDCTL_BOOT_IMAGE),y) + CSRCS += esp32_boot_image.c +endif DEPPATH += --dep-path src VPATH += :src diff --git a/boards/xtensa/esp32/common/src/esp32_boot_image.c b/boards/xtensa/esp32/common/src/esp32_boot_image.c index 56e1551b589c5..442f9ecf1dbb2 100644 --- a/boards/xtensa/esp32/common/src/esp32_boot_image.c +++ b/boards/xtensa/esp32/common/src/esp32_boot_image.c @@ -34,8 +34,8 @@ #include #include -#include "esp_loader.h" #include "esp_app_format.h" +#include "esp_loader.h" /**************************************************************************** * Pre-processor Definitions @@ -80,7 +80,7 @@ static void IRAM_ATTR esp32_boot_loader_stub(void *arg); static void IRAM_ATTR esp32_boot_loader_stub(void *arg) { struct esp32_boot_loader_args_s *args = - (struct esp32_boot_loader_args_s *)arg; + (struct esp32_boot_loader_args_s *)arg; void (*entry_point)(void) = (void (*)(void))args->entry_addr; /* Disable interrupts */ @@ -107,9 +107,7 @@ static void IRAM_ATTR esp32_boot_loader_stub(void *arg) /* Should never reach here */ - while (1) - { - } + PANIC(); } /**************************************************************************** @@ -172,6 +170,13 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) return -errno; } + /* Skip image header if present (e.g. MCUboot/nxboot header) */ + + if (hdr_size > 0) + { + lseek(fd, hdr_size, SEEK_SET); + } + /* Read image header */ ret = read(fd, &image_header, sizeof(esp_image_header_t)); @@ -190,7 +195,7 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) } args.entry_addr = image_header.entry_addr; - current_offset = sizeof(esp_image_header_t); + current_offset = hdr_size + sizeof(esp_image_header_t); /* Parse segments */ From 637c3300a5ecc4d28b3cd6e32e5260e29e6f8377 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Tue, 10 Feb 2026 17:53:07 +0530 Subject: [PATCH 05/16] boards/esp32: parse MCUboot load header in board_boot_image Read the MCUboot-Espressif load header at hdr_size and use it to populate entry point plus IROM/DROM mapping parameters. This replaces the incorrect esp_image_header_t parsing path in board_boot_image() for this flow and aligns with the image layout used by MCUboot/nxboot on ESP32. Signed-off-by: aviralgarg05 --- .../esp32/common/src/esp32_boot_image.c | 113 +++++++++--------- 1 file changed, 54 insertions(+), 59 deletions(-) diff --git a/boards/xtensa/esp32/common/src/esp32_boot_image.c b/boards/xtensa/esp32/common/src/esp32_boot_image.c index 442f9ecf1dbb2..bb192f0cc6db3 100644 --- a/boards/xtensa/esp32/common/src/esp32_boot_image.c +++ b/boards/xtensa/esp32/common/src/esp32_boot_image.c @@ -26,6 +26,8 @@ #include #include +#include +#include #include #include @@ -34,19 +36,43 @@ #include #include -#include "esp_app_format.h" #include "esp_loader.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#define ESP32_APP_IMAGE_MAGIC 0xE9 +#define ESP32_APP_LOAD_HEADER_MAGIC 0xace637d3 /**************************************************************************** * Private Types ****************************************************************************/ +struct esp32_load_header_s +{ + uint32_t header_magic; + uint32_t entry_addr; + uint32_t iram_dest_addr; + uint32_t iram_flash_offset; + uint32_t iram_size; + uint32_t dram_dest_addr; + uint32_t dram_flash_offset; + uint32_t dram_size; + uint32_t lp_rtc_iram_dest_addr; + uint32_t lp_rtc_iram_flash_offset; + uint32_t lp_rtc_iram_size; + uint32_t lp_rtc_dram_dest_addr; + uint32_t lp_rtc_dram_flash_offset; + uint32_t lp_rtc_dram_size; + uint32_t irom_map_addr; + uint32_t irom_flash_offset; + uint32_t irom_size; + uint32_t drom_map_addr; + uint32_t drom_flash_offset; + uint32_t drom_size; + uint32_t reserved[4]; +}; + struct esp32_boot_loader_args_s { uint32_t entry_addr; @@ -122,7 +148,7 @@ static void IRAM_ATTR esp32_boot_loader_stub(void *arg) * * Input Parameters: * path - Path to the image file/partition - * hdr_size - Size of the image header (unused for ESP32) + * hdr_size - Size of the prepended image header (e.g. MCUboot/nxboot) * * Returned Value: * Does not return on success; returns error code on failure. @@ -134,20 +160,17 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) int fd; int ret; uint32_t offset; - esp_image_header_t image_header; - esp_image_segment_header_t segment_hdr; + struct esp32_load_header_s load_header; struct esp32_boot_loader_args_s args = { 0 }; - uint32_t current_offset; - int i; - - /* Check for legacy format (not supported) */ + /* Legacy/simple boot image formats are not supported */ -#ifdef CONFIG_ESP32_APP_FORMAT_LEGACY - ferr("ERROR: Legacy format not supported for board_boot_image\n"); +#if defined(CONFIG_ESP32_APP_FORMAT_LEGACY) || \ + defined(CONFIG_ESPRESSIF_SIMPLE_BOOT) + ferr("ERROR: Unsupported image format for board_boot_image\n"); return -ENOTSUP; #endif @@ -174,67 +197,39 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) if (hdr_size > 0) { - lseek(fd, hdr_size, SEEK_SET); + if (lseek(fd, hdr_size, SEEK_SET) < 0) + { + ferr("ERROR: Failed to seek load header: %d\n", errno); + close(fd); + return -errno; + } } - /* Read image header */ + /* Read image load header generated for MCUboot app format */ - ret = read(fd, &image_header, sizeof(esp_image_header_t)); - if (ret != sizeof(esp_image_header_t)) + ret = read(fd, &load_header, sizeof(struct esp32_load_header_s)); + if (ret != sizeof(struct esp32_load_header_s)) { - ferr("ERROR: Failed to read image header: %d\n", errno); + ferr("ERROR: Failed to read image load header: %d\n", errno); close(fd); return -errno; } - if (image_header.magic != ESP32_APP_IMAGE_MAGIC) + if (load_header.header_magic != ESP32_APP_LOAD_HEADER_MAGIC) { - ferr("ERROR: Invalid image magic: 0x%02x\n", image_header.magic); + ferr("ERROR: Invalid load header magic: 0x%08" PRIx32 "\n", + load_header.header_magic); close(fd); return -EINVAL; } - args.entry_addr = image_header.entry_addr; - current_offset = hdr_size + sizeof(esp_image_header_t); - - /* Parse segments */ - - for (i = 0; i < image_header.segment_count; i++) - { - ret = read(fd, &segment_hdr, sizeof(esp_image_segment_header_t)); - if (ret != sizeof(esp_image_segment_header_t)) - { - ferr("ERROR: Failed to read segment header: %d\n", errno); - close(fd); - return -errno; - } - - /* Check for IROM/DROM segments */ - - if (segment_hdr.load_addr >= 0x3f400000 && - segment_hdr.load_addr < 0x3f800000) /* DROM */ - { - args.drom_addr = - offset + current_offset + sizeof(esp_image_segment_header_t); - args.drom_vaddr = segment_hdr.load_addr; - args.drom_size = segment_hdr.data_len; - } - else if (segment_hdr.load_addr >= 0x400d0000 && - segment_hdr.load_addr < 0x40400000) /* IROM */ - { - args.irom_addr = - offset + current_offset + sizeof(esp_image_segment_header_t); - args.irom_vaddr = segment_hdr.load_addr; - args.irom_size = segment_hdr.data_len; - } - - current_offset += sizeof(esp_image_segment_header_t) + - segment_hdr.data_len; - - /* Advance file pointer to next segment */ - - lseek(fd, segment_hdr.data_len, SEEK_CUR); - } + args.entry_addr = load_header.entry_addr; + args.drom_addr = offset + load_header.drom_flash_offset; + args.drom_vaddr = load_header.drom_map_addr; + args.drom_size = load_header.drom_size; + args.irom_addr = offset + load_header.irom_flash_offset; + args.irom_vaddr = load_header.irom_map_addr; + args.irom_size = load_header.irom_size; close(fd); From faa037fda61f5e797f4c1af2c445b1bd22702aaf Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Tue, 10 Feb 2026 20:38:33 +0530 Subject: [PATCH 06/16] ci: retrigger build after transient mbedtls fetch failure Trigger CI after a transient external mbedTLS archive fetch failure in Build run 21864863666. Signed-off-by: aviralgarg05 From 29a700f1f4134f2e2af1abaa2f65c7aeffbde69f Mon Sep 17 00:00:00 2001 From: Aviral Garg Date: Wed, 11 Feb 2026 12:23:01 +0530 Subject: [PATCH 07/16] boards/esp32: load RAM sections in board_boot_image board_boot_image chain-boots directly to the selected slot and does not go through ROM bootloader section loading. Load IRAM/DRAM/LP RTC sections from the image load header before jumping, and keep ROM remap in the IRAM stub for non-primary-slot boot. Also include the required loader/cache headers so BOARDCTL_BOOT_IMAGE builds cleanly when this file is enabled. Signed-off-by: aviralgarg05 --- .../esp32/common/src/esp32_boot_image.c | 123 +++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/boards/xtensa/esp32/common/src/esp32_boot_image.c b/boards/xtensa/esp32/common/src/esp32_boot_image.c index bb192f0cc6db3..67d9e4d97e661 100644 --- a/boards/xtensa/esp32/common/src/esp32_boot_image.c +++ b/boards/xtensa/esp32/common/src/esp32_boot_image.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -36,7 +37,8 @@ #include #include -#include "esp_loader.h" +#include "espressif/esp_loader.h" +#include "xtensa_attr.h" /**************************************************************************** * Pre-processor Definitions @@ -88,12 +90,80 @@ struct esp32_boot_loader_args_s * Private Function Prototypes ****************************************************************************/ +#ifdef CONFIG_ARCH_CHIP_ESP32 +extern void cache_read_disable(int cpu); +extern void cache_flush(int cpu); +#endif + +static int esp32_load_ram_segment(int fd, uint32_t flash_offset, + uint32_t dest_addr, uint32_t size, + FAR const char *name); static void IRAM_ATTR esp32_boot_loader_stub(void *arg); /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: esp32_load_ram_segment + * + * Description: + * Load a RAM-resident segment from the application image into its + * destination address. + * + ****************************************************************************/ + +static int esp32_load_ram_segment(int fd, uint32_t flash_offset, + uint32_t dest_addr, uint32_t size, + FAR const char *name) +{ + uint8_t *dest; + off_t read_offset; + ssize_t nread; + size_t remaining; + + if (size == 0) + { + return OK; + } + + if (dest_addr == 0) + { + ferr("ERROR: Invalid %s destination address\n", name); + return -EINVAL; + } + + finfo("Loading %-12s: dst=0x%08" PRIx32 " off=0x%08" PRIx32 + " size=0x%08" PRIx32 "\n", + name, dest_addr, flash_offset, size); + + dest = (uint8_t *)(uintptr_t)dest_addr; + read_offset = (off_t)flash_offset; + remaining = (size_t)size; + + while (remaining > 0) + { + nread = pread(fd, dest, remaining, read_offset); + if (nread < 0) + { + ferr("ERROR: Failed to read %s segment: %d\n", name, errno); + return -errno; + } + + if (nread == 0) + { + ferr("ERROR: Unexpected EOF while reading %s segment\n", name); + return -EIO; + } + + dest += nread; + read_offset += nread; + remaining -= nread; + } + + return OK; +} + /**************************************************************************** * Name: esp32_boot_loader_stub * @@ -124,8 +194,15 @@ static void IRAM_ATTR esp32_boot_loader_stub(void *arg) /* Map new segments */ - map_rom_segments(args->drom_addr, args->drom_vaddr, args->drom_size, - args->irom_addr, args->irom_vaddr, args->irom_size); + /* board_boot_image() may boot from non-primary slots, so remap ROM + * segments here before entering the new image. + */ + + if (map_rom_segments(args->drom_addr, args->drom_vaddr, args->drom_size, + args->irom_addr, args->irom_vaddr, args->irom_size)) + { + PANIC(); + } /* Jump to entry point */ @@ -223,6 +300,46 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) return -EINVAL; } + /* RAM sections are normally loaded by the ROM bootloader. Since + * board_boot_image() chain-boots directly, load these sections here. + */ + + ret = esp32_load_ram_segment(fd, load_header.iram_flash_offset, + load_header.iram_dest_addr, + load_header.iram_size, "iram"); + if (ret < 0) + { + close(fd); + return ret; + } + + ret = esp32_load_ram_segment(fd, load_header.dram_flash_offset, + load_header.dram_dest_addr, + load_header.dram_size, "dram"); + if (ret < 0) + { + close(fd); + return ret; + } + + ret = esp32_load_ram_segment(fd, load_header.lp_rtc_iram_flash_offset, + load_header.lp_rtc_iram_dest_addr, + load_header.lp_rtc_iram_size, "lp_rtc_iram"); + if (ret < 0) + { + close(fd); + return ret; + } + + ret = esp32_load_ram_segment(fd, load_header.lp_rtc_dram_flash_offset, + load_header.lp_rtc_dram_dest_addr, + load_header.lp_rtc_dram_size, "lp_rtc_dram"); + if (ret < 0) + { + close(fd); + return ret; + } + args.entry_addr = load_header.entry_addr; args.drom_addr = offset + load_header.drom_flash_offset; args.drom_vaddr = load_header.drom_map_addr; From 2299941a1338b9ea7c275fd30a3d44a9e52e990f Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Wed, 11 Feb 2026 13:14:48 +0530 Subject: [PATCH 08/16] boards/esp32: remove ROM remap in board_boot_image path For location-fixed MCUboot images, ROM mapping is handled by image\nstartup. board_boot_image only needs to load RAM sections and jump to\nentry.\n\nDrop the extra ROM remap/cache handling in the IRAM stub and remove\npartition-offset handling that is no longer used in this flow. Signed-off-by: aviralgarg05 --- .../esp32/common/src/esp32_boot_image.c | 57 +------------------ 1 file changed, 2 insertions(+), 55 deletions(-) diff --git a/boards/xtensa/esp32/common/src/esp32_boot_image.c b/boards/xtensa/esp32/common/src/esp32_boot_image.c index 67d9e4d97e661..459314a64aed0 100644 --- a/boards/xtensa/esp32/common/src/esp32_boot_image.c +++ b/boards/xtensa/esp32/common/src/esp32_boot_image.c @@ -29,15 +29,11 @@ #include #include #include -#include #include -#include #include -#include #include -#include "espressif/esp_loader.h" #include "xtensa_attr.h" /**************************************************************************** @@ -78,23 +74,12 @@ struct esp32_load_header_s struct esp32_boot_loader_args_s { uint32_t entry_addr; - uint32_t drom_addr; - uint32_t drom_vaddr; - uint32_t drom_size; - uint32_t irom_addr; - uint32_t irom_vaddr; - uint32_t irom_size; }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ -#ifdef CONFIG_ARCH_CHIP_ESP32 -extern void cache_read_disable(int cpu); -extern void cache_flush(int cpu); -#endif - static int esp32_load_ram_segment(int fd, uint32_t flash_offset, uint32_t dest_addr, uint32_t size, FAR const char *name); @@ -183,27 +168,10 @@ static void IRAM_ATTR esp32_boot_loader_stub(void *arg) up_irq_disable(); - /* Disable cache */ - -#ifdef CONFIG_ARCH_CHIP_ESP32 - cache_read_disable(0); - cache_flush(0); -#else - cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); -#endif - - /* Map new segments */ - - /* board_boot_image() may boot from non-primary slots, so remap ROM - * segments here before entering the new image. + /* For location-fixed MCUboot images, ROM mappings are handled by + * the image startup path. */ - if (map_rom_segments(args->drom_addr, args->drom_vaddr, args->drom_size, - args->irom_addr, args->irom_vaddr, args->irom_size)) - { - PANIC(); - } - /* Jump to entry point */ entry_point(); @@ -236,7 +204,6 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) { int fd; int ret; - uint32_t offset; struct esp32_load_header_s load_header; struct esp32_boot_loader_args_s args = { @@ -260,16 +227,6 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) return -errno; } - /* Get partition offset */ - - ret = ioctl(fd, OTA_IMG_GET_OFFSET, (unsigned long)&offset); - if (ret < 0) - { - ferr("ERROR: Failed to get partition offset: %d\n", errno); - close(fd); - return -errno; - } - /* Skip image header if present (e.g. MCUboot/nxboot header) */ if (hdr_size > 0) @@ -341,20 +298,10 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) } args.entry_addr = load_header.entry_addr; - args.drom_addr = offset + load_header.drom_flash_offset; - args.drom_vaddr = load_header.drom_map_addr; - args.drom_size = load_header.drom_size; - args.irom_addr = offset + load_header.irom_flash_offset; - args.irom_vaddr = load_header.irom_map_addr; - args.irom_size = load_header.irom_size; close(fd); finfo("Booting image: entry=0x%08" PRIx32 "\n", args.entry_addr); - finfo(" drom=0x%08" PRIx32 " (0x%08" PRIx32 ")\n", - args.drom_vaddr, args.drom_size); - finfo(" irom=0x%08" PRIx32 " (0x%08" PRIx32 ")\n", - args.irom_vaddr, args.irom_size); /* Invoke IRAM loader stub */ From ff2416b905748bdc7116c55ea03192875eace0d2 Mon Sep 17 00:00:00 2001 From: Aviral Garg Date: Wed, 11 Feb 2026 13:21:46 +0530 Subject: [PATCH 09/16] arch/esp32: remove unused OTA_IMG_GET_OFFSET ioctl Drop the temporary OTA_IMG_GET_OFFSET extension from the partition API. After removing ROM remap from board_boot_image(), this ioctl is no longer used by the boot path, so keeping it only increases PR scope without benefit. Signed-off-by: aviralgarg05 --- arch/xtensa/include/esp32/partition.h | 1 - arch/xtensa/src/esp32/esp32_partition.c | 3 --- 2 files changed, 4 deletions(-) diff --git a/arch/xtensa/include/esp32/partition.h b/arch/xtensa/include/esp32/partition.h index 360e4764290d3..02652e678d8ec 100644 --- a/arch/xtensa/include/esp32/partition.h +++ b/arch/xtensa/include/esp32/partition.h @@ -43,7 +43,6 @@ enum ota_img_ctrl OTA_IMG_GET_SUBTYPE = 0xe6, OTA_IMG_INVALIDATE_BOOT = 0xe7, OTA_IMG_IS_MAPPED_AS_TEXT = 0xe8, - OTA_IMG_GET_OFFSET = 0xe9, }; /* OTA image boot sequency */ diff --git a/arch/xtensa/src/esp32/esp32_partition.c b/arch/xtensa/src/esp32/esp32_partition.c index 80a10a2237e24..f9e102a5eb5b3 100644 --- a/arch/xtensa/src/esp32/esp32_partition.c +++ b/arch/xtensa/src/esp32/esp32_partition.c @@ -705,9 +705,6 @@ static int esp32_part_ioctl(struct mtd_dev_s *dev, int cmd, } } - break; - case OTA_IMG_GET_OFFSET: - *(uint32_t *)arg = mtd_priv->offset; break; default: { From 9b16f948a3de9e75ebd6fcd58bf823bec90258b5 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Wed, 11 Feb 2026 14:24:58 +0530 Subject: [PATCH 10/16] ci: retrigger build after transient argtable3 fetch failure The previous Build workflow failed in Linux (arm64-01) while downloading argtable3 with: gzip: stdin: not in gzip format This appears to be a transient upstream/network artifact fetch issue, so this commit retriggers CI without source changes. Signed-off-by: aviralgarg05 From 134a565118040e50562a0c74cd9b0090a857a949 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Sat, 14 Feb 2026 17:54:05 +0530 Subject: [PATCH 11/16] boards/xtensa/esp32: harden board_boot_image chain-boot handoff Preload RAM sections to temporary buffers and perform the final copy from RTC fast memory before jumping to the new image entry point. Use a dedicated handoff stack and overlap checks to avoid self-overwrite during chain boot. Signed-off-by: aviralgarg05 --- .../esp32/common/src/esp32_boot_image.c | 261 ++++++++++++++---- 1 file changed, 213 insertions(+), 48 deletions(-) diff --git a/boards/xtensa/esp32/common/src/esp32_boot_image.c b/boards/xtensa/esp32/common/src/esp32_boot_image.c index 459314a64aed0..7b68e8e293216 100644 --- a/boards/xtensa/esp32/common/src/esp32_boot_image.c +++ b/boards/xtensa/esp32/common/src/esp32_boot_image.c @@ -25,14 +25,17 @@ #include #include +#include #include #include #include +#include #include #include #include #include +#include #include "xtensa_attr.h" @@ -41,6 +44,8 @@ ****************************************************************************/ #define ESP32_APP_LOAD_HEADER_MAGIC 0xace637d3 +#define ESP32_LOAD_SEGMENT_COUNT 4 +#define ESP32_BOOTLOADER_STACK_SIZE 2048 /**************************************************************************** * Private Types @@ -71,44 +76,94 @@ struct esp32_load_header_s uint32_t reserved[4]; }; +struct esp32_boot_loader_segment_s +{ + uint32_t dest_addr; + uint32_t size; + FAR uint8_t *buffer; +}; + struct esp32_boot_loader_args_s { uint32_t entry_addr; + uintptr_t stack_top; + struct esp32_boot_loader_segment_s segments[ESP32_LOAD_SEGMENT_COUNT]; }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ -static int esp32_load_ram_segment(int fd, uint32_t flash_offset, - uint32_t dest_addr, uint32_t size, - FAR const char *name); -static void IRAM_ATTR esp32_boot_loader_stub(void *arg); +static bool esp32_ranges_overlap(uintptr_t start1, size_t size1, + uintptr_t start2, size_t size2); +static int esp32_prepare_ram_segment(int fd, uint32_t flash_offset, + uint32_t dest_addr, uint32_t size, + FAR const char *name, + FAR struct esp32_boot_loader_args_s + *args, + int index); +static void esp32_release_ram_segments(FAR struct esp32_boot_loader_args_s + *args); +static void RTC_IRAM_ATTR esp32_copy_segment(FAR const void *src, + uint32_t dest_addr, + uint32_t size); +static void RTC_IRAM_ATTR esp32_boot_loader_stub(void); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct esp32_boot_loader_args_s g_boot_loader_args; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: esp32_load_ram_segment + * Name: esp32_ranges_overlap + * + * Description: + * Return true when two address ranges overlap. + * + ****************************************************************************/ + +static bool esp32_ranges_overlap(uintptr_t start1, size_t size1, + uintptr_t start2, size_t size2) +{ + uintptr_t end1 = start1 + size1; + uintptr_t end2 = start2 + size2; + + return (start1 < end2) && (start2 < end1); +} + +/**************************************************************************** + * Name: esp32_prepare_ram_segment * * Description: - * Load a RAM-resident segment from the application image into its - * destination address. + * Read one RAM segment into a temporary buffer that is copied by the final + * RTC loader stage. * ****************************************************************************/ -static int esp32_load_ram_segment(int fd, uint32_t flash_offset, - uint32_t dest_addr, uint32_t size, - FAR const char *name) +static int esp32_prepare_ram_segment(int fd, uint32_t flash_offset, + uint32_t dest_addr, uint32_t size, + FAR const char *name, + FAR struct esp32_boot_loader_args_s + *args, + int index) { - uint8_t *dest; + FAR uint8_t *buffer; off_t read_offset; ssize_t nread; size_t remaining; + DEBUGASSERT(index >= 0 && index < ESP32_LOAD_SEGMENT_COUNT); + if (size == 0) { + args->segments[index].dest_addr = 0; + args->segments[index].size = 0; + args->segments[index].buffer = NULL; return OK; } @@ -118,65 +173,146 @@ static int esp32_load_ram_segment(int fd, uint32_t flash_offset, return -EINVAL; } - finfo("Loading %-12s: dst=0x%08" PRIx32 " off=0x%08" PRIx32 + buffer = kmm_malloc(size); + if (buffer == NULL) + { + ferr("ERROR: Failed to allocate %s preload buffer (%" PRIu32 ")\n", + name, size); + return -ENOMEM; + } + + finfo("Preloading %-9s: dst=0x%08" PRIx32 " off=0x%08" PRIx32 " size=0x%08" PRIx32 "\n", name, dest_addr, flash_offset, size); - dest = (uint8_t *)(uintptr_t)dest_addr; read_offset = (off_t)flash_offset; remaining = (size_t)size; while (remaining > 0) { - nread = pread(fd, dest, remaining, read_offset); + nread = pread(fd, buffer + (size - remaining), remaining, read_offset); if (nread < 0) { ferr("ERROR: Failed to read %s segment: %d\n", name, errno); + kmm_free(buffer); return -errno; } if (nread == 0) { ferr("ERROR: Unexpected EOF while reading %s segment\n", name); + kmm_free(buffer); return -EIO; } - dest += nread; read_offset += nread; remaining -= nread; } + if (esp32_ranges_overlap((uintptr_t)buffer, size, + (uintptr_t)dest_addr, size)) + { + ferr("ERROR: %s preload buffer overlaps destination\n", name); + kmm_free(buffer); + return -EFAULT; + } + + args->segments[index].dest_addr = dest_addr; + args->segments[index].size = size; + args->segments[index].buffer = buffer; return OK; } +/**************************************************************************** + * Name: esp32_release_ram_segments + * + * Description: + * Free preloaded segment buffers used by the boot loader handoff. + * + ****************************************************************************/ + +static void esp32_release_ram_segments(FAR struct esp32_boot_loader_args_s + *args) +{ + int i; + + for (i = 0; i < ESP32_LOAD_SEGMENT_COUNT; i++) + { + if (args->segments[i].buffer != NULL) + { + kmm_free(args->segments[i].buffer); + args->segments[i].buffer = NULL; + } + } +} + +/**************************************************************************** + * Name: esp32_copy_segment + * + * Description: + * Copy one preloaded segment into its destination address. + * + ****************************************************************************/ + +static void RTC_IRAM_ATTR esp32_copy_segment(FAR const void *src, + uint32_t dest_addr, + uint32_t size) +{ + FAR const uint8_t *s = (FAR const uint8_t *)src; + FAR uint8_t *d = (FAR uint8_t *)(uintptr_t)dest_addr; + + while (size-- > 0) + { + *d++ = *s++; + } +} + /**************************************************************************** * Name: esp32_boot_loader_stub * * Description: - * This function resides in IRAM and is responsible for switching MMU - * mappings and jumping to the new application. + * Final loader stage. The routine executes from RTC fast memory and copies + * preloaded RAM segments into their target addresses just before jumping + * to the new image entry point. * ****************************************************************************/ -static void IRAM_ATTR esp32_boot_loader_stub(void *arg) +static void RTC_IRAM_ATTR esp32_boot_loader_stub(void) { - struct esp32_boot_loader_args_s *args = - (struct esp32_boot_loader_args_s *)arg; - void (*entry_point)(void) = (void (*)(void))args->entry_addr; + FAR const struct esp32_boot_loader_args_s *args = &g_boot_loader_args; + register uintptr_t stack_top = args->stack_top; + register uint32_t entry_addr = args->entry_addr; + register FAR const void *dram_src = args->segments[3].buffer; + register uint32_t dram_dst = args->segments[3].dest_addr; + register uint32_t dram_size = args->segments[3].size; /* Disable interrupts */ up_irq_disable(); - /* For location-fixed MCUboot images, ROM mappings are handled by - * the image startup path. + /* Use a dedicated handoff stack that does not overlap the DRAM segment + * destination copied in the final step. + */ + + __asm__ __volatile__("mov sp, %0" : : "r"(stack_top)); + + /* Copy IRAM and RTC sections first, then DRAM last. This avoids executing + * from memory that can be overwritten during the chain-boot transition. */ - /* Jump to entry point */ + esp32_copy_segment(args->segments[0].buffer, args->segments[0].dest_addr, + args->segments[0].size); + esp32_copy_segment(args->segments[1].buffer, args->segments[1].dest_addr, + args->segments[1].size); + esp32_copy_segment(args->segments[2].buffer, args->segments[2].dest_addr, + args->segments[2].size); + esp32_copy_segment(dram_src, dram_dst, dram_size); + + /* Jump using a register-held entry address to avoid relying on DRAM. */ - entry_point(); + __asm__ __volatile__("jx %0" : : "r"(entry_addr)); - /* Should never reach here */ + /* Should never return */ PANIC(); } @@ -204,11 +340,8 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) { int fd; int ret; + uintptr_t stack_buf; struct esp32_load_header_s load_header; - struct esp32_boot_loader_args_s args = - { - 0 - }; /* Legacy/simple boot image formats are not supported */ @@ -257,55 +390,87 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) return -EINVAL; } - /* RAM sections are normally loaded by the ROM bootloader. Since - * board_boot_image() chain-boots directly, load these sections here. + memset(&g_boot_loader_args, 0, sizeof(g_boot_loader_args)); + g_boot_loader_args.entry_addr = load_header.entry_addr; + + /* Preload segments into temporary buffers. They are copied to destination + * addresses by the final RTC-resident loader stage. */ - ret = esp32_load_ram_segment(fd, load_header.iram_flash_offset, - load_header.iram_dest_addr, - load_header.iram_size, "iram"); + ret = esp32_prepare_ram_segment(fd, load_header.iram_flash_offset, + load_header.iram_dest_addr, + load_header.iram_size, "iram", + &g_boot_loader_args, 0); if (ret < 0) { close(fd); return ret; } - ret = esp32_load_ram_segment(fd, load_header.dram_flash_offset, - load_header.dram_dest_addr, - load_header.dram_size, "dram"); + ret = esp32_prepare_ram_segment(fd, load_header.lp_rtc_iram_flash_offset, + load_header.lp_rtc_iram_dest_addr, + load_header.lp_rtc_iram_size, + "lp_rtc_iram", &g_boot_loader_args, 1); if (ret < 0) { + esp32_release_ram_segments(&g_boot_loader_args); close(fd); return ret; } - ret = esp32_load_ram_segment(fd, load_header.lp_rtc_iram_flash_offset, - load_header.lp_rtc_iram_dest_addr, - load_header.lp_rtc_iram_size, "lp_rtc_iram"); + ret = esp32_prepare_ram_segment(fd, load_header.lp_rtc_dram_flash_offset, + load_header.lp_rtc_dram_dest_addr, + load_header.lp_rtc_dram_size, + "lp_rtc_dram", &g_boot_loader_args, 2); if (ret < 0) { + esp32_release_ram_segments(&g_boot_loader_args); close(fd); return ret; } - ret = esp32_load_ram_segment(fd, load_header.lp_rtc_dram_flash_offset, - load_header.lp_rtc_dram_dest_addr, - load_header.lp_rtc_dram_size, "lp_rtc_dram"); + ret = esp32_prepare_ram_segment(fd, load_header.dram_flash_offset, + load_header.dram_dest_addr, + load_header.dram_size, "dram", + &g_boot_loader_args, 3); if (ret < 0) { + esp32_release_ram_segments(&g_boot_loader_args); close(fd); return ret; } - args.entry_addr = load_header.entry_addr; + stack_buf = (uintptr_t)kmm_malloc(ESP32_BOOTLOADER_STACK_SIZE); + if (stack_buf == 0) + { + ferr("ERROR: Failed to allocate boot loader stack\n"); + esp32_release_ram_segments(&g_boot_loader_args); + close(fd); + return -ENOMEM; + } + + if (esp32_ranges_overlap(stack_buf, ESP32_BOOTLOADER_STACK_SIZE, + load_header.dram_dest_addr, + load_header.dram_size)) + { + ferr("ERROR: Boot loader stack overlaps DRAM destination\n"); + esp32_release_ram_segments(&g_boot_loader_args); + kmm_free((FAR void *)stack_buf); + close(fd); + return -EFAULT; + } + + g_boot_loader_args.stack_top = + (stack_buf + ESP32_BOOTLOADER_STACK_SIZE) & ~(uintptr_t)0xf; close(fd); - finfo("Booting image: entry=0x%08" PRIx32 "\n", args.entry_addr); + finfo("Booting image: entry=0x%08" PRIx32 "\n", + g_boot_loader_args.entry_addr); - /* Invoke IRAM loader stub */ + /* Invoke final RTC loader stub. */ - esp32_boot_loader_stub(&args); + esp32_boot_loader_stub(); return 0; } From a8956bb728380f1ad246d03c2d265694508933d1 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Sat, 14 Feb 2026 17:54:08 +0530 Subject: [PATCH 12/16] Documentation/esp32-devkitc: document board_boot_image MCUboot path Document that the ESP32 DevKitC mcuboot_nsh flow invokes board_boot_image() through BOARDIOC_BOOT_IMAGE and add a reference to the MCUboot application documentation for generic boot flow details. Signed-off-by: aviralgarg05 --- .../platforms/xtensa/esp32/boards/esp32-devkitc/index.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/platforms/xtensa/esp32/boards/esp32-devkitc/index.rst b/Documentation/platforms/xtensa/esp32/boards/esp32-devkitc/index.rst index 0828f4e0b395c..f4e324fbc1b5b 100644 --- a/Documentation/platforms/xtensa/esp32/boards/esp32-devkitc/index.rst +++ b/Documentation/platforms/xtensa/esp32/boards/esp32-devkitc/index.rst @@ -655,6 +655,12 @@ This configuration is the same as the ``nsh`` configuration, but it generates th image in a format that can be used by MCUboot. It also makes the ``make bootloader`` command to build the MCUboot bootloader image using the Espressif HAL. +When ``mcuboot`` is used as bootloader, this board uses the +``board_boot_image()`` implementation in the chain-boot path through +``boardctl(BOARDIOC_BOOT_IMAGE)``. +See :doc:`/applications/boot/mcuboot/index` for general MCUboot boot flow +details and platform requirements. + mcuboot_update_agent -------------------- From ade8f9a456dc00ef02b8993b9972a66465a5c50c Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Sat, 14 Feb 2026 19:01:37 +0530 Subject: [PATCH 13/16] ci: retrigger build after transient minmea fetch failure Build workflow run 22017418819 failed in Linux (sim-02) while downloading the minmea archive:\n\n End-of-central-directory signature not found\n\nThis retries CI without source changes because the failure is external and non-deterministic. Signed-off-by: aviralgarg05 From 61e153befd92dd0b7a5b28c81320557146845c8a Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Mon, 16 Feb 2026 23:38:02 +0530 Subject: [PATCH 14/16] boards/xtensa/esp32: use partition offset + mmap in board_boot_image Use BIOC_PARTINFO to resolve the selected slot flash offset and load\nsegments via bootloader_mmap()/bootloader_munmap() rather than\npreloading all segments into heap buffers.\n\nKeep a minimal RTC handoff stage for the final DRAM copy and entry\njump to avoid chain-boot self-overwrite while reducing memory usage. Signed-off-by: aviralgarg05 --- .../esp32/common/src/esp32_boot_image.c | 399 +++++++++++------- 1 file changed, 246 insertions(+), 153 deletions(-) diff --git a/boards/xtensa/esp32/common/src/esp32_boot_image.c b/boards/xtensa/esp32/common/src/esp32_boot_image.c index 7b68e8e293216..a1cdf78264097 100644 --- a/boards/xtensa/esp32/common/src/esp32_boot_image.c +++ b/boards/xtensa/esp32/common/src/esp32_boot_image.c @@ -31,12 +31,15 @@ #include #include #include +#include #include #include +#include #include #include +#include "bootloader_flash_priv.h" #include "xtensa_attr.h" /**************************************************************************** @@ -44,7 +47,6 @@ ****************************************************************************/ #define ESP32_APP_LOAD_HEADER_MAGIC 0xace637d3 -#define ESP32_LOAD_SEGMENT_COUNT 4 #define ESP32_BOOTLOADER_STACK_SIZE 2048 /**************************************************************************** @@ -76,18 +78,13 @@ struct esp32_load_header_s uint32_t reserved[4]; }; -struct esp32_boot_loader_segment_s -{ - uint32_t dest_addr; - uint32_t size; - FAR uint8_t *buffer; -}; - struct esp32_boot_loader_args_s { uint32_t entry_addr; uintptr_t stack_top; - struct esp32_boot_loader_segment_s segments[ESP32_LOAD_SEGMENT_COUNT]; + uint32_t dram_dest_addr; + uint32_t dram_size; + FAR const void *dram_src; }; /**************************************************************************** @@ -96,14 +93,17 @@ struct esp32_boot_loader_args_s static bool esp32_ranges_overlap(uintptr_t start1, size_t size1, uintptr_t start2, size_t size2); -static int esp32_prepare_ram_segment(int fd, uint32_t flash_offset, - uint32_t dest_addr, uint32_t size, - FAR const char *name, - FAR struct esp32_boot_loader_args_s - *args, - int index); -static void esp32_release_ram_segments(FAR struct esp32_boot_loader_args_s - *args); +static int esp32_get_partition_offset(int fd, FAR uint32_t *offset); +static int esp32_flash_offset_add(uint32_t base, uint32_t offset, + FAR uint32_t *result); +static int esp32_read_load_header(uint32_t flash_offset, + FAR struct esp32_load_header_s *header); +static int esp32_copy_flash_segment(uint32_t flash_offset, + uint32_t dest_addr, uint32_t size, + FAR const char *name); +static int esp32_prepare_dram_handoff(uint32_t flash_offset, + FAR const struct esp32_load_header_s + *load_header); static void RTC_IRAM_ATTR esp32_copy_segment(FAR const void *src, uint32_t dest_addr, uint32_t size); @@ -137,120 +137,217 @@ static bool esp32_ranges_overlap(uintptr_t start1, size_t size1, } /**************************************************************************** - * Name: esp32_prepare_ram_segment + * Name: esp32_get_partition_offset * * Description: - * Read one RAM segment into a temporary buffer that is copied by the final - * RTC loader stage. + * Return the byte offset in flash of the opened partition node. * ****************************************************************************/ -static int esp32_prepare_ram_segment(int fd, uint32_t flash_offset, - uint32_t dest_addr, uint32_t size, - FAR const char *name, - FAR struct esp32_boot_loader_args_s - *args, - int index) +static int esp32_get_partition_offset(int fd, FAR uint32_t *offset) { - FAR uint8_t *buffer; - off_t read_offset; - ssize_t nread; - size_t remaining; + struct partition_info_s partinfo; + uint64_t partition_offset; - DEBUGASSERT(index >= 0 && index < ESP32_LOAD_SEGMENT_COUNT); + if (offset == NULL) + { + return -EINVAL; + } - if (size == 0) + if (ioctl(fd, BIOC_PARTINFO, (unsigned long)((uintptr_t)&partinfo)) < 0) { - args->segments[index].dest_addr = 0; - args->segments[index].size = 0; - args->segments[index].buffer = NULL; - return OK; + ferr("ERROR: BIOC_PARTINFO failed: %d\n", errno); + return -errno; } - if (dest_addr == 0) + partition_offset = (uint64_t)partinfo.startsector * + (uint64_t)partinfo.sectorsize; + if (partition_offset > UINT32_MAX) + { + ferr("ERROR: Partition offset overflow: %" PRIu64 "\n", + partition_offset); + return -EOVERFLOW; + } + + *offset = (uint32_t)partition_offset; + return OK; +} + +/**************************************************************************** + * Name: esp32_flash_offset_add + * + * Description: + * Safely compute a 32-bit flash offset sum. + * + ****************************************************************************/ + +static int esp32_flash_offset_add(uint32_t base, uint32_t offset, + FAR uint32_t *result) +{ + uint64_t sum; + + if (result == NULL) { - ferr("ERROR: Invalid %s destination address\n", name); return -EINVAL; } - buffer = kmm_malloc(size); - if (buffer == NULL) + sum = (uint64_t)base + (uint64_t)offset; + if (sum > UINT32_MAX) { - ferr("ERROR: Failed to allocate %s preload buffer (%" PRIu32 ")\n", - name, size); - return -ENOMEM; + ferr("ERROR: Flash offset overflow: 0x%08" PRIx32 " + 0x%08" PRIx32 + "\n", base, offset); + return -EOVERFLOW; } - finfo("Preloading %-9s: dst=0x%08" PRIx32 " off=0x%08" PRIx32 - " size=0x%08" PRIx32 "\n", - name, dest_addr, flash_offset, size); + *result = (uint32_t)sum; + return OK; +} - read_offset = (off_t)flash_offset; - remaining = (size_t)size; +/**************************************************************************** + * Name: esp32_read_load_header + * + * Description: + * Read the MCUboot load header from flash using ROM mmap routines. + * + ****************************************************************************/ + +static int esp32_read_load_header(uint32_t flash_offset, + FAR struct esp32_load_header_s *header) +{ + FAR const void *mapping; - while (remaining > 0) + if (header == NULL) { - nread = pread(fd, buffer + (size - remaining), remaining, read_offset); - if (nread < 0) - { - ferr("ERROR: Failed to read %s segment: %d\n", name, errno); - kmm_free(buffer); - return -errno; - } - - if (nread == 0) - { - ferr("ERROR: Unexpected EOF while reading %s segment\n", name); - kmm_free(buffer); - return -EIO; - } - - read_offset += nread; - remaining -= nread; + return -EINVAL; } - if (esp32_ranges_overlap((uintptr_t)buffer, size, - (uintptr_t)dest_addr, size)) + mapping = bootloader_mmap(flash_offset, sizeof(*header)); + if (mapping == NULL) { - ferr("ERROR: %s preload buffer overlaps destination\n", name); - kmm_free(buffer); - return -EFAULT; + ferr("ERROR: Failed to mmap image load header at 0x%08" PRIx32 "\n", + flash_offset); + return -EIO; } - args->segments[index].dest_addr = dest_addr; - args->segments[index].size = size; - args->segments[index].buffer = buffer; + memcpy(header, mapping, sizeof(*header)); + bootloader_munmap(mapping); return OK; } /**************************************************************************** - * Name: esp32_release_ram_segments + * Name: esp32_copy_flash_segment * * Description: - * Free preloaded segment buffers used by the boot loader handoff. + * Load one segment from flash to RAM via ROM mmap routines. * ****************************************************************************/ -static void esp32_release_ram_segments(FAR struct esp32_boot_loader_args_s - *args) +static int esp32_copy_flash_segment(uint32_t flash_offset, + uint32_t dest_addr, uint32_t size, + FAR const char *name) { - int i; + FAR const void *mapping; + + if (size == 0) + { + return OK; + } + + if (dest_addr == 0) + { + ferr("ERROR: Invalid %s destination address\n", name); + return -EINVAL; + } + + mapping = bootloader_mmap(flash_offset, size); + if (mapping == NULL) + { + ferr("ERROR: Failed to mmap %s segment\n", name); + return -EIO; + } + + finfo("Loading %-9s: dst=0x%08" PRIx32 " off=0x%08" PRIx32 + " size=0x%08" PRIx32 "\n", + name, dest_addr, flash_offset, size); + + esp32_copy_segment(mapping, dest_addr, size); + bootloader_munmap(mapping); + + return OK; +} + +/**************************************************************************** + * Name: esp32_prepare_dram_handoff + * + * Description: + * Prepare final DRAM copy handoff data. DRAM is copied in the RTC loader + * just before jumping to the new entry point. + * + ****************************************************************************/ + +static int esp32_prepare_dram_handoff(uint32_t flash_offset, + FAR const struct esp32_load_header_s + *load_header) +{ + uintptr_t stack_buf; - for (i = 0; i < ESP32_LOAD_SEGMENT_COUNT; i++) + DEBUGASSERT(load_header != NULL); + + memset(&g_boot_loader_args, 0, sizeof(g_boot_loader_args)); + + g_boot_loader_args.entry_addr = load_header->entry_addr; + g_boot_loader_args.dram_dest_addr = load_header->dram_dest_addr; + g_boot_loader_args.dram_size = load_header->dram_size; + + if (g_boot_loader_args.dram_size == 0) + { + return -EINVAL; + } + + if (g_boot_loader_args.dram_dest_addr == 0) + { + return -EINVAL; + } + + g_boot_loader_args.dram_src = + bootloader_mmap(flash_offset, g_boot_loader_args.dram_size); + if (g_boot_loader_args.dram_src == NULL) + { + ferr("ERROR: Failed to mmap dram segment\n"); + return -EIO; + } + + stack_buf = (uintptr_t)kmm_malloc(ESP32_BOOTLOADER_STACK_SIZE); + if (stack_buf == 0) + { + ferr("ERROR: Failed to allocate boot loader stack\n"); + bootloader_munmap(g_boot_loader_args.dram_src); + g_boot_loader_args.dram_src = NULL; + return -ENOMEM; + } + + if (esp32_ranges_overlap(stack_buf, ESP32_BOOTLOADER_STACK_SIZE, + g_boot_loader_args.dram_dest_addr, + g_boot_loader_args.dram_size)) { - if (args->segments[i].buffer != NULL) - { - kmm_free(args->segments[i].buffer); - args->segments[i].buffer = NULL; - } + ferr("ERROR: Boot loader stack overlaps DRAM destination\n"); + kmm_free((FAR void *)stack_buf); + bootloader_munmap(g_boot_loader_args.dram_src); + g_boot_loader_args.dram_src = NULL; + return -EFAULT; } + + g_boot_loader_args.stack_top = + (stack_buf + ESP32_BOOTLOADER_STACK_SIZE) & ~(uintptr_t)0xf; + + return OK; } /**************************************************************************** * Name: esp32_copy_segment * * Description: - * Copy one preloaded segment into its destination address. + * Copy one segment into its destination address. * ****************************************************************************/ @@ -272,8 +369,7 @@ static void RTC_IRAM_ATTR esp32_copy_segment(FAR const void *src, * * Description: * Final loader stage. The routine executes from RTC fast memory and copies - * preloaded RAM segments into their target addresses just before jumping - * to the new image entry point. + * the DRAM segment just before jumping to the new image entry point. * ****************************************************************************/ @@ -282,9 +378,9 @@ static void RTC_IRAM_ATTR esp32_boot_loader_stub(void) FAR const struct esp32_boot_loader_args_s *args = &g_boot_loader_args; register uintptr_t stack_top = args->stack_top; register uint32_t entry_addr = args->entry_addr; - register FAR const void *dram_src = args->segments[3].buffer; - register uint32_t dram_dst = args->segments[3].dest_addr; - register uint32_t dram_size = args->segments[3].size; + register FAR const void *dram_src = args->dram_src; + register uint32_t dram_dst = args->dram_dest_addr; + register uint32_t dram_size = args->dram_size; /* Disable interrupts */ @@ -296,16 +392,10 @@ static void RTC_IRAM_ATTR esp32_boot_loader_stub(void) __asm__ __volatile__("mov sp, %0" : : "r"(stack_top)); - /* Copy IRAM and RTC sections first, then DRAM last. This avoids executing - * from memory that can be overwritten during the chain-boot transition. + /* DRAM must be copied in the final stage to avoid self-overwrite while + * still executing from the currently running image. */ - esp32_copy_segment(args->segments[0].buffer, args->segments[0].dest_addr, - args->segments[0].size); - esp32_copy_segment(args->segments[1].buffer, args->segments[1].dest_addr, - args->segments[1].size); - esp32_copy_segment(args->segments[2].buffer, args->segments[2].dest_addr, - args->segments[2].size); esp32_copy_segment(dram_src, dram_dst, dram_size); /* Jump using a register-held entry address to avoid relying on DRAM. */ @@ -340,7 +430,12 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) { int fd; int ret; - uintptr_t stack_buf; + uint32_t partition_offset; + uint32_t load_header_offset; + uint32_t iram_offset; + uint32_t dram_offset; + uint32_t lp_rtc_iram_offset; + uint32_t lp_rtc_dram_offset; struct esp32_load_header_s load_header; /* Legacy/simple boot image formats are not supported */ @@ -360,26 +455,26 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) return -errno; } - /* Skip image header if present (e.g. MCUboot/nxboot header) */ - - if (hdr_size > 0) + ret = esp32_get_partition_offset(fd, &partition_offset); + if (ret < 0) { - if (lseek(fd, hdr_size, SEEK_SET) < 0) - { - ferr("ERROR: Failed to seek load header: %d\n", errno); - close(fd); - return -errno; - } + close(fd); + return ret; } - /* Read image load header generated for MCUboot app format */ + ret = esp32_flash_offset_add(partition_offset, hdr_size, + &load_header_offset); + if (ret < 0) + { + close(fd); + return ret; + } - ret = read(fd, &load_header, sizeof(struct esp32_load_header_s)); - if (ret != sizeof(struct esp32_load_header_s)) + ret = esp32_read_load_header(load_header_offset, &load_header); + if (ret < 0) { - ferr("ERROR: Failed to read image load header: %d\n", errno); close(fd); - return -errno; + return ret; } if (load_header.header_magic != ESP32_APP_LOAD_HEADER_MAGIC) @@ -390,78 +485,76 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) return -EINVAL; } - memset(&g_boot_loader_args, 0, sizeof(g_boot_loader_args)); - g_boot_loader_args.entry_addr = load_header.entry_addr; - - /* Preload segments into temporary buffers. They are copied to destination - * addresses by the final RTC-resident loader stage. - */ + ret = esp32_flash_offset_add(partition_offset, + load_header.iram_flash_offset, + &iram_offset); + if (ret < 0) + { + close(fd); + return ret; + } - ret = esp32_prepare_ram_segment(fd, load_header.iram_flash_offset, - load_header.iram_dest_addr, - load_header.iram_size, "iram", - &g_boot_loader_args, 0); + ret = esp32_flash_offset_add(partition_offset, + load_header.dram_flash_offset, + &dram_offset); if (ret < 0) { close(fd); return ret; } - ret = esp32_prepare_ram_segment(fd, load_header.lp_rtc_iram_flash_offset, - load_header.lp_rtc_iram_dest_addr, - load_header.lp_rtc_iram_size, - "lp_rtc_iram", &g_boot_loader_args, 1); + ret = esp32_flash_offset_add(partition_offset, + load_header.lp_rtc_iram_flash_offset, + &lp_rtc_iram_offset); if (ret < 0) { - esp32_release_ram_segments(&g_boot_loader_args); close(fd); return ret; } - ret = esp32_prepare_ram_segment(fd, load_header.lp_rtc_dram_flash_offset, - load_header.lp_rtc_dram_dest_addr, - load_header.lp_rtc_dram_size, - "lp_rtc_dram", &g_boot_loader_args, 2); + ret = esp32_flash_offset_add(partition_offset, + load_header.lp_rtc_dram_flash_offset, + &lp_rtc_dram_offset); if (ret < 0) { - esp32_release_ram_segments(&g_boot_loader_args); close(fd); return ret; } - ret = esp32_prepare_ram_segment(fd, load_header.dram_flash_offset, - load_header.dram_dest_addr, - load_header.dram_size, "dram", - &g_boot_loader_args, 3); + ret = esp32_copy_flash_segment(iram_offset, load_header.iram_dest_addr, + load_header.iram_size, "iram"); if (ret < 0) { - esp32_release_ram_segments(&g_boot_loader_args); close(fd); return ret; } - stack_buf = (uintptr_t)kmm_malloc(ESP32_BOOTLOADER_STACK_SIZE); - if (stack_buf == 0) + ret = esp32_copy_flash_segment(lp_rtc_iram_offset, + load_header.lp_rtc_iram_dest_addr, + load_header.lp_rtc_iram_size, + "lp_rtc_iram"); + if (ret < 0) { - ferr("ERROR: Failed to allocate boot loader stack\n"); - esp32_release_ram_segments(&g_boot_loader_args); close(fd); - return -ENOMEM; + return ret; } - if (esp32_ranges_overlap(stack_buf, ESP32_BOOTLOADER_STACK_SIZE, - load_header.dram_dest_addr, - load_header.dram_size)) + ret = esp32_copy_flash_segment(lp_rtc_dram_offset, + load_header.lp_rtc_dram_dest_addr, + load_header.lp_rtc_dram_size, + "lp_rtc_dram"); + if (ret < 0) { - ferr("ERROR: Boot loader stack overlaps DRAM destination\n"); - esp32_release_ram_segments(&g_boot_loader_args); - kmm_free((FAR void *)stack_buf); close(fd); - return -EFAULT; + return ret; } - g_boot_loader_args.stack_top = - (stack_buf + ESP32_BOOTLOADER_STACK_SIZE) & ~(uintptr_t)0xf; + ret = esp32_prepare_dram_handoff(dram_offset, &load_header); + if (ret < 0) + { + close(fd); + return ret; + } close(fd); From 06fadfd17b60887a8af6d7576bfd9870184656a4 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Sat, 21 Feb 2026 18:01:29 +0530 Subject: [PATCH 15/16] boards/xtensa/esp32: reserve IRAM/DRAM handoff regions for boot Rework board_boot_image() to use a fixed handoff layout instead of heap\nallocation in the final chain-boot path.\n\n- validate load-header entry and segment placement against reserved regions\n- reserve top DRAM area for handoff args + new stack\n- reserve top IRAM area for a copied boot stub\n- map segments via bootloader_mmap/munmap and copy RTC segments before handoff\n- jump through copied IRAM stub to perform IRAM/DRAM final copy and branch\n to the new entry point Signed-off-by: aviralgarg05 --- .../esp32/common/src/esp32_boot_image.c | 423 ++++++++++++------ 1 file changed, 285 insertions(+), 138 deletions(-) diff --git a/boards/xtensa/esp32/common/src/esp32_boot_image.c b/boards/xtensa/esp32/common/src/esp32_boot_image.c index a1cdf78264097..c164ba9ecf456 100644 --- a/boards/xtensa/esp32/common/src/esp32_boot_image.c +++ b/boards/xtensa/esp32/common/src/esp32_boot_image.c @@ -25,29 +25,38 @@ #include #include -#include #include #include #include -#include +#include #include +#include #include #include #include +#include #include #include -#include #include "bootloader_flash_priv.h" +#include "soc/soc.h" #include "xtensa_attr.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#define ESP32_APP_LOAD_HEADER_MAGIC 0xace637d3 -#define ESP32_BOOTLOADER_STACK_SIZE 2048 +#define ESP32_APP_LOAD_HEADER_MAGIC 0xace637d3 +#define ESP32_BOOTLOADER_STACK_SIZE 2048 +#define ESP32_BOOTLOADER_STUB_ALIGN 16 +#define ESP32_BOOTLOADER_STUB_SECTION \ + __attribute__((section(".iram1.bootstub"))) + +#define ESP32_ALIGN_UP(value, align) \ + (((uint32_t)(value) + ((uint32_t)(align) - 1)) & ~((uint32_t)(align) - 1)) +#define ESP32_ALIGN_DOWN(value, align) \ + ((uint32_t)(value) & ~((uint32_t)(align) - 1)) /**************************************************************************** * Private Types @@ -81,59 +90,81 @@ struct esp32_load_header_s struct esp32_boot_loader_args_s { uint32_t entry_addr; - uintptr_t stack_top; + uint32_t stack_top; + uint32_t iram_src; + uint32_t iram_dest_addr; + uint32_t iram_size; + uint32_t dram_src; uint32_t dram_dest_addr; uint32_t dram_size; - FAR const void *dram_src; }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ -static bool esp32_ranges_overlap(uintptr_t start1, size_t size1, - uintptr_t start2, size_t size2); +static bool esp32_region_contains(uint32_t low, uint32_t high, + uint32_t start, uint32_t size); static int esp32_get_partition_offset(int fd, FAR uint32_t *offset); static int esp32_flash_offset_add(uint32_t base, uint32_t offset, FAR uint32_t *result); static int esp32_read_load_header(uint32_t flash_offset, FAR struct esp32_load_header_s *header); -static int esp32_copy_flash_segment(uint32_t flash_offset, - uint32_t dest_addr, uint32_t size, - FAR const char *name); -static int esp32_prepare_dram_handoff(uint32_t flash_offset, - FAR const struct esp32_load_header_s - *load_header); -static void RTC_IRAM_ATTR esp32_copy_segment(FAR const void *src, - uint32_t dest_addr, - uint32_t size); -static void RTC_IRAM_ATTR esp32_boot_loader_stub(void); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct esp32_boot_loader_args_s g_boot_loader_args; +static int esp32_map_flash_segment(uint32_t flash_offset, uint32_t size, + FAR const char *name, + FAR const void **mapping); +static void esp32_unmap_flash_segment(FAR const void **mapping); +static int esp32_prepare_handoff_layout( + FAR const struct esp32_load_header_s *load_header, + uint32_t stub_size, + FAR uint32_t *stub_dst, + FAR uint32_t *args_addr, + FAR uint32_t *stack_top); +static void IRAM_ATTR esp32_copy_segment(FAR const void *src, + uint32_t dest_addr, + uint32_t size); +static void ESP32_BOOTLOADER_STUB_SECTION __attribute__((used, noinline, + naked)) + esp32_boot_loader_stub( + FAR const struct esp32_boot_loader_args_s *args); +static void ESP32_BOOTLOADER_STUB_SECTION __attribute__((used, noinline, + naked)) + esp32_boot_loader_stub_end(void); /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: esp32_ranges_overlap + * Name: esp32_region_contains * * Description: - * Return true when two address ranges overlap. + * Return true if [start, start + size) is fully inside [low, high). * ****************************************************************************/ -static bool esp32_ranges_overlap(uintptr_t start1, size_t size1, - uintptr_t start2, size_t size2) +static bool esp32_region_contains(uint32_t low, uint32_t high, + uint32_t start, uint32_t size) { - uintptr_t end1 = start1 + size1; - uintptr_t end2 = start2 + size2; + uint64_t end; - return (start1 < end2) && (start2 < end1); + if (size == 0) + { + return true; + } + + if (start < low) + { + return false; + } + + end = (uint64_t)start + (uint64_t)size; + if (end > (uint64_t)high) + { + return false; + } + + return true; } /**************************************************************************** @@ -235,110 +266,145 @@ static int esp32_read_load_header(uint32_t flash_offset, } /**************************************************************************** - * Name: esp32_copy_flash_segment + * Name: esp32_map_flash_segment * * Description: - * Load one segment from flash to RAM via ROM mmap routines. + * Map one segment from flash for later copy. * ****************************************************************************/ -static int esp32_copy_flash_segment(uint32_t flash_offset, - uint32_t dest_addr, uint32_t size, - FAR const char *name) +static int esp32_map_flash_segment(uint32_t flash_offset, uint32_t size, + FAR const char *name, + FAR const void **mapping) { - FAR const void *mapping; - - if (size == 0) + if (mapping == NULL) { - return OK; + return -EINVAL; } - if (dest_addr == 0) + *mapping = NULL; + + if (size == 0) { - ferr("ERROR: Invalid %s destination address\n", name); - return -EINVAL; + return OK; } - mapping = bootloader_mmap(flash_offset, size); - if (mapping == NULL) + *mapping = bootloader_mmap(flash_offset, size); + if (*mapping == NULL) { ferr("ERROR: Failed to mmap %s segment\n", name); return -EIO; } - finfo("Loading %-9s: dst=0x%08" PRIx32 " off=0x%08" PRIx32 - " size=0x%08" PRIx32 "\n", - name, dest_addr, flash_offset, size); + return OK; +} - esp32_copy_segment(mapping, dest_addr, size); - bootloader_munmap(mapping); +/**************************************************************************** + * Name: esp32_unmap_flash_segment + * + * Description: + * Unmap one mapped flash segment. + * + ****************************************************************************/ - return OK; +static void esp32_unmap_flash_segment(FAR const void **mapping) +{ + if (mapping != NULL && *mapping != NULL) + { + bootloader_munmap(*mapping); + *mapping = NULL; + } } /**************************************************************************** - * Name: esp32_prepare_dram_handoff + * Name: esp32_prepare_handoff_layout * * Description: - * Prepare final DRAM copy handoff data. DRAM is copied in the RTC loader - * just before jumping to the new entry point. + * Reserve DRAM region for new stack+args and IRAM region for stub code, + * then validate image layout against reserved regions. * ****************************************************************************/ -static int esp32_prepare_dram_handoff(uint32_t flash_offset, - FAR const struct esp32_load_header_s - *load_header) +static int esp32_prepare_handoff_layout( + FAR const struct esp32_load_header_s *load_header, + uint32_t stub_size, + FAR uint32_t *stub_dst, + FAR uint32_t *args_addr, + FAR uint32_t *stack_top) { - uintptr_t stack_buf; + uint32_t reserved_dram; + uint32_t dram_reserved_start; + uint32_t iram_reserved_start; + uint32_t args_size; + + if (load_header == NULL || stub_dst == NULL || args_addr == NULL || + stack_top == NULL) + { + return -EINVAL; + } + + if (!esp32_region_contains(SOC_IRAM_LOW, SOC_IRAM_HIGH, + load_header->entry_addr, 1)) + { + ferr("ERROR: Entry point is not in IRAM: 0x%08" PRIx32 "\n", + load_header->entry_addr); + return -EINVAL; + } - DEBUGASSERT(load_header != NULL); + args_size = ESP32_ALIGN_UP(sizeof(struct esp32_boot_loader_args_s), + ESP32_BOOTLOADER_STUB_ALIGN); + reserved_dram = args_size + ESP32_BOOTLOADER_STACK_SIZE; - memset(&g_boot_loader_args, 0, sizeof(g_boot_loader_args)); + if (reserved_dram >= (SOC_DRAM_HIGH - SOC_DRAM_LOW)) + { + ferr("ERROR: Reserved DRAM region too large\n"); + return -EINVAL; + } - g_boot_loader_args.entry_addr = load_header->entry_addr; - g_boot_loader_args.dram_dest_addr = load_header->dram_dest_addr; - g_boot_loader_args.dram_size = load_header->dram_size; + dram_reserved_start = ESP32_ALIGN_DOWN(SOC_DRAM_HIGH - reserved_dram, + ESP32_BOOTLOADER_STUB_ALIGN); + iram_reserved_start = ESP32_ALIGN_DOWN(SOC_IRAM_HIGH - stub_size, + ESP32_BOOTLOADER_STUB_ALIGN); - if (g_boot_loader_args.dram_size == 0) + if (iram_reserved_start < SOC_IRAM_LOW) { + ferr("ERROR: Reserved IRAM region too large\n"); return -EINVAL; } - if (g_boot_loader_args.dram_dest_addr == 0) + if (!esp32_region_contains(SOC_IRAM_LOW, iram_reserved_start, + load_header->iram_dest_addr, + load_header->iram_size)) { + ferr("ERROR: IRAM segment overlaps reserved IRAM stub region\n"); return -EINVAL; } - g_boot_loader_args.dram_src = - bootloader_mmap(flash_offset, g_boot_loader_args.dram_size); - if (g_boot_loader_args.dram_src == NULL) + if (!esp32_region_contains(SOC_DRAM_LOW, dram_reserved_start, + load_header->dram_dest_addr, + load_header->dram_size)) { - ferr("ERROR: Failed to mmap dram segment\n"); - return -EIO; + ferr("ERROR: DRAM segment overlaps reserved DRAM stack region\n"); + return -EINVAL; } - stack_buf = (uintptr_t)kmm_malloc(ESP32_BOOTLOADER_STACK_SIZE); - if (stack_buf == 0) + if (load_header->lp_rtc_iram_size > 0 && + load_header->lp_rtc_iram_dest_addr == 0) { - ferr("ERROR: Failed to allocate boot loader stack\n"); - bootloader_munmap(g_boot_loader_args.dram_src); - g_boot_loader_args.dram_src = NULL; - return -ENOMEM; + ferr("ERROR: Invalid lp_rtc_iram destination\n"); + return -EINVAL; } - if (esp32_ranges_overlap(stack_buf, ESP32_BOOTLOADER_STACK_SIZE, - g_boot_loader_args.dram_dest_addr, - g_boot_loader_args.dram_size)) + if (load_header->lp_rtc_dram_size > 0 && + load_header->lp_rtc_dram_dest_addr == 0) { - ferr("ERROR: Boot loader stack overlaps DRAM destination\n"); - kmm_free((FAR void *)stack_buf); - bootloader_munmap(g_boot_loader_args.dram_src); - g_boot_loader_args.dram_src = NULL; - return -EFAULT; + ferr("ERROR: Invalid lp_rtc_dram destination\n"); + return -EINVAL; } - g_boot_loader_args.stack_top = - (stack_buf + ESP32_BOOTLOADER_STACK_SIZE) & ~(uintptr_t)0xf; + *stub_dst = iram_reserved_start; + *args_addr = dram_reserved_start; + *stack_top = ESP32_ALIGN_DOWN(SOC_DRAM_HIGH, ESP32_BOOTLOADER_STUB_ALIGN); return OK; } @@ -351,9 +417,9 @@ static int esp32_prepare_dram_handoff(uint32_t flash_offset, * ****************************************************************************/ -static void RTC_IRAM_ATTR esp32_copy_segment(FAR const void *src, - uint32_t dest_addr, - uint32_t size) +static void IRAM_ATTR esp32_copy_segment(FAR const void *src, + uint32_t dest_addr, + uint32_t size) { FAR const uint8_t *s = (FAR const uint8_t *)src; FAR uint8_t *d = (FAR uint8_t *)(uintptr_t)dest_addr; @@ -368,43 +434,61 @@ static void RTC_IRAM_ATTR esp32_copy_segment(FAR const void *src, * Name: esp32_boot_loader_stub * * Description: - * Final loader stage. The routine executes from RTC fast memory and copies - * the DRAM segment just before jumping to the new image entry point. + * Final loader stage copied to the reserved IRAM area before handoff. * ****************************************************************************/ -static void RTC_IRAM_ATTR esp32_boot_loader_stub(void) +static void ESP32_BOOTLOADER_STUB_SECTION __attribute__((used, noinline, + naked)) +esp32_boot_loader_stub(FAR const struct esp32_boot_loader_args_s *args) { - FAR const struct esp32_boot_loader_args_s *args = &g_boot_loader_args; - register uintptr_t stack_top = args->stack_top; - register uint32_t entry_addr = args->entry_addr; - register FAR const void *dram_src = args->dram_src; - register uint32_t dram_dst = args->dram_dest_addr; - register uint32_t dram_size = args->dram_size; - - /* Disable interrupts */ - - up_irq_disable(); - - /* Use a dedicated handoff stack that does not overlap the DRAM segment - * destination copied in the final step. - */ - - __asm__ __volatile__("mov sp, %0" : : "r"(stack_top)); - - /* DRAM must be copied in the final stage to avoid self-overwrite while - * still executing from the currently running image. - */ - - esp32_copy_segment(dram_src, dram_dst, dram_size); - - /* Jump using a register-held entry address to avoid relying on DRAM. */ - - __asm__ __volatile__("jx %0" : : "r"(entry_addr)); + __asm__ __volatile__( + "l32i a3, a2, 4\n" /* stack_top */ + "mov sp, a3\n" + "l32i a4, a2, 8\n" /* iram_src */ + "l32i a5, a2, 12\n" /* iram_dest_addr */ + "l32i a6, a2, 16\n" /* iram_size */ + "1:\n" + "beqz a6, 2f\n" + "l8ui a7, a4, 0\n" + "s8i a7, a5, 0\n" + "addi a4, a4, 1\n" + "addi a5, a5, 1\n" + "addi a6, a6, -1\n" + "j 1b\n" + "2:\n" + "l32i a4, a2, 20\n" /* dram_src */ + "l32i a5, a2, 24\n" /* dram_dest_addr */ + "l32i a6, a2, 28\n" /* dram_size */ + "3:\n" + "beqz a6, 4f\n" + "l8ui a7, a4, 0\n" + "s8i a7, a5, 0\n" + "addi a4, a4, 1\n" + "addi a5, a5, 1\n" + "addi a6, a6, -1\n" + "j 3b\n" + "4:\n" + "l32i a3, a2, 0\n" /* entry_addr */ + "jx a3\n" + : + : + : "a3", "a4", "a5", "a6", "a7", "memory"); +} - /* Should never return */ +/**************************************************************************** + * Name: esp32_boot_loader_stub_end + * + * Description: + * Marker used to determine the boot stub size. + * + ****************************************************************************/ - PANIC(); +static void ESP32_BOOTLOADER_STUB_SECTION __attribute__((used, noinline, + naked)) +esp32_boot_loader_stub_end(void) +{ + __asm__ __volatile__("ret.n\n"); } /**************************************************************************** @@ -436,7 +520,16 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) uint32_t dram_offset; uint32_t lp_rtc_iram_offset; uint32_t lp_rtc_dram_offset; - struct esp32_load_header_s load_header; + uint32_t stub_dst; + uint32_t stub_size; + uint32_t args_addr; + uint32_t stack_top; + FAR const void *iram_src = NULL; + FAR const void *dram_src = NULL; + FAR const void *lp_rtc_iram_src = NULL; + FAR const void *lp_rtc_dram_src = NULL; + FAR struct esp32_boot_loader_args_s *stub_args; + FAR struct esp32_load_header_s load_header; /* Legacy/simple boot image formats are not supported */ @@ -446,7 +539,15 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) return -ENOTSUP; #endif - /* Open the image file */ + stub_size = (uint32_t)((uintptr_t)esp32_boot_loader_stub_end - + (uintptr_t)esp32_boot_loader_stub); + if (stub_size == 0) + { + ferr("ERROR: Invalid boot loader stub size\n"); + return -EINVAL; + } + + stub_size = ESP32_ALIGN_UP(stub_size, ESP32_BOOTLOADER_STUB_ALIGN); fd = open(path, O_RDONLY); if (fd < 0) @@ -485,6 +586,14 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) return -EINVAL; } + ret = esp32_prepare_handoff_layout(&load_header, stub_size, + &stub_dst, &args_addr, &stack_top); + if (ret < 0) + { + close(fd); + return ret; + } + ret = esp32_flash_offset_add(partition_offset, load_header.iram_flash_offset, &iram_offset); @@ -521,49 +630,87 @@ int board_boot_image(FAR const char *path, uint32_t hdr_size) return ret; } - ret = esp32_copy_flash_segment(iram_offset, load_header.iram_dest_addr, - load_header.iram_size, "iram"); + ret = esp32_map_flash_segment(iram_offset, load_header.iram_size, + "iram", &iram_src); if (ret < 0) { close(fd); return ret; } - ret = esp32_copy_flash_segment(lp_rtc_iram_offset, - load_header.lp_rtc_iram_dest_addr, - load_header.lp_rtc_iram_size, - "lp_rtc_iram"); + ret = esp32_map_flash_segment(dram_offset, load_header.dram_size, + "dram", &dram_src); if (ret < 0) { + esp32_unmap_flash_segment(&iram_src); close(fd); return ret; } - ret = esp32_copy_flash_segment(lp_rtc_dram_offset, - load_header.lp_rtc_dram_dest_addr, - load_header.lp_rtc_dram_size, - "lp_rtc_dram"); + ret = esp32_map_flash_segment(lp_rtc_iram_offset, + load_header.lp_rtc_iram_size, + "lp_rtc_iram", &lp_rtc_iram_src); if (ret < 0) { + esp32_unmap_flash_segment(&dram_src); + esp32_unmap_flash_segment(&iram_src); close(fd); return ret; } - ret = esp32_prepare_dram_handoff(dram_offset, &load_header); + ret = esp32_map_flash_segment(lp_rtc_dram_offset, + load_header.lp_rtc_dram_size, + "lp_rtc_dram", &lp_rtc_dram_src); if (ret < 0) { + esp32_unmap_flash_segment(&lp_rtc_iram_src); + esp32_unmap_flash_segment(&dram_src); + esp32_unmap_flash_segment(&iram_src); close(fd); return ret; } + /* Copy the final handoff stub into the reserved IRAM region. */ + + esp32_copy_segment((FAR const void *)(uintptr_t)esp32_boot_loader_stub, + stub_dst, stub_size); + up_invalidate_icache((uintptr_t)stub_dst, (uintptr_t)stub_dst + stub_size); + + /* Prepare handoff args in reserved DRAM region below the new stack. */ + + stub_args = (FAR struct esp32_boot_loader_args_s *)(uintptr_t)args_addr; + stub_args->entry_addr = load_header.entry_addr; + stub_args->stack_top = stack_top; + stub_args->iram_src = (uint32_t)(uintptr_t)iram_src; + stub_args->iram_dest_addr = load_header.iram_dest_addr; + stub_args->iram_size = load_header.iram_size; + stub_args->dram_src = (uint32_t)(uintptr_t)dram_src; + stub_args->dram_dest_addr = load_header.dram_dest_addr; + stub_args->dram_size = load_header.dram_size; + close(fd); - finfo("Booting image: entry=0x%08" PRIx32 "\n", - g_boot_loader_args.entry_addr); + /* From this point on we cannot safely return to NuttX. */ + + up_irq_disable(); + + if (load_header.lp_rtc_iram_size > 0) + { + esp32_copy_segment(lp_rtc_iram_src, + load_header.lp_rtc_iram_dest_addr, + load_header.lp_rtc_iram_size); + } - /* Invoke final RTC loader stub. */ + if (load_header.lp_rtc_dram_size > 0) + { + esp32_copy_segment(lp_rtc_dram_src, + load_header.lp_rtc_dram_dest_addr, + load_header.lp_rtc_dram_size); + } - esp32_boot_loader_stub(); + ((void (*)(FAR const struct esp32_boot_loader_args_s *)) + (uintptr_t)stub_dst)(stub_args); + PANIC(); return 0; } From a4cdbdf84f8d01f9212cbf52694ec1aada4e4e26 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Fri, 27 Feb 2026 15:39:59 +0530 Subject: [PATCH 16/16] arch/esp32: drop formatting-only churn in partition header Restore partition.h formatting to match upstream and keep this PR\nfocused on board_boot_image changes only. Signed-off-by: aviralgarg05 --- arch/xtensa/include/esp32/partition.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/xtensa/include/esp32/partition.h b/arch/xtensa/include/esp32/partition.h index 02652e678d8ec..20a8c21bb061a 100644 --- a/arch/xtensa/include/esp32/partition.h +++ b/arch/xtensa/include/esp32/partition.h @@ -35,13 +35,13 @@ enum ota_img_ctrl { - OTA_IMG_GET_BOOT = 0xe1, - OTA_IMG_SET_BOOT = 0xe2, - OTA_IMG_SET_ENCRYPTED = 0xe3, - OTA_IMG_GET_ENCRYPTED = 0xe4, - OTA_IMG_GET_TYPE = 0xe5, - OTA_IMG_GET_SUBTYPE = 0xe6, - OTA_IMG_INVALIDATE_BOOT = 0xe7, + OTA_IMG_GET_BOOT = 0xe1, + OTA_IMG_SET_BOOT = 0xe2, + OTA_IMG_SET_ENCRYPTED = 0xe3, + OTA_IMG_GET_ENCRYPTED = 0xe4, + OTA_IMG_GET_TYPE = 0xe5, + OTA_IMG_GET_SUBTYPE = 0xe6, + OTA_IMG_INVALIDATE_BOOT = 0xe7, OTA_IMG_IS_MAPPED_AS_TEXT = 0xe8, }; @@ -49,9 +49,9 @@ enum ota_img_ctrl enum ota_img_bootseq { - OTA_IMG_BOOT_FACTORY = 0, - OTA_IMG_BOOT_OTA_0 = 1, - OTA_IMG_BOOT_OTA_1 = 2, + OTA_IMG_BOOT_FACTORY = 0, + OTA_IMG_BOOT_OTA_0 = 1, + OTA_IMG_BOOT_OTA_1 = 2, OTA_IMG_BOOT_SEQ_MAX }; @@ -72,7 +72,7 @@ enum ota_img_bootseq * ****************************************************************************/ -int esp32_partition_read_decrypt(const char *label, size_t offset, void *buf, - size_t size); +int esp32_partition_read_decrypt(const char *label, size_t offset, + void *buf, size_t size); #endif /* __ARCH_XTENSA_INCLUDE_ESP32_PARTITION_H */