/* * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include "esp_flash_partitions.h" #include "esp_flash_internal.h" #include "esp_image_format.h" #include "esp_flash.h" #include "esp_partition.h" #include "esp_log.h" // Returns the number of partitions belonging to the specified flash chip static unsigned int count_partitions(esp_flash_t *flash_chip) { unsigned int partition_count = 0; esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); assert(it != NULL); for (; it != NULL; it = esp_partition_next(it)) { if (esp_partition_get(it)->flash_chip == flash_chip) { partition_count++; } } esp_partition_iterator_release(it); return partition_count; } // Compare function for qsort to sort partitions by address static int compare_partitions(const void *a, const void *b) { const esp_partition_t *part_a = *(const esp_partition_t **)a; const esp_partition_t *part_b = *(const esp_partition_t **)b; return ((int32_t)part_a->address - (int32_t)part_b->address); } static const esp_partition_t **get_sorted_partition_array(esp_flash_t *flash_chip, unsigned int *out_partition_count) { // Number of partitions on the flash chip unsigned int partition_count = count_partitions(flash_chip); assert(partition_count != 0); *out_partition_count = partition_count; // Allocate an array for copying partitions const esp_partition_t **part_array = (const esp_partition_t **) calloc(partition_count, sizeof(esp_partition_t *)); assert(part_array != NULL); // Copy partitions to the array unsigned i = 0; esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); assert(it != NULL); for (; it != NULL; it = esp_partition_next(it)) { const esp_partition_t *p = esp_partition_get(it); if (p->flash_chip == flash_chip) { part_array[i++] = p; } } esp_partition_iterator_release(it); assert(i == partition_count); // Sort partitions by address using qsort qsort(part_array, partition_count, sizeof(esp_partition_t *), compare_partitions); return part_array; } esp_err_t partition_utils_find_unallocated(esp_flash_t *flash_chip, size_t required_size, uint32_t start_offset, uint32_t *found_offset, size_t *found_size) { if (flash_chip == NULL) { flash_chip = esp_flash_default_chip; } if (required_size == 0 || found_offset == NULL) { return ESP_ERR_INVALID_ARG; } // Get a sorted partition array for the given flash chip unsigned int partition_count; const esp_partition_t **sorted_partitions = get_sorted_partition_array(flash_chip, &partition_count); if (sorted_partitions == NULL) { return ESP_ERR_NO_MEM; } // Scan for unallocated space between partitions, starting after the start_offset with unused space >= required_size uint32_t last_end_address = start_offset; for (size_t i = 0; i < partition_count; ++i) { if (sorted_partitions[i]->address > start_offset && sorted_partitions[i]->address > last_end_address) { size_t unallocated_size = sorted_partitions[i]->address - last_end_address; if (unallocated_size >= required_size) { *found_offset = last_end_address; if (found_size != NULL) { *found_size = unallocated_size; } free(sorted_partitions); return ESP_OK; } } last_end_address = sorted_partitions[i]->address + sorted_partitions[i]->size; } // Check for unallocated space after the last partition last_end_address = MAX(last_end_address, start_offset); size_t unallocated_size = flash_chip->size - last_end_address; if (unallocated_size >= required_size) { *found_offset = last_end_address; if (found_size != NULL) { *found_size = unallocated_size; } free(sorted_partitions); return ESP_OK; } free(sorted_partitions); return ESP_ERR_NOT_FOUND; }