diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index 8ef9e0ba70..cabfe87cff 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -52,7 +52,7 @@ typedef struct ota_ops_entry_ { uint32_t handle; const esp_partition_t *part; - uint32_t erased_size; + bool need_erase; uint32_t wrote_size; uint8_t partial_bytes; uint8_t partial_data[16]; @@ -158,16 +158,17 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp } #endif - // If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition - if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) { - ret = esp_partition_erase_range(partition, 0, partition->size); - } else { - const int aligned_erase_size = (image_size + SPI_FLASH_SEC_SIZE - 1) & ~(SPI_FLASH_SEC_SIZE - 1); - ret = esp_partition_erase_range(partition, 0, aligned_erase_size); - } - - if (ret != ESP_OK) { - return ret; + if (image_size != OTA_WITH_SEQUENTIAL_WRITES) { + // If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition + if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) { + ret = esp_partition_erase_range(partition, 0, partition->size); + } else { + const int aligned_erase_size = (image_size + SPI_FLASH_SEC_SIZE - 1) & ~(SPI_FLASH_SEC_SIZE - 1); + ret = esp_partition_erase_range(partition, 0, aligned_erase_size); + } + if (ret != ESP_OK) { + return ret; + } } new_entry = (ota_ops_entry_t *) calloc(sizeof(ota_ops_entry_t), 1); @@ -177,14 +178,9 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp LIST_INSERT_HEAD(&s_ota_ops_entries_head, new_entry, entries); - if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) { - new_entry->erased_size = partition->size; - } else { - new_entry->erased_size = image_size; - } - new_entry->part = partition; new_entry->handle = ++s_ota_ops_last_handle; + new_entry->need_erase = (image_size == OTA_WITH_SEQUENTIAL_WRITES); *out_handle = new_entry->handle; return ESP_OK; } @@ -203,8 +199,22 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size) // find ota handle in linked list for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { if (it->handle == handle) { - // must erase the partition before writing to it - assert(it->erased_size > 0 && "must erase the partition before writing to it"); + if (it->need_erase) { + // must erase the partition before writing to it + uint32_t first_sector = it->wrote_size / SPI_FLASH_SEC_SIZE; + uint32_t last_sector = (it->wrote_size + size) / SPI_FLASH_SEC_SIZE; + + ret = ESP_OK; + if ((it->wrote_size % SPI_FLASH_SEC_SIZE) == 0) { + ret = esp_partition_erase_range(it->part, it->wrote_size, ((last_sector - first_sector) + 1) * SPI_FLASH_SEC_SIZE); + } else if (first_sector != last_sector) { + ret = esp_partition_erase_range(it->part, (first_sector + 1) * SPI_FLASH_SEC_SIZE, (last_sector - first_sector) * SPI_FLASH_SEC_SIZE); + } + if (ret != ESP_OK) { + return ret; + } + } + if (it->wrote_size == 0 && it->partial_bytes == 0 && size > 0 && data_bytes[0] != ESP_IMAGE_HEADER_MAGIC) { ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x)", data_bytes[0]); return ESP_ERR_OTA_VALIDATE_FAILED; @@ -270,7 +280,7 @@ esp_err_t esp_ota_write_with_offset(esp_ota_handle_t handle, const void *data, s for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { if (it->handle == handle) { // must erase the partition before writing to it - assert(it->erased_size > 0 && "must erase the partition before writing to it"); + assert(it->need_erase == 0 && "must erase the partition before writing to it"); /* esp_ota_write_with_offset is used to write data in non contiguous manner. * Hence, unaligned data(less than 16 bytes) cannot be cached if flash encryption is enabled. @@ -310,7 +320,7 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle) /* 'it' holds the ota_ops_entry_t for 'handle' */ // esp_ota_end() is only valid if some data was written to this handle - if ((it->erased_size == 0) || (it->wrote_size == 0)) { + if (it->wrote_size == 0) { ret = ESP_ERR_INVALID_ARG; goto cleanup; } diff --git a/components/app_update/include/esp_ota_ops.h b/components/app_update/include/esp_ota_ops.h index ac0ae656e0..cf24e75fa7 100644 --- a/components/app_update/include/esp_ota_ops.h +++ b/components/app_update/include/esp_ota_ops.h @@ -29,6 +29,7 @@ extern "C" #endif #define OTA_SIZE_UNKNOWN 0xffffffff /*!< Used for esp_ota_begin() if new image size is unknown */ +#define OTA_WITH_SEQUENTIAL_WRITES 0xfffffffe /*!< Used for esp_ota_begin() if new image size is unknown and erase can be done in incremental manner (assuming write operation is in continuous sequence) */ #define ESP_ERR_OTA_BASE 0x1500 /*!< Base error code for ota_ops api */ #define ESP_ERR_OTA_PARTITION_CONFLICT (ESP_ERR_OTA_BASE + 0x01) /*!< Error if request was to write or erase the current running partition */