From e9e388a0855791afeb939faeb28c58a6390c2a89 Mon Sep 17 00:00:00 2001 From: "radek.tandler" Date: Fri, 20 Jan 2023 17:58:52 +0100 Subject: [PATCH 1/2] Storage: ESP Partition extended options for the SPI Flash emulation Various extensions and fixes to improve Linux target SPI Flash emulation. Used by the host tests --- components/esp_partition/CMakeLists.txt | 10 + components/esp_partition/Kconfig | 10 +- .../partition_api_test/CMakeLists.txt | 35 ++ .../main/partition_api_test.c | 432 ++++++++++++++++-- .../partition_api_test/partition_table_8M.csv | 6 + .../partition_api_test/sdkconfig.defaults | 1 + .../include/esp_private/partition_linux.h | 61 ++- components/esp_partition/partition.c | 13 + components/esp_partition/partition_linux.c | 392 ++++++++++++---- .../spiffs/host_test/main/host_test_spiffs.c | 4 +- 10 files changed, 826 insertions(+), 138 deletions(-) create mode 100644 components/esp_partition/host_test/partition_api_test/partition_table_8M.csv diff --git a/components/esp_partition/CMakeLists.txt b/components/esp_partition/CMakeLists.txt index 7201b772119..5220e476714 100644 --- a/components/esp_partition/CMakeLists.txt +++ b/components/esp_partition/CMakeLists.txt @@ -21,6 +21,16 @@ idf_component_register(SRCS "${srcs}" REQUIRES ${reqs} PRIV_REQUIRES ${priv_reqs}) +if(${target} STREQUAL "linux") + # link bsd library for strlcpy + find_library(LIB_BSD bsd) + if(LIB_BSD) + target_link_libraries(${COMPONENT_LIB} PRIVATE ${LIB_BSD}) + elseif(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + message(WARNING "Missing LIBBSD library. Install libbsd-dev package and/or check linker directories.") + endif() +endif() + if(CMAKE_C_COMPILER_ID MATCHES "GNU") # These flags are GCC specific set_property(SOURCE ${cache_srcs} APPEND_STRING PROPERTY COMPILE_FLAGS diff --git a/components/esp_partition/Kconfig b/components/esp_partition/Kconfig index d70173b2086..4eea35dcfa6 100644 --- a/components/esp_partition/Kconfig +++ b/components/esp_partition/Kconfig @@ -1,10 +1,10 @@ -menu "ESP_PARTITION" +menu "Partition API Configuration" + # This option enables gathering statistics and flash wear levelling simulation. + # Linux target only (host tests). config ESP_PARTITION_ENABLE_STATS - bool "Enable esp_partition statistics gathering" - default n + bool depends on IDF_TARGET_LINUX - help - This option enables statistics gathering and flash wear simulation. Linux only. + default n endmenu diff --git a/components/esp_partition/host_test/partition_api_test/CMakeLists.txt b/components/esp_partition/host_test/partition_api_test/CMakeLists.txt index 469a614a143..072b9d936d9 100644 --- a/components/esp_partition/host_test/partition_api_test/CMakeLists.txt +++ b/components/esp_partition/host_test/partition_api_test/CMakeLists.txt @@ -7,3 +7,38 @@ set(COMPONENTS main) list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/") project(partition_api_test) + +#extra step to build 8M partition table on top of (default) 4M partition table built by partition-table dependency +set(flashsize_opt --flash-size 8MB) +set(partition_csv "partition_table_8M.csv") +set(partition_bin "partition-table_8M.bin") + +idf_build_get_property(build_dir BUILD_DIR) +idf_build_get_property(python PYTHON) + +set(gen_partition_table "${python}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../partition_table/gen_esp32part.py" "-q" + "${flashsize_opt}" "--") + +set(partition_table_display + COMMAND ${CMAKE_COMMAND} -E echo "Partition table binary generated. Contents:" + COMMAND ${CMAKE_COMMAND} -E echo "*******************************************************************************" + COMMAND ${gen_partition_table} "${build_dir}/partition_table/${partition_bin}" + COMMAND ${CMAKE_COMMAND} -E echo "*******************************************************************************" +) + +add_custom_command(OUTPUT "${build_dir}/partition_table/${partition_bin}" + COMMAND ${gen_partition_table} + "${CMAKE_CURRENT_SOURCE_DIR}/${partition_csv}" + "${build_dir}/partition_table/${partition_bin}" + ${partition_table_display} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${partition_csv} + VERBATIM) + +add_custom_target(partition_table_bin_8M DEPENDS "${build_dir}/partition_table/${partition_bin}" + ) +add_custom_target(partition-table-8M + DEPENDS partition_table_bin_8M + ${partition_table_display} + VERBATIM) + +add_dependencies(partition_api_test.elf partition-table partition-table-8M) diff --git a/components/esp_partition/host_test/partition_api_test/main/partition_api_test.c b/components/esp_partition/host_test/partition_api_test/main/partition_api_test.c index a54d4170f6c..f5d2dbcd257 100644 --- a/components/esp_partition/host_test/partition_api_test/main/partition_api_test.c +++ b/components/esp_partition/host_test/partition_api_test/main/partition_api_test.c @@ -7,6 +7,11 @@ */ #include +#if __has_include() +// for strlcpy +#include +#endif +#include #include "esp_err.h" #include "esp_partition.h" #include "esp_private/partition_linux.h" @@ -144,7 +149,331 @@ TEST(partition_api, test_partition_mmap) TEST_ASSERT_EQUAL(err,ESP_ERR_INVALID_SIZE); } -#define EMULATED_VIRTUAL_SECTOR_COUNT (ESP_PARTITION_EMULATED_FLASH_SIZE / ESP_PARTITION_EMULATED_SECTOR_SIZE) +TEST(partition_api, test_partition_mmap_diff_size) +{ + // Scenario: default temporary flash file, explicitly specified size and file with partition table + // Check the size of "storage" partition. Should be 6M = 6*1024*1024 + + // unmap file to have correct initial conditions, regardless of result + esp_partition_file_munmap(); + + // get and initialize the control structure for file mmap + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl = esp_partition_get_file_mmap_ctrl_input(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl); + + memset(p_file_mmap_ctrl, 0, sizeof(*p_file_mmap_ctrl)); + p_file_mmap_ctrl->flash_file_size = 0x800000; // 8MB + strlcpy(p_file_mmap_ctrl->partition_file_name, "./build/partition_table/partition-table_8M.bin", sizeof(p_file_mmap_ctrl->partition_file_name)); + + // esp_partition_find_first calls the esp_partition_file_mmap in the background + const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage"); + TEST_ASSERT_NOT_NULL(partition_data); + + // Check partition size + size_t exp_size = 0x600000; // 6MB + size_t act_size = partition_data->size; + TEST_ASSERT_EQUAL(exp_size, act_size); + + // cleanup after test + esp_partition_file_munmap(); +} + +TEST(partition_api, test_partition_mmap_reopen) +{ + // Scenario: default temporary flash file, write some data + // Remember name of temporary file, reset remove flag, unmmap file. + // Set file name from previous step, mmap file, read and compare data + + // unmap file to have correct initial conditions, regardless of result + esp_partition_file_munmap(); + + // get and initialize the control structure for file mmap + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input); + + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + + // esp_partition_find_first calls the esp_partition_file_mmap in the background + const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage"); + TEST_ASSERT_NOT_NULL(partition_data); + + const char *test_string = "Is HAL6000 an IBM6000 ?"; + size_t test_string_len = strlen(test_string) + 1; + + // write test string + esp_err_t err = esp_partition_write(partition_data, 0, test_string, test_string_len); + TEST_ESP_OK(err); + + // remember memory mapped file name + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_act = esp_partition_get_file_mmap_ctrl_act(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_act); + + char generated_file_name[PATH_MAX]; + strlcpy(generated_file_name, p_file_mmap_ctrl_act->flash_file_name, sizeof(generated_file_name)); + + // ensure remove flag is not set + p_file_mmap_ctrl_input->remove_dump = false; + + // unmap + err = esp_partition_file_munmap(); + TEST_ESP_OK(err); + + // initialize control struct with memory mapped file name + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + strlcpy(p_file_mmap_ctrl_input->flash_file_name, generated_file_name, sizeof(p_file_mmap_ctrl_input->flash_file_name)); + + // get partiton + partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage"); + TEST_ASSERT_NOT_NULL(partition_data); + + // read verify string + char *verify_string = malloc(test_string_len); + err = esp_partition_read(partition_data, 0, verify_string, test_string_len); + TEST_ESP_OK(err); + + // compare strings + bool strings_equal = (strncmp(test_string, verify_string, test_string_len) == 0); + TEST_ASSERT_EQUAL(strings_equal,true); + + free(verify_string); + + // cleanup after test + esp_partition_file_munmap(); +} + +TEST(partition_api, test_partition_mmap_remove) +{ + // Scenario: default temporary flash file, write some data + // Remember name of temporary file, set remove flag, unmmap file. + // Set file name from previous step, try to get partition "storage", should fail with NULL returned + + // unmap file to have correct initial conditions, regardless of result + esp_partition_file_munmap(); + + // get and initialize the control structure for file mmap + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input); + + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + + // esp_partition_find_first calls the esp_partition_file_mmap in the background + const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage"); + TEST_ASSERT_NOT_NULL(partition_data); + + const char *test_string = "This text should dismiss after esp_partition_file_munmap"; + size_t test_string_len = strlen(test_string) + 1; + + // write test string + esp_err_t err = esp_partition_write(partition_data, 0, test_string, test_string_len); + TEST_ESP_OK(err); + + // remember memory mapped file name + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_act = esp_partition_get_file_mmap_ctrl_act(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_act); + + char generated_file_name[PATH_MAX]; + strlcpy(generated_file_name, p_file_mmap_ctrl_act->flash_file_name, sizeof(generated_file_name)); + + // ensure remove flag is set + p_file_mmap_ctrl_input->remove_dump = true; + + // unmap + err = esp_partition_file_munmap(); + TEST_ESP_OK(err); + + // initialize control struct with memory mapped file name + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + strlcpy(p_file_mmap_ctrl_input->flash_file_name, generated_file_name, sizeof(p_file_mmap_ctrl_input->flash_file_name)); + + // get partiton, should fail with NULL returned + partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage"); + TEST_ASSERT_EQUAL(NULL, partition_data); + + // cleanup after test + esp_partition_file_munmap(); + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); +} + +TEST(partition_api, test_partition_mmap_name_size) +{ + // Negative Scenario: conflicting settings - flash_file_name together with one or both of + // flash_file_size, partition_file_name + // esp_partition_file_mmap should return ESP_ERR_INVALID_ARG + + // unmap file to have correct initial conditions, regardless of result + esp_partition_file_munmap(); + + // get and initialize the control structure for file mmap + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input); + + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + const char *flash_file_name = "/tmp/xyz"; + strlcpy(p_file_mmap_ctrl_input->flash_file_name, flash_file_name, sizeof(p_file_mmap_ctrl_input->flash_file_name)); + p_file_mmap_ctrl_input->flash_file_size = 1; // anything different from 0 + + const uint8_t *p_mem_block = NULL; + esp_err_t err = esp_partition_file_mmap(&p_mem_block); + + // expected result is invalid argument + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + + // cleanup after test + esp_partition_file_munmap(); + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); +} + +TEST(partition_api, test_partition_mmap_size_no_partition) +{ + // Negative Scenario: conflicting settings - flash_file_name empty, flash_file_size set + // and partition_file_name not set + // esp_partition_file_mmap should return ESP_ERR_INVALID_ARG + + // unmap file to have correct initial conditions, regardless of result + esp_partition_file_munmap(); + + // get and initialize the control structure for file mmap + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input); + + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + p_file_mmap_ctrl_input->flash_file_size = 1; // anything different from 0 + + const uint8_t *p_mem_block = NULL; + esp_err_t err = esp_partition_file_mmap(&p_mem_block); + + // expected result is invalid argument + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + + // cleanup after test + esp_partition_file_munmap(); + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); +} + +TEST(partition_api, test_partition_mmap_no_size_partition) +{ + // Negative Scenario: conflicting settings - flash_file_name empty, flash_file_size not set + // and partition_file_name set + // esp_partition_file_mmap should return ESP_ERR_INVALID_ARG + + // unmap file to have correct initial conditions, regardless of result + esp_partition_file_munmap(); + + // get and initialize the control structure for file mmap + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input); + + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + const char *partition_file_name = "/tmp/xyz.bin"; + strlcpy(p_file_mmap_ctrl_input->partition_file_name, partition_file_name, sizeof(p_file_mmap_ctrl_input->partition_file_name)); + + const uint8_t *p_mem_block = NULL; + esp_err_t err = esp_partition_file_mmap(&p_mem_block); + + // expected result is invalid argument + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err); + + // cleanup after test + esp_partition_file_munmap(); + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); +} + +TEST(partition_api, test_partition_mmap_ffile_nf) +{ + // Negative Scenario: specified flash_file_name file not found + // esp_partition_file_mmap should return ESP_ERR_NOT_FOUND + + // unmap file to have correct initial conditions, regardless of result + esp_partition_file_munmap(); + + // get and initialize the control structure for file mmap + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input); + + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + const char *flash_file_name = "/tmp/strangefilename.tmp"; + + // make sure file doesn't exist + if (access(flash_file_name, F_OK) == 0) { + // our strange file exists, skip rest of test + } else { + strlcpy(p_file_mmap_ctrl_input->flash_file_name, flash_file_name, sizeof(p_file_mmap_ctrl_input->flash_file_name)); + + const uint8_t *p_mem_block = NULL; + esp_err_t err = esp_partition_file_mmap(&p_mem_block); + + // expected result is file not found + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + + // cleanup after test + esp_partition_file_munmap(); + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + } +} + +TEST(partition_api, test_partition_mmap_pfile_nf) +{ + // Negative Scenario: specified partition_file_name file not found + // esp_partition_file_mmap should return ESP_ERR_NOT_FOUND + + // unmap file to have correct initial conditions, regardless of result + esp_partition_file_munmap(); + + // get and initialize the control structure for file mmap + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input); + + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + const char *partition_file_name = "/tmp/strangefilename.tmp"; + + // make sure file doesn't exist + if (access(partition_file_name, F_OK) == 0) { + // our strange file exists, skip rest of test + } else { + strlcpy(p_file_mmap_ctrl_input->partition_file_name, partition_file_name, sizeof(p_file_mmap_ctrl_input->partition_file_name)); + p_file_mmap_ctrl_input->flash_file_size = 0x10000; // any non zero value to pass validation + + const uint8_t *p_mem_block = NULL; + esp_err_t err = esp_partition_file_mmap(&p_mem_block); + + // expected result is file not found + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err); + + // cleanup after test + esp_partition_file_munmap(); + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + } +} + +TEST(partition_api, test_partition_mmap_size_too_small) +{ + // Negative Scenario: specified flash file size too small + // to hold at least partition table at default offset + // esp_partition_file_mmap should return ESP_ERR_INVALID_SIZE + + // unmap file to have correct initial conditions, regardless of result + esp_partition_file_munmap(); + + // get and initialize the control structure for file mmap + esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input(); + TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input); + + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); + + // set valid partition table name and very small flash size + strlcpy(p_file_mmap_ctrl_input->partition_file_name, "./build/partition_table/partition-table.bin", sizeof(p_file_mmap_ctrl_input->partition_file_name)); + p_file_mmap_ctrl_input->flash_file_size = 1; + + const uint8_t *p_mem_block = NULL; + esp_err_t err = esp_partition_file_mmap(&p_mem_block); + + // expected result is invalid argument + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_SIZE, err); + + // cleanup after test + esp_partition_file_munmap(); + memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input)); +} typedef struct { @@ -154,9 +483,24 @@ typedef struct size_t read_bytes; size_t write_bytes; size_t total_time; - size_t sector_erase_count[EMULATED_VIRTUAL_SECTOR_COUNT]; + size_t *sector_erase_count; + size_t sector_erase_count_size; } t_stats; +void init_stats(t_stats *p_stats) +{ + memset(p_stats, 0, sizeof(t_stats)); + p_stats->sector_erase_count_size = esp_partition_get_file_mmap_ctrl_act()->flash_file_size / ESP_PARTITION_EMULATED_SECTOR_SIZE; + p_stats->sector_erase_count = calloc(p_stats->sector_erase_count_size, sizeof(size_t)); +} + +void dispose_stats(t_stats *p_stats) +{ + if(p_stats->sector_erase_count != NULL){ + free(p_stats->sector_erase_count); + } +} + void print_stats(const t_stats *p_stats) { ESP_LOGI(TAG, "read_ops:%06lu write_ops:%06lu erase_ops:%06lu read_bytes:%06lu write_bytes:%06lu total_time:%06lu\n", @@ -177,7 +521,7 @@ void read_stats(t_stats *p_stats) p_stats->write_bytes = esp_partition_get_write_bytes(); p_stats->total_time = esp_partition_get_total_time(); - for(size_t i = 0; i < EMULATED_VIRTUAL_SECTOR_COUNT; i++) + for(size_t i = 0; i < p_stats->sector_erase_count_size; i++) p_stats->sector_erase_count[i] = esp_partition_get_sector_erase_count(i); } @@ -198,7 +542,7 @@ bool evaluate_stats(const t_stats *p_initial_stats, const t_stats *p_final_stats if(p_expected_difference_stats->total_time != SIZE_MAX) TEST_ASSERT_EQUAL(p_initial_stats->total_time + p_expected_difference_stats->total_time, p_final_stats->total_time); - for(size_t i = 0; i < EMULATED_VIRTUAL_SECTOR_COUNT; i++) + for(size_t i = 0; i < p_initial_stats->sector_erase_count_size; i++) { if(p_expected_difference_stats->sector_erase_count[i] != SIZE_MAX) { @@ -220,7 +564,11 @@ TEST(partition_api, test_partition_stats) t_stats initial_stats; t_stats final_stats; - t_stats zero_stats = {0}; + t_stats zero_stats; + + init_stats(&initial_stats); + init_stats(&final_stats); + init_stats(&zero_stats); // get actual statistics read_stats(&initial_stats); @@ -256,15 +604,16 @@ TEST(partition_api, test_partition_stats) if((non_aligned_portions % ESP_PARTITION_EMULATED_SECTOR_SIZE) > 0) erase_ops += 1; - t_stats expected_difference_stats = { - .read_ops = 1, - .write_ops = 1, - .erase_ops = erase_ops, - .read_bytes = size, - .write_bytes = size, - .total_time = SIZE_MAX - }; - for (size_t i = 0; i < EMULATED_VIRTUAL_SECTOR_COUNT; i++) + t_stats expected_difference_stats; + init_stats(&expected_difference_stats); + + expected_difference_stats.read_ops = 1; + expected_difference_stats.write_ops = 1; + expected_difference_stats.erase_ops = erase_ops; + expected_difference_stats.read_bytes = size; + expected_difference_stats.write_bytes = size; + expected_difference_stats.total_time = SIZE_MAX; + for (size_t i = 0; i < expected_difference_stats.sector_erase_count_size; i++) expected_difference_stats.sector_erase_count[i] = SIZE_MAX; evaluate_stats(&initial_stats, &final_stats, &expected_difference_stats); @@ -276,15 +625,20 @@ TEST(partition_api, test_partition_stats) // evaluate zero statistics evaluate_stats(&zero_stats, &final_stats, &zero_stats); + // free symanically allocated space + dispose_stats(&initial_stats); + dispose_stats(&final_stats); + dispose_stats(&zero_stats); + dispose_stats(&expected_difference_stats); free(test_data_ptr); } -TEST(partition_api, test_partition_wear_emulation) +TEST(partition_api, test_partition_power_off_emulation) { const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage"); TEST_ASSERT_NOT_NULL(partition_data); - // no offset, map whole partition + //no offset, map whole partition size_t offset = 0; size_t size = partition_data->size; @@ -293,9 +647,9 @@ TEST(partition_api, test_partition_wear_emulation) TEST_ASSERT_NOT_NULL(test_data_ptr); memset(test_data_ptr, 0xff, size); - // --- wear off --- - // ensure wear emulation is off - esp_partition_fail_after(SIZE_MAX); + // --- power-off off --- + // ensure power-off emulation is off + esp_partition_fail_after(SIZE_MAX, 0); // erase partition data esp_err_t err = esp_partition_erase_range(partition_data, offset, size); @@ -309,40 +663,39 @@ TEST(partition_api, test_partition_wear_emulation) err = esp_partition_erase_range(partition_data, offset, size); TEST_ESP_OK(err); - // --- wear on, write --- - // ensure wear emulation is on, below the limit for size - // esp_partition_write consumes one wear cycle per 4 bytes written - esp_partition_fail_after(size / 4 - 1); + // --- power-off on, write --- + // ensure power-off emulation is on, below the limit for size + // esp_partition_write consumes one power off failure cycle per 4 bytes written + esp_partition_fail_after(size / 4 - 1, ESP_PARTITION_FAIL_AFTER_MODE_BOTH); // write data - should fail err = esp_partition_write(partition_data, offset, test_data_ptr, size); TEST_ASSERT_EQUAL(ESP_FAIL, err); - // --- wear on, erase has just enough wear cycles available--- - // ensure wear emulation is on, at the limit for size - // esp_partition_erase_range consumes one wear cycle per one virtual sector erased - esp_partition_fail_after(size / ESP_PARTITION_EMULATED_SECTOR_SIZE); + // --- power-off on, erase has just enough power off failure cycles available--- + // ensure power-off emulation is on, at the limit for size + // esp_partition_erase_range consumes one power-off emulation cycle per one virtual sector erased + esp_partition_fail_after(size / ESP_PARTITION_EMULATED_SECTOR_SIZE, ESP_PARTITION_FAIL_AFTER_MODE_BOTH); // write data - should be ok err = esp_partition_erase_range(partition_data, offset, size); TEST_ASSERT_EQUAL(ESP_OK, err); - // --- wear on, erase has one cycle less than required--- - // ensure wear emulation is on, below the limit for size - // esp_partition_erase_range consumes one wear cycle per one virtual sector erased - esp_partition_fail_after(size / ESP_PARTITION_EMULATED_SECTOR_SIZE - 1); + // --- power-off on, erase has one cycle less than required--- + // ensure power-off emulation is on, below the limit for size + // esp_partition_erase_range consumes one power-off emulation cycle per one virtual sector erased + esp_partition_fail_after(size / ESP_PARTITION_EMULATED_SECTOR_SIZE - 1, ESP_PARTITION_FAIL_AFTER_MODE_BOTH); // write data - should fail err = esp_partition_erase_range(partition_data, offset, size); TEST_ASSERT_EQUAL(ESP_FAIL, err); // ---cleanup --- - // disable wear emulation - esp_partition_fail_after(SIZE_MAX); + // disable power-off emulation + esp_partition_fail_after(SIZE_MAX, 0); free(test_data_ptr); } - TEST_GROUP_RUNNER(partition_api) { RUN_TEST_CASE(partition_api, test_partition_find_basic); @@ -351,8 +704,17 @@ TEST_GROUP_RUNNER(partition_api) RUN_TEST_CASE(partition_api, test_partition_find_first); RUN_TEST_CASE(partition_api, test_partition_ops); RUN_TEST_CASE(partition_api, test_partition_mmap); + RUN_TEST_CASE(partition_api, test_partition_mmap_diff_size); + RUN_TEST_CASE(partition_api, test_partition_mmap_reopen); + RUN_TEST_CASE(partition_api, test_partition_mmap_remove); + RUN_TEST_CASE(partition_api, test_partition_mmap_name_size); + RUN_TEST_CASE(partition_api, test_partition_mmap_size_no_partition); + RUN_TEST_CASE(partition_api, test_partition_mmap_no_size_partition); + RUN_TEST_CASE(partition_api, test_partition_mmap_ffile_nf); + RUN_TEST_CASE(partition_api, test_partition_mmap_pfile_nf); + RUN_TEST_CASE(partition_api, test_partition_mmap_size_too_small); RUN_TEST_CASE(partition_api, test_partition_stats); - RUN_TEST_CASE(partition_api, test_partition_wear_emulation); + RUN_TEST_CASE(partition_api, test_partition_power_off_emulation); } static void run_all_tests(void) diff --git a/components/esp_partition/host_test/partition_api_test/partition_table_8M.csv b/components/esp_partition/host_test/partition_api_test/partition_table_8M.csv new file mode 100644 index 00000000000..57a411fba71 --- /dev/null +++ b/components/esp_partition/host_test/partition_api_test/partition_table_8M.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +storage, data, , , 6M, diff --git a/components/esp_partition/host_test/partition_api_test/sdkconfig.defaults b/components/esp_partition/host_test/partition_api_test/sdkconfig.defaults index d621ed02e0a..9dffe9cfe8a 100644 --- a/components/esp_partition/host_test/partition_api_test/sdkconfig.defaults +++ b/components/esp_partition/host_test/partition_api_test/sdkconfig.defaults @@ -1,4 +1,5 @@ CONFIG_IDF_TARGET="linux" +IDF_TARGET_LINUX=y CONFIG_COMPILER_CXX_EXCEPTIONS=y CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n CONFIG_UNITY_ENABLE_FIXTURE=y diff --git a/components/esp_partition/include/esp_private/partition_linux.h b/components/esp_partition/include/esp_private/partition_linux.h index f2a007a7cea..673155dd53b 100644 --- a/components/esp_partition/include/esp_private/partition_linux.h +++ b/components/esp_partition/include/esp_private/partition_linux.h @@ -8,6 +8,7 @@ #include #include +#include #include "esp_err.h" #ifdef __cplusplus @@ -24,7 +25,12 @@ extern "C" { #define ESP_PARTITION_EMULATED_SECTOR_SIZE 0x1000 /** @brief emulated whole flash size for the partition API on Linux */ -#define ESP_PARTITION_EMULATED_FLASH_SIZE 0x400000 //4MB fixed +#define ESP_PARTITION_DEFAULT_EMULATED_FLASH_SIZE 0x400000 //4MB fixed + +/** @brief mode of fail after */ +#define ESP_PARTITION_FAIL_AFTER_MODE_ERASE 0x01 +#define ESP_PARTITION_FAIL_AFTER_MODE_WRITE 0x02 +#define ESP_PARTITION_FAIL_AFTER_MODE_BOTH 0x03 /** * @brief Partition type to string conversion routine @@ -166,21 +172,22 @@ size_t esp_partition_get_write_bytes(void); size_t esp_partition_get_total_time(void); /** - * @brief Initializes emulation of failure caused by wear on behalf of write/erase operations + * @brief Initializes emulation of lost power failure in write/erase operations * - * Function initializes down counter emulating remaining write / erase cycles. - * Once this counter reaches 0, emulation of all subsequent write / erase operations fails + * Function initializes down counter emulating power off failure during write / erase operations. + * Once this counter reaches 0, actual as well as all subsequent write / erase operations fail * Initial state of down counter is disabled. * - * @param[in] count Number of remaining write / erase cycles before failure. Call with SIZE_MAX to disable simulation of flash wear. + * @param[in] count Number of remaining write / erase cycles before emulated failure. Call with SIZE_MAX to disable failure emulation. + * @param[in] mode Controls whether remaining cycles are applied to erase, write or both operations * */ -void esp_partition_fail_after(size_t count); +void esp_partition_fail_after(size_t count, uint8_t mode); /** * @brief Returns count of erase operations performed on virtual emulated sector * - * Function returns number of erase operatinos performed on virtual sector specified by the parameter sector. + * Function returns number of erase operations performed on virtual sector specified by the parameter sector. * The esp_parttion mapped address space is virtually split into sectors of the size ESP_PARTITION_EMULATED_SECTOR_SIZE. * Calls to the esp_partition_erase_range are impacting one or multiple virtual sectors, for each of them, the respective * count is incremented. @@ -193,6 +200,46 @@ void esp_partition_fail_after(size_t count); */ size_t esp_partition_get_sector_erase_count(size_t sector); +typedef struct { + char flash_file_name[PATH_MAX]; /*!< name of flash dump file, zero-terminated ASCII string */ + size_t flash_file_size; /*!< size of flash dump file in bytes */ + char partition_file_name[PATH_MAX]; /*!< name of file containing binary representation of partition table, zero-terminated ASCII string */ + bool remove_dump; /*!< flag is set to true if dump file has to be removed after esp_partition_file_munmap */ +} esp_partition_file_mmap_ctrl_t; + +/** + * @brief Returns pointer to the structure controlling mapping of flash file + * + * Function returns pointer to structure used by esp_partition_file_mmap and esp_partition_file_munmap + * Caller can change this structure members prior calls involving the above functions to + * Specify existing flash file which will represent the content of flash memory after mapping + * Specify size and partition file name used to create empty flash memory + * Control whether the actual flash file will be deleted of kept after call to esp_partition_file_munmap + * + * @return + * - pointer to flash file mapping control structure + * +*/ +esp_partition_file_mmap_ctrl_t* esp_partition_get_file_mmap_ctrl_input(void); + +/** + * @brief Returns pointer to the structure reflecting actual settings of flash file emulation + * + * Function returns pointer to structure containing: + * flash file name representing emulated flash memory + * size of file representing emulated flash memory + * file name holding binary used to initialize partition table (if it was used) + * + * @return + * - pointer to flash file mapping actuall values in control structure + * +*/ +esp_partition_file_mmap_ctrl_t* esp_partition_get_file_mmap_ctrl_act(void); + +// private function in partition.c to unload partitions and free space allocated by them +void unload_partitions(void); + + #ifdef __cplusplus } #endif diff --git a/components/esp_partition/partition.c b/components/esp_partition/partition.c index 2bf015ec20b..24bcbc1dbba 100644 --- a/components/esp_partition/partition.c +++ b/components/esp_partition/partition.c @@ -225,6 +225,19 @@ static esp_err_t load_partitions(void) return err; } +void unload_partitions(void) +{ + _lock_acquire(&s_partition_list_lock); + partition_list_item_t *it; + SLIST_FOREACH(it, &s_partition_list, next) { + SLIST_REMOVE(&s_partition_list, it, partition_list_item_, next); + free(it); + } + _lock_release(&s_partition_list_lock); + + assert(SLIST_EMPTY(&s_partition_list)); +} + static esp_err_t ensure_partitions_loaded(void) { esp_err_t err = ESP_OK; diff --git a/components/esp_partition/partition_linux.c b/components/esp_partition/partition_linux.c index 810e3f19e07..0b2dca4a37b 100644 --- a/components/esp_partition/partition_linux.c +++ b/components/esp_partition/partition_linux.c @@ -7,8 +7,13 @@ #include #include #include +#if __has_include() +// for strlcpy +#include +#endif #include #include +#include #include #include #include @@ -19,21 +24,29 @@ #include "esp_log.h" static const char *TAG = "linux_spiflash"; + static void *s_spiflash_mem_file_buf = NULL; +static int s_spiflash_mem_file_fd = -1; static const esp_partition_mmap_handle_t s_default_partition_mmap_handle = 0; +// input control structure, always contains what was specified by caller +static esp_partition_file_mmap_ctrl_t s_esp_partition_file_mmap_ctrl_input = {0}; +// actual control structure, contains what is actually used by the esp_partition +static esp_partition_file_mmap_ctrl_t s_esp_partition_file_mmap_ctrl_act = {0}; + #ifdef CONFIG_ESP_PARTITION_ENABLE_STATS -// variables holding stats and controlling wear emulation -size_t s_esp_partition_stat_read_ops = 0; -size_t s_esp_partition_stat_write_ops = 0; -size_t s_esp_partition_stat_read_bytes = 0; -size_t s_esp_partition_stat_write_bytes = 0; -size_t s_esp_partition_stat_erase_ops = 0; -size_t s_esp_partition_stat_total_time = 0; -size_t s_esp_partition_emulated_flash_life = SIZE_MAX; +// variables holding stats and controlling power-off emulation +static size_t s_esp_partition_stat_read_ops = 0; +static size_t s_esp_partition_stat_write_ops = 0; +static size_t s_esp_partition_stat_read_bytes = 0; +static size_t s_esp_partition_stat_write_bytes = 0; +static size_t s_esp_partition_stat_erase_ops = 0; +static size_t s_esp_partition_stat_total_time = 0; +static size_t s_esp_partition_emulated_power_off_counter = SIZE_MAX; +static uint8_t s_esp_partition_emulated_power_off_mode = 0; // tracking erase count individually for each emulated sector -size_t s_esp_partition_stat_sector_erase_count[ESP_PARTITION_EMULATED_FLASH_SIZE / ESP_PARTITION_EMULATED_SECTOR_SIZE] = {0}; +static size_t *s_esp_partition_stat_sector_erase_count = NULL; // forward declaration of hooks static void esp_partition_hook_read(const void *srcAddr, const size_t size); @@ -86,71 +99,191 @@ const char *esp_partition_subtype_to_str(const uint32_t type, const uint32_t sub esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) { - //create temporary file to hold complete SPIFLASH size - char temp_spiflash_mem_file_name[PATH_MAX] = {"/tmp/idf-partition-XXXXXX"}; - int spiflash_mem_file_fd = mkstemp(temp_spiflash_mem_file_name); + // temporary file is used only if control structure doesn't specify file name. + bool open_existing_file = false; + + if(strlen(s_esp_partition_file_mmap_ctrl_input.flash_file_name) > 0) { + // Open existing file. If size or partition table file were specified, raise errors + if(s_esp_partition_file_mmap_ctrl_input.flash_file_size > 0) { + ESP_LOGE(TAG, "Flash emulation file size: %u was specified while together with the file name: %s (illegal). Use file size = 0", + s_esp_partition_file_mmap_ctrl_input.flash_file_size, + s_esp_partition_file_mmap_ctrl_input.flash_file_name); + return ESP_ERR_INVALID_ARG; + } - if (spiflash_mem_file_fd == -1) { - ESP_LOGE(TAG, "Failed to create SPI FLASH emulation file %s: %s", temp_spiflash_mem_file_name, strerror(errno)); - return ESP_ERR_NOT_FINISHED; - } + if(strlen(s_esp_partition_file_mmap_ctrl_input.partition_file_name) > 0) { + ESP_LOGE(TAG, "Partition file name: %s was specified together with the flash emulation file name: %s (illegal). Use empty partition file name", + s_esp_partition_file_mmap_ctrl_input.partition_file_name, + s_esp_partition_file_mmap_ctrl_input.flash_file_name); + return ESP_ERR_INVALID_ARG; + } - if (ftruncate(spiflash_mem_file_fd, ESP_PARTITION_EMULATED_FLASH_SIZE) != 0) { - ESP_LOGE(TAG, "Failed to set size of SPI FLASH memory emulation file %s: %s", temp_spiflash_mem_file_name, strerror(errno)); - return ESP_ERR_INVALID_SIZE; - } + // copy flash file name to actual control struct + strlcpy(s_esp_partition_file_mmap_ctrl_act.flash_file_name, s_esp_partition_file_mmap_ctrl_input.flash_file_name, sizeof(s_esp_partition_file_mmap_ctrl_act.flash_file_name)); - ESP_LOGV(TAG, "SPIFLASH memory emulation file created: %s (size: %d B)", temp_spiflash_mem_file_name, ESP_PARTITION_EMULATED_FLASH_SIZE); + open_existing_file = true; + } else { + // Open temporary file. If size was specified, also partition table has to be specified, otherwise raise error. + // If none of size, partition table were specified, defaults are used. + // Name of temporary file is available in s_esp_partition_file_mmap_ctrl.flash_file_name + + bool has_partfile = (strlen(s_esp_partition_file_mmap_ctrl_input.partition_file_name) > 0); + bool has_len = (s_esp_partition_file_mmap_ctrl_input.flash_file_size > 0); + + // conflicting input + if(has_partfile != has_len) { + ESP_LOGE(TAG, "Invalid combination of Partition file name: %s flash file size: %u was specified. Use either both parameters or none.", + s_esp_partition_file_mmap_ctrl_input.partition_file_name, + s_esp_partition_file_mmap_ctrl_input.flash_file_size); + return ESP_ERR_INVALID_ARG; + } - //create memory-mapping for the partitions holder file - if ((s_spiflash_mem_file_buf = mmap(NULL, ESP_PARTITION_EMULATED_FLASH_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, spiflash_mem_file_fd, 0)) == MAP_FAILED) { - ESP_LOGE(TAG, "Failed to mmap() SPI FLASH memory emulation file: %s", strerror(errno)); - return ESP_ERR_NO_MEM; + // check if partition file is present, if not, use default + if(!has_partfile) { + strlcpy(s_esp_partition_file_mmap_ctrl_act.partition_file_name, "build/partition_table/partition-table.bin", sizeof(s_esp_partition_file_mmap_ctrl_act.partition_file_name)); + } else { + strlcpy(s_esp_partition_file_mmap_ctrl_act.partition_file_name, s_esp_partition_file_mmap_ctrl_input.partition_file_name, sizeof(s_esp_partition_file_mmap_ctrl_act.partition_file_name)); + } + + // check if flash size is present, if not set to default + if(!has_len) { + s_esp_partition_file_mmap_ctrl_act.flash_file_size = ESP_PARTITION_DEFAULT_EMULATED_FLASH_SIZE; + } else { + s_esp_partition_file_mmap_ctrl_act.flash_file_size = s_esp_partition_file_mmap_ctrl_input.flash_file_size; + } + + // specify pattern file name for temporary flash file + strlcpy(s_esp_partition_file_mmap_ctrl_act.flash_file_name, "/tmp/idf-partition-XXXXXX", sizeof(s_esp_partition_file_mmap_ctrl_act.flash_file_name)); } - //initialize whole range with bit-1 (NOR FLASH default) - memset(s_spiflash_mem_file_buf, 0xFF, ESP_PARTITION_EMULATED_FLASH_SIZE); + esp_err_t ret = ESP_OK; - //upload partition table to the mmap file at real offset as in SPIFLASH - const char *partition_table_file_name = "build/partition_table/partition-table.bin"; + if(open_existing_file) { - FILE *f_partition_table = fopen(partition_table_file_name, "r+"); - if (f_partition_table == NULL) { - ESP_LOGE(TAG, "Failed to open partition table file %s: %s", partition_table_file_name, strerror(errno)); - return ESP_ERR_NOT_FOUND; - } + s_spiflash_mem_file_fd = open(s_esp_partition_file_mmap_ctrl_act.flash_file_name, O_RDWR); - if (fseek(f_partition_table, 0L, SEEK_END) != 0) { - ESP_LOGE(TAG, "Failed to seek in partition table file %s: %s", partition_table_file_name, strerror(errno)); - return ESP_ERR_INVALID_SIZE; - } + if (s_spiflash_mem_file_fd == -1) { + ESP_LOGE(TAG, "Failed to open SPI FLASH emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); + return ESP_ERR_NOT_FOUND; + } - int partition_table_file_size = ftell(f_partition_table); - ESP_LOGV(TAG, "Using partition table file %s (size: %d B):", partition_table_file_name, partition_table_file_size); + do { + // seek to the end + off_t size = lseek(s_spiflash_mem_file_fd, 0L, SEEK_END); + if(size < 0) { + ESP_LOGE(TAG, "Failed to seek in SPI FLASH emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); + ret = ESP_ERR_NOT_FINISHED; + break; + } + + s_esp_partition_file_mmap_ctrl_act.flash_file_size = size; + + // seek to beginning + size = lseek(s_spiflash_mem_file_fd, 0L, SEEK_SET); + if(size < 0) { + ESP_LOGE(TAG, "Failed to seek in SPI FLASH emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); + ret = ESP_ERR_NOT_FINISHED; + break; + } + + //create memory-mapping for the flash holder file + if ((s_spiflash_mem_file_buf = mmap(NULL, s_esp_partition_file_mmap_ctrl_act.flash_file_size, PROT_READ | PROT_WRITE, MAP_SHARED, s_spiflash_mem_file_fd, 0)) == MAP_FAILED) { + ESP_LOGE(TAG, "Failed to mmap() SPI FLASH memory emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); + ret = ESP_ERR_NOT_FINISHED; + break; + } + } while(false); + } else { + //create temporary file to hold complete SPIFLASH size + s_spiflash_mem_file_fd = mkstemp(s_esp_partition_file_mmap_ctrl_act.flash_file_name); - uint8_t *part_table_in_spiflash = s_spiflash_mem_file_buf + ESP_PARTITION_TABLE_OFFSET; + if (s_spiflash_mem_file_fd == -1) { + ESP_LOGE(TAG, "Failed to create SPI FLASH emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); + return ESP_ERR_NOT_FINISHED; + } - //copy partition table from the file to emulated SPIFLASH memory space - if (fseek(f_partition_table, 0L, SEEK_SET) != 0) { - ESP_LOGE(TAG, "Failed to seek in partition table file %s: %s", partition_table_file_name, strerror(errno)); - return ESP_ERR_INVALID_SIZE; - } + do { + // resize file + if (ftruncate(s_spiflash_mem_file_fd, s_esp_partition_file_mmap_ctrl_act.flash_file_size) != 0) { + ESP_LOGE(TAG, "Failed to set size of SPI FLASH memory emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); + ret = ESP_ERR_INVALID_SIZE; + break; + } + + ESP_LOGV(TAG, "SPIFLASH memory emulation file created: %s (size: %d B)", s_esp_partition_file_mmap_ctrl_act.flash_file_name, s_esp_partition_file_mmap_ctrl_act.flash_file_size); + + // create memory-mapping for the flash holder file + if ((s_spiflash_mem_file_buf = mmap(NULL, s_esp_partition_file_mmap_ctrl_act.flash_file_size, PROT_READ | PROT_WRITE, MAP_SHARED, s_spiflash_mem_file_fd, 0)) == MAP_FAILED) { + ESP_LOGE(TAG, "Failed to mmap() SPI FLASH memory emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); + ret = ESP_ERR_NO_MEM; + break; + } + + // initialize whole range with bit-1 (NOR FLASH default) + memset(s_spiflash_mem_file_buf, 0xFF, s_esp_partition_file_mmap_ctrl_act.flash_file_size); + + // upload partition table to the mmap file at real offset as in SPIFLASH + FILE *f_partition_table = fopen(s_esp_partition_file_mmap_ctrl_act.partition_file_name, "r+"); + if (f_partition_table == NULL) { + ESP_LOGE(TAG, "Failed to open partition table file %s: %s", s_esp_partition_file_mmap_ctrl_act.partition_file_name, strerror(errno)); + ret = ESP_ERR_NOT_FOUND; + break; + } + + if (fseek(f_partition_table, 0L, SEEK_END) != 0) { + ESP_LOGE(TAG, "Failed to seek in partition table file %s: %s", s_esp_partition_file_mmap_ctrl_act.partition_file_name, strerror(errno)); + ret = ESP_ERR_INVALID_SIZE; + break; + } + + int partition_table_file_size = ftell(f_partition_table); + ESP_LOGV(TAG, "Using partition table file %s (size: %d B):", s_esp_partition_file_mmap_ctrl_act.partition_file_name, partition_table_file_size); + + // check whether partition table fits into the memory mapped file + if(partition_table_file_size + ESP_PARTITION_TABLE_OFFSET > s_esp_partition_file_mmap_ctrl_act.flash_file_size) { + ESP_LOGE(TAG, "Flash file: %s (size: %d B) cannot hold partition table requiring %d B", + s_esp_partition_file_mmap_ctrl_act.flash_file_name, + s_esp_partition_file_mmap_ctrl_act.flash_file_size, + partition_table_file_size + ESP_PARTITION_TABLE_OFFSET); + ret = ESP_ERR_INVALID_SIZE; + break; + } + + //copy partition table from the file to emulated SPIFLASH memory space + if (fseek(f_partition_table, 0L, SEEK_SET) != 0) { + ESP_LOGE(TAG, "Failed to seek in partition table file %s: %s", s_esp_partition_file_mmap_ctrl_act.partition_file_name, strerror(errno)); + ret = ESP_ERR_INVALID_SIZE; + break; + } + + uint8_t *part_table_in_spiflash = s_spiflash_mem_file_buf + ESP_PARTITION_TABLE_OFFSET; + + size_t res = fread(part_table_in_spiflash, 1, partition_table_file_size, f_partition_table); + fclose(f_partition_table); + if (res != partition_table_file_size) { + ESP_LOGE(TAG, "Failed to read partition table file %s", s_esp_partition_file_mmap_ctrl_act.partition_file_name); + ret = ESP_ERR_INVALID_STATE; + break; + } + } while(false); + } + + if (ret != ESP_OK) { + if(close(s_spiflash_mem_file_fd)) { + ESP_LOGE(TAG, "Failed to close() SPIFLASH memory emulation file: %s", strerror(errno)); + } + s_spiflash_mem_file_fd = -1; - size_t res = fread(part_table_in_spiflash, 1, partition_table_file_size, f_partition_table); - fclose(f_partition_table); - if (res != partition_table_file_size) { - ESP_LOGE(TAG, "Failed to read partition table file %s", partition_table_file_name); - return ESP_ERR_INVALID_STATE; + return ret; } #ifdef CONFIG_LOG_DEFAULT_LEVEL_VERBOSE - uint8_t *part_ptr = part_table_in_spiflash; - uint8_t *part_end_ptr = part_table_in_spiflash + partition_table_file_size; + uint8_t *part_ptr = s_spiflash_mem_file_buf + ESP_PARTITION_TABLE_OFFSET; ESP_LOGV(TAG, ""); ESP_LOGV(TAG, "Partition table sucessfully imported, partitions found:"); - while (part_ptr < part_end_ptr) { + while (true) { esp_partition_info_t *p_part_item = (esp_partition_info_t *)part_ptr; if (p_part_item->magic != ESP_PARTITION_MAGIC ) { break; @@ -170,9 +303,17 @@ esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) ESP_LOGV(TAG, ""); #endif +#ifdef CONFIG_ESP_PARTITION_ENABLE_STATS + free(s_esp_partition_stat_sector_erase_count); + s_esp_partition_stat_sector_erase_count = malloc(sizeof(size_t) * s_esp_partition_file_mmap_ctrl_act.flash_file_size / ESP_PARTITION_EMULATED_SECTOR_SIZE); +#endif + //return mmapped file starting address *part_desc_addr_start = s_spiflash_mem_file_buf; + // clear input control structure + memset(&s_esp_partition_file_mmap_ctrl_input, 0, sizeof(s_esp_partition_file_mmap_ctrl_input)); + return ESP_OK; } @@ -181,26 +322,54 @@ esp_err_t esp_partition_file_munmap(void) if (s_spiflash_mem_file_buf == NULL) { return ESP_ERR_NO_MEM; } - if (ESP_PARTITION_EMULATED_FLASH_SIZE == 0) { + if (s_esp_partition_file_mmap_ctrl_act.flash_file_size == 0) { return ESP_ERR_INVALID_SIZE; } + if(s_spiflash_mem_file_fd == -1) { + return ESP_ERR_NOT_FOUND; + } - if (munmap(s_spiflash_mem_file_buf, ESP_PARTITION_EMULATED_FLASH_SIZE) != 0) { - ESP_LOGE(TAG, "Failed to munmap() SPI FLASH memory emulation file: %s", strerror(errno)); + unload_partitions(); + +#ifdef CONFIG_ESP_PARTITION_ENABLE_STATS + free(s_esp_partition_stat_sector_erase_count); + s_esp_partition_stat_sector_erase_count = NULL; +#endif + + // unmap the flash emulation memory file + if (munmap(s_spiflash_mem_file_buf, s_esp_partition_file_mmap_ctrl_act.flash_file_size) != 0) { + ESP_LOGE(TAG, "Failed to munmap() SPIFLASH memory emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); return ESP_ERR_INVALID_RESPONSE; } + // close memory mapped file + if(close(s_spiflash_mem_file_fd)) { + ESP_LOGE(TAG, "Failed to close() SPIFLASH memory emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); + return ESP_ERR_INVALID_RESPONSE; + } + + if(s_esp_partition_file_mmap_ctrl_input.remove_dump) { + // delete spi flash file + if(remove(s_esp_partition_file_mmap_ctrl_act.flash_file_name) != 0) { + ESP_LOGE(TAG, "Failed to remove() SPI FLASH memory emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); + return ESP_ERR_INVALID_RESPONSE; + } + } + + // cleanup + memset(&s_esp_partition_file_mmap_ctrl_act, 0, sizeof(s_esp_partition_file_mmap_ctrl_act)); s_spiflash_mem_file_buf = NULL; + s_spiflash_mem_file_fd = -1; return ESP_OK; } esp_err_t esp_partition_write(const esp_partition_t *partition, size_t dst_offset, const void *src, size_t size) { - assert(partition != NULL); + assert(partition != NULL && s_spiflash_mem_file_buf != NULL); if (partition->encrypted) { - return ESP_ERR_NOT_SUPPORTED; + return ESP_ERR_NOT_SUPPORTED; } if (dst_offset > partition->size) { return ESP_ERR_INVALID_ARG; @@ -217,8 +386,9 @@ esp_err_t esp_partition_write(const esp_partition_t *partition, size_t dst_offse void *dst_addr = s_spiflash_mem_file_buf + partition->address + dst_offset; ESP_LOGV(TAG, "esp_partition_write(): partition=%s dst_offset=%zu src=%p size=%zu (real dst address: %p)", partition->label, dst_offset, src, size, dst_addr); - // hook gathers statistics and can emulate limited number of write cycles + // hook gathers statistics and can emulate power-off if (!ESP_PARTITION_HOOK_WRITE(dst_addr, size)) { + free(write_buf); return ESP_FAIL; } @@ -235,7 +405,7 @@ esp_err_t esp_partition_write(const esp_partition_t *partition, size_t dst_offse esp_err_t esp_partition_read(const esp_partition_t *partition, size_t src_offset, void *dst, size_t size) { - assert(partition != NULL); + assert(partition != NULL && s_spiflash_mem_file_buf != NULL); if (partition->encrypted) { return ESP_ERR_NOT_SUPPORTED; @@ -248,7 +418,6 @@ esp_err_t esp_partition_read(const esp_partition_t *partition, size_t src_offset } void *src_addr = s_spiflash_mem_file_buf + partition->address + src_offset; - ESP_LOGV(TAG, "esp_partition_read(): partition=%s src_offset=%zu dst=%p size=%zu (real src address: %p)", partition->label, src_offset, dst, size, src_addr); memcpy(dst, src_addr, size); @@ -284,7 +453,7 @@ esp_err_t esp_partition_erase_range(const esp_partition_t *partition, size_t off void *target_addr = s_spiflash_mem_file_buf + partition->address + offset; ESP_LOGV(TAG, "esp_partition_erase_range(): partition=%s offset=%zu size=%zu (real target address: %p)", partition->label, offset, size, target_addr); - // hook gathers statistics and can emulate limited number of write/erase cycles + // hook gathers statistics and can emulate power-off if (!ESP_PARTITION_HOOK_ERASE(target_addr, size)) { return ESP_FAIL; } @@ -328,7 +497,6 @@ esp_err_t esp_partition_mmap(const esp_partition_t *partition, size_t offset, si // check if memory mapped file is already present, if not, map it now if (s_spiflash_mem_file_buf == NULL) { - ESP_LOGE(TAG, "esp_partition_mmap(): in esp_partition_file_mmap"); uint8_t *part_desc_addr_start = NULL; rc = esp_partition_file_mmap((const uint8_t **) &part_desc_addr_start); } @@ -338,16 +506,25 @@ esp_err_t esp_partition_mmap(const esp_partition_t *partition, size_t offset, si *out_ptr = (void *) (s_spiflash_mem_file_buf + req_flash_addr); *out_handle = s_default_partition_mmap_handle; } else { - *out_ptr = (void *) NULL; + *out_ptr = NULL; *out_handle = 0; } return rc; } // Intentionally does nothing. -void esp_partition_munmap(esp_partition_mmap_handle_t handle) +void esp_partition_munmap(esp_partition_mmap_handle_t handle __attribute__((unused))) { - ; +} + +esp_partition_file_mmap_ctrl_t* esp_partition_get_file_mmap_ctrl_input(void) +{ + return &s_esp_partition_file_mmap_ctrl_input; +} + +esp_partition_file_mmap_ctrl_t* esp_partition_get_file_mmap_ctrl_act(void) +{ + return &s_esp_partition_file_mmap_ctrl_act; } #ifdef CONFIG_ESP_PARTITION_ENABLE_STATS @@ -372,7 +549,7 @@ static size_t esp_partition_stat_time_interpolate(uint32_t bytes, size_t *lut) } // Registers read access statistics of emulated SPI FLASH device (Linux host) -// Ffunction increases nmuber of read operations, accumulates number of read bytes +// Function increases nmuber of read operations, accumulates number of read bytes // and accumulates emulated read operation time (size dependent) static void esp_partition_hook_read(const void *srcAddr, const size_t size) { @@ -385,40 +562,63 @@ static void esp_partition_hook_read(const void *srcAddr, const size_t size) } // Registers write access statistics of emulated SPI FLASH device (Linux host) -// If enabled by the esp_partition_fail_after, function emulates physical limitation of write/erase operations by -// decrementing the s_esp_partition_emulated_life for each 4 bytes written +// If enabled by the esp_partition_fail_after, function emulates power-off event during write/erase operations by +// decrementing the s_esp_partition_emulated_power_off_counter for each 4 bytes written // If zero threshold is reached, false is returned. // Else the function increases nmuber of write operations, accumulates number // of bytes written and accumulates emulated write operation time (size dependent) and returns true. static bool esp_partition_hook_write(const void *dstAddr, const size_t size) { - ESP_LOGV(TAG, "esp_partition_hook_write()"); + ESP_LOGV(TAG, "%s", __FUNCTION__); - // wear emulation + // power-off emulation for (size_t i = 0; i < size / 4; ++i) { - if (s_esp_partition_emulated_flash_life != SIZE_MAX && s_esp_partition_emulated_flash_life-- == 0) { + if (s_esp_partition_emulated_power_off_counter != SIZE_MAX && s_esp_partition_emulated_power_off_counter-- == 0) { return false; } } + bool ret_val = true; + + // one power down cycle per 4 bytes written + size_t write_cycles = size / 4; + + // check whether power off simulation is active for write + if(s_esp_partition_emulated_power_off_counter != SIZE_MAX && + s_esp_partition_emulated_power_off_counter & ESP_PARTITION_FAIL_AFTER_MODE_WRITE) { + + // check if power down happens during this call + if(s_esp_partition_emulated_power_off_counter >= write_cycles) { + // OK + s_esp_partition_emulated_power_off_counter -= write_cycles; + } else { + // failure in this call - reduce cycle count to the number of remainint power on cycles + write_cycles = s_esp_partition_emulated_power_off_counter; + // clear remaining cycles + s_esp_partition_emulated_power_off_counter = 0; + // final result value will be false + ret_val = false; + } + } + // stats ++s_esp_partition_stat_write_ops; - s_esp_partition_stat_write_bytes += size; - s_esp_partition_stat_total_time += esp_partition_stat_time_interpolate((uint32_t) size, s_esp_partition_stat_write_times); + s_esp_partition_stat_write_bytes += write_cycles * 4; + s_esp_partition_stat_total_time += esp_partition_stat_time_interpolate((uint32_t) (write_cycles * 4), s_esp_partition_stat_write_times); - return true; + return ret_val; } // Registers erase access statistics of emulated SPI FLASH device (Linux host) -// If enabled by the esp_partition_fail_after, function emulates physical limitation of write/erase operations by -// decrementing the s_esp_partition_emulated_life for each erased virtual sector. +// If enabled by 'esp_partition_fail_after' parameter, the function emulates a power-off event during write/erase +// operations by decrementing the s_esp_partition_emulated_power_off_counterpower for each erased virtual sector. // If zero threshold is reached, false is returned. // Else, for statistics purpose, the impacted virtual sectors are identified based on // ESP_PARTITION_EMULATED_SECTOR_SIZE and their respective counts of erase operations are incremented // Total number of erase operations is increased by the number of impacted virtual sectors static bool esp_partition_hook_erase(const void *dstAddr, const size_t size) { - ESP_LOGV(TAG, "esp_partition_hook_erase()"); + ESP_LOGV(TAG, "%s", __FUNCTION__); if (size == 0) { return true; @@ -430,19 +630,34 @@ static bool esp_partition_hook_erase(const void *dstAddr, const size_t size) size_t last_sector_idx = (offset + size - 1) / ESP_PARTITION_EMULATED_SECTOR_SIZE; size_t sector_count = 1 + last_sector_idx - first_sector_idx; - for (size_t sector_index = first_sector_idx; sector_index < first_sector_idx + sector_count; sector_index++) { - // wear emulation - if (s_esp_partition_emulated_flash_life != SIZE_MAX && s_esp_partition_emulated_flash_life-- == 0) { - return false; + bool ret_val = true; + + // check whether power off simulation is active for erase + if(s_esp_partition_emulated_power_off_counter != SIZE_MAX && + s_esp_partition_emulated_power_off_counter & ESP_PARTITION_FAIL_AFTER_MODE_ERASE) { + + // check if power down happens during this call + if(s_esp_partition_emulated_power_off_counter >= sector_count) { + // OK + s_esp_partition_emulated_power_off_counter -= sector_count; + } else { + // failure in this call - reduce sector_count to the number of remainint power on cycles + sector_count = s_esp_partition_emulated_power_off_counter; + // clear remaining cycles + s_esp_partition_emulated_power_off_counter = 0; + // final result value will be false + ret_val = false; } + } - // stats + // update statistcs for all sectors until power down cycle + for (size_t sector_index = first_sector_idx; sector_index < first_sector_idx + sector_count; sector_index++) { ++s_esp_partition_stat_erase_ops; s_esp_partition_stat_sector_erase_count[sector_index]++; s_esp_partition_stat_total_time += s_esp_partition_stat_block_erase_time; } - return true; + return ret_val; } void esp_partition_clear_stats(void) @@ -454,7 +669,7 @@ void esp_partition_clear_stats(void) s_esp_partition_stat_write_ops = 0; s_esp_partition_stat_total_time = 0; - memset(s_esp_partition_stat_sector_erase_count, 0, sizeof(s_esp_partition_stat_sector_erase_count)); + memset(s_esp_partition_stat_sector_erase_count, 0, sizeof(size_t) * s_esp_partition_file_mmap_ctrl_act.flash_file_size / ESP_PARTITION_EMULATED_SECTOR_SIZE); } size_t esp_partition_get_read_ops(void) @@ -487,9 +702,10 @@ size_t esp_partition_get_total_time(void) return s_esp_partition_stat_total_time; } -void esp_partition_fail_after(size_t count) +void esp_partition_fail_after(size_t count, uint8_t mode) { - s_esp_partition_emulated_flash_life = count; + s_esp_partition_emulated_power_off_counter = count; + s_esp_partition_emulated_power_off_mode = mode; } size_t esp_partition_get_sector_erase_count(size_t sector) diff --git a/components/spiffs/host_test/main/host_test_spiffs.c b/components/spiffs/host_test/main/host_test_spiffs.c index 24a3352c1b6..9b0cb018a44 100644 --- a/components/spiffs/host_test/main/host_test_spiffs.c +++ b/components/spiffs/host_test/main/host_test_spiffs.c @@ -132,7 +132,6 @@ static void check_spiffs_files(spiffs *fs, const char *base_path, char *cur_path struct stat sb; stat(path, &sb); - if (S_ISDIR(sb.st_mode)) { if (!strcmp(name, ".") || !strcmp(name, "..")) { continue; @@ -249,7 +248,6 @@ TEST(spiffs, can_read_spiffs_image) char *img = (char *) malloc(img_size); TEST_ASSERT(fread(img, 1, img_size, img_file) == img_size); fclose(img_file); - TEST_ASSERT_TRUE(partition->size == img_size); esp_partition_erase_range(partition, 0, partition->size); @@ -265,7 +263,7 @@ TEST(spiffs, can_read_spiffs_image) spiffs_res = SPIFFS_check(&fs); TEST_ASSERT_TRUE(spiffs_res == SPIFFS_OK); - char path_buf[PATH_MAX]; + char path_buf[PATH_MAX] = {0}; // The image is created from the spiffs source directory. Compare the files in that // directory to the files read from the SPIFFS image. From abc4d67a9d993f6b698f064db9adb52961db396a Mon Sep 17 00:00:00 2001 From: Martin Vychodil Date: Tue, 28 Feb 2023 23:47:11 +0100 Subject: [PATCH 2/2] Storage: Fixed formatting of esp_partition Linux code --- components/esp_partition/Kconfig | 6 +- .../partition_api_test/sdkconfig.defaults | 2 +- components/esp_partition/partition_linux.c | 68 +++++++++---------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/components/esp_partition/Kconfig b/components/esp_partition/Kconfig index 4eea35dcfa6..6a0159bc2a8 100644 --- a/components/esp_partition/Kconfig +++ b/components/esp_partition/Kconfig @@ -1,10 +1,10 @@ menu "Partition API Configuration" - # This option enables gathering statistics and flash wear levelling simulation. - # Linux target only (host tests). config ESP_PARTITION_ENABLE_STATS - bool + bool "Host test statistics enabled" depends on IDF_TARGET_LINUX default n + help + This option enables gathering host test statistics and SPI flash wear levelling simulation. endmenu diff --git a/components/esp_partition/host_test/partition_api_test/sdkconfig.defaults b/components/esp_partition/host_test/partition_api_test/sdkconfig.defaults index 9dffe9cfe8a..29f922994d3 100644 --- a/components/esp_partition/host_test/partition_api_test/sdkconfig.defaults +++ b/components/esp_partition/host_test/partition_api_test/sdkconfig.defaults @@ -1,5 +1,5 @@ CONFIG_IDF_TARGET="linux" -IDF_TARGET_LINUX=y +CONFIG_IDF_TARGET_LINUX=y CONFIG_COMPILER_CXX_EXCEPTIONS=y CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n CONFIG_UNITY_ENABLE_FIXTURE=y diff --git a/components/esp_partition/partition_linux.c b/components/esp_partition/partition_linux.c index 0b2dca4a37b..50ebe0103cf 100644 --- a/components/esp_partition/partition_linux.c +++ b/components/esp_partition/partition_linux.c @@ -102,19 +102,19 @@ esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) // temporary file is used only if control structure doesn't specify file name. bool open_existing_file = false; - if(strlen(s_esp_partition_file_mmap_ctrl_input.flash_file_name) > 0) { + if (strlen(s_esp_partition_file_mmap_ctrl_input.flash_file_name) > 0) { // Open existing file. If size or partition table file were specified, raise errors - if(s_esp_partition_file_mmap_ctrl_input.flash_file_size > 0) { + if (s_esp_partition_file_mmap_ctrl_input.flash_file_size > 0) { ESP_LOGE(TAG, "Flash emulation file size: %u was specified while together with the file name: %s (illegal). Use file size = 0", - s_esp_partition_file_mmap_ctrl_input.flash_file_size, - s_esp_partition_file_mmap_ctrl_input.flash_file_name); + s_esp_partition_file_mmap_ctrl_input.flash_file_size, + s_esp_partition_file_mmap_ctrl_input.flash_file_name); return ESP_ERR_INVALID_ARG; } - if(strlen(s_esp_partition_file_mmap_ctrl_input.partition_file_name) > 0) { + if (strlen(s_esp_partition_file_mmap_ctrl_input.partition_file_name) > 0) { ESP_LOGE(TAG, "Partition file name: %s was specified together with the flash emulation file name: %s (illegal). Use empty partition file name", - s_esp_partition_file_mmap_ctrl_input.partition_file_name, - s_esp_partition_file_mmap_ctrl_input.flash_file_name); + s_esp_partition_file_mmap_ctrl_input.partition_file_name, + s_esp_partition_file_mmap_ctrl_input.flash_file_name); return ESP_ERR_INVALID_ARG; } @@ -131,22 +131,22 @@ esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) bool has_len = (s_esp_partition_file_mmap_ctrl_input.flash_file_size > 0); // conflicting input - if(has_partfile != has_len) { + if (has_partfile != has_len) { ESP_LOGE(TAG, "Invalid combination of Partition file name: %s flash file size: %u was specified. Use either both parameters or none.", - s_esp_partition_file_mmap_ctrl_input.partition_file_name, - s_esp_partition_file_mmap_ctrl_input.flash_file_size); + s_esp_partition_file_mmap_ctrl_input.partition_file_name, + s_esp_partition_file_mmap_ctrl_input.flash_file_size); return ESP_ERR_INVALID_ARG; } // check if partition file is present, if not, use default - if(!has_partfile) { + if (!has_partfile) { strlcpy(s_esp_partition_file_mmap_ctrl_act.partition_file_name, "build/partition_table/partition-table.bin", sizeof(s_esp_partition_file_mmap_ctrl_act.partition_file_name)); } else { strlcpy(s_esp_partition_file_mmap_ctrl_act.partition_file_name, s_esp_partition_file_mmap_ctrl_input.partition_file_name, sizeof(s_esp_partition_file_mmap_ctrl_act.partition_file_name)); } // check if flash size is present, if not set to default - if(!has_len) { + if (!has_len) { s_esp_partition_file_mmap_ctrl_act.flash_file_size = ESP_PARTITION_DEFAULT_EMULATED_FLASH_SIZE; } else { s_esp_partition_file_mmap_ctrl_act.flash_file_size = s_esp_partition_file_mmap_ctrl_input.flash_file_size; @@ -158,7 +158,7 @@ esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) esp_err_t ret = ESP_OK; - if(open_existing_file) { + if (open_existing_file) { s_spiflash_mem_file_fd = open(s_esp_partition_file_mmap_ctrl_act.flash_file_name, O_RDWR); @@ -170,7 +170,7 @@ esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) do { // seek to the end off_t size = lseek(s_spiflash_mem_file_fd, 0L, SEEK_END); - if(size < 0) { + if (size < 0) { ESP_LOGE(TAG, "Failed to seek in SPI FLASH emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); ret = ESP_ERR_NOT_FINISHED; break; @@ -180,7 +180,7 @@ esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) // seek to beginning size = lseek(s_spiflash_mem_file_fd, 0L, SEEK_SET); - if(size < 0) { + if (size < 0) { ESP_LOGE(TAG, "Failed to seek in SPI FLASH emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); ret = ESP_ERR_NOT_FINISHED; break; @@ -192,7 +192,7 @@ esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) ret = ESP_ERR_NOT_FINISHED; break; } - } while(false); + } while (false); } else { //create temporary file to hold complete SPIFLASH size s_spiflash_mem_file_fd = mkstemp(s_esp_partition_file_mmap_ctrl_act.flash_file_name); @@ -240,11 +240,11 @@ esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) ESP_LOGV(TAG, "Using partition table file %s (size: %d B):", s_esp_partition_file_mmap_ctrl_act.partition_file_name, partition_table_file_size); // check whether partition table fits into the memory mapped file - if(partition_table_file_size + ESP_PARTITION_TABLE_OFFSET > s_esp_partition_file_mmap_ctrl_act.flash_file_size) { + if (partition_table_file_size + ESP_PARTITION_TABLE_OFFSET > s_esp_partition_file_mmap_ctrl_act.flash_file_size) { ESP_LOGE(TAG, "Flash file: %s (size: %d B) cannot hold partition table requiring %d B", - s_esp_partition_file_mmap_ctrl_act.flash_file_name, - s_esp_partition_file_mmap_ctrl_act.flash_file_size, - partition_table_file_size + ESP_PARTITION_TABLE_OFFSET); + s_esp_partition_file_mmap_ctrl_act.flash_file_name, + s_esp_partition_file_mmap_ctrl_act.flash_file_size, + partition_table_file_size + ESP_PARTITION_TABLE_OFFSET); ret = ESP_ERR_INVALID_SIZE; break; } @@ -265,11 +265,11 @@ esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start) ret = ESP_ERR_INVALID_STATE; break; } - } while(false); + } while (false); } if (ret != ESP_OK) { - if(close(s_spiflash_mem_file_fd)) { + if (close(s_spiflash_mem_file_fd)) { ESP_LOGE(TAG, "Failed to close() SPIFLASH memory emulation file: %s", strerror(errno)); } s_spiflash_mem_file_fd = -1; @@ -325,7 +325,7 @@ esp_err_t esp_partition_file_munmap(void) if (s_esp_partition_file_mmap_ctrl_act.flash_file_size == 0) { return ESP_ERR_INVALID_SIZE; } - if(s_spiflash_mem_file_fd == -1) { + if (s_spiflash_mem_file_fd == -1) { return ESP_ERR_NOT_FOUND; } @@ -343,14 +343,14 @@ esp_err_t esp_partition_file_munmap(void) } // close memory mapped file - if(close(s_spiflash_mem_file_fd)) { + if (close(s_spiflash_mem_file_fd)) { ESP_LOGE(TAG, "Failed to close() SPIFLASH memory emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); return ESP_ERR_INVALID_RESPONSE; } - if(s_esp_partition_file_mmap_ctrl_input.remove_dump) { + if (s_esp_partition_file_mmap_ctrl_input.remove_dump) { // delete spi flash file - if(remove(s_esp_partition_file_mmap_ctrl_act.flash_file_name) != 0) { + if (remove(s_esp_partition_file_mmap_ctrl_act.flash_file_name) != 0) { ESP_LOGE(TAG, "Failed to remove() SPI FLASH memory emulation file %s: %s", s_esp_partition_file_mmap_ctrl_act.flash_file_name, strerror(errno)); return ESP_ERR_INVALID_RESPONSE; } @@ -517,12 +517,12 @@ void esp_partition_munmap(esp_partition_mmap_handle_t handle __attribute__((unus { } -esp_partition_file_mmap_ctrl_t* esp_partition_get_file_mmap_ctrl_input(void) +esp_partition_file_mmap_ctrl_t *esp_partition_get_file_mmap_ctrl_input(void) { return &s_esp_partition_file_mmap_ctrl_input; } -esp_partition_file_mmap_ctrl_t* esp_partition_get_file_mmap_ctrl_act(void) +esp_partition_file_mmap_ctrl_t *esp_partition_get_file_mmap_ctrl_act(void) { return &s_esp_partition_file_mmap_ctrl_act; } @@ -584,11 +584,11 @@ static bool esp_partition_hook_write(const void *dstAddr, const size_t size) size_t write_cycles = size / 4; // check whether power off simulation is active for write - if(s_esp_partition_emulated_power_off_counter != SIZE_MAX && - s_esp_partition_emulated_power_off_counter & ESP_PARTITION_FAIL_AFTER_MODE_WRITE) { + if (s_esp_partition_emulated_power_off_counter != SIZE_MAX && + s_esp_partition_emulated_power_off_counter & ESP_PARTITION_FAIL_AFTER_MODE_WRITE) { // check if power down happens during this call - if(s_esp_partition_emulated_power_off_counter >= write_cycles) { + if (s_esp_partition_emulated_power_off_counter >= write_cycles) { // OK s_esp_partition_emulated_power_off_counter -= write_cycles; } else { @@ -633,11 +633,11 @@ static bool esp_partition_hook_erase(const void *dstAddr, const size_t size) bool ret_val = true; // check whether power off simulation is active for erase - if(s_esp_partition_emulated_power_off_counter != SIZE_MAX && - s_esp_partition_emulated_power_off_counter & ESP_PARTITION_FAIL_AFTER_MODE_ERASE) { + if (s_esp_partition_emulated_power_off_counter != SIZE_MAX && + s_esp_partition_emulated_power_off_counter & ESP_PARTITION_FAIL_AFTER_MODE_ERASE) { // check if power down happens during this call - if(s_esp_partition_emulated_power_off_counter >= sector_count) { + if (s_esp_partition_emulated_power_off_counter >= sector_count) { // OK s_esp_partition_emulated_power_off_counter -= sector_count; } else {