99#include <string.h>
1010#include <stdio.h>
1111#include <sys/lock.h>
12+ #include <sys/param.h>
1213
1314/* interim to enable test_wl_host and test_fatfs_on_host compilation (both use IDF_TARGET_ESP32)
1415 * should go back to #include "sys/queue.h" once the tests are switched to CMake
2425#include "esp_flash_partitions.h"
2526#include "esp_attr.h"
2627#include "esp_partition.h"
27- #if !CONFIG_IDF_TARGET_LINUX
2828#include "esp_flash.h"
29+ #if !CONFIG_IDF_TARGET_LINUX
2930#include "esp_flash_encrypt.h"
30- #include "spi_flash_mmap.h"
3131#endif
32+ #include "spi_flash_mmap.h"
3233#include "esp_log.h"
3334#include "esp_rom_md5.h"
3435#include "bootloader_util.h"
4950#define INVARIANTS
5051#endif
5152
53+ #define ALIGN_UP (num , align ) (((num) + ((align) - 1)) & ~((align) - 1))
54+
5255typedef struct partition_list_item_ {
5356 esp_partition_t info ;
5457 bool user_registered ;
@@ -68,6 +71,31 @@ static _lock_t s_partition_list_lock;
6871
6972static const char * TAG = "partition" ;
7073
74+ static bool is_partition_encrypted (bool encryption_config , esp_partition_type_t type , esp_partition_subtype_t subtype )
75+ {
76+ #if CONFIG_IDF_TARGET_LINUX
77+ (void ) type ;
78+ (void ) subtype ;
79+ (void ) encryption_config ;
80+ return false;
81+ #else
82+ bool ret_encrypted = encryption_config ;
83+ if (!esp_flash_encryption_enabled ()) {
84+ /* If flash encryption is not turned on, no partitions should be treated as encrypted */
85+ ret_encrypted = false;
86+ } else if (type == ESP_PARTITION_TYPE_APP
87+ || (type == ESP_PARTITION_TYPE_BOOTLOADER )
88+ || (type == ESP_PARTITION_TYPE_PARTITION_TABLE )
89+ || (type == ESP_PARTITION_TYPE_DATA && subtype == ESP_PARTITION_SUBTYPE_DATA_OTA )
90+ || (type == ESP_PARTITION_TYPE_DATA && subtype == ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS )) {
91+ /* If encryption is turned on, all app partitions and OTA data
92+ are always encrypted */
93+ ret_encrypted = true;
94+ }
95+ return ret_encrypted ;
96+ #endif
97+ }
98+
7199// Create linked list of partition_list_item_t structures.
72100// This function is called only once, with s_partition_list_lock taken.
73101static esp_err_t load_partitions (void )
@@ -151,25 +179,10 @@ static esp_err_t load_partitions(void)
151179#endif
152180 item -> info .type = entry .type ;
153181 item -> info .subtype = entry .subtype ;
154- item -> info .encrypted = entry .flags & PART_FLAG_ENCRYPTED ;
182+ item -> info .encrypted = is_partition_encrypted ( entry .flags & PART_FLAG_ENCRYPTED , entry . type , entry . subtype ) ;
155183 item -> info .readonly = entry .flags & PART_FLAG_READONLY ;
156184 item -> user_registered = false;
157185
158- #if CONFIG_IDF_TARGET_LINUX
159- item -> info .encrypted = false;
160- #else
161- if (!esp_flash_encryption_enabled ()) {
162- /* If flash encryption is not turned on, no partitions should be treated as encrypted */
163- item -> info .encrypted = false;
164- } else if (entry .type == ESP_PARTITION_TYPE_APP
165- || (entry .type == ESP_PARTITION_TYPE_DATA && entry .subtype == ESP_PARTITION_SUBTYPE_DATA_OTA )
166- || (entry .type == ESP_PARTITION_TYPE_DATA && entry .subtype == ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS )) {
167- /* If encryption is turned on, all app partitions and OTA data
168- are always encrypted */
169- item -> info .encrypted = true;
170- }
171- #endif
172-
173186#if CONFIG_NVS_COMPATIBLE_PRE_V4_3_ENCRYPTION_FLAG
174187 if (entry .type == ESP_PARTITION_TYPE_DATA &&
175188 entry .subtype == ESP_PARTITION_SUBTYPE_DATA_NVS &&
@@ -392,10 +405,10 @@ esp_err_t esp_partition_register_external(esp_flash_t *flash_chip, size_t offset
392405 * out_partition = NULL ;
393406 }
394407
395- #if CONFIG_IDF_TARGET_LINUX
396- return ESP_ERR_NOT_SUPPORTED ;
397-
398- #else
408+ #if ! CONFIG_IDF_TARGET_LINUX
409+ if ( flash_chip == NULL ) {
410+ flash_chip = esp_flash_default_chip ;
411+ }
399412 if (offset + size > flash_chip -> size ) {
400413 return ESP_ERR_INVALID_SIZE ;
401414 }
@@ -415,7 +428,14 @@ esp_err_t esp_partition_register_external(esp_flash_t *flash_chip, size_t offset
415428 item -> info .size = size ;
416429 item -> info .type = type ;
417430 item -> info .subtype = subtype ;
431+ #if CONFIG_IDF_TARGET_LINUX
432+ item -> info .erase_size = ESP_PARTITION_EMULATED_SECTOR_SIZE ;
418433 item -> info .encrypted = false;
434+ #else
435+ item -> info .erase_size = SPI_FLASH_SEC_SIZE ;
436+ item -> info .encrypted = (flash_chip == esp_flash_default_chip ) ? is_partition_encrypted (false, type , subtype ) : false;
437+ #endif // CONFIG_IDF_TARGET_LINUX
438+ item -> info .readonly = false;
419439 item -> user_registered = true;
420440 strlcpy (item -> info .label , label , sizeof (item -> info .label ));
421441
@@ -466,3 +486,75 @@ esp_err_t esp_partition_deregister_external(const esp_partition_t *partition)
466486 _lock_release (& s_partition_list_lock );
467487 return result ;
468488}
489+
490+ esp_err_t esp_partition_copy (const esp_partition_t * dest_part , uint32_t dest_offset , const esp_partition_t * src_part , uint32_t src_offset , size_t size )
491+ {
492+ if (src_part == NULL || dest_part == NULL || src_part == dest_part ) {
493+ return ESP_ERR_INVALID_ARG ;
494+ }
495+
496+ if (src_offset > src_part -> size || dest_offset > dest_part -> size ) {
497+ return ESP_ERR_INVALID_SIZE ;
498+ }
499+
500+ // Check if the source partition is on external flash and return error
501+ #if !CONFIG_IDF_TARGET_LINUX
502+ if (src_part -> flash_chip != esp_flash_default_chip ) {
503+ ESP_LOGE (TAG , "Source partition is on external flash. Operation not supported." );
504+ return ESP_ERR_NOT_SUPPORTED ;
505+ }
506+ #endif
507+
508+ size_t dest_erase_size = size ;
509+ if (size == SIZE_MAX ) {
510+ size = src_part -> size - src_offset ;
511+ dest_erase_size = dest_part -> size - dest_offset ; // Erase the whole destination partition
512+ }
513+
514+ uint32_t src_end_offset ;
515+ uint32_t dest_end_offset ;
516+ if ((__builtin_add_overflow (src_offset , size , & src_end_offset ) || (src_end_offset > src_part -> size ))
517+ || (__builtin_add_overflow (dest_offset , size , & dest_end_offset ) || (dest_end_offset > dest_part -> size ))) { // with overflow checks
518+ return ESP_ERR_INVALID_SIZE ;
519+ }
520+
521+ esp_err_t error = esp_partition_erase_range (dest_part , dest_offset , ALIGN_UP (dest_erase_size , SPI_FLASH_SEC_SIZE ));
522+ if (error ) {
523+ ESP_LOGE (TAG , "Erasing destination partition range failed (err=0x%x)" , error );
524+ return error ;
525+ }
526+
527+ uint32_t src_current_offset = src_offset ;
528+ uint32_t dest_current_offset = dest_offset ;
529+ size_t remaining_size = size ;
530+ /* Read the portion that fits in the free MMU pages */
531+ uint32_t mmu_free_pages_count = spi_flash_mmap_get_free_pages (SPI_FLASH_MMAP_DATA );
532+ int attempts_for_mmap = 0 ;
533+ while (remaining_size > 0 ) {
534+ uint32_t chunk_size = MIN (remaining_size , mmu_free_pages_count * SPI_FLASH_MMU_PAGE_SIZE );
535+ esp_partition_mmap_handle_t src_part_map ;
536+ const void * src_data = NULL ;
537+ error = esp_partition_mmap (src_part , src_current_offset , chunk_size , ESP_PARTITION_MMAP_DATA , & src_data , & src_part_map );
538+ if (error == ESP_OK ) {
539+ attempts_for_mmap = 0 ;
540+ error = esp_partition_write (dest_part , dest_current_offset , src_data , chunk_size );
541+ if (error != ESP_OK ) {
542+ ESP_LOGE (TAG , "Writing to destination partition failed (err=0x%x)" , error );
543+ esp_partition_munmap (src_part_map );
544+ break ;
545+ }
546+ esp_partition_munmap (src_part_map );
547+ } else {
548+ mmu_free_pages_count = spi_flash_mmap_get_free_pages (SPI_FLASH_MMAP_DATA );
549+ chunk_size = 0 ;
550+ if (++ attempts_for_mmap >= 3 ) {
551+ ESP_LOGE (TAG , "Failed to mmap source partition after a few attempts, mmu_free_pages = %" PRIu32 " (err=0x%x)" , mmu_free_pages_count , error );
552+ break ;
553+ }
554+ }
555+ src_current_offset += chunk_size ;
556+ dest_current_offset += chunk_size ;
557+ remaining_size -= chunk_size ;
558+ }
559+ return error ;
560+ }
0 commit comments