| 
									
										
										
										
											2021-11-06 17:23:21 +08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD | 
					
						
							| 
									
										
										
										
											2021-11-06 17:23:21 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <assert.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <sys/lock.h>
 | 
					
						
							| 
									
										
										
										
											2023-03-06 01:36:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* interim to enable test_wl_host and test_fatfs_on_host compilation (both use IDF_TARGET_ESP32)
 | 
					
						
							|  |  |  |  * should go back to #include "sys/queue.h" once the tests are switched to CMake | 
					
						
							|  |  |  |  * see IDF-7000 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #if __has_include(<bsd/string.h>)
 | 
					
						
							|  |  |  | #include <bsd/sys/queue.h>
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #include "sys/queue.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #include "sdkconfig.h"
 | 
					
						
							| 
									
										
										
										
											2018-04-19 09:42:26 +05:00
										 |  |  | #include "esp_flash_partitions.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | #include "esp_attr.h"
 | 
					
						
							|  |  |  | #include "esp_partition.h"
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #if !CONFIG_IDF_TARGET_LINUX
 | 
					
						
							| 
									
										
										
										
											2022-10-14 14:15:32 +02:00
										 |  |  | #include "esp_flash.h"
 | 
					
						
							| 
									
										
										
										
											2016-11-11 17:00:34 +11:00
										 |  |  | #include "esp_flash_encrypt.h"
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | #include "esp_log.h"
 | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  | #include "esp_rom_md5.h"
 | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  | #include "bootloader_util.h"
 | 
					
						
							| 
									
										
										
										
											2023-03-06 01:36:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #if CONFIG_IDF_TARGET_LINUX
 | 
					
						
							|  |  |  | #if __has_include(<bsd/string.h>)
 | 
					
						
							|  |  |  | #include <bsd/string.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #include "esp_private/partition_linux.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 18:12:04 +02:00
										 |  |  | #ifndef CONFIG_IDF_TARGET_LINUX
 | 
					
						
							|  |  |  | #define MMU_PAGE_SIZE CONFIG_MMU_PAGE_SIZE
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | // No relation to the page size on Linux; assume the same value as on ESP32
 | 
					
						
							|  |  |  | #define MMU_PAGE_SIZE 65536
 | 
					
						
							|  |  |  | #endif // CONFIG_MMU_PAGE_SIZE
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | #ifndef NDEBUG
 | 
					
						
							|  |  |  | // Enable built-in checks in queue.h in debug builds
 | 
					
						
							|  |  |  | #define INVARIANTS
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct partition_list_item_ { | 
					
						
							|  |  |  |     esp_partition_t info; | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  |     bool user_registered; | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |     SLIST_ENTRY(partition_list_item_) next; | 
					
						
							|  |  |  | } partition_list_item_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct esp_partition_iterator_opaque_ { | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |     esp_partition_type_t type;                      // requested type
 | 
					
						
							|  |  |  |     esp_partition_subtype_t subtype;                // requested subtype
 | 
					
						
							|  |  |  |     const char *label;                              // requested label (can be NULL)
 | 
					
						
							|  |  |  |     partition_list_item_t *next_item;               // next item to iterate to
 | 
					
						
							|  |  |  |     esp_partition_t *info;                          // pointer to info (it is redundant, but makes code more readable)
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | } esp_partition_iterator_opaque_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | static SLIST_HEAD(partition_list_head_, partition_list_item_) s_partition_list = SLIST_HEAD_INITIALIZER(s_partition_list); | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | static _lock_t s_partition_list_lock; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | static const char *TAG = "partition"; | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Create linked list of partition_list_item_t structures.
 | 
					
						
							|  |  |  | // This function is called only once, with s_partition_list_lock taken.
 | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | static esp_err_t load_partitions(void) | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  |     const uint8_t *p_start; | 
					
						
							|  |  |  |     const uint8_t *p_end; | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #if !CONFIG_IDF_TARGET_LINUX
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |     spi_flash_mmap_handle_t handle; | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Temporary list of loaded partitions, if valid then we copy this to s_partition_list
 | 
					
						
							|  |  |  |     typeof(s_partition_list) new_partitions_list = SLIST_HEAD_INITIALIZER(s_partition_list); | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |     partition_list_item_t *last = NULL; | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if CONFIG_PARTITION_TABLE_MD5
 | 
					
						
							|  |  |  |     const uint8_t *md5_part = NULL; | 
					
						
							|  |  |  |     const uint8_t *stored_md5; | 
					
						
							|  |  |  |     uint8_t calc_md5[ESP_ROM_MD5_DIGEST_LEN]; | 
					
						
							|  |  |  |     md5_context_t context; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     esp_rom_md5_init(&context); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 18:12:04 +02:00
										 |  |  |     uint32_t partition_align_pg_size = (ESP_PARTITION_TABLE_OFFSET) & ~(MMU_PAGE_SIZE - 1); | 
					
						
							| 
									
										
										
										
											2021-11-06 17:23:21 +08:00
										 |  |  |     uint32_t partition_pad = ESP_PARTITION_TABLE_OFFSET - partition_align_pg_size; | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if CONFIG_IDF_TARGET_LINUX
 | 
					
						
							|  |  |  |     esp_err_t err = esp_partition_file_mmap(&p_start); | 
					
						
							| 
									
										
										
										
											2022-10-14 14:15:32 +02:00
										 |  |  |     size_t mapped_size = ESP_PARTITION_EMULATED_SECTOR_SIZE; | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2021-11-06 17:23:21 +08:00
										 |  |  |     esp_err_t err = spi_flash_mmap(partition_align_pg_size, | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  |                                    SPI_FLASH_SEC_SIZE, SPI_FLASH_MMAP_DATA, (const void **)&p_start, &handle); | 
					
						
							| 
									
										
										
										
											2022-10-14 14:15:32 +02:00
										 |  |  |     size_t mapped_size = SPI_FLASH_SEC_SIZE; | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |     if (err != ESP_OK) { | 
					
						
							|  |  |  |         return err; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |     // calculate partition address within mmap-ed region
 | 
					
						
							| 
									
										
										
										
											2021-11-06 17:23:21 +08:00
										 |  |  |     p_start += partition_pad; | 
					
						
							| 
									
										
										
										
											2022-10-14 14:15:32 +02:00
										 |  |  |     p_end = p_start + mapped_size; | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |     for (const uint8_t *p_entry = p_start; p_entry < p_end; p_entry += sizeof(esp_partition_info_t)) { | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  |         esp_partition_info_t entry; | 
					
						
							|  |  |  |         // copying to RAM instead of using pointer to flash to avoid any chance of TOCTOU due to cache miss
 | 
					
						
							|  |  |  |         // when flash encryption is used
 | 
					
						
							|  |  |  |         memcpy(&entry, p_entry, sizeof(entry)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if CONFIG_PARTITION_TABLE_MD5
 | 
					
						
							|  |  |  |         if (entry.magic == ESP_PARTITION_MAGIC_MD5) { | 
					
						
							|  |  |  |             md5_part = p_entry; | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  | #endif
 | 
					
						
							|  |  |  |         if (entry.magic != ESP_PARTITION_MAGIC) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if CONFIG_PARTITION_TABLE_MD5
 | 
					
						
							|  |  |  |         esp_rom_md5_update(&context, &entry, sizeof(entry)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |         // allocate new linked list item and populate it with data from partition table
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |         partition_list_item_t *item = (partition_list_item_t *) calloc(sizeof(partition_list_item_t), 1); | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  |         if (item == NULL) { | 
					
						
							|  |  |  |             err = ESP_ERR_NO_MEM; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #if CONFIG_IDF_TARGET_LINUX
 | 
					
						
							|  |  |  |         item->info.flash_chip = NULL; | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  |         item->info.flash_chip = esp_flash_default_chip; | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  |         item->info.address = entry.pos.offset; | 
					
						
							|  |  |  |         item->info.size = entry.pos.size; | 
					
						
							| 
									
										
										
										
											2022-10-14 14:15:32 +02:00
										 |  |  | #if CONFIG_IDF_TARGET_LINUX
 | 
					
						
							|  |  |  |         item->info.erase_size = ESP_PARTITION_EMULATED_SECTOR_SIZE; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |         item->info.erase_size = SPI_FLASH_SEC_SIZE; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  |         item->info.type = entry.type; | 
					
						
							|  |  |  |         item->info.subtype = entry.subtype; | 
					
						
							|  |  |  |         item->info.encrypted = entry.flags & PART_FLAG_ENCRYPTED; | 
					
						
							| 
									
										
										
										
											2023-07-17 11:59:28 +02:00
										 |  |  |         item->info.readonly = entry.flags & PART_FLAG_READONLY; | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  |         item->user_registered = false; | 
					
						
							| 
									
										
										
										
											2019-04-18 14:10:18 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #if CONFIG_IDF_TARGET_LINUX
 | 
					
						
							|  |  |  |         item->info.encrypted = false; | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2019-04-18 14:10:18 -05:00
										 |  |  |         if (!esp_flash_encryption_enabled()) { | 
					
						
							|  |  |  |             /* If flash encryption is not turned on, no partitions should be treated as encrypted */ | 
					
						
							|  |  |  |             item->info.encrypted = false; | 
					
						
							| 
									
										
										
										
											2021-11-11 15:25:04 +05:30
										 |  |  |         } else if (entry.type == ESP_PARTITION_TYPE_APP | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |                    || (entry.type == ESP_PARTITION_TYPE_DATA && entry.subtype == ESP_PARTITION_SUBTYPE_DATA_OTA) | 
					
						
							|  |  |  |                    || (entry.type == ESP_PARTITION_TYPE_DATA && entry.subtype == ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS)) { | 
					
						
							| 
									
										
										
										
											2017-01-26 18:30:32 +11:00
										 |  |  |             /* If encryption is turned on, all app partitions and OTA data
 | 
					
						
							|  |  |  |                are always encrypted */ | 
					
						
							| 
									
										
										
										
											2016-11-11 17:00:34 +11:00
										 |  |  |             item->info.encrypted = true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-01-26 18:30:32 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-11 12:16:24 +05:30
										 |  |  | #if CONFIG_NVS_COMPATIBLE_PRE_V4_3_ENCRYPTION_FLAG
 | 
					
						
							|  |  |  |         if (entry.type == ESP_PARTITION_TYPE_DATA && | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |                 entry.subtype == ESP_PARTITION_SUBTYPE_DATA_NVS && | 
					
						
							|  |  |  |                 (entry.flags & PART_FLAG_ENCRYPTED)) { | 
					
						
							| 
									
										
										
										
											2021-11-11 12:16:24 +05:30
										 |  |  |             ESP_LOGI(TAG, "Ignoring encrypted flag for \"%s\" partition", entry.label); | 
					
						
							|  |  |  |             item->info.encrypted = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-05-20 09:51:29 +10:00
										 |  |  |         // item->info.label is initialized by calloc, so resulting string will be null terminated
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |         strncpy(item->info.label, (const char *) entry.label, sizeof(item->info.label) - 1); | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |         // add it to the list
 | 
					
						
							|  |  |  |         if (last == NULL) { | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  |             SLIST_INSERT_HEAD(&new_partitions_list, item, next); | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             SLIST_INSERT_AFTER(last, item, next); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-03-04 15:34:03 +08:00
										 |  |  |         last = item; | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if CONFIG_PARTITION_TABLE_MD5
 | 
					
						
							|  |  |  |     if (md5_part == NULL) { | 
					
						
							|  |  |  |         ESP_LOGE(TAG, "No MD5 found in partition table"); | 
					
						
							|  |  |  |         err = ESP_ERR_NOT_FOUND; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         stored_md5 = md5_part + ESP_PARTITION_MD5_OFFSET; | 
					
						
							|  |  |  |         esp_rom_md5_final(calc_md5, &context); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #if !CONFIG_IDF_TARGET_LINUX
 | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  |         ESP_LOG_BUFFER_HEXDUMP("calculated md5", calc_md5, ESP_ROM_MD5_DIGEST_LEN, ESP_LOG_VERBOSE); | 
					
						
							|  |  |  |         ESP_LOG_BUFFER_HEXDUMP("stored md5", stored_md5, ESP_ROM_MD5_DIGEST_LEN, ESP_LOG_VERBOSE); | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (memcmp(calc_md5, stored_md5, ESP_ROM_MD5_DIGEST_LEN) != 0) { | 
					
						
							|  |  |  |             ESP_LOGE(TAG, "Partition table MD5 mismatch"); | 
					
						
							|  |  |  |             err = ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |             ESP_LOGV(TAG, "Partition table MD5 verified"); | 
					
						
							| 
									
										
										
										
											2021-02-04 11:12:04 +11:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (err == ESP_OK) { | 
					
						
							|  |  |  |         /* Don't copy the list to the static variable unless it's verified */ | 
					
						
							|  |  |  |         s_partition_list = new_partitions_list; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         /* Otherwise, free all the memory we just allocated */ | 
					
						
							|  |  |  |         partition_list_item_t *it = new_partitions_list.slh_first; | 
					
						
							|  |  |  |         while (it) { | 
					
						
							|  |  |  |             partition_list_item_t *next = it->next.sle_next; | 
					
						
							|  |  |  |             free(it); | 
					
						
							|  |  |  |             it = next; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #if !CONFIG_IDF_TARGET_LINUX
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  |     spi_flash_munmap(handle); | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 17:58:52 +01:00
										 |  |  | void unload_partitions(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _lock_acquire(&s_partition_list_lock); | 
					
						
							| 
									
										
										
										
											2023-03-06 01:36:59 +01:00
										 |  |  |     partition_list_item_t *it; | 
					
						
							|  |  |  |     partition_list_item_t *tmp; | 
					
						
							| 
									
										
										
										
											2023-03-05 19:32:36 +01:00
										 |  |  |     SLIST_FOREACH_SAFE(it, &s_partition_list, next, tmp) { | 
					
						
							| 
									
										
										
										
											2023-01-20 17:58:52 +01:00
										 |  |  |         SLIST_REMOVE(&s_partition_list, it, partition_list_item_, next); | 
					
						
							|  |  |  |         free(it); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _lock_release(&s_partition_list_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert(SLIST_EMPTY(&s_partition_list)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | static esp_err_t ensure_partitions_loaded(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     esp_err_t err = ESP_OK; | 
					
						
							|  |  |  |     if (SLIST_EMPTY(&s_partition_list)) { | 
					
						
							|  |  |  |         // only lock if list is empty (and check again after acquiring lock)
 | 
					
						
							|  |  |  |         _lock_acquire(&s_partition_list_lock); | 
					
						
							|  |  |  |         if (SLIST_EMPTY(&s_partition_list)) { | 
					
						
							|  |  |  |             ESP_LOGV(TAG, "Loading the partition table"); | 
					
						
							|  |  |  |             err = load_partitions(); | 
					
						
							|  |  |  |             if (err != ESP_OK) { | 
					
						
							|  |  |  |                 ESP_LOGE(TAG, "load_partitions returned 0x%x", err); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         _lock_release(&s_partition_list_lock); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  |     return err; | 
					
						
							| 
									
										
										
										
											2016-10-19 18:04:25 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-10-21 18:44:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | static esp_partition_iterator_opaque_t *iterator_create(esp_partition_type_t type, | 
					
						
							|  |  |  |         esp_partition_subtype_t subtype, const char *label) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     esp_partition_iterator_opaque_t *it = | 
					
						
							|  |  |  |         (esp_partition_iterator_opaque_t *) malloc(sizeof(esp_partition_iterator_opaque_t)); | 
					
						
							| 
									
										
										
										
											2022-03-14 18:16:42 +01:00
										 |  |  |     if (it == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |     it->type = type; | 
					
						
							|  |  |  |     it->subtype = subtype; | 
					
						
							|  |  |  |     it->label = label; | 
					
						
							|  |  |  |     it->next_item = SLIST_FIRST(&s_partition_list); | 
					
						
							|  |  |  |     it->info = NULL; | 
					
						
							|  |  |  |     return it; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_partition_iterator_t esp_partition_find(esp_partition_type_t type, | 
					
						
							|  |  |  |         esp_partition_subtype_t subtype, const char *label) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (ensure_partitions_loaded() != ESP_OK) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Searching for a specific subtype without specifying the type doesn't make
 | 
					
						
							|  |  |  |     // sense, and is likely a usage error.
 | 
					
						
							|  |  |  |     if (type == ESP_PARTITION_TYPE_ANY && subtype != ESP_PARTITION_SUBTYPE_ANY) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // create an iterator pointing to the start of the list
 | 
					
						
							|  |  |  |     // (next item will be the first one)
 | 
					
						
							|  |  |  |     esp_partition_iterator_t it = iterator_create(type, subtype, label); | 
					
						
							| 
									
										
										
										
											2022-03-14 18:16:42 +01:00
										 |  |  |     if (it == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |     // advance iterator to the next item which matches constraints
 | 
					
						
							|  |  |  |     it = esp_partition_next(it); | 
					
						
							|  |  |  |     // if nothing found, it == NULL and iterator has been released
 | 
					
						
							|  |  |  |     return it; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_partition_iterator_t esp_partition_next(esp_partition_iterator_t it) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(it); | 
					
						
							|  |  |  |     // iterator reached the end of linked list?
 | 
					
						
							|  |  |  |     if (it->next_item == NULL) { | 
					
						
							|  |  |  |         esp_partition_iterator_release(it); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _lock_acquire(&s_partition_list_lock); | 
					
						
							|  |  |  |     for (; it->next_item != NULL; it->next_item = SLIST_NEXT(it->next_item, next)) { | 
					
						
							|  |  |  |         esp_partition_t *p = &it->next_item->info; | 
					
						
							|  |  |  |         if (it->type != ESP_PARTITION_TYPE_ANY && it->type != p->type) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (it->subtype != ESP_PARTITION_SUBTYPE_ANY && it->subtype != p->subtype) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (it->label != NULL && strcmp(it->label, p->label) != 0) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // all constraints match, bail out
 | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _lock_release(&s_partition_list_lock); | 
					
						
							|  |  |  |     if (it->next_item == NULL) { | 
					
						
							|  |  |  |         esp_partition_iterator_release(it); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     it->info = &it->next_item->info; | 
					
						
							|  |  |  |     it->next_item = SLIST_NEXT(it->next_item, next); | 
					
						
							|  |  |  |     return it; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const esp_partition_t *esp_partition_find_first(esp_partition_type_t type, | 
					
						
							|  |  |  |         esp_partition_subtype_t subtype, const char *label) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     esp_partition_iterator_t it = esp_partition_find(type, subtype, label); | 
					
						
							|  |  |  |     if (it == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const esp_partition_t *res = esp_partition_get(it); | 
					
						
							|  |  |  |     esp_partition_iterator_release(it); | 
					
						
							|  |  |  |     return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-21 18:44:57 +08:00
										 |  |  | void esp_partition_iterator_release(esp_partition_iterator_t iterator) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // iterator == NULL is okay
 | 
					
						
							|  |  |  |     free(iterator); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | const esp_partition_t *esp_partition_get(esp_partition_iterator_t iterator) | 
					
						
							| 
									
										
										
										
											2016-10-21 18:44:57 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(iterator != NULL); | 
					
						
							|  |  |  |     return iterator->info; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | const esp_partition_t *esp_partition_verify(const esp_partition_t *partition) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(partition != NULL); | 
					
						
							|  |  |  |     const char *label = (strlen(partition->label) > 0) ? partition->label : NULL; | 
					
						
							|  |  |  |     esp_partition_iterator_t it = esp_partition_find(partition->type, | 
					
						
							|  |  |  |                                   partition->subtype, | 
					
						
							|  |  |  |                                   label); | 
					
						
							|  |  |  |     while (it != NULL) { | 
					
						
							|  |  |  |         const esp_partition_t *p = esp_partition_get(it); | 
					
						
							|  |  |  |         /* Can't memcmp() whole structure here as padding contents may be different */ | 
					
						
							|  |  |  |         if (p->flash_chip == partition->flash_chip | 
					
						
							|  |  |  |                 && p->address == partition->address | 
					
						
							|  |  |  |                 && partition->size == p->size | 
					
						
							|  |  |  |                 && partition->encrypted == p->encrypted) { | 
					
						
							|  |  |  |             esp_partition_iterator_release(it); | 
					
						
							|  |  |  |             return p; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         it = esp_partition_next(it); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     esp_partition_iterator_release(it); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-17 11:59:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | esp_err_t esp_partition_register_external(esp_flash_t *flash_chip, size_t offset, size_t size, | 
					
						
							|  |  |  |         const char *label, esp_partition_type_t type, esp_partition_subtype_t subtype, | 
					
						
							|  |  |  |         const esp_partition_t **out_partition) | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     if (out_partition != NULL) { | 
					
						
							|  |  |  |         *out_partition = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-14 14:15:32 +02:00
										 |  |  | #if CONFIG_IDF_TARGET_LINUX
 | 
					
						
							|  |  |  |     return ESP_ERR_NOT_SUPPORTED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  |     if (offset + size > flash_chip->size) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_SIZE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-14 14:15:32 +02:00
										 |  |  | #endif // CONFIG_IDF_TARGET_LINUX
 | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-30 16:11:09 +02:00
										 |  |  |     esp_err_t err = ensure_partitions_loaded(); | 
					
						
							|  |  |  |     if (err != ESP_OK) { | 
					
						
							|  |  |  |         return err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |     partition_list_item_t *item = (partition_list_item_t *) calloc(sizeof(partition_list_item_t), 1); | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  |     if (item == NULL) { | 
					
						
							|  |  |  |         return ESP_ERR_NO_MEM; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     item->info.flash_chip = flash_chip; | 
					
						
							|  |  |  |     item->info.address = offset; | 
					
						
							|  |  |  |     item->info.size = size; | 
					
						
							|  |  |  |     item->info.type = type; | 
					
						
							|  |  |  |     item->info.subtype = subtype; | 
					
						
							|  |  |  |     item->info.encrypted = false; | 
					
						
							|  |  |  |     item->user_registered = true; | 
					
						
							|  |  |  |     strlcpy(item->info.label, label, sizeof(item->info.label)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _lock_acquire(&s_partition_list_lock); | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  |     partition_list_item_t *it = NULL; | 
					
						
							|  |  |  |     partition_list_item_t *last = NULL; | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  |     SLIST_FOREACH(it, &s_partition_list, next) { | 
					
						
							|  |  |  |         /* Check if the new partition overlaps an existing one */ | 
					
						
							|  |  |  |         if (it->info.flash_chip == flash_chip && | 
					
						
							|  |  |  |                 bootloader_util_regions_overlap(offset, offset + size, | 
					
						
							|  |  |  |                                                 it->info.address, it->info.address + it->info.size)) { | 
					
						
							|  |  |  |             _lock_release(&s_partition_list_lock); | 
					
						
							|  |  |  |             free(item); | 
					
						
							|  |  |  |             return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         last = it; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (last == NULL) { | 
					
						
							|  |  |  |         SLIST_INSERT_HEAD(&s_partition_list, item, next); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         SLIST_INSERT_AFTER(last, item, next); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _lock_release(&s_partition_list_lock); | 
					
						
							|  |  |  |     if (out_partition != NULL) { | 
					
						
							|  |  |  |         *out_partition = &item->info; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-28 18:16:13 +01:00
										 |  |  | esp_err_t esp_partition_deregister_external(const esp_partition_t *partition) | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     esp_err_t result = ESP_ERR_NOT_FOUND; | 
					
						
							|  |  |  |     _lock_acquire(&s_partition_list_lock); | 
					
						
							|  |  |  |     partition_list_item_t *it; | 
					
						
							| 
									
										
										
										
											2023-03-06 01:36:59 +01:00
										 |  |  |     partition_list_item_t *tmp; | 
					
						
							|  |  |  |     SLIST_FOREACH_SAFE(it, &s_partition_list, next, tmp) { | 
					
						
							| 
									
										
										
										
											2019-06-19 01:31:43 +08:00
										 |  |  |         if (&it->info == partition) { | 
					
						
							|  |  |  |             if (!it->user_registered) { | 
					
						
							|  |  |  |                 result = ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             SLIST_REMOVE(&s_partition_list, it, partition_list_item_, next); | 
					
						
							|  |  |  |             free(it); | 
					
						
							|  |  |  |             result = ESP_OK; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _lock_release(&s_partition_list_lock); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } |