From 4c0cf40a3988fa14cc02670d61e5bc07f9f1051c Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Fri, 18 Jun 2021 11:52:47 +0800 Subject: [PATCH] efuse: Burn operation does not block reading --- .gitlab/ci/target-test.yml | 7 ++ components/efuse/esp32/esp_efuse_utility.c | 2 +- components/efuse/esp32c3/esp_efuse_utility.c | 2 +- components/efuse/esp32s2/esp_efuse_utility.c | 2 +- components/efuse/esp32s3/esp_efuse_utility.c | 2 +- components/efuse/include/esp_efuse.h | 1 + .../efuse/private_include/esp_efuse_utility.h | 10 ++ components/efuse/src/esp_efuse_api.c | 35 ++++--- components/efuse/src/esp_efuse_utility.c | 22 +++++ components/efuse/test/test_efuse.c | 94 ++++++++++++++++++- components/esp_common/src/esp_err_to_name.c | 7 ++ .../sdkconfig.ci.anti_rollback | 1 + .../system/startup/sdkconfig.ci.verbose_log | 5 + 13 files changed, 174 insertions(+), 16 deletions(-) create mode 100644 tools/test_apps/system/startup/sdkconfig.ci.verbose_log diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index 015c1f326e..c66bd7c643 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -474,6 +474,13 @@ UT_006: - UT_T1_SPIMODE - psram +UT_007: + extends: .unit_test_esp32_template + parallel: 2 + tags: + - ESP32_IDF + - UT_T1_1 + UT_008: extends: .unit_test_esp32_template tags: diff --git a/components/efuse/esp32/esp_efuse_utility.c b/components/efuse/esp32/esp_efuse_utility.c index 164213a4d2..2f3cb16c20 100644 --- a/components/efuse/esp32/esp_efuse_utility.c +++ b/components/efuse/esp32/esp_efuse_utility.c @@ -72,7 +72,7 @@ void esp_efuse_utility_clear_program_registers(void) } // Burn values written to the efuse write registers -void esp_efuse_utility_burn_efuses(void) +void esp_efuse_utility_burn_chip(void) { #ifdef CONFIG_EFUSE_VIRTUAL ESP_LOGW(TAG, "Virtual efuses enabled: Not really burning eFuses"); diff --git a/components/efuse/esp32c3/esp_efuse_utility.c b/components/efuse/esp32c3/esp_efuse_utility.c index 036a1f8228..5105352da5 100644 --- a/components/efuse/esp32c3/esp_efuse_utility.c +++ b/components/efuse/esp32c3/esp_efuse_utility.c @@ -75,7 +75,7 @@ void esp_efuse_utility_clear_program_registers(void) } // Burn values written to the efuse write registers -void esp_efuse_utility_burn_efuses(void) +void esp_efuse_utility_burn_chip(void) { #ifdef CONFIG_EFUSE_VIRTUAL ESP_LOGW(TAG, "Virtual efuses enabled: Not really burning eFuses"); diff --git a/components/efuse/esp32s2/esp_efuse_utility.c b/components/efuse/esp32s2/esp_efuse_utility.c index 2c4408d318..a5d5dc2867 100644 --- a/components/efuse/esp32s2/esp_efuse_utility.c +++ b/components/efuse/esp32s2/esp_efuse_utility.c @@ -68,7 +68,7 @@ void esp_efuse_utility_clear_program_registers(void) } // Burn values written to the efuse write registers -void esp_efuse_utility_burn_efuses(void) +void esp_efuse_utility_burn_chip(void) { #ifdef CONFIG_EFUSE_VIRTUAL ESP_LOGW(TAG, "Virtual efuses enabled: Not really burning eFuses"); diff --git a/components/efuse/esp32s3/esp_efuse_utility.c b/components/efuse/esp32s3/esp_efuse_utility.c index 1f7b55973e..5ab670fa65 100644 --- a/components/efuse/esp32s3/esp_efuse_utility.c +++ b/components/efuse/esp32s3/esp_efuse_utility.c @@ -68,7 +68,7 @@ void esp_efuse_utility_clear_program_registers(void) } // Burn values written to the efuse write registers -void esp_efuse_utility_burn_efuses(void) +void esp_efuse_utility_burn_chip(void) { #ifdef CONFIG_EFUSE_VIRTUAL ESP_LOGW(TAG, "Virtual efuses enabled: Not really burning eFuses"); diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h index fd19764f8d..957424c4a8 100644 --- a/components/efuse/include/esp_efuse.h +++ b/components/efuse/include/esp_efuse.h @@ -33,6 +33,7 @@ extern "C" { #define ESP_ERR_EFUSE_REPEATED_PROG (ESP_ERR_EFUSE + 0x03) /*!< Error repeated programming of programmed bits is strictly forbidden. */ #define ESP_ERR_CODING (ESP_ERR_EFUSE + 0x04) /*!< Error while a encoding operation. */ #define ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS (ESP_ERR_EFUSE + 0x05) /*!< Error not enough unused key blocks available */ +#define ESP_ERR_DAMAGED_READING (ESP_ERR_EFUSE + 0x06) /*!< Error. Burn or reset was done during a reading operation leads to damage read data. This error is internal to the efuse component and not returned by any public API. */ /** * @brief Type definition for an eFuse field diff --git a/components/efuse/private_include/esp_efuse_utility.h b/components/efuse/private_include/esp_efuse_utility.h index 59b4db4f88..3016d55dd2 100644 --- a/components/efuse/private_include/esp_efuse_utility.h +++ b/components/efuse/private_include/esp_efuse_utility.h @@ -96,6 +96,16 @@ esp_err_t esp_efuse_utility_fill_buff(unsigned int num_reg, esp_efuse_block_t ef */ void esp_efuse_utility_burn_efuses(void); +/** + * @brief Chip specific operations to perform the burn of values written to the efuse write registers. + * + * @note Use esp_efuse_utility_burn_efuses() to burn efuses. + * + * If CONFIG_EFUSE_VIRTUAL is set, writing will not be performed. + * After the function is completed, the writing registers are cleared. + */ +void esp_efuse_utility_burn_chip(void); + /** * @brief Returns the number of array elements for placing these "bits" in an array with the length of each element equal to "size_of_base". */ diff --git a/components/efuse/src/esp_efuse_api.c b/components/efuse/src/esp_efuse_api.c index af1d75faa7..a89205fc82 100644 --- a/components/efuse/src/esp_efuse_api.c +++ b/components/efuse/src/esp_efuse_api.c @@ -17,6 +17,8 @@ const static char *TAG = "efuse"; #define EFUSE_LOCK_ACQUIRE_RECURSIVE() #define EFUSE_LOCK_RELEASE_RECURSIVE() #else +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include static _lock_t s_efuse_lock; #define EFUSE_LOCK_ACQUIRE_RECURSIVE() _lock_acquire_recursive(&s_efuse_lock) @@ -30,15 +32,20 @@ static int s_batch_writing_mode = 0; // read value from EFUSE, writing it into an array esp_err_t esp_efuse_read_field_blob(const esp_efuse_desc_t* field[], void* dst, size_t dst_size_bits) { - EFUSE_LOCK_ACQUIRE_RECURSIVE(); esp_err_t err = ESP_OK; if (field == NULL || dst == NULL || dst_size_bits == 0) { err = ESP_ERR_INVALID_ARG; } else { - memset((uint8_t *)dst, 0, esp_efuse_utility_get_number_of_items(dst_size_bits, 8)); - err = esp_efuse_utility_process(field, dst, dst_size_bits, esp_efuse_utility_fill_buff); + do { + memset((uint8_t *)dst, 0, esp_efuse_utility_get_number_of_items(dst_size_bits, 8)); + err = esp_efuse_utility_process(field, dst, dst_size_bits, esp_efuse_utility_fill_buff); +#ifndef BOOTLOADER_BUILD + if (err == ESP_ERR_DAMAGED_READING) { + vTaskDelay(1); + } +#endif // BOOTLOADER_BUILD + } while (err == ESP_ERR_DAMAGED_READING); } - EFUSE_LOCK_RELEASE_RECURSIVE(); return err; } @@ -53,15 +60,20 @@ bool esp_efuse_read_field_bit(const esp_efuse_desc_t *field[]) // read number of bits programmed as "1" in the particular field esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_cnt) { - EFUSE_LOCK_ACQUIRE_RECURSIVE(); esp_err_t err = ESP_OK; if (field == NULL || out_cnt == NULL) { err = ESP_ERR_INVALID_ARG; } else { - *out_cnt = 0; - err = esp_efuse_utility_process(field, out_cnt, 0, esp_efuse_utility_count_once); + do { + *out_cnt = 0; + err = esp_efuse_utility_process(field, out_cnt, 0, esp_efuse_utility_count_once); +#ifndef BOOTLOADER_BUILD + if (err == ESP_ERR_DAMAGED_READING) { + vTaskDelay(1); + } +#endif // BOOTLOADER_BUILD + } while (err == ESP_ERR_DAMAGED_READING); } - EFUSE_LOCK_RELEASE_RECURSIVE(); return err; } @@ -163,9 +175,10 @@ int esp_efuse_get_field_size(const esp_efuse_desc_t* field[]) // reading efuse register. uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg) { - EFUSE_LOCK_ACQUIRE_RECURSIVE(); - uint32_t ret_val = esp_efuse_utility_read_reg(blk, num_reg); - EFUSE_LOCK_RELEASE_RECURSIVE(); + uint32_t ret_val = 0; + esp_err_t err = esp_efuse_read_block(blk, &ret_val, num_reg * 32, 32); + assert(err == ESP_OK); + (void)err; return ret_val; } diff --git a/components/efuse/src/esp_efuse_utility.c b/components/efuse/src/esp_efuse_utility.c index 376706afd0..df6b647c6f 100644 --- a/components/efuse/src/esp_efuse_utility.c +++ b/components/efuse/src/esp_efuse_utility.c @@ -14,6 +14,11 @@ static const char *TAG = "efuse"; +// This counter is used to implement independent read access for efuses. +// During the read operation, the counter should be unchanged and even. +// If it is not so, we must repeat the read to make sure that the burn operation does not affect the read data. +static volatile unsigned s_burn_counter = 0; + // Array for emulate efuse registers. #ifdef CONFIG_EFUSE_VIRTUAL uint32_t virt_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK]; @@ -50,6 +55,7 @@ esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, int req_size = (ptr_size_bits == 0) ? field_len : MIN(ptr_size_bits, field_len); int i = 0; + unsigned count_before = s_burn_counter; while (err == ESP_OK && req_size > bits_counter && field[i] != NULL) { if (check_range_of_bits(field[i]->efuse_block, field[i]->bit_start, field[i]->bit_count) == false) { ESP_EARLY_LOGE(TAG, "Range of data does not match the coding scheme"); @@ -72,6 +78,12 @@ esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, } i++; } + unsigned count_after = s_burn_counter; + if (err == ESP_OK && + (func_proc == esp_efuse_utility_fill_buff || func_proc == esp_efuse_utility_count_once) && // these functions are used for read APIs: read_field_blob and read_field_cnt + (count_before != count_after || (count_after & 1) == 1)) { + err = ESP_ERR_DAMAGED_READING; + } assert(bits_counter <= req_size); return err; } @@ -141,7 +153,9 @@ esp_err_t esp_efuse_utility_write_cnt(unsigned int num_reg, esp_efuse_block_t ef // Reset efuse write registers void esp_efuse_utility_reset(void) { + ++s_burn_counter; esp_efuse_utility_clear_program_registers(); + ++s_burn_counter; for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) { for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) { REG_WRITE(addr_wr_block, 0); @@ -149,6 +163,14 @@ void esp_efuse_utility_reset(void) } } +// Burn values written to the efuse write registers +void esp_efuse_utility_burn_efuses(void) +{ + ++s_burn_counter; + esp_efuse_utility_burn_chip(); + ++s_burn_counter; +} + // Erase the virt_blocks array. void esp_efuse_utility_erase_virt_blocks(void) { diff --git a/components/efuse/test/test_efuse.c b/components/efuse/test/test_efuse.c index 5586bd0163..0cd39c0381 100644 --- a/components/efuse/test/test_efuse.c +++ b/components/efuse/test/test_efuse.c @@ -669,7 +669,7 @@ static void task2(void* arg) TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, sizeof(mac) * 8)); int64_t t2 = esp_timer_get_time(); int diff_ms = (t2 - t1) / 1000; - TEST_ASSERT_GREATER_THAN(delay_ms, diff_ms); + TEST_ASSERT_GREATER_THAN(diff_ms, delay_ms); ESP_LOGI(TAG, "read MAC address: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); xSemaphoreGive(sema); @@ -788,8 +788,100 @@ TEST_CASE("Test a write/read protection", "[efuse]") esp_efuse_utility_erase_virt_blocks(); } +static volatile bool cmd_stop_reset_task1; +static void efuse_burn_task(void* arg) +{ + SemaphoreHandle_t sema = (SemaphoreHandle_t) arg; + ESP_LOGI(TAG, "Start burn task"); + size_t test3_len_6 = 2; + while (!cmd_stop_reset_task1) { + esp_efuse_utility_update_virt_blocks(); + esp_efuse_utility_reset(); + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, test3_len_6)); + } + xSemaphoreGive(sema); + ESP_LOGI(TAG, "Stop burn task"); + vTaskDelete(NULL); +} + +static void efuse_read_task(void* arg) +{ + SemaphoreHandle_t sema = (SemaphoreHandle_t) arg; + ESP_LOGI(TAG, "Start read task"); + size_t test3_len_6 = 0; + while (!cmd_stop_reset_task1) { + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST3_LEN_6, &test3_len_6, 6)); + } + xSemaphoreGive(sema); + ESP_LOGI(TAG, "Stop read task"); + vTaskDelete(NULL); +} + +TEST_CASE("Check a case when ESP_ERR_DAMAGED_READING occurs and read and burn are not blocked", "[efuse]") +{ + cmd_stop_reset_task1 = false; + TaskHandle_t read_task_hdl; + xSemaphoreHandle sema[2]; + sema[0] = xSemaphoreCreateBinary(); + sema[1] = xSemaphoreCreateBinary(); + + esp_efuse_utility_update_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + xTaskCreatePinnedToCore(efuse_burn_task, "efuse_burn_task", 3072, sema[0], 2, NULL, 0); + xTaskCreatePinnedToCore(efuse_read_task, "efuse_read_task", 3072, sema[1], 2, &read_task_hdl, 0); + vTaskDelay(10 / portTICK_PERIOD_MS); + + for (unsigned i = 1; i < 30; ++i) { + vTaskPrioritySet(read_task_hdl, 2 + i % 2); + vTaskDelay(10 / portTICK_PERIOD_MS); + } + vTaskDelay(10 / portTICK_PERIOD_MS); + cmd_stop_reset_task1 = true; + vTaskDelay(10 / portTICK_PERIOD_MS); + TEST_ASSERT_EQUAL(pdPASS, xSemaphoreTake(sema[0], 1000 / portTICK_PERIOD_MS)); + TEST_ASSERT_EQUAL(pdPASS, xSemaphoreTake(sema[1], 1000 / portTICK_PERIOD_MS)); + + vSemaphoreDelete(sema[0]); + vSemaphoreDelete(sema[1]); +} #endif // #ifdef CONFIG_EFUSE_VIRTUAL +#ifndef CONFIG_FREERTOS_UNICORE +static volatile bool cmd_stop_reset_task; +static void reset_task(void* arg) +{ + ESP_LOGI(TAG, "Start reset task"); + while (!cmd_stop_reset_task) { + esp_efuse_utility_reset(); + vTaskDelay(1); + } + vTaskDelete(NULL); +} + +TEST_CASE("Check a case when ESP_ERR_DAMAGED_READING occurs during reading efuses", "[efuse]") +{ + cmd_stop_reset_task = false; + esp_efuse_utility_update_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + uint8_t mac[6]; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, sizeof(mac) * 8)); + ESP_LOGI(TAG, "read MAC address: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + xTaskCreatePinnedToCore(reset_task, "reset_task", 3072, NULL, UNITY_FREERTOS_PRIORITY - 1, NULL, 1); + + uint8_t new_mac[6]; + for (int i = 0; i < 1000; ++i) { + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &new_mac, sizeof(new_mac) * 8)); + TEST_ASSERT_EQUAL_HEX8_ARRAY(mac, new_mac, sizeof(mac)); + } + cmd_stop_reset_task = true; + ESP_LOGI(TAG, "read new MAC address: %02x:%02x:%02x:%02x:%02x:%02x", new_mac[0], new_mac[1], new_mac[2], new_mac[3], new_mac[4], new_mac[5]); + vTaskDelay(100 / portTICK_PERIOD_MS); +} +#endif // if not CONFIG_FREERTOS_UNICORE + #ifdef CONFIG_IDF_ENV_FPGA TEST_CASE("Test a real write (FPGA)", "[efuse]") { diff --git a/components/esp_common/src/esp_err_to_name.c b/components/esp_common/src/esp_err_to_name.c index 79bbdc0e6f..8f18f4fcc6 100644 --- a/components/esp_common/src/esp_err_to_name.c +++ b/components/esp_common/src/esp_err_to_name.c @@ -296,6 +296,13 @@ static const esp_err_msg_t esp_err_msg_table[] = { # endif # ifdef ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS ERR_TBL_IT(ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS), /* 5637 0x1605 Error not enough unused key blocks available */ +# endif +# ifdef ESP_ERR_DAMAGED_READING + ERR_TBL_IT(ESP_ERR_DAMAGED_READING), /* 5638 0x1606 Error. Burn or reset was done during a + reading operation leads to damage read + data. This error is internal to the + efuse component and not returned by any + public API. */ # endif // components/bootloader_support/include/esp_image_format.h # ifdef ESP_ERR_IMAGE_BASE diff --git a/tools/test_apps/system/bootloader_sections/sdkconfig.ci.anti_rollback b/tools/test_apps/system/bootloader_sections/sdkconfig.ci.anti_rollback index e2914f2e94..346883f5a4 100644 --- a/tools/test_apps/system/bootloader_sections/sdkconfig.ci.anti_rollback +++ b/tools/test_apps/system/bootloader_sections/sdkconfig.ci.anti_rollback @@ -3,3 +3,4 @@ CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x9000 diff --git a/tools/test_apps/system/startup/sdkconfig.ci.verbose_log b/tools/test_apps/system/startup/sdkconfig.ci.verbose_log new file mode 100644 index 0000000000..36a4add1fd --- /dev/null +++ b/tools/test_apps/system/startup/sdkconfig.ci.verbose_log @@ -0,0 +1,5 @@ +CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE=y +CONFIG_BOOTLOADER_LOG_LEVEL=5 +CONFIG_LOG_DEFAULT_LEVEL_VERBOSE=y +CONFIG_LOG_DEFAULT_LEVEL=5 +CONFIG_PARTITION_TABLE_OFFSET=0x9000