50 return validate_result;
53 int num_partitions = 0;
54 const esp_partition_info_t *new_partition_table =
reinterpret_cast<const esp_partition_info_t *
>(this->buf_);
55 esp_err_t err = esp_partition_table_verify(new_partition_table,
true, &num_partitions);
57 ESP_LOGE(TAG,
"esp_partition_table_verify failed (new partition table) (err=0x%X)", err);
63 bool checksum_found =
false;
64 for (
size_t i = 0; i < ESP_PARTITION_TABLE_MAX_ENTRIES; i++) {
65 if (new_partition_table[i].magic == ESP_PARTITION_MAGIC_MD5) {
66 checksum_found =
true;
70 if (!checksum_found) {
71 ESP_LOGE(TAG,
"New partition table has no checksum");
78 int app_partitions_found = 0;
79 int new_app_part_index = -1;
80 int new_app_part_index_with_copy = -1;
81 const esp_partition_t *app_copy_dest_part =
nullptr;
82 bool otadata_partition_found =
false;
83 bool otadata_overlap =
false;
84 bool nvs_partition_found =
false;
85 for (
int i = 0; i < num_partitions; i++) {
86 const esp_partition_info_t *new_part = &new_partition_table[i];
87 if (new_part->type == ESP_PARTITION_TYPE_APP) {
88 app_partitions_found++;
89 if (new_part->pos.size >= running_app_size) {
90 if (new_part->pos.offset == running_app_offset) {
91 if (new_app_part_index == -1) {
92 new_app_part_index = i;
94 }
else if (new_app_part_index_with_copy == -1 &&
95 !check_overlap(running_app_offset, running_app_size, new_part->pos.offset, running_app_size)) {
98 const esp_partition_t *p = find_app_partition_at(new_part->pos.offset, running_app_size);
100 new_app_part_index_with_copy = i;
101 app_copy_dest_part = p;
105 }
else if (new_part->type == ESP_PARTITION_TYPE_DATA) {
106 if (new_part->subtype == ESP_PARTITION_SUBTYPE_DATA_OTA) {
107 otadata_partition_found =
true;
108 otadata_overlap = check_overlap(running_app_offset, running_app_size, new_part->pos.offset, new_part->pos.size);
109 }
else if (new_part->subtype == ESP_PARTITION_SUBTYPE_DATA_NVS &&
110 strncmp(
reinterpret_cast<const char *
>(new_part->label),
"nvs",
sizeof(new_part->label)) == 0) {
111 nvs_partition_found =
true;
116 if (new_app_part_index == -1 && new_app_part_index_with_copy == -1) {
121 "The new partition table must contain a compatible app partition with:\n"
122 " size: at least %" PRIu32
" bytes (0x%" PRIX32
")\n"
125 esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY,
nullptr);
126 while (it !=
nullptr) {
127 const esp_partition_t *partition = esp_partition_get(it);
128 if (partition->size >= running_app_size) {
129 ESP_LOGE(TAG,
" 0x%" PRIX32, partition->address);
131 it = esp_partition_next(it);
133 esp_partition_iterator_release(it);
134 ESP_LOGE(TAG,
"Upload a different partition table. No flash content was modified.");
137 if (app_partitions_found < 2) {
138 ESP_LOGE(TAG,
"New partition table needs at least 2 app partitions, found %d", app_partitions_found);
141 if (!otadata_partition_found) {
142 ESP_LOGE(TAG,
"New partition table is missing the required otadata partition");
145 if (!nvs_partition_found) {
146 ESP_LOGE(TAG,
"New partition table is missing the required nvs partition");
149 if (otadata_overlap) {
152 "New otadata partition overlaps with the running app at address: 0x%" PRIX32
", running app size: %" PRIu32
154 running_app_offset, (
uint32_t) running_app_size);
158 if (new_app_part_index != -1) {
169 if (this->buf_written_ == 0 || this->image_size_ != this->buf_written_) {
170 ESP_LOGE(TAG,
"Not enough data received");
177 size_t running_app_size;
179 if (running_app_size == 0) {
180 ESP_LOGE(TAG,
"Failed to determine running app position");
187 return validate_result;
192 ESP_LOGE(TAG,
"Starting partition table update.\n"
193 " DO NOT REMOVE POWER until the device reboots successfully.\n"
194 " Loss of power during this operation may render the device\n"
195 " unable to boot until it is recovered via a serial flash.");
202 const esp_partition_info_t *new_partition_table =
reinterpret_cast<const esp_partition_info_t *
>(this->buf_);
208 const esp_partition_t *running_app_part = find_app_partition_at(running_app_offset, running_app_size);
209 if (running_app_part ==
nullptr) {
210 ESP_LOGE(TAG,
"Cannot resolve running app partition at address 0x%" PRIX32, running_app_offset);
213 ESP_LOGD(TAG,
"Copying running app from 0x%X to 0x%X (size: 0x%X)", running_app_part->address,
215 err = esp_partition_copy(plan.
copy_dest_part, 0, running_app_part, 0, running_app_size);
217 ESP_LOGE(TAG,
"esp_partition_copy failed (err=0x%X)", err);
231 err = esp_ota_begin(this->partition_table_part_, ESP_PARTITION_TABLE_MAX_LEN, &this->update_handle_);
233 esp_ota_abort(this->update_handle_);
234 this->update_handle_ = 0;
235 ESP_LOGE(TAG,
"esp_ota_begin failed (err=0x%X)", err);
238 err = esp_ota_write(this->update_handle_, this->buf_, ESP_PARTITION_TABLE_MAX_LEN);
240 esp_ota_abort(this->update_handle_);
241 this->update_handle_ = 0;
242 ESP_LOGE(TAG,
"esp_ota_write failed (err=0x%X)", err);
245 err = esp_ota_end(this->update_handle_);
246 this->update_handle_ = 0;
248 ESP_LOGE(TAG,
"esp_ota_end failed (err=0x%X)", err);
254 esp_partition_unload_all();
255 this->partition_table_part_ =
nullptr;
258 const esp_partition_info_t *new_part = &new_partition_table[plan.
target_app_index];
259 const esp_partition_t *new_boot_partition = find_app_partition_at(new_part->pos.offset, 0);
260 if (new_boot_partition ==
nullptr) {
261 ESP_LOGE(TAG,
"Selected app partition not found after partition table update");
264 ESP_LOGD(TAG,
"Setting next boot partition to 0x%X", new_boot_partition->address);
265 err = esp_ota_set_boot_partition(new_boot_partition);
267 ESP_LOGE(TAG,
"esp_ota_set_boot_partition failed (err=0x%X)", err);
274 esp_err_t err = esp_partition_register_external(
275 nullptr, ESP_PRIMARY_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_SIZE,
"PrimaryPrtTable",
276 ESP_PARTITION_TYPE_PARTITION_TABLE, ESP_PARTITION_SUBTYPE_PARTITION_TABLE_PRIMARY, &this->partition_table_part_);
278 ESP_LOGE(TAG,
"esp_partition_register_external failed (partition table) (err=0x%X)", err);
282 int num_partitions = 0;
283 const esp_partition_info_t *existing_partition_table =
nullptr;
284 esp_partition_mmap_handle_t partition_table_map;
285 err = esp_partition_mmap(this->partition_table_part_, 0, ESP_PARTITION_TABLE_MAX_LEN, ESP_PARTITION_MMAP_DATA,
286 reinterpret_cast<const void **
>(&existing_partition_table), &partition_table_map);
288 ESP_LOGE(TAG,
"esp_partition_mmap failed (partition table) (err=0x%X)", err);
291 err = esp_partition_table_verify(existing_partition_table,
true, &num_partitions);
292 esp_partition_munmap(partition_table_map);
294 ESP_LOGE(TAG,
"esp_partition_table_verify failed (existing partition table) (err=0x%X)", err);
309 if (!s_running_app_initialized) {
310 const esp_partition_t *running_app_part = esp_ota_get_running_partition();
311 if (running_app_part ==
nullptr || running_app_part->erase_size == 0) {
318 uint32_t pending_offset = running_app_part->address;
319 size_t pending_size = running_app_part->size;
321 const esp_partition_pos_t running_app_pos = {
322 .offset = running_app_part->address,
323 .size = running_app_part->size,
325 esp_image_metadata_t image_metadata = {};
326 image_metadata.start_addr = running_app_part->address;
327 if (esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &running_app_pos, &image_metadata) == ESP_OK &&
328 image_metadata.image_len < running_app_part->size) {
329 pending_size = image_metadata.image_len;
332 pending_size = ((pending_size + running_app_part->erase_size - 1) / running_app_part->erase_size) *
333 running_app_part->erase_size;
335 s_running_app_cached_offset = pending_offset;
336 s_running_app_cached_size = pending_size;
337 s_running_app_initialized =
true;
340 offset = s_running_app_cached_offset;
341 size = s_running_app_cached_size;