mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
bootloader: Fallback if OTA data is invalid
Make bootloader more robust if either OTA data or some OTA app slots are corrupt.
This commit is contained in:
parent
cd5cc9927b
commit
5eef5e7a5d
@ -129,6 +129,9 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t* partition);
|
|||||||
* If esp_ota_set_boot_partition() has not been called, the result is
|
* If esp_ota_set_boot_partition() has not been called, the result is
|
||||||
* equivalent to esp_ota_get_running_partition().
|
* equivalent to esp_ota_get_running_partition().
|
||||||
*
|
*
|
||||||
|
* Note that there is no guarantee the returned partition is a valid app. Use esp_image_load(ESP_IMAGE_VERIFY, ...) to verify if the
|
||||||
|
* partition contains a bootable image.
|
||||||
|
*
|
||||||
* @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application.
|
* @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application.
|
||||||
*/
|
*/
|
||||||
const esp_partition_t* esp_ota_get_boot_partition(void);
|
const esp_partition_t* esp_ota_get_boot_partition(void);
|
||||||
@ -142,6 +145,9 @@ const esp_partition_t* esp_ota_get_boot_partition(void);
|
|||||||
* esp_ota_set_boot_partition(). Only the app whose code is currently
|
* esp_ota_set_boot_partition(). Only the app whose code is currently
|
||||||
* running will have its partition information returned.
|
* running will have its partition information returned.
|
||||||
*
|
*
|
||||||
|
* The partition returned by this function may also differ from esp_ota_get_boot_partition() if the configured boot
|
||||||
|
* partition is somehow invalid, and the bootloader fell back to a different app partition at boot.
|
||||||
|
*
|
||||||
* @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application.
|
* @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application.
|
||||||
*/
|
*/
|
||||||
const esp_partition_t* esp_ota_get_running_partition(void);
|
const esp_partition_t* esp_ota_get_running_partition(void);
|
||||||
|
@ -28,11 +28,13 @@ extern "C"
|
|||||||
|
|
||||||
#define SPI_ERROR_LOG "spi flash error"
|
#define SPI_ERROR_LOG "spi flash error"
|
||||||
|
|
||||||
|
#define MAX_OTA_SLOTS 16
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
esp_partition_pos_t ota_info;
|
esp_partition_pos_t ota_info;
|
||||||
esp_partition_pos_t factory;
|
esp_partition_pos_t factory;
|
||||||
esp_partition_pos_t test;
|
esp_partition_pos_t test;
|
||||||
esp_partition_pos_t ota[16];
|
esp_partition_pos_t ota[MAX_OTA_SLOTS];
|
||||||
uint32_t app_count;
|
uint32_t app_count;
|
||||||
uint32_t selected_subtype;
|
uint32_t selected_subtype;
|
||||||
} bootloader_state_t;
|
} bootloader_state_t;
|
||||||
|
@ -63,7 +63,7 @@ static const char* TAG = "boot";
|
|||||||
#define MAP_ERR_MSG "Image contains multiple %s segments. Only the last one will be mapped."
|
#define MAP_ERR_MSG "Image contains multiple %s segments. Only the last one will be mapped."
|
||||||
|
|
||||||
void bootloader_main();
|
void bootloader_main();
|
||||||
static void unpack_load_app(const esp_partition_pos_t *app_node);
|
static void unpack_load_app(const esp_image_metadata_t *data);
|
||||||
static void print_flash_info(const esp_image_header_t* pfhdr);
|
static void print_flash_info(const esp_image_header_t* pfhdr);
|
||||||
static void set_cache_and_start_app(uint32_t drom_addr,
|
static void set_cache_and_start_app(uint32_t drom_addr,
|
||||||
uint32_t drom_load_addr,
|
uint32_t drom_load_addr,
|
||||||
@ -245,6 +245,179 @@ static bool ota_select_valid(const esp_ota_select_entry_t *s)
|
|||||||
return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
|
return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* indexes used by index_to_partition are the OTA index
|
||||||
|
number, or these special constants */
|
||||||
|
#define FACTORY_INDEX (-1)
|
||||||
|
#define TEST_APP_INDEX (-2)
|
||||||
|
#define INVALID_INDEX (-99)
|
||||||
|
|
||||||
|
/* Given a partition index, return the partition position data from the bootloader_state_t structure */
|
||||||
|
static esp_partition_pos_t index_to_partition(const bootloader_state_t *bs, int index)
|
||||||
|
{
|
||||||
|
if (index == FACTORY_INDEX) {
|
||||||
|
return bs->factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == TEST_APP_INDEX) {
|
||||||
|
return bs->test;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0 && index < MAX_OTA_SLOTS) {
|
||||||
|
return bs->ota[index % bs->app_count];
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_partition_pos_t invalid = { 0 };
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_invalid_app_partition(int index)
|
||||||
|
{
|
||||||
|
switch(index) {
|
||||||
|
case FACTORY_INDEX:
|
||||||
|
ESP_LOGE(TAG, "Factory app partition is not bootable");
|
||||||
|
break;
|
||||||
|
case TEST_APP_INDEX:
|
||||||
|
ESP_LOGE(TAG, "Factory test app partition is not bootable");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGE(TAG, "OTA app partition slot %d is not bootable", index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the index of the selected boot partition.
|
||||||
|
|
||||||
|
This is the preferred boot partition, as determined by the partition table & OTA data.
|
||||||
|
|
||||||
|
This partition will only be booted if it contains a valid app image, otherwise load_boot_image() will search
|
||||||
|
for a valid partition using this selection as the starting point.
|
||||||
|
*/
|
||||||
|
static int get_selected_boot_partition(const bootloader_state_t *bs)
|
||||||
|
{
|
||||||
|
esp_ota_select_entry_t sa,sb;
|
||||||
|
const esp_ota_select_entry_t *ota_select_map;
|
||||||
|
|
||||||
|
if (bs->ota_info.offset != 0) {
|
||||||
|
// partition table has OTA data partition
|
||||||
|
if (bs->ota_info.size < 2 * SPI_SEC_SIZE) {
|
||||||
|
ESP_LOGE(TAG, "ota_info partition size %d is too small (minimum %d bytes)", bs->ota_info.size, sizeof(esp_ota_select_entry_t));
|
||||||
|
return INVALID_INDEX; // can't proceed
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "OTA data offset 0x%x", bs->ota_info.offset);
|
||||||
|
ota_select_map = bootloader_mmap(bs->ota_info.offset, bs->ota_info.size);
|
||||||
|
if (!ota_select_map) {
|
||||||
|
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs->ota_info.offset, bs->ota_info.size);
|
||||||
|
return INVALID_INDEX; // can't proceed
|
||||||
|
}
|
||||||
|
memcpy(&sa, ota_select_map, sizeof(esp_ota_select_entry_t));
|
||||||
|
memcpy(&sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
|
||||||
|
bootloader_munmap(ota_select_map);
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "OTA sequence values A 0x%08x B 0x%08x", sa.ota_seq, sb.ota_seq);
|
||||||
|
if(sa.ota_seq == UINT32_MAX && sb.ota_seq == UINT32_MAX) {
|
||||||
|
ESP_LOGD(TAG, "OTA sequence numbers both empty (all-0xFF)");
|
||||||
|
if (bs->factory.offset != 0) {
|
||||||
|
ESP_LOGI(TAG, "Defaulting to factory image");
|
||||||
|
return FACTORY_INDEX;
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "No factory image, trying OTA 0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(ota_select_valid(&sa) && ota_select_valid(&sb)) {
|
||||||
|
ESP_LOGD(TAG, "Both OTA sequence valid, using OTA slot %d", MAX(sa.ota_seq, sb.ota_seq)-1);
|
||||||
|
return MAX(sa.ota_seq, sb.ota_seq) - 1;
|
||||||
|
} else if(ota_select_valid(&sa)) {
|
||||||
|
ESP_LOGD(TAG, "Only OTA sequence A is valid, using OTA slot %d", sa.ota_seq - 1);
|
||||||
|
return sa.ota_seq - 1;
|
||||||
|
} else if(ota_select_valid(&sb)) {
|
||||||
|
ESP_LOGD(TAG, "Only OTA sequence B is valid, using OTA slot %d", sb.ota_seq - 1);
|
||||||
|
return sb.ota_seq - 1;
|
||||||
|
} else if (bs->factory.offset != 0) {
|
||||||
|
ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
|
||||||
|
return FACTORY_INDEX;
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "ota data partition invalid and no factory, will try all partitions");
|
||||||
|
return FACTORY_INDEX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, start from factory app partition and let the search logic
|
||||||
|
// proceed from there
|
||||||
|
return FACTORY_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if a partition has a valid app image that was successfully loaded */
|
||||||
|
static bool try_load_partition(const esp_partition_pos_t *partition, esp_image_metadata_t *data)
|
||||||
|
{
|
||||||
|
if (partition->size == 0) {
|
||||||
|
ESP_LOGD(TAG, "Can't boot from zero-length partition");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esp_image_load(ESP_IMAGE_LOAD, partition, data) == ESP_OK) {
|
||||||
|
ESP_LOGI(TAG, "Loaded app from partition at offset 0x%x",
|
||||||
|
partition->offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load the app for booting. Start from partition 'start_index', if not bootable then work backwards to FACTORY_INDEX
|
||||||
|
* (ie try any OTA slots in descending order and then the factory partition).
|
||||||
|
*
|
||||||
|
* If still nothing, start from 'start_index + 1' and work up to highest numbered OTA partition.
|
||||||
|
*
|
||||||
|
* If still nothing, try TEST_APP_INDEX
|
||||||
|
*
|
||||||
|
* Returns true on success, false if there's no bootable app in the partition table.
|
||||||
|
*/
|
||||||
|
static bool load_boot_image(const bootloader_state_t *bs, int start_index, esp_image_metadata_t *result)
|
||||||
|
{
|
||||||
|
int index = start_index;
|
||||||
|
esp_partition_pos_t part;
|
||||||
|
|
||||||
|
/* work backwards from start_index, down to the factory app */
|
||||||
|
do {
|
||||||
|
ESP_LOGD(TAG, "Trying partition index %d...", index);
|
||||||
|
part = index_to_partition(bs, index);
|
||||||
|
ESP_LOGD(TAG, "part offs 0x%x size 0x%x", part.offset, part.size);
|
||||||
|
if (try_load_partition(&part, result)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (part.size > 0) {
|
||||||
|
log_invalid_app_partition(index);
|
||||||
|
}
|
||||||
|
index--;
|
||||||
|
} while(index >= FACTORY_INDEX);
|
||||||
|
|
||||||
|
/* failing that work forwards from start_index, try valid OTA slots */
|
||||||
|
index = start_index + 1;
|
||||||
|
while (index < bs->app_count) {
|
||||||
|
ESP_LOGD(TAG, "Trying partition index %d...", index);
|
||||||
|
part = index_to_partition(bs, index);
|
||||||
|
if (try_load_partition(&part, result)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
log_invalid_app_partition(index);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (try_load_partition(&bs->test, result)) {
|
||||||
|
ESP_LOGW(TAG, "Falling back to test app as only bootable partition");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGE(TAG, "No bootable app partitions in the partition table");
|
||||||
|
bzero(result, sizeof(esp_image_metadata_t));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function : bootloader_main
|
* @function : bootloader_main
|
||||||
* @description: entry function of 2nd bootloader
|
* @description: entry function of 2nd bootloader
|
||||||
@ -262,12 +435,7 @@ void bootloader_main()
|
|||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
#endif
|
#endif
|
||||||
esp_image_header_t fhdr;
|
esp_image_header_t fhdr;
|
||||||
bootloader_state_t bs;
|
bootloader_state_t bs = { 0 };
|
||||||
esp_rom_spiflash_result_t spiRet1,spiRet2;
|
|
||||||
esp_ota_select_entry_t sa,sb;
|
|
||||||
const esp_ota_select_entry_t *ota_select_map;
|
|
||||||
|
|
||||||
memset(&bs, 0, sizeof(bs));
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "compile time " __TIME__ );
|
ESP_LOGI(TAG, "compile time " __TIME__ );
|
||||||
ets_set_appcpu_boot_addr(0);
|
ets_set_appcpu_boot_addr(0);
|
||||||
@ -308,77 +476,13 @@ void bootloader_main()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_partition_pos_t load_part_pos;
|
int boot_index = get_selected_boot_partition(&bs);
|
||||||
|
if (boot_index == INVALID_INDEX) {
|
||||||
if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition
|
return; // Unrecoverable failure (not due to corrupt ota data or bad partition contents)
|
||||||
//ESP_LOGE("OTA info sector handling is not implemented");
|
}
|
||||||
if (bs.ota_info.size < 2 * SPI_SEC_SIZE) {
|
// Start from the default, look for the first bootable partition
|
||||||
ESP_LOGE(TAG, "ERROR: ota_info partition size %d is too small (minimum %d bytes)", bs.ota_info.size, sizeof(esp_ota_select_entry_t));
|
esp_image_metadata_t image_data;
|
||||||
return;
|
if (!load_boot_image(&bs, boot_index, &image_data)) {
|
||||||
}
|
|
||||||
ota_select_map = bootloader_mmap(bs.ota_info.offset, bs.ota_info.size);
|
|
||||||
if (!ota_select_map) {
|
|
||||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs.ota_info.offset, bs.ota_info.size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(&sa, ota_select_map, sizeof(esp_ota_select_entry_t));
|
|
||||||
memcpy(&sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
|
|
||||||
bootloader_munmap(ota_select_map);
|
|
||||||
ESP_LOGD(TAG, "OTA sequence values A 0x%08x B 0x%08x", sa.ota_seq, sb.ota_seq);
|
|
||||||
if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) {
|
|
||||||
ESP_LOGD(TAG, "OTA sequence numbers both empty (all-0xFF");
|
|
||||||
// init status flash
|
|
||||||
if (bs.factory.offset != 0) { // if have factory bin,boot factory bin
|
|
||||||
ESP_LOGD(TAG, "Defaulting to factory image");
|
|
||||||
load_part_pos = bs.factory;
|
|
||||||
} else {
|
|
||||||
ESP_LOGD(TAG, "No factory image, defaulting to OTA 0");
|
|
||||||
load_part_pos = bs.ota[0];
|
|
||||||
sa.ota_seq = 0x01;
|
|
||||||
sa.crc = ota_select_crc(&sa);
|
|
||||||
sb.ota_seq = 0x00;
|
|
||||||
sb.crc = ota_select_crc(&sb);
|
|
||||||
|
|
||||||
Cache_Read_Disable(0);
|
|
||||||
spiRet1 = esp_rom_spiflash_erase_sector(bs.ota_info.offset/0x1000);
|
|
||||||
spiRet2 = esp_rom_spiflash_erase_sector(bs.ota_info.offset/0x1000+1);
|
|
||||||
if (spiRet1 != ESP_ROM_SPIFLASH_RESULT_OK || spiRet2 != ESP_ROM_SPIFLASH_RESULT_OK ) {
|
|
||||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
spiRet1 = esp_rom_spiflash_write(bs.ota_info.offset,(uint32_t *)&sa,sizeof(esp_ota_select_entry_t));
|
|
||||||
spiRet2 = esp_rom_spiflash_write(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(esp_ota_select_entry_t));
|
|
||||||
if (spiRet1 != ESP_ROM_SPIFLASH_RESULT_OK || spiRet2 != ESP_ROM_SPIFLASH_RESULT_OK ) {
|
|
||||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Cache_Read_Enable(0);
|
|
||||||
}
|
|
||||||
//TODO:write data in ota info
|
|
||||||
} else {
|
|
||||||
if(ota_select_valid(&sa) && ota_select_valid(&sb)) {
|
|
||||||
ESP_LOGD(TAG, "Both OTA sequence valid, using OTA slot %d", MAX(sa.ota_seq, sb.ota_seq)-1);
|
|
||||||
load_part_pos = bs.ota[(MAX(sa.ota_seq, sb.ota_seq) - 1)%bs.app_count];
|
|
||||||
} else if(ota_select_valid(&sa)) {
|
|
||||||
ESP_LOGD(TAG, "Only OTA sequence A is valid, using OTA slot %d", sa.ota_seq - 1);
|
|
||||||
load_part_pos = bs.ota[(sa.ota_seq - 1) % bs.app_count];
|
|
||||||
} else if(ota_select_valid(&sb)) {
|
|
||||||
ESP_LOGD(TAG, "Only OTA sequence B is valid, using OTA slot %d", sa.ota_seq - 1);
|
|
||||||
load_part_pos = bs.ota[(sb.ota_seq - 1) % bs.app_count];
|
|
||||||
} else if (bs.factory.offset != 0) {
|
|
||||||
ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
|
|
||||||
load_part_pos = bs.factory;
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG, "ota data partition invalid and no factory, can't boot");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (bs.factory.offset != 0) { // otherwise, look for factory app partition
|
|
||||||
load_part_pos = bs.factory;
|
|
||||||
} else if (bs.test.offset != 0) { // otherwise, look for test app parition
|
|
||||||
load_part_pos = bs.test;
|
|
||||||
} else { // nothing to load, bail out
|
|
||||||
ESP_LOGE(TAG, "nothing to load");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,17 +505,17 @@ void bootloader_main()
|
|||||||
bool flash_encryption_enabled = esp_flash_encryption_enabled();
|
bool flash_encryption_enabled = esp_flash_encryption_enabled();
|
||||||
err = esp_flash_encrypt_check_and_update();
|
err = esp_flash_encrypt_check_and_update();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Flash encryption check failed (%d).", err);
|
ESP_LOGE(TAG, "Flash encryption check failed (%d).", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!flash_encryption_enabled && esp_flash_encryption_enabled()) {
|
if (!flash_encryption_enabled && esp_flash_encryption_enabled()) {
|
||||||
/* Flash encryption was just enabled for the first time,
|
/* Flash encryption was just enabled for the first time,
|
||||||
so issue a system reset to ensure flash encryption
|
so issue a system reset to ensure flash encryption
|
||||||
cache resets properly */
|
cache resets properly */
|
||||||
ESP_LOGI(TAG, "Resetting with flash encryption enabled...");
|
ESP_LOGI(TAG, "Resetting with flash encryption enabled...");
|
||||||
REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
|
REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -419,23 +523,11 @@ void bootloader_main()
|
|||||||
bootloader_random_disable();
|
bootloader_random_disable();
|
||||||
|
|
||||||
// copy loaded segments to RAM, set up caches for mapped segments, and start application
|
// copy loaded segments to RAM, set up caches for mapped segments, and start application
|
||||||
ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
|
unpack_load_app(&image_data);
|
||||||
unpack_load_app(&load_part_pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unpack_load_app(const esp_partition_pos_t* partition)
|
static void unpack_load_app(const esp_image_metadata_t* data)
|
||||||
{
|
{
|
||||||
esp_err_t err;
|
|
||||||
esp_image_metadata_t data;
|
|
||||||
|
|
||||||
/* TODO: load the app image as part of OTA boot decision, so can fallback if loading fails */
|
|
||||||
/* Loading the image here also includes secure boot verification */
|
|
||||||
err = esp_image_load(ESP_IMAGE_LOAD, partition, &data);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t drom_addr = 0;
|
uint32_t drom_addr = 0;
|
||||||
uint32_t drom_load_addr = 0;
|
uint32_t drom_load_addr = 0;
|
||||||
uint32_t drom_size = 0;
|
uint32_t drom_size = 0;
|
||||||
@ -444,15 +536,15 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
|
|||||||
uint32_t irom_size = 0;
|
uint32_t irom_size = 0;
|
||||||
|
|
||||||
// Find DROM & IROM addresses, to configure cache mappings
|
// Find DROM & IROM addresses, to configure cache mappings
|
||||||
for (int i = 0; i < data.image.segment_count; i++) {
|
for (int i = 0; i < data->image.segment_count; i++) {
|
||||||
esp_image_segment_header_t *header = &data.segments[i];
|
const esp_image_segment_header_t *header = &data->segments[i];
|
||||||
if (header->load_addr >= SOC_IROM_LOW && header->load_addr < SOC_IROM_HIGH) {
|
if (header->load_addr >= SOC_IROM_LOW && header->load_addr < SOC_IROM_HIGH) {
|
||||||
if (drom_addr != 0) {
|
if (drom_addr != 0) {
|
||||||
ESP_LOGE(TAG, MAP_ERR_MSG, "DROM");
|
ESP_LOGE(TAG, MAP_ERR_MSG, "DROM");
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(TAG, "Mapping segment %d as %s", i, "DROM");
|
ESP_LOGD(TAG, "Mapping segment %d as %s", i, "DROM");
|
||||||
}
|
}
|
||||||
drom_addr = data.segment_data[i];
|
drom_addr = data->segment_data[i];
|
||||||
drom_load_addr = header->load_addr;
|
drom_load_addr = header->load_addr;
|
||||||
drom_size = header->data_len;
|
drom_size = header->data_len;
|
||||||
}
|
}
|
||||||
@ -462,7 +554,7 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
|
|||||||
} else {
|
} else {
|
||||||
ESP_LOGD(TAG, "Mapping segment %d as %s", i, "IROM");
|
ESP_LOGD(TAG, "Mapping segment %d as %s", i, "IROM");
|
||||||
}
|
}
|
||||||
irom_addr = data.segment_data[i];
|
irom_addr = data->segment_data[i];
|
||||||
irom_load_addr = header->load_addr;
|
irom_load_addr = header->load_addr;
|
||||||
irom_size = header->data_len;
|
irom_size = header->data_len;
|
||||||
}
|
}
|
||||||
@ -475,7 +567,7 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
|
|||||||
irom_addr,
|
irom_addr,
|
||||||
irom_load_addr,
|
irom_load_addr,
|
||||||
irom_size,
|
irom_size,
|
||||||
data.image.entry_addr);
|
data->image.entry_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_cache_and_start_app(
|
static void set_cache_and_start_app(
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
/* Pre-partition table fixed flash offsets */
|
/* Pre-partition table fixed flash offsets */
|
||||||
#define ESP_BOOTLOADER_DIGEST_OFFSET 0x0
|
#define ESP_BOOTLOADER_DIGEST_OFFSET 0x0
|
||||||
#define ESP_BOOTLOADER_OFFSET 0x1000 /* Offset of bootloader image. Has matching value in bootloader KConfig.projbuild file. */
|
#define ESP_BOOTLOADER_OFFSET 0x1000 /* Offset of bootloader image. Has matching value in bootloader KConfig.projbuild file. */
|
||||||
|
#define ESP_BOOTLOADER_SIZE (ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET)
|
||||||
#define ESP_PARTITION_TABLE_OFFSET 0x8000 /* Offset of partition table. Has matching value in partition_table Kconfig.projbuild file. */
|
#define ESP_PARTITION_TABLE_OFFSET 0x8000 /* Offset of partition table. Has matching value in partition_table Kconfig.projbuild file. */
|
||||||
|
|
||||||
#define ESP_PARTITION_TABLE_MAX_LEN 0xC00 /* Maximum length of partition table data */
|
#define ESP_PARTITION_TABLE_MAX_LEN 0xC00 /* Maximum length of partition table data */
|
||||||
|
@ -142,7 +142,6 @@ esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *
|
|||||||
*/
|
*/
|
||||||
esp_err_t esp_image_verify_bootloader(uint32_t *length);
|
esp_err_t esp_image_verify_bootloader(uint32_t *length);
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t drom_addr;
|
uint32_t drom_addr;
|
||||||
uint32_t drom_load_addr;
|
uint32_t drom_load_addr;
|
||||||
|
@ -87,7 +87,7 @@ esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *
|
|||||||
|
|
||||||
if (part->size > SIXTEEN_MB) {
|
if (part->size > SIXTEEN_MB) {
|
||||||
err = ESP_ERR_INVALID_ARG;
|
err = ESP_ERR_INVALID_ARG;
|
||||||
FAIL_LOAD("partition size %d invalid, larger than 16MB", part->size);
|
FAIL_LOAD("partition size 0x%x invalid, larger than 16MB", part->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bzero(data, sizeof(esp_image_metadata_t));
|
bzero(data, sizeof(esp_image_metadata_t));
|
||||||
|
@ -190,9 +190,13 @@ static void ota_example_task(void *pvParameter)
|
|||||||
const esp_partition_t *configured = esp_ota_get_boot_partition();
|
const esp_partition_t *configured = esp_ota_get_boot_partition();
|
||||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||||
|
|
||||||
assert(configured == running); /* fresh from reset, should be running from configured boot partition */
|
if (configured != running) {
|
||||||
|
ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
|
||||||
|
configured->address, running->address);
|
||||||
|
ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)");
|
||||||
|
}
|
||||||
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
|
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
|
||||||
configured->type, configured->subtype, configured->address);
|
running->type, running->subtype, running->address);
|
||||||
|
|
||||||
/* Wait for the callback to set the CONNECTED_BIT in the
|
/* Wait for the callback to set the CONNECTED_BIT in the
|
||||||
event group.
|
event group.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user