From 7626145e6daeac6121f7139d4af0ed2f7b8ffceb Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Mon, 19 Nov 2018 11:36:19 +0800 Subject: [PATCH 01/15] bootloader: Add support efuse component --- .../bootloader/subproject/CMakeLists.txt | 2 +- components/bootloader/subproject/Makefile | 2 +- .../subproject/main/esp32.bootloader.ld | 2 +- components/bootloader_support/CMakeLists.txt | 5 +- .../test/test_efuse_coding_scheme.c | 94 ------------------- 5 files changed, 5 insertions(+), 100 deletions(-) delete mode 100644 components/bootloader_support/test/test_efuse_coding_scheme.c diff --git a/components/bootloader/subproject/CMakeLists.txt b/components/bootloader/subproject/CMakeLists.txt index da45604348..aad0ff99eb 100644 --- a/components/bootloader/subproject/CMakeLists.txt +++ b/components/bootloader/subproject/CMakeLists.txt @@ -10,7 +10,7 @@ if(NOT IDF_PATH) "in by the parent build process.") endif() -set(COMPONENTS bootloader esptool_py esp32 partition_table soc bootloader_support log spi_flash micro-ecc soc main) +set(COMPONENTS bootloader esptool_py esp32 partition_table soc bootloader_support log spi_flash micro-ecc soc main efuse) set(BOOTLOADER_BUILD 1) add_definitions(-DBOOTLOADER_BUILD=1) diff --git a/components/bootloader/subproject/Makefile b/components/bootloader/subproject/Makefile index e01dc3c8a2..7093ef4f09 100644 --- a/components/bootloader/subproject/Makefile +++ b/components/bootloader/subproject/Makefile @@ -8,7 +8,7 @@ endif PROJECT_NAME := bootloader -COMPONENTS := esptool_py bootloader_support log spi_flash micro-ecc soc main +COMPONENTS := esptool_py bootloader_support log spi_flash micro-ecc soc main efuse # Clear C and CXX from top level project CFLAGS = diff --git a/components/bootloader/subproject/main/esp32.bootloader.ld b/components/bootloader/subproject/main/esp32.bootloader.ld index 348026f043..1eb345f767 100644 --- a/components/bootloader/subproject/main/esp32.bootloader.ld +++ b/components/bootloader/subproject/main/esp32.bootloader.ld @@ -45,7 +45,6 @@ SECTIONS *libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*) *libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*) *libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*) - *libbootloader_support.a:efuse.*(.literal .text .literal.* .text.*) *libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*) *libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*) *libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*) @@ -54,6 +53,7 @@ SECTIONS *libmicro-ecc.a:*.*(.literal .text .literal.* .text.*) *libspi_flash.a:*.*(.literal .text .literal.* .text.*) *libsoc.a:rtc_wdt.*(.literal .text .literal.* .text.*) + *libefuse.a:*.*(.literal .text .literal.* .text.*) *(.fini.literal) *(.fini) *(.gnu.version) diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index 088040f16f..3bd3e9b148 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -4,7 +4,6 @@ set(COMPONENT_SRCS "src/bootloader_clock.c" "src/bootloader_random.c" "src/bootloader_sha.c" "src/bootloader_utility.c" - "src/efuse.c" "src/esp_image_format.c" "src/flash_encrypt.c" "src/flash_partitions.c" @@ -15,7 +14,7 @@ set(COMPONENT_SRCS "src/bootloader_clock.c" if(${BOOTLOADER_BUILD}) set(COMPONENT_ADD_INCLUDEDIRS "include include_bootloader") set(COMPONENT_REQUIRES) - set(COMPONENT_PRIV_REQUIRES spi_flash micro-ecc) + set(COMPONENT_PRIV_REQUIRES spi_flash micro-ecc efuse) list(APPEND COMPONENT_SRCS "src/bootloader_init.c") if(CONFIG_SECURE_SIGNED_APPS) @@ -55,7 +54,7 @@ else() set(COMPONENT_ADD_INCLUDEDIRS "include") set(COMPONENT_PRIV_INCLUDEDIRS "include_bootloader") set(COMPONENT_REQUIRES) - set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls micro-ecc) + set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls micro-ecc efuse) endif() register_component() diff --git a/components/bootloader_support/test/test_efuse_coding_scheme.c b/components/bootloader_support/test/test_efuse_coding_scheme.c deleted file mode 100644 index b9d5202f95..0000000000 --- a/components/bootloader_support/test/test_efuse_coding_scheme.c +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include -#include "esp_efuse.h" -#include "unity.h" - -typedef struct { - uint8_t unencoded[24]; - uint32_t encoded[8]; -} coding_scheme_test_t; - -/* Randomly generated byte strings, encoded and written to ESP32 - using espefuse algorithm, then verified to have no encoding errors - and correct readback. -*/ -static const coding_scheme_test_t coding_scheme_data[] = { - { - .unencoded = { 0x96, 0xa9, 0xab, 0xb2, 0xda, 0xdd, 0x21, 0xd2, 0x35, 0x22, 0xd3, 0x30, 0x3b, 0xf8, 0xcb, 0x77, 0x8d, 0x8d, 0xf4, 0x96, 0x25, 0xc4, 0xb9, 0x94 }, - .encoded = { 0xb2aba996, 0x6821ddda, 0x2235d221, 0x430730d3, 0x77cbf83b, 0x627f8d8d, 0xc42596f4, 0x4dae94b9 }, - }, - { - .unencoded = { 0x0e, 0x6b, 0x1a, 0x1d, 0xa5, 0x9f, 0x24, 0xcf, 0x91, 0x5b, 0xe7, 0xe1, 0x7c, 0x0a, 0x6e, 0xdc, 0x5e, 0x8e, 0xb1, 0xec, 0xd1, 0xf3, 0x75, 0x48 }, - .encoded = { 0x1d1a6b0e, 0x5e589fa5, 0x5b91cf24, 0x6127e1e7, 0xdc6e0a7c, 0x5d148e5e, 0xf3d1ecb1, 0x57424875 }, - }, - { - .unencoded = { 0x0a, 0x79, 0x5a, 0x1c, 0xb1, 0x45, 0x71, 0x2c, 0xb3, 0xda, 0x9e, 0xdc, 0x76, 0x27, 0xf5, 0xca, 0xe7, 0x00, 0x39, 0x95, 0x6c, 0x53, 0xc2, 0x07 }, - .encoded = { 0x1c5a790a, 0x4ac145b1, 0xdab32c71, 0x6476dc9e, 0xcaf52776, 0x4d8900e7, 0x536c9539, 0x495607c2 }, - }, - { - .unencoded = { 0x76, 0x46, 0x88, 0x2d, 0x4c, 0xe1, 0x50, 0x5d, 0xd6, 0x7c, 0x41, 0x15, 0xc6, 0x1f, 0xd4, 0x60, 0x10, 0x15, 0x2a, 0x72, 0x2d, 0x89, 0x93, 0x13 }, - .encoded = { 0x2d884676, 0x4838e14c, 0x7cd65d50, 0x4bf31541, 0x60d41fc6, 0x39681510, 0x892d722a, 0x497c1393 }, - }, - { - .unencoded = { 0x32, 0xbc, 0x40, 0x92, 0x13, 0x37, 0x1a, 0xae, 0xb6, 0x00, 0xed, 0x30, 0xb8, 0x82, 0xee, 0xfc, 0xcf, 0x6d, 0x7f, 0xc5, 0xfa, 0x0e, 0xdd, 0x84 }, - .encoded = { 0x9240bc32, 0x49783713, 0x00b6ae1a, 0x46df30ed, 0xfcee82b8, 0x6e8a6dcf, 0x0efac57f, 0x571784dd }, - }, - { - .unencoded = { 0x29, 0xb3, 0x04, 0x95, 0xf2, 0x3c, 0x81, 0xe6, 0x5a, 0xf3, 0x42, 0x82, 0xd1, 0x79, 0xe2, 0x12, 0xbe, 0xc3, 0xd4, 0x10, 0x63, 0x66, 0x9f, 0xe3 }, - .encoded = { 0x9504b329, 0x51c53cf2, 0xf35ae681, 0x460e8242, 0x12e279d1, 0x5825c3be, 0x666310d4, 0x5ebde39f }, - }, - { - .unencoded = { 0xda, 0xda, 0x71, 0x4a, 0x62, 0x33, 0xdd, 0x31, 0x87, 0xf3, 0x70, 0x12, 0x33, 0x3b, 0x3b, 0xe9, 0xed, 0xc4, 0x6e, 0x6a, 0xc7, 0xd5, 0x85, 0xfc }, - .encoded = { 0x4a71dada, 0x4e6a3362, 0xf38731dd, 0x4bfa1270, 0xe93b3b33, 0x61f3c4ed, 0xd5c76a6e, 0x636ffc85 }, - }, - { - .unencoded = { 0x45, 0x64, 0x51, 0x34, 0x1c, 0x82, 0x81, 0x77, 0xf8, 0x89, 0xb1, 0x15, 0x82, 0x94, 0xdd, 0x64, 0xa2, 0x46, 0x0e, 0xfb, 0x1a, 0x70, 0x4b, 0x9f }, - .encoded = { 0x34516445, 0x39da821c, 0x89f87781, 0x4f2315b1, 0x64dd9482, 0x474b46a2, 0x701afb0e, 0x5e4b9f4b }, - }, - { - .unencoded = { 0x89, 0x87, 0x15, 0xb6, 0x66, 0x34, 0x49, 0x18, 0x8b, 0x7b, 0xb2, 0xf6, 0x96, 0x1e, 0x2e, 0xf1, 0x03, 0x9d, 0x4e, 0x16, 0x32, 0xd6, 0x23, 0x22 }, - .encoded = { 0xb6158789, 0x4eff3466, 0x7b8b1849, 0x63e5f6b2, 0xf12e1e96, 0x54c99d03, 0xd632164e, 0x42bd2223 }, - }, - { - .unencoded = { 0xa7, 0xa0, 0xb5, 0x21, 0xd2, 0xa3, 0x9f, 0x65, 0xa9, 0xeb, 0x72, 0xa2, 0x2e, 0xa6, 0xfb, 0x9c, 0x48, 0x7e, 0x68, 0x08, 0x7a, 0xb1, 0x4f, 0xbc }, - .encoded = { 0x21b5a0a7, 0x4ce2a3d2, 0xeba9659f, 0x5868a272, 0x9cfba62e, 0x5fd97e48, 0xb17a0868, 0x5b58bc4f }, - }, - { - .unencoded = { 0xf7, 0x05, 0xe3, 0x6c, 0xb1, 0x55, 0xcb, 0x2f, 0x8d, 0x3e, 0x0b, 0x2e, 0x3e, 0xb7, 0x02, 0xf5, 0x91, 0xb1, 0xfe, 0x8b, 0x58, 0x50, 0xb2, 0x40 }, - .encoded = { 0x6ce305f7, 0x569955b1, 0x3e8d2fcb, 0x56722e0b, 0xf502b73e, 0x535eb191, 0x50588bfe, 0x3a8f40b2 }, - }, - { - .unencoded = { 0x0f, 0x93, 0xb0, 0xd5, 0x60, 0xba, 0x40, 0x2a, 0x62, 0xa6, 0x92, 0x82, 0xb8, 0x91, 0x2c, 0xd7, 0x23, 0xdc, 0x6f, 0x7f, 0x2f, 0xbe, 0x41, 0xf5 }, - .encoded = { 0xd5b0930f, 0x5123ba60, 0xa6622a40, 0x3bbe8292, 0xd72c91b8, 0x582ddc23, 0xbe2f7f6f, 0x6935f541 }, - }, - { - .unencoded = { 0x7f, 0x0c, 0x99, 0xde, 0xff, 0x2e, 0xd2, 0x1c, 0x48, 0x98, 0x70, 0x85, 0x15, 0x01, 0x2a, 0xfb, 0xcd, 0xf2, 0xa0, 0xf9, 0x0e, 0xbc, 0x9f, 0x0c }, - .encoded = { 0xde990c7f, 0x6fe52eff, 0x98481cd2, 0x3deb8570, 0xfb2a0115, 0x61faf2cd, 0xbc0ef9a0, 0x55780c9f }, - }, - { - .unencoded = { 0x9a, 0x10, 0x92, 0x03, 0x81, 0xfe, 0x41, 0x57, 0x77, 0x02, 0xcb, 0x20, 0x67, 0xa4, 0x97, 0xf3, 0xf8, 0xc7, 0x0d, 0x65, 0xcd, 0xfc, 0x15, 0xef }, - .encoded = { 0x0392109a, 0x4b64fe81, 0x02775741, 0x418820cb, 0xf397a467, 0x6998c7f8, 0xfccd650d, 0x6ba3ef15 }, - }, -}; - -TEST_CASE("Test 3/4 Coding Scheme Algorithm", "[bootloader_support]") -{ - const int num_tests = sizeof(coding_scheme_data)/sizeof(coding_scheme_test_t); - for (int i = 0; i < num_tests; i++) { - uint32_t result[8]; - const coding_scheme_test_t *t = &coding_scheme_data[i]; - - printf("Test case %d...\n", i); - esp_err_t r = esp_efuse_apply_34_encoding(t->unencoded, result, sizeof(t->unencoded)); - TEST_ASSERT_EQUAL_HEX(ESP_OK, r); - TEST_ASSERT_EQUAL_HEX32_ARRAY(t->encoded, result, 8); - - // Do the same, 6 bytes at a time - for (int offs = 0; offs < sizeof(t->unencoded); offs += 6) { - bzero(result, sizeof(result)); - r = esp_efuse_apply_34_encoding(t->unencoded + offs, result, 6); - TEST_ASSERT_EQUAL_HEX(ESP_OK, r); - TEST_ASSERT_EQUAL_HEX32_ARRAY(t->encoded + (offs / 6 * 2), result, 2); - } - } -} From ed179ade8d8f0c52d0f798c36239339068549361 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Mon, 19 Nov 2018 11:38:05 +0800 Subject: [PATCH 02/15] esp32: Add using efuse component --- components/esp32/CMakeLists.txt | 2 +- components/esp32/esp_err_to_name.c | 3 ++ components/esp32/system_api.c | 50 ++++++++---------------------- 3 files changed, 17 insertions(+), 38 deletions(-) diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index dac411782c..75b76010d9 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -53,7 +53,7 @@ else() "hwcrypto/sha.c") set(COMPONENT_ADD_INCLUDEDIRS "include") - set(COMPONENT_REQUIRES driver tcpip_adapter esp_event) + set(COMPONENT_REQUIRES driver tcpip_adapter esp_event efuse) # driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t # tcpip_adapter is a public requirement because esp_event.h uses tcpip_adapter types # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function. diff --git a/components/esp32/esp_err_to_name.c b/components/esp32/esp_err_to_name.c index ba09a439f8..8172f9efe7 100644 --- a/components/esp32/esp_err_to_name.c +++ b/components/esp32/esp_err_to_name.c @@ -7,6 +7,9 @@ #if __has_include("esp32/ulp.h") #include "esp32/ulp.h" #endif +#if __has_include("esp_efuse.h") +#include "esp_efuse.h" +#endif #if __has_include("esp_err.h") #include "esp_err.h" #endif diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index d9b49183a3..f9f5239b1f 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -37,6 +37,8 @@ #include "freertos/xtensa_api.h" #include "esp_heap_caps.h" #include "esp_system_internal.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" static const char* TAG = "system_api"; @@ -77,31 +79,17 @@ esp_err_t esp_base_mac_addr_get(uint8_t *mac) esp_err_t esp_efuse_mac_get_custom(uint8_t *mac) { - uint32_t mac_low; - uint32_t mac_high; - uint8_t efuse_crc; - uint8_t calc_crc; - - uint8_t version = REG_READ(EFUSE_BLK3_RDATA5_REG) >> 24; - + uint8_t version; + esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM_VER, &version, 8); if (version != 1) { ESP_LOGE(TAG, "Base MAC address from BLK3 of EFUSE version error, version = %d", version); return ESP_ERR_INVALID_VERSION; } - mac_low = REG_READ(EFUSE_BLK3_RDATA1_REG); - mac_high = REG_READ(EFUSE_BLK3_RDATA0_REG); - - mac[0] = mac_high >> 8; - mac[1] = mac_high >> 16; - mac[2] = mac_high >> 24; - mac[3] = mac_low; - mac[4] = mac_low >> 8; - mac[5] = mac_low >> 16; - - efuse_crc = mac_high; - - calc_crc = esp_crc8(mac, 6); + uint8_t efuse_crc; + esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48); + esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM_CRC, &efuse_crc, 8); + uint8_t calc_crc = esp_crc8(mac, 6); if (efuse_crc != calc_crc) { ESP_LOGE(TAG, "Base MAC address from BLK3 of EFUSE CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc); @@ -112,29 +100,17 @@ esp_err_t esp_efuse_mac_get_custom(uint8_t *mac) esp_err_t esp_efuse_mac_get_default(uint8_t* mac) { - uint32_t mac_low; - uint32_t mac_high; uint8_t efuse_crc; - uint8_t calc_crc; - - mac_low = REG_READ(EFUSE_BLK0_RDATA1_REG); - mac_high = REG_READ(EFUSE_BLK0_RDATA2_REG); - - mac[0] = mac_high >> 8; - mac[1] = mac_high; - mac[2] = mac_low >> 24; - mac[3] = mac_low >> 16; - mac[4] = mac_low >> 8; - mac[5] = mac_low; - - efuse_crc = mac_high >> 16; - - calc_crc = esp_crc8(mac, 6); + esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, 48); + esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY_CRC, &efuse_crc, 8); + uint8_t calc_crc = esp_crc8(mac, 6); if (efuse_crc != calc_crc) { // Small range of MAC addresses are accepted even if CRC is invalid. // These addresses are reserved for Espressif internal use. + uint32_t mac_high = ((uint32_t)mac[0] << 8) | mac[1]; if ((mac_high & 0xFFFF) == 0x18fe) { + uint32_t mac_low = ((uint32_t)mac[2] << 24) | ((uint32_t)mac[3] << 16) | ((uint32_t)mac[4] << 8) | mac[5]; if ((mac_low >= 0x346a85c7) && (mac_low <= 0x346a85f8)) { return ESP_OK; } From d82023bf06ec36d58f8e70ff1146455dff26f29e Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Mon, 19 Nov 2018 11:39:41 +0800 Subject: [PATCH 03/15] soc: Add support efuse --- components/soc/CMakeLists.txt | 2 +- components/soc/esp32/include/soc/efuse_reg.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index ec532ad872..551063b39c 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -13,6 +13,6 @@ list(APPEND COMPONENT_SRCS "src/memory_layout_utils.c") set(COMPONENT_ADD_LDFRAGMENTS linker.lf) -set(COMPONENT_REQUIRES) +set(COMPONENT_REQUIRES efuse) register_component() diff --git a/components/soc/esp32/include/soc/efuse_reg.h b/components/soc/esp32/include/soc/efuse_reg.h index ee404d22e6..e3f660496e 100644 --- a/components/soc/esp32/include/soc/efuse_reg.h +++ b/components/soc/esp32/include/soc/efuse_reg.h @@ -316,6 +316,7 @@ #define EFUSE_CODING_SCHEME_VAL_NONE 0x0 #define EFUSE_CODING_SCHEME_VAL_34 0x1 +#define EFUSE_CODING_SCHEME_VAL_REPEAT 0x2 #define EFUSE_BLK0_WDATA0_REG (DR_REG_EFUSE_BASE + 0x01c) /* EFUSE_FLASH_CRYPT_CNT : R/W ;bitpos:[27:20] ;default: 8'b0 ; */ From ba903e761856b515d722126feafa16ffd2d0b840 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Mon, 19 Nov 2018 11:41:26 +0800 Subject: [PATCH 04/15] docs: Add efuse --- docs/Doxyfile | 2 + docs/en/api-reference/system/efuse.rst | 285 ++++++++++++++++++++++ docs/en/api-reference/system/index.rst | 1 + docs/zh_CN/api-reference/system/efuse.rst | 1 + 4 files changed, 289 insertions(+) create mode 100644 docs/en/api-reference/system/efuse.rst create mode 100644 docs/zh_CN/api-reference/system/efuse.rst diff --git a/docs/Doxyfile b/docs/Doxyfile index 3fd46b66c6..b79aa3e2c3 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -191,6 +191,8 @@ INPUT = \ ### esp_event, Event Loop Library ../../components/esp_event/include/esp_event.h \ ../../components/esp_event/include/esp_event_base.h \ + ### eFuse Manager + ../../components/efuse/include/esp_efuse.h \ ### ESP Pthread parameters ../../components/pthread/include/esp_pthread.h \ ### diff --git a/docs/en/api-reference/system/efuse.rst b/docs/en/api-reference/system/efuse.rst new file mode 100644 index 0000000000..cf6ac1b67f --- /dev/null +++ b/docs/en/api-reference/system/efuse.rst @@ -0,0 +1,285 @@ +eFuse Manager +============= + + +Introduction +------------ + +The eFuse Manager library is designed to structure access to eFuse bits and make using these easy. This library operates eFuse bits by a structure name wich assigned in eFuse table. This sections introduces some concepts used by eFuse Manager. + + +Hardware description +-------------------- + +The ESP32 has a number of eFuses which can store system and user parameters. Each eFuse this is one bit wich can programmed to 1, after this it can never be reverted to 0. +Some of system parameters are using these eFuse bits directly by hardware modules and have special place (for example EFUSE_BLK0). For more details see `ESP32 Technical Reference Manual `_ in part 20 eFuse controller. Some eFuse bits are available for user applications. + +ESP32 has 4 eFuse bit blocks of 256 bits each (not all bits are available): + +* EFUSE_BLK0 is used entirely for system purposes; +* EFUSE_BLK1 is used for flash encrypt key. If not using that Flash Encryption feature, they can be used for another purpose; +* EFUSE_BLK2 is used for security boot key. If not using that Secure Boot feature, they can be used for another purpose; +* EFUSE_BLK3 is used for a custom MAC address, some bits are free and can be used for user applications, note that some bits are already used in idf. + +Each block is divided into 8 32-bits registers. + + +eFuse Manager component +----------------------- + +The component has API functions for reading and writing fields. Access to the fields is carried out through the structures that describe the location of the efuse bits in the blocks. The component provides the ability to form fields of any length and from any number of individual bits. The description of the fields is made in a csv file in a table form. To generate from a tabular form (csv file) in the C-source uses the tool `efuse_table_gen.py`. The tool checks the csv file for uniqueness of field names and bit intersection, in case of using a `custom` file from the user's project directory, the utility will check with the `common` csv file. + +CSV files: + +* common (`esp_efuse_table.csv`) - contains efuse fields are used inside the IDF field. C-source generation should be done manually when changing this file (run command 'make efuse_common_table' or `idf.py efuse_common_table`). Note that changes to this file can lead to incorrect IDF operation. Changes are not desirable! +* custom - (may be absent, selected through :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains efuse fields that are used by the user in their application. C-source generation will be done automatically when changing this file. + + +Description CSV file +-------------------- + +The CSV file contains a description of the efuse fields. In the simple case, one field has one line of description. +Table header: + +:: + + # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count(1..256), comment + + +Individual params in csv file the following meanings: + +field_name + Name of field. The prefix `ESP_EFUSE_` will be added to the name, and this field name will be available in the code. This name will be used to access the fields. The name must be unique for all fields. If the line has an empty name, then this line is combined with the previous field. This allows you to set an arbitrary order of bits in the field, and expand the field as well. + +efuse_block + Block number. It determines where the efuse bits will be placed for this field. Available EFUSE_BLK0..EFUSE_BLK3. + +bit_start + Start bit number (0..255). The bit_start field can be omitted. In this case, it will be set to bit_start + bit_count from the previous record, if it has the same efuse_block. Otherwise (if efuse_block is different, or this is the first entry), an error will be generated. + +bit_count + The number of bits to use in this field (1..256). This parameter can not be omitted. + +comment + This param is using for comment field, it also move to C-header file. The comment field can be omitted. + +If a non-sequential bit order is required to describe a field, then the field description in the following lines should be continued without specifying a name, this will indicate that it belongs to one field. For example two fields MAC_FACTORY and MAC_FACTORY_CRC: + +:: + + # Factory MAC address # + ####################### + MAC_FACTORY, EFUSE_BLK0, 72, 8, Factory MAC addr [0] + , EFUSE_BLK0, 64, 8, Factory MAC addr [1] + , EFUSE_BLK0, 56, 8, Factory MAC addr [2] + , EFUSE_BLK0, 48, 8, Factory MAC addr [3] + , EFUSE_BLK0, 40, 8, Factory MAC addr [4] + , EFUSE_BLK0, 32, 8, Factory MAC addr [5] + MAC_FACTORY_CRC, EFUSE_BLK0, 80, 8, CRC8 for factory MAC address + +This field will available in code as ESP_EFUSE_MAC_FACTORY and ESP_EFUSE_MAC_FACTORY_CRC. + +efuse_table_gen.py tool +----------------------- + +The tool is designed to generate C-source files from CSV file and validate fields. First of all, the check is carried out on the uniqueness of the names and overlaps of the field bits. If an additional `custom` file is used, it will be checked with the existing `common` file (esp_efuse_table.csv). In case of errors, a message will be displayed and the string that caused the error. C-source files contain structures of type `esp_efuse_desc_t`. + +To generate a `common` files, use the following command 'make efuse_common_table' or `idf.py efuse_common_table` or: + +:: + + ./efuse_table_gen.py esp32/esp_efuse_table.csv + +After generation in the folder `esp32` create: + +* `esp_efuse_table.c` file. +* In `include` folder `esp_efuse_table.c` file. + +To generate custom files, you need to build the project, the build system tracks changes in the csv file and starts the regeneration of the C-source files itself. In this case, the tool will be called with the following parameters: + +:: + + ./efuse_table_gen.py esp32/esp_efuse_table.csv PROJECT_PATH/main/esp_efuse_custom_table.csv + +After generation in the folder PROJECT_PATH/main create: + +* `esp_efuse_custom_table.c` file. +* In `include` folder `esp_efuse_custom_table.c` file. + +To use the generated fields, you need to include two files: + +:: + + #include "esp_efuse.h" + #include "esp_efuse_table.h" or "esp_efuse_custom_table.h" + +eFuse API +--------- + +Access to the fields is via a pointer to the description structure. API functions have some basic operation: + +* :cpp:func:`esp_efuse_read_field_blob` - returns an array of read efuse bits. +* :cpp:func:`esp_efuse_read_field_cnt` - returns the number of bits programmed as "1". +* :cpp:func:`esp_efuse_write_field_blob` - writes an array. +* :cpp:func:`esp_efuse_write_field_cnt` - writes a required count of bits as "1". +* :cpp:func:`esp_efuse_get_field_size` - returns the number of bits by the field name. +* :cpp:func:`esp_efuse_read_reg` - returns value of efuse register. + +For frequently used fields, special functions are made, like this :cpp:func:`esp_efuse_get_chip_ver`, :cpp:func:`esp_efuse_get_pkg_ver`. + + +How add a new field +------------------- + +1. Find a free bits for field. Show `efuse_table.csv` file or run the next command: + +:: + + $ ./efuse_table_gen.py --info esp32/esp_efuse_table.csv + Sorted efuse table: + #1 WR_DIS_FLASH_CRYPT_CNT EFUSE_BLK0 2 1 + #2 WR_DIS_BLK1 EFUSE_BLK0 7 1 + #3 WR_DIS_BLK2 EFUSE_BLK0 8 1 + #4 WR_DIS_BLK3 EFUSE_BLK0 9 1 + #5 RD_DIS_BLK1 EFUSE_BLK0 16 1 + #6 RD_DIS_BLK2 EFUSE_BLK0 17 1 + #7 RD_DIS_BLK3 EFUSE_BLK0 18 1 + #8 FLASH_CRYPT_CNT EFUSE_BLK0 20 8 + #9 MAC_FACTORY EFUSE_BLK0 32 8 + #10 MAC_FACTORY EFUSE_BLK0 40 8 + #11 MAC_FACTORY EFUSE_BLK0 48 8 + #12 MAC_FACTORY EFUSE_BLK0 56 8 + #13 MAC_FACTORY EFUSE_BLK0 64 8 + #14 MAC_FACTORY EFUSE_BLK0 72 8 + #15 MAC_FACTORY_CRC EFUSE_BLK0 80 8 + #16 CHIP_VER_DIS_APP_CPU EFUSE_BLK0 96 1 + #17 CHIP_VER_DIS_BT EFUSE_BLK0 97 1 + #18 CHIP_VER_PKG EFUSE_BLK0 105 3 + #19 CHIP_CPU_FREQ_LOW EFUSE_BLK0 108 1 + #20 CHIP_CPU_FREQ_RATED EFUSE_BLK0 109 1 + #21 CHIP_VER_REV1 EFUSE_BLK0 111 1 + #22 ADC_VREF_AND_SDIO_DREF EFUSE_BLK0 136 6 + #23 XPD_SDIO_REG EFUSE_BLK0 142 1 + #24 SDIO_TIEH EFUSE_BLK0 143 1 + #25 SDIO_FORCE EFUSE_BLK0 144 1 + #26 ENCRYPT_CONFIG EFUSE_BLK0 188 4 + #27 CONSOLE_DEBUG_DISABLE EFUSE_BLK0 194 1 + #28 ABS_DONE_0 EFUSE_BLK0 196 1 + #29 DISABLE_JTAG EFUSE_BLK0 198 1 + #30 DISABLE_DL_ENCRYPT EFUSE_BLK0 199 1 + #31 DISABLE_DL_DECRYPT EFUSE_BLK0 200 1 + #32 DISABLE_DL_CACHE EFUSE_BLK0 201 1 + #33 ENCRYPT_FLASH_KEY EFUSE_BLK1 0 256 + #34 SECURE_BOOT_KEY EFUSE_BLK2 0 256 + #35 MAC_CUSTOM_CRC EFUSE_BLK3 0 8 + #36 MAC_CUSTOM EFUSE_BLK3 8 48 + #37 ADC1_TP_LOW EFUSE_BLK3 96 7 + #38 ADC1_TP_HIGH EFUSE_BLK3 103 9 + #39 ADC2_TP_LOW EFUSE_BLK3 112 7 + #40 ADC2_TP_HIGH EFUSE_BLK3 119 9 + #41 MAC_CUSTOM_VER EFUSE_BLK3 184 8 + + Used bits in efuse table: + EFUSE_BLK0 + [2 2] [7 9] [16 18] [20 27] [32 87] [96 97] [105 109] [111 111] [136 144] [188 191] [194 194] [196 196] [198 201] + + EFUSE_BLK1 + [0 255] + + EFUSE_BLK2 + [0 255] + + EFUSE_BLK3 + [0 55] [96 127] [184 191] + + Note: Not printed ranges are free for using. + + Parsing efuse CSV input file esp32/esp_efuse_table.csv ... + Verifying efuse table... + +The number of bits not included in square brackets is free. All fields are checked for overlapping. + +2. Fill a line for field: field_name, efuse_block, bit_start, bit_count, comment. + +3. Run a command `make show_efuse_table` to check and generate header file. + +Debug efuse & Unit tests +------------------------ + +eFuse manager have option :envvar:`CONFIG_EFUSE_VIRTUAL` in Kconfig which will make an operation write is virtual. It can help to debug app and unit tests. + +esptool have an useful tool for reading/writing ESP32 efuse bits - `espefuse.py `_. + +:: + + espefuse.py -p COM4 summary + + espefuse.py v2.3.1 + Connecting........_ + Security fuses: + FLASH_CRYPT_CNT Flash encryption mode counter = 0 R/W (0x4) + FLASH_CRYPT_CONFIG Flash encryption config (key tweak bits) = 0 R/W (0x0) + CONSOLE_DEBUG_DISABLE Disable ROM BASIC interpreter fallback = 0 R/W (0x0) + ABS_DONE_0 secure boot enabled for bootloader = 0 R/W (0x0) + ABS_DONE_1 secure boot abstract 1 locked = 0 R/W (0x0) + JTAG_DISABLE Disable JTAG = 0 R/W (0x0) + DISABLE_DL_ENCRYPT Disable flash encryption in UART bootloader = 0 R/W (0x0) + DISABLE_DL_DECRYPT Disable flash decryption in UART bootloader = 0 R/W (0x0) + DISABLE_DL_CACHE Disable flash cache in UART bootloader = 0 R/W (0x0) + BLK1 Flash encryption key + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLK2 Secure boot key + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + BLK3 Variable Block 3 + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + + Efuse fuses: + WR_DIS Efuse write disable mask = 0 R/W (0x0) + RD_DIS Efuse read disablemask = 0 R/W (0x0) + CODING_SCHEME Efuse variable block length scheme = 0 R/W (0x0) + KEY_STATUS Usage of efuse block 3 (reserved) = 0 R/W (0x0) + + Config fuses: + XPD_SDIO_FORCE Ignore MTDI pin (GPIO12) for VDD_SDIO on reset = 0 R/W (0x0) + XPD_SDIO_REG If XPD_SDIO_FORCE, enable VDD_SDIO reg on reset = 0 R/W (0x0) + XPD_SDIO_TIEH If XPD_SDIO_FORCE & XPD_SDIO_REG, 1=3.3V 0=1.8V = 0 R/W (0x0) + SPI_PAD_CONFIG_CLK Override SD_CLK pad (GPIO6/SPICLK) = 0 R/W (0x0) + SPI_PAD_CONFIG_Q Override SD_DATA_0 pad (GPIO7/SPIQ) = 0 R/W (0x0) + SPI_PAD_CONFIG_D Override SD_DATA_1 pad (GPIO8/SPID) = 0 R/W (0x0) + SPI_PAD_CONFIG_HD Override SD_DATA_2 pad (GPIO9/SPIHD) = 0 R/W (0x0) + SPI_PAD_CONFIG_CS0 Override SD_CMD pad (GPIO11/SPICS0) = 0 R/W (0x0) + DISABLE_SDIO_HOST Disable SDIO host = 0 R/W (0x0) + + Identity fuses: + MAC MAC Address + = 24:0a:c4:03:bb:68 (CRC 82 OK) R/W + CHIP_VER_REV1 Silicon Revision 1 = 0 R/W (0x0) + CHIP_VERSION Reserved for future chip versions = 0 R/W (0x0) + CHIP_PACKAGE Chip package identifier = 0 R/W (0x0) + + Calibration fuses: + BLK3_PART_RESERVE BLOCK3 partially served for ADC calibration data = 0 R/W (0x0) + ADC_VREF Voltage reference calibration = 1100 R/W (0x0) + + Flash voltage (VDD_SDIO) determined by GPIO12 on reset (High for 1.8V, Low/NC for 3.3V). + +To get a dump for all efuse registers. + +:: + + espefuse.py -p COM4 dump + + $ espefuse.py -p COM4 dump + espefuse.py v2.3.1 + Connecting........__ + EFUSE block 0: + 00000000 c403bb68 0082240a 00000000 00000035 00000000 00000000 + EFUSE block 1: + 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 + EFUSE block 2: + 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 + EFUSE block 3: + 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 + + +.. include:: /_build/inc/esp_efuse.inc \ No newline at end of file diff --git a/docs/en/api-reference/system/index.rst b/docs/en/api-reference/system/index.rst index 0d24fcc945..a02f74aa64 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -11,6 +11,7 @@ System API Himem (large external SPI RAM) API Interrupt Allocation Watchdogs + eFuse Manager Inter-Processor Call High Resolution Timer Logging diff --git a/docs/zh_CN/api-reference/system/efuse.rst b/docs/zh_CN/api-reference/system/efuse.rst new file mode 100644 index 0000000000..c30c7bc081 --- /dev/null +++ b/docs/zh_CN/api-reference/system/efuse.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/system/efuse.rst \ No newline at end of file From 91676b8620bf7c8903337955d335a2b6c31cbea7 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Mon, 19 Nov 2018 11:45:21 +0800 Subject: [PATCH 05/15] build_system: Add support efuse --- make/project.mk | 2 +- tools/ci/executable-list.txt | 2 ++ tools/idf.py | 2 ++ tools/unit-test-app/sdkconfig.defaults | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/make/project.mk b/make/project.mk index a1307b0454..6f86cbef07 100644 --- a/make/project.mk +++ b/make/project.mk @@ -521,7 +521,7 @@ endef define GenerateComponentTargets .PHONY: component-$(2)-build component-$(2)-clean -component-$(2)-build: check-submodules $(call prereq_if_explicit, component-$(2)-clean) | $(BUILD_DIR_BASE)/$(2) +component-$(2)-build: check-submodules efuse_table $(call prereq_if_explicit, component-$(2)-clean) | $(BUILD_DIR_BASE)/$(2) $(call ComponentMake,$(1),$(2)) build component-$(2)-clean: | $(BUILD_DIR_BASE)/$(2) $(BUILD_DIR_BASE)/$(2)/component_project_vars.mk diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 06821ebbd9..e379ec9497 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -5,6 +5,8 @@ components/espcoredump/espcoredump.py components/heap/test_multi_heap_host/test_all_configs.sh components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py +components/efuse/efuse_table_gen.py +components/efuse/test_efuse_host/efuse_tests.py components/partition_table/gen_esp32part.py components/partition_table/parttool.py components/app_update/gen_empty_partition.py diff --git a/tools/idf.py b/tools/idf.py index 5550fc4305..927efca0f6 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -422,6 +422,8 @@ ACTIONS = { "bootloader-flash": (flash, ["bootloader"], ["erase_flash"]), "app": (build_target, [], ["clean", "fullclean", "reconfigure"]), "app-flash": (flash, ["app"], ["erase_flash"]), + "efuse_common_table": (build_target, [], ["reconfigure"]), + "efuse_custom_table": (build_target, [], ["reconfigure"]), "partition_table": (build_target, [], ["reconfigure"]), "partition_table-flash": (flash, ["partition_table"], ["erase_flash"]), "flash": (flash, ["all"], ["erase_flash"]), diff --git a/tools/unit-test-app/sdkconfig.defaults b/tools/unit-test-app/sdkconfig.defaults index 65fdb2c0c4..afaf11031b 100644 --- a/tools/unit-test-app/sdkconfig.defaults +++ b/tools/unit-test-app/sdkconfig.defaults @@ -28,5 +28,6 @@ CONFIG_ESP_TIMER_PROFILING=y CONFIG_ADC2_DISABLE_DAC=n CONFIG_WARN_WRITE_STRINGS=y CONFIG_SPI_MASTER_IN_IRAM=y +CONFIG_EFUSE_VIRTUAL=y CONFIG_SPIRAM_BANKSWITCH_ENABLE=n CONFIG_FATFS_ALLOC_EXTRAM_FIRST=y From 693a5c209bb20db0a8721b2a3eacaed8641e98c0 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Mon, 19 Nov 2018 11:46:21 +0800 Subject: [PATCH 06/15] efuse: Add API efuse Added support 3/4 coding scheme --- components/efuse/CMakeLists.txt | 54 ++ components/efuse/Kconfig | 37 ++ components/efuse/Makefile.projbuild | 48 ++ components/efuse/component.mk | 10 + components/efuse/efuse_table_gen.py | 415 +++++++++++++ components/efuse/esp32/component.mk | 0 components/efuse/esp32/esp_efuse_table.c | 362 ++++++++++++ components/efuse/esp32/esp_efuse_table.csv | 80 +++ .../efuse/esp32/include/esp_efuse_table.h | 66 +++ components/efuse/esp32/sources.cmake | 1 + components/efuse/include/esp_efuse.h | 294 ++++++++++ components/efuse/src/esp_efuse_api.c | 214 +++++++ components/efuse/src/esp_efuse_fields.c | 117 ++++ components/efuse/src/esp_efuse_utility.c | 512 ++++++++++++++++ components/efuse/src/esp_efuse_utility.h | 140 +++++ components/efuse/test/CMakeLists.txt | 6 + components/efuse/test/component.mk | 6 + components/efuse/test/esp_efuse_test_table.c | 103 ++++ .../efuse/test/esp_efuse_test_table.csv | 33 ++ .../efuse/test/include/esp_efuse_test_table.h | 36 ++ components/efuse/test/test_efuse.c | 546 ++++++++++++++++++ .../efuse/test/test_efuse_coding_scheme.c | 204 +++++++ .../efuse/test_efuse_host/efuse_tests.py | 295 ++++++++++ 23 files changed, 3579 insertions(+) create mode 100644 components/efuse/CMakeLists.txt create mode 100644 components/efuse/Kconfig create mode 100644 components/efuse/Makefile.projbuild create mode 100644 components/efuse/component.mk create mode 100644 components/efuse/efuse_table_gen.py create mode 100644 components/efuse/esp32/component.mk create mode 100644 components/efuse/esp32/esp_efuse_table.c create mode 100644 components/efuse/esp32/esp_efuse_table.csv create mode 100644 components/efuse/esp32/include/esp_efuse_table.h create mode 100644 components/efuse/esp32/sources.cmake create mode 100644 components/efuse/include/esp_efuse.h create mode 100644 components/efuse/src/esp_efuse_api.c create mode 100644 components/efuse/src/esp_efuse_fields.c create mode 100644 components/efuse/src/esp_efuse_utility.c create mode 100644 components/efuse/src/esp_efuse_utility.h create mode 100644 components/efuse/test/CMakeLists.txt create mode 100644 components/efuse/test/component.mk create mode 100644 components/efuse/test/esp_efuse_test_table.c create mode 100644 components/efuse/test/esp_efuse_test_table.csv create mode 100644 components/efuse/test/include/esp_efuse_test_table.h create mode 100644 components/efuse/test/test_efuse.c create mode 100644 components/efuse/test/test_efuse_coding_scheme.c create mode 100644 components/efuse/test_efuse_host/efuse_tests.py diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt new file mode 100644 index 0000000000..e11e1e74f3 --- /dev/null +++ b/components/efuse/CMakeLists.txt @@ -0,0 +1,54 @@ +set(SOC_NAME ${IDF_TARGET}) + +if(EXISTS "${COMPONENT_PATH}/${SOC_NAME}") + include(${COMPONENT_PATH}/${SOC_NAME}/sources.cmake) + spaces2list(EFUSE_SOC_SRCS) + add_prefix(COMPONENT_SRCS "${SOC_NAME}/" ${EFUSE_SOC_SRCS}) + set(COMPONENT_ADD_INCLUDEDIRS include + ${SOC_NAME}/include) +endif() + +list(APPEND COMPONENT_SRCS "src/esp_efuse_api.c" + "src/esp_efuse_fields.c" + "src/esp_efuse_utility.c") + +set(COMPONENT_REQUIRES) +set(COMPONENT_PRIV_REQUIRES bootloader_support) +register_component() + + +################### +# Make common files esp_efuse_table.c and include/esp_efuse_table.h files. +# The generated files are used in the bootloader and application space. +# To generate new *.c/*.h files run the command manually "make efuse_common_table". +set(EFUSE_COMMON_TABLE_CSV_PATH "${COMPONENT_PATH}/${SOC_NAME}/esp_efuse_table.csv") +add_custom_target(efuse_common_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH}) + + +# custom gen header files +if(${CONFIG_EFUSE_CUSTOM_TABLE}) + # Custom filename expands any path relative to the project + get_filename_component(EFUSE_CUSTOM_TABLE_CSV_PATH "${CONFIG_EFUSE_CUSTOM_TABLE_FILENAME}" ABSOLUTE BASE_DIR "${PROJECT_PATH}") + + add_custom_target(efuse_custom_table ALL + COMMAND ${CMAKE_COMMAND} -E echo "Efuse CSV ${EFUSE_CUSTOM_TABLE_CSV_PATH} does not exist. Either change efuse table file in menuconfig or create this input file." + COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt" + COMMAND ${CMAKE_COMMAND} -P ${IDF_PATH}/tools/cmake/scripts/fail.cmake) + +string(REPLACE ".csv" ".c" HEADER_CUSTOM ${EFUSE_CUSTOM_TABLE_CSV_PATH}) +add_custom_command(OUTPUT ${HEADER_CUSTOM} + COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" + ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} + DEPENDS ${EFUSE_CUSTOM_TABLE_CSV_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" + VERBATIM) + +if(EXISTS ${EFUSE_CUSTOM_TABLE_CSV_PATH}) + add_custom_target(efuse_custom_table ALL DEPENDS ${HEADER_CUSTOM} ${EFUSE_CUSTOM_TABLE_CSV_PATH}) +endif() + +endif()#if(${CONFIG_EFUSE_CUSTOM_TABLE}) + +################### +# Generates files for unit test. This command is run manually. +set(EFUSE_TEST_TABLE_CSV_PATH "${COMPONENT_PATH}/test/esp_efuse_test_table.csv") +add_custom_target(efuse_test_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_TEST_TABLE_CSV_PATH}) diff --git a/components/efuse/Kconfig b/components/efuse/Kconfig new file mode 100644 index 0000000000..d07ae851fd --- /dev/null +++ b/components/efuse/Kconfig @@ -0,0 +1,37 @@ +menu "eFuse bit Manager" + +config EFUSE_CUSTOM_TABLE + bool "Use custom eFuse table" + default n + help + Allows to generate a structure for eFuse from the CSV file. + +config EFUSE_CUSTOM_TABLE_FILENAME + string "Custom eFuse CSV file" if EFUSE_CUSTOM_TABLE + default main/esp_efuse_custom_table.csv + help + Name of the custom eFuse CSV filename. This path is evaluated + relative to the project root directory. + +config EFUSE_VIRTUAL + bool "Emulate eFuse work" + default n + help + If this option is set, all permanent changes (via eFuse) are disabled. + Log output will state changes which would be applied, but they will not be. + +choice EFUSE_CODE_SCHEME + prompt "eFuse Code Scheme" + default EFUSE_CODE_SCHEME_NONE + help + Selector eFuse code scheme. + +config EFUSE_CODE_SCHEME_NONE + bool "None" +config EFUSE_CODE_SCHEME_3_4 + bool "3/4" +config EFUSE_CODE_SCHEME_REPEAT + bool "Repeat" +endchoice + +endmenu diff --git a/components/efuse/Makefile.projbuild b/components/efuse/Makefile.projbuild new file mode 100644 index 0000000000..35e0355a92 --- /dev/null +++ b/components/efuse/Makefile.projbuild @@ -0,0 +1,48 @@ +# +# eFuse Manager ganeretes header file. +# +# .PHONY: efuse_table efuse_custom_table efuse_common_table efuse_test_table show_efuse_table + +GEN_EFUSE_TABLE := $(PYTHON) $(COMPONENT_PATH)/efuse_table_gen.py + +efuse_table: efuse_custom_table + +################### +# Make common files esp_efuse_table.c and include/esp_efuse_table.h files. +# The generated files are used in the bootloader and application space. +# To generate new *.c/*.h files run the command manually "make efuse_common_table". +SOC_NAME := $(IDF_TARGET) +EFUSE_COMMON_TABLE_CSV_PATH := $(COMPONENT_PATH)/$(SOC_NAME)/esp_efuse_table.csv +efuse_common_table: + $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) + +################### +# Make custom files +# Changes in esp_efuse_custom_table.csv file lead to regeneration of esp_efuse_custom_table.c and include/esp_efuse_custom_table.h files. +# The generated files are used only in the application. +ifdef IS_BOOTLOADER_BUILD +efuse_custom_table: +else + +ifdef CONFIG_EFUSE_CUSTOM_TABLE +# Path to CSV file is relative to project path for custom CSV files. +EFUSE_CUSTOM_TABLE_CSV_PATH := $(call dequote,$(abspath $(call dequote, $(PROJECT_PATH))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME)))) +EFUSE_CUSTOM_TABLE_OUT_PATH := $(call dequote,$(abspath $(call dequote, $(BUILD_DIR_BASE))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME)))) +efuse_custom_table: $(EFUSE_CUSTOM_TABLE_OUT_PATH:.csv=.o) + +$(EFUSE_CUSTOM_TABLE_OUT_PATH:.csv=.o): $(EFUSE_CUSTOM_TABLE_CSV_PATH) + @echo "$(EFUSE_CUSTOM_TABLE_OUT_PATH)" + @echo "$(EFUSE_CUSTOM_TABLE_CSV_PATH)" + $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) + +else +efuse_custom_table: +endif + +endif + +################### +# Generates files for unit test. This command is run manually. +EFUSE_TEST_TABLE_CSV_PATH := $(COMPONENT_PATH)/test/esp_efuse_test_table.csv +efuse_test_table: + $(GEN_EFUSE_TABLE) $(EFUSE_TEST_TABLE_CSV_PATH) diff --git a/components/efuse/component.mk b/components/efuse/component.mk new file mode 100644 index 0000000000..393f21020b --- /dev/null +++ b/components/efuse/component.mk @@ -0,0 +1,10 @@ +# +# Component Makefile +# currently the only SoC supported; to be moved into Kconfig +SOC_NAME := $(IDF_TARGET) + +COMPONENT_SRCDIRS := $(SOC_NAME) src + +COMPONENT_ADD_INCLUDEDIRS := $(SOC_NAME)/include include + +-include $(COMPONENT_PATH)/$(SOC_NAME)/component.mk \ No newline at end of file diff --git a/components/efuse/efuse_table_gen.py b/components/efuse/efuse_table_gen.py new file mode 100644 index 0000000000..a64f2f9495 --- /dev/null +++ b/components/efuse/efuse_table_gen.py @@ -0,0 +1,415 @@ +#!/usr/bin/env python +# +# ESP32 efuse table generation tool +# +# Converts efuse table to header file efuse_table.h. +# +# Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import print_function, division +import argparse +import os +import re +import struct +import sys +import hashlib +import binascii +import ntpath + +__version__ = '1.0' + +quiet = False + +copyright = '''// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at", +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License +''' + +def status(msg): + """ Print status message to stderr """ + if not quiet: + critical(msg) + +def critical(msg): + """ Print critical message to stderr """ + sys.stderr.write(msg) + sys.stderr.write('\n') + +class FuseTable(list): + def __init__(self): + super(FuseTable, self).__init__(self) + self.md5_digest = "" + + @classmethod + def from_csv(cls, csv_contents): + res = FuseTable() + res.md5_digest = res.calc_md5(csv_contents) + lines = csv_contents.splitlines() + def expand_vars(f): + f = os.path.expandvars(f) + m = re.match(r'(? 1 ) + if len(duplicates) != 0: + i_count = 0 + for p in res: + if len(duplicates.intersection([p.field_name])) != 0: + p.group = str(i_count) + i_count += 1 + else: + i_count = 0 + res.verify_duplicate_name() + + return res + + def verify_duplicate_name(self): + # check on duplicate name + names = [ p.field_name for p in self ] + duplicates = set( n for n in names if names.count(n) > 1 ) + + # print sorted duplicate partitions by name + if len(duplicates) != 0: + fl_error = False + for p in self: + field_name = p.field_name + p.group + if field_name != "" and len(duplicates.intersection([field_name])) != 0: + fl_error = True + print ("Field at %s, %s, %s, %s have dublicate field_name" + % ( p.field_name, p.efuse_block, p.bit_start, p.bit_count)) + if fl_error == True: + raise InputError("Field names must be unique") + + def verify(self): + + '''list_field_names = []''' + for p in self: + p.verify() + + self.verify_duplicate_name() + + # check for overlaps + last = None + for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): + if last is not None and last.efuse_block == p.efuse_block and p.bit_start < last.bit_start + last.bit_count: + raise InputError("Field at %s, %s, %s, %s overlaps %s, %s, %s, %s" + % ( p.field_name, p.efuse_block, p.bit_start, p.bit_count, + last.field_name, last.efuse_block, last.bit_start, last.bit_count)) + last = p + + def calc_md5(self, csv_contents): + return hashlib.md5(csv_contents).hexdigest() + + def show_range_used_bits(self): + # print used and free bits + rows = '' + rows += 'Sorted efuse table:\n' + num = 1 + for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): + rows += "#%d \t%s \t\t%s \t\t%d \t\t%d" % (num, p.field_name, p.efuse_block, p.bit_start, p.bit_count) + "\n" + num += 1 + + rows += '\nUsed bits in efuse table:\n' + last = None + for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): + if last is None: + rows += '%s \n[%d ' % (p.efuse_block, p.bit_start) + if last is not None: + if last.efuse_block != p.efuse_block: + rows += '%d] \n\n%s \n[%d ' % (last.bit_start + last.bit_count - 1, p.efuse_block, p.bit_start) + elif last.bit_start + last.bit_count != p.bit_start: + rows += '%d] [%d ' % (last.bit_start + last.bit_count - 1, p.bit_start) + last = p + rows += '%d] \n' % (last.bit_start + last.bit_count - 1) + rows += '\nNote: Not printed ranges are free for using.\n' + return rows + + def to_header(self, file_name): + rows = [ copyright ] + rows += [ "#ifdef __cplusplus", + 'extern "C" {', + "#endif", + "", + "", + "// md5_digest " + self.md5_digest, + "// This file was generated automatically from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", + "// If you want to change some fields, you need to change " + file_name + ".csv file then build system will generate this header file", + "// To show efuse_table run the command 'make show_efuse_table'.", + "", + ""] + + last_field_name = '' + for p in self: + if (p.field_name != last_field_name): + rows += [ "extern const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[];" ] + last_field_name = p.field_name + + rows += [ "", + "#ifdef __cplusplus", + "}", + "#endif", + ""] + return '\n'.join(rows) + "\n" + + def to_c_file(self, file_name, debug): + rows = [ copyright ] + rows += [ '#include "esp_efuse.h"', + '#include "' + file_name + '.h"', + "", + "// md5_digest " + self.md5_digest, + "// This file was generated automatically from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", + "// If you want to change some fields, you need to change " + file_name + ".csv file then build system will generate this header file", + "// To show efuse_table run the command 'make show_efuse_table'.", + "", + ""] + + last_name = '' + for p in self: + if (p.field_name != last_name): + if last_name != '': + rows += [ "};\n"] + rows += [ "static const esp_efuse_desc_t " + p.field_name + "[] = {" ] + last_name = p.field_name + rows += [ p.to_struct(debug) + "," ] + rows += [ "};\n" ] + + rows += ["\n\n\n"] + + last_name = '' + for p in self: + if (p.field_name != last_name): + if last_name != '': + rows += [" NULL", + "};\n" ] + rows += [ "const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[] = {" ] + last_name = p.field_name + index = str(0) if str(p.group) == "" else str(p.group) + rows += [ " &" + p.field_name + "[" + index + "], \t\t// " + p.comment ] + rows += [" NULL", + "};\n" ] + + return '\n'.join(rows) + "\n" + +class FuseDefinition(object): + + def __init__(self): + self.field_name = "" + self.group = "" + self.efuse_block = "" + self.bit_start = None + self.bit_count = None + self.comment = "" + + @classmethod + def from_csv(cls, line): + """ Parse a line from the CSV """ + line_w_defaults = line + ",,,," # lazy way to support default fields + fields = [ f.strip() for f in line_w_defaults.split(",") ] + + res = FuseDefinition() + res.field_name = fields[0] + res.efuse_block = res.parse_block(fields[1]) + res.bit_start = res.parse_num(fields[2]) + res.bit_count = res.parse_num(fields[3]) + if res.bit_count is None or res.bit_count == 0: + raise InputError("Field bit_count can't be empty") + res.comment = fields[4] + return res + + def parse_num(self, strval): + if strval == "": + return None # Field will fill in default + return self.parse_int(strval) + + def parse_int(self, v): + try: + return int(v, 0) + except ValueError: + raise InputError("Invalid field value %s" % v) + + def parse_block(self, strval): + if strval == "": + raise InputError("Field 'efuse_block' can't be left empty.") + if strval != "EFUSE_BLK0" and strval != "EFUSE_BLK1" and strval != "EFUSE_BLK2" and strval != "EFUSE_BLK3": + raise InputError("Field 'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3") + return strval + + def verify(self): + '''if self.field_name is None: + raise ValidationError(self, "field_name field is not set")''' + if self.efuse_block is None: + raise ValidationError(self, "efuse_block field is not set") + if self.bit_count is None: + raise ValidationError(self, "bit_count field is not set") + + max_bits = 256 + if self.efuse_block == "EFUSE_BLK0": + max_bits = 224 + if self.bit_start + self.bit_count > max_bits: + raise ValidationError(self, "The field is outside the boundaries of the %s block" % (self.efuse_block)) + + def get_full_name(self): + def get_postfix(group): + postfix = "" + if group != "": + postfix = "_PART_" + group + return postfix + + return self.field_name + get_postfix(self.group) + + def to_struct(self, debug): + start = " {" + if (debug == True): + start = " {" + '"' + self.field_name + '" ,' + return ", ".join([start + self.efuse_block, + str(self.bit_start), + str(self.bit_count) + "}, \t // " + self.comment]) + +def process_input_file(file): + status("Parsing efuse CSV input file " + file.name + " ...") + input = file.read() + table = FuseTable.from_csv(input) + + status("Verifying efuse table...") + table.verify() + return table + +def create_output_files(name, output_table, debug): + file_name = os.path.splitext(os.path.basename(name))[0] + gen_dir = os.path.dirname(name) + + dir_for_file_h = gen_dir + "/include" + try: + os.stat(dir_for_file_h) + except: + os.mkdir(dir_for_file_h) + + file_h_path = os.path.join(dir_for_file_h, file_name + ".h") + file_c_path = os.path.join(gen_dir, file_name + ".c") + + status("Creating efuse *.h file " + file_h_path + " ...") + output = output_table.to_header(file_name) + with open(file_h_path, 'w') as f: + f.write(output) + f.close() + + status("Creating efuse *.c file " + file_c_path + " ...") + output = output_table.to_c_file(file_name, debug) + with open(file_c_path, 'w') as f: + f.write(output) + f.close() + +def main(): + global quiet + + parser = argparse.ArgumentParser(description='ESP32 eFuse Manager') + + parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') + parser.add_argument('--debug', help='Create header file with debug info', default=False, action="store_false") + parser.add_argument('--info', help='Print info about range of used bits', default=False, action="store_true") + parser.add_argument('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('rb')) + parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('rb'), nargs='?', default=None) + + args = parser.parse_args() + + quiet = args.quiet + debug = args.debug + info = args.info + + common_table = process_input_file(args.common_input) + if args.custom_input is not None: + custom_table = process_input_file(args.custom_input) + common_table += custom_table + common_table.verify() + if info == True: + output_table = common_table + else: + output_table = custom_table + name = args.custom_input.name + else: + output_table = common_table + name = args.common_input.name + output_table.verify() + + # save files. + if info == False: + create_output_files(name, output_table, debug) + else: + print(output_table.show_range_used_bits()) + + return 0 + +class InputError(RuntimeError): + def __init__(self, e): + super(InputError, self).__init__(e) + +class ValidationError(InputError): + def __init__(self, p, message): + super(ValidationError, self).__init__( + "Entry %s invalid: %s" % (p.field_name, message)) + +if __name__ == '__main__': + try: + main() + except InputError as e: + print(e, file=sys.stderr) + sys.exit(2) diff --git a/components/efuse/esp32/component.mk b/components/efuse/esp32/component.mk new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/efuse/esp32/esp_efuse_table.c b/components/efuse/esp32/esp_efuse_table.c new file mode 100644 index 0000000000..69685c0e89 --- /dev/null +++ b/components/efuse/esp32/esp_efuse_table.c @@ -0,0 +1,362 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at", +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#include "esp_efuse.h" +#include "esp_efuse_table.h" + + +// md5_digest 963d6d14dc4bd997fd5d4b9de351745d +// This file was generated automatically from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_table.csv file then build system will generate this header file +// To show efuse_table run the command 'make show_efuse_table'. + + +static const esp_efuse_desc_t MAC_FACTORY[] = { + {EFUSE_BLK0, 72, 8}, // Factory MAC addr [0], + {EFUSE_BLK0, 64, 8}, // Factory MAC addr [1], + {EFUSE_BLK0, 56, 8}, // Factory MAC addr [2], + {EFUSE_BLK0, 48, 8}, // Factory MAC addr [3], + {EFUSE_BLK0, 40, 8}, // Factory MAC addr [4], + {EFUSE_BLK0, 32, 8}, // Factory MAC addr [5], +}; + +static const esp_efuse_desc_t MAC_FACTORY_CRC[] = { + {EFUSE_BLK0, 80, 8}, // CRC8 for factory MAC address, +}; + +static const esp_efuse_desc_t MAC_CUSTOM_CRC[] = { + {EFUSE_BLK3, 0, 8}, // CRC8 for custom MAC address., +}; + +static const esp_efuse_desc_t MAC_CUSTOM[] = { + {EFUSE_BLK3, 8, 48}, // Custom MAC, +}; + +static const esp_efuse_desc_t MAC_CUSTOM_VER[] = { + {EFUSE_BLK3, 184, 8}, // Custom MAC version, +}; + +static const esp_efuse_desc_t SECURE_BOOT_KEY[] = { + {EFUSE_BLK2, 0, 256}, // Security boot. Key., +}; + +static const esp_efuse_desc_t ABS_DONE_0[] = { + {EFUSE_BLK0, 196, 1}, // Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0, +}; + +static const esp_efuse_desc_t ENCRYPT_FLASH_KEY[] = { + {EFUSE_BLK1, 0, 256}, // Flash encrypt. Key., +}; + +static const esp_efuse_desc_t ENCRYPT_CONFIG[] = { + {EFUSE_BLK0, 188, 4}, // Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M, +}; + +static const esp_efuse_desc_t DISABLE_DL_ENCRYPT[] = { + {EFUSE_BLK0, 199, 1}, // Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT., +}; + +static const esp_efuse_desc_t DISABLE_DL_DECRYPT[] = { + {EFUSE_BLK0, 200, 1}, // Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT., +}; + +static const esp_efuse_desc_t DISABLE_DL_CACHE[] = { + {EFUSE_BLK0, 201, 1}, // Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE., +}; + +static const esp_efuse_desc_t DISABLE_JTAG[] = { + {EFUSE_BLK0, 198, 1}, // Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG., +}; + +static const esp_efuse_desc_t CONSOLE_DEBUG_DISABLE[] = { + {EFUSE_BLK0, 194, 1}, // Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE., +}; + +static const esp_efuse_desc_t FLASH_CRYPT_CNT[] = { + {EFUSE_BLK0, 20, 8}, // Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT., +}; + +static const esp_efuse_desc_t WR_DIS_FLASH_CRYPT_CNT[] = { + {EFUSE_BLK0, 2, 1}, // Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT, +}; + +static const esp_efuse_desc_t WR_DIS_BLK1[] = { + {EFUSE_BLK0, 7, 1}, // Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1, +}; + +static const esp_efuse_desc_t WR_DIS_BLK2[] = { + {EFUSE_BLK0, 8, 1}, // Security boot. Write protection security key. EFUSE_WR_DIS_BLK2, +}; + +static const esp_efuse_desc_t WR_DIS_BLK3[] = { + {EFUSE_BLK0, 9, 1}, // Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3, +}; + +static const esp_efuse_desc_t RD_DIS_BLK1[] = { + {EFUSE_BLK0, 16, 1}, // Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1, +}; + +static const esp_efuse_desc_t RD_DIS_BLK2[] = { + {EFUSE_BLK0, 17, 1}, // Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2, +}; + +static const esp_efuse_desc_t RD_DIS_BLK3[] = { + {EFUSE_BLK0, 18, 1}, // Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3, +}; + +static const esp_efuse_desc_t CHIP_VER_DIS_APP_CPU[] = { + {EFUSE_BLK0, 96, 1}, // EFUSE_RD_CHIP_VER_DIS_APP_CPU, +}; + +static const esp_efuse_desc_t CHIP_VER_DIS_BT[] = { + {EFUSE_BLK0, 97, 1}, // EFUSE_RD_CHIP_VER_DIS_BT, +}; + +static const esp_efuse_desc_t CHIP_VER_PKG[] = { + {EFUSE_BLK0, 105, 3}, // EFUSE_RD_CHIP_VER_PKG, +}; + +static const esp_efuse_desc_t CHIP_CPU_FREQ_LOW[] = { + {EFUSE_BLK0, 108, 1}, // EFUSE_RD_CHIP_CPU_FREQ_LOW, +}; + +static const esp_efuse_desc_t CHIP_CPU_FREQ_RATED[] = { + {EFUSE_BLK0, 109, 1}, // EFUSE_RD_CHIP_CPU_FREQ_RATED, +}; + +static const esp_efuse_desc_t CHIP_VER_REV1[] = { + {EFUSE_BLK0, 111, 1}, // EFUSE_RD_CHIP_VER_REV1, +}; + +static const esp_efuse_desc_t XPD_SDIO_REG[] = { + {EFUSE_BLK0, 142, 1}, // EFUSE_RD_XPD_SDIO_REG, +}; + +static const esp_efuse_desc_t SDIO_TIEH[] = { + {EFUSE_BLK0, 143, 1}, // EFUSE_RD_SDIO_TIEH, +}; + +static const esp_efuse_desc_t SDIO_FORCE[] = { + {EFUSE_BLK0, 144, 1}, // EFUSE_RD_SDIO_FORCE, +}; + +static const esp_efuse_desc_t ADC_VREF_AND_SDIO_DREF[] = { + {EFUSE_BLK0, 136, 6}, // EFUSE_RD_ADC_VREF[0..4] or ( SDIO_DREFH[0 1], +}; + +static const esp_efuse_desc_t ADC1_TP_LOW[] = { + {EFUSE_BLK3, 96, 7}, // TP_REG EFUSE_RD_ADC1_TP_LOW, +}; + +static const esp_efuse_desc_t ADC2_TP_LOW[] = { + {EFUSE_BLK3, 112, 7}, // TP_REG EFUSE_RD_ADC2_TP_LOW, +}; + +static const esp_efuse_desc_t ADC1_TP_HIGH[] = { + {EFUSE_BLK3, 103, 9}, // TP_REG EFUSE_RD_ADC1_TP_HIGH, +}; + +static const esp_efuse_desc_t ADC2_TP_HIGH[] = { + {EFUSE_BLK3, 119, 9}, // TP_REG EFUSE_RD_ADC2_TP_HIGH, +}; + + + + + +const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY[] = { + &MAC_FACTORY[0], // Factory MAC addr [0] + &MAC_FACTORY[1], // Factory MAC addr [1] + &MAC_FACTORY[2], // Factory MAC addr [2] + &MAC_FACTORY[3], // Factory MAC addr [3] + &MAC_FACTORY[4], // Factory MAC addr [4] + &MAC_FACTORY[5], // Factory MAC addr [5] + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY_CRC[] = { + &MAC_FACTORY_CRC[0], // CRC8 for factory MAC address + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_CRC[] = { + &MAC_CUSTOM_CRC[0], // CRC8 for custom MAC address. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM[] = { + &MAC_CUSTOM[0], // Custom MAC + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_VER[] = { + &MAC_CUSTOM_VER[0], // Custom MAC version + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY[] = { + &SECURE_BOOT_KEY[0], // Security boot. Key. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ABS_DONE_0[] = { + &ABS_DONE_0[0], // Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_FLASH_KEY[] = { + &ENCRYPT_FLASH_KEY[0], // Flash encrypt. Key. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_CONFIG[] = { + &ENCRYPT_CONFIG[0], // Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_ENCRYPT[] = { + &DISABLE_DL_ENCRYPT[0], // Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_DECRYPT[] = { + &DISABLE_DL_DECRYPT[0], // Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_CACHE[] = { + &DISABLE_DL_CACHE[0], // Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_DISABLE_JTAG[] = { + &DISABLE_JTAG[0], // Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CONSOLE_DEBUG_DISABLE[] = { + &CONSOLE_DEBUG_DISABLE[0], // Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_FLASH_CRYPT_CNT[] = { + &FLASH_CRYPT_CNT[0], // Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT[] = { + &WR_DIS_FLASH_CRYPT_CNT[0], // Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK1[] = { + &WR_DIS_BLK1[0], // Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK2[] = { + &WR_DIS_BLK2[0], // Security boot. Write protection security key. EFUSE_WR_DIS_BLK2 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK3[] = { + &WR_DIS_BLK3[0], // Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK1[] = { + &RD_DIS_BLK1[0], // Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK2[] = { + &RD_DIS_BLK2[0], // Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK3[] = { + &RD_DIS_BLK3[0], // Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_APP_CPU[] = { + &CHIP_VER_DIS_APP_CPU[0], // EFUSE_RD_CHIP_VER_DIS_APP_CPU + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_BT[] = { + &CHIP_VER_DIS_BT[0], // EFUSE_RD_CHIP_VER_DIS_BT + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[] = { + &CHIP_VER_PKG[0], // EFUSE_RD_CHIP_VER_PKG + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[] = { + &CHIP_CPU_FREQ_LOW[0], // EFUSE_RD_CHIP_CPU_FREQ_LOW + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[] = { + &CHIP_CPU_FREQ_RATED[0], // EFUSE_RD_CHIP_CPU_FREQ_RATED + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[] = { + &CHIP_VER_REV1[0], // EFUSE_RD_CHIP_VER_REV1 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[] = { + &XPD_SDIO_REG[0], // EFUSE_RD_XPD_SDIO_REG + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[] = { + &SDIO_TIEH[0], // EFUSE_RD_SDIO_TIEH + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[] = { + &SDIO_FORCE[0], // EFUSE_RD_SDIO_FORCE + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC_VREF_AND_SDIO_DREF[] = { + &ADC_VREF_AND_SDIO_DREF[0], // EFUSE_RD_ADC_VREF[0..4] or ( SDIO_DREFH[0 1] + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_LOW[] = { + &ADC1_TP_LOW[0], // TP_REG EFUSE_RD_ADC1_TP_LOW + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_LOW[] = { + &ADC2_TP_LOW[0], // TP_REG EFUSE_RD_ADC2_TP_LOW + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_HIGH[] = { + &ADC1_TP_HIGH[0], // TP_REG EFUSE_RD_ADC1_TP_HIGH + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_HIGH[] = { + &ADC2_TP_HIGH[0], // TP_REG EFUSE_RD_ADC2_TP_HIGH + NULL +}; + diff --git a/components/efuse/esp32/esp_efuse_table.csv b/components/efuse/esp32/esp_efuse_table.csv new file mode 100644 index 0000000000..8c6db79dd4 --- /dev/null +++ b/components/efuse/esp32/esp_efuse_table.csv @@ -0,0 +1,80 @@ +# field_name, | efuse_block, | bit_start, | bit_count, |comment # +# | (EFUSE_BLK0 | (0..255) | (1..256) | # +# | EFUSE_BLK1 | | | # +# | EFUSE_BLK2 | | | # +# | EFUSE_BLK3) | | | # +########################################################################## +# !!!!!!!!!!! # +# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table" +# this will generate new source files, next rebuild all the sources. +# !!!!!!!!!!! # + +# Factory MAC address # +####################### +MAC_FACTORY, EFUSE_BLK0, 72, 8, Factory MAC addr [0] +, EFUSE_BLK0, 64, 8, Factory MAC addr [1] +, EFUSE_BLK0, 56, 8, Factory MAC addr [2] +, EFUSE_BLK0, 48, 8, Factory MAC addr [3] +, EFUSE_BLK0, 40, 8, Factory MAC addr [4] +, EFUSE_BLK0, 32, 8, Factory MAC addr [5] +MAC_FACTORY_CRC, EFUSE_BLK0, 80, 8, CRC8 for factory MAC address + +# Custom MAC address # +###################### +MAC_CUSTOM_CRC, EFUSE_BLK3, 0, 8, CRC8 for custom MAC address. +MAC_CUSTOM, EFUSE_BLK3, 8, 48, Custom MAC +MAC_CUSTOM_VER, EFUSE_BLK3, 184, 8, Custom MAC version + +# Security boot # +################# +SECURE_BOOT_KEY, EFUSE_BLK2, 0, 256, Security boot. Key. +ABS_DONE_0, EFUSE_BLK0, 196, 1, Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0 + +# Flash encrypt # +################# +ENCRYPT_FLASH_KEY, EFUSE_BLK1, 0, 256, Flash encrypt. Key. +ENCRYPT_CONFIG, EFUSE_BLK0, 188, 4, Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M + +DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT. +DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT. +DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE. +DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG. +CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE. +FLASH_CRYPT_CNT, EFUSE_BLK0, 20, 8, Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT. + +# Write protection # +#################### +WR_DIS_FLASH_CRYPT_CNT, EFUSE_BLK0, 2, 1, Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT +WR_DIS_BLK1, EFUSE_BLK0, 7, 1, Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1 +WR_DIS_BLK2, EFUSE_BLK0, 8, 1, Security boot. Write protection security key. EFUSE_WR_DIS_BLK2 +WR_DIS_BLK3, EFUSE_BLK0, 9, 1, Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3 + +# Read protection # +################### +RD_DIS_BLK1, EFUSE_BLK0, 16, 1, Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1 +RD_DIS_BLK2, EFUSE_BLK0, 17, 1, Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2 +RD_DIS_BLK3, EFUSE_BLK0, 18, 1, Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3 + +# Chip info # +############# +CHIP_VER_DIS_APP_CPU, EFUSE_BLK0, 96, 1, EFUSE_RD_CHIP_VER_DIS_APP_CPU +CHIP_VER_DIS_BT, EFUSE_BLK0, 97, 1, EFUSE_RD_CHIP_VER_DIS_BT +CHIP_VER_PKG, EFUSE_BLK0, 105, 3, EFUSE_RD_CHIP_VER_PKG +CHIP_CPU_FREQ_LOW, EFUSE_BLK0, 108, 1, EFUSE_RD_CHIP_CPU_FREQ_LOW +CHIP_CPU_FREQ_RATED, EFUSE_BLK0, 109, 1, EFUSE_RD_CHIP_CPU_FREQ_RATED +CHIP_VER_REV1, EFUSE_BLK0, 111, 1, EFUSE_RD_CHIP_VER_REV1 +XPD_SDIO_REG, EFUSE_BLK0, 142, 1, EFUSE_RD_XPD_SDIO_REG +SDIO_TIEH, EFUSE_BLK0, 143, 1, EFUSE_RD_SDIO_TIEH +SDIO_FORCE, EFUSE_BLK0, 144, 1, EFUSE_RD_SDIO_FORCE + +#SDIO_DREFH, EFUSE_BLK0, 136, 2, EFUSE_RD_SDIO_DREFH +#SDIO_DREFM, EFUSE_BLK0, 138, 2, EFUSE_RD_SDIO_DREFM +#SDIO_DREFL, EFUSE_BLK0, 140, 2, EFUSE_RD_SDIO_DREFL + +# esp_adc_cal # +############### +ADC_VREF_AND_SDIO_DREF, EFUSE_BLK0, 136, 6, EFUSE_RD_ADC_VREF[0..4] or ( SDIO_DREFH[0 1], SDIO_DREFM[2 3], SDIO_DREFL[4 5] ) +ADC1_TP_LOW, EFUSE_BLK3, 96, 7, TP_REG EFUSE_RD_ADC1_TP_LOW +ADC2_TP_LOW, EFUSE_BLK3, 112, 7, TP_REG EFUSE_RD_ADC2_TP_LOW +ADC1_TP_HIGH, EFUSE_BLK3, 103, 9, TP_REG EFUSE_RD_ADC1_TP_HIGH +ADC2_TP_HIGH, EFUSE_BLK3, 119, 9, TP_REG EFUSE_RD_ADC2_TP_HIGH diff --git a/components/efuse/esp32/include/esp_efuse_table.h b/components/efuse/esp32/include/esp_efuse_table.h new file mode 100644 index 0000000000..c7e7c44481 --- /dev/null +++ b/components/efuse/esp32/include/esp_efuse_table.h @@ -0,0 +1,66 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at", +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#ifdef __cplusplus +extern "C" { +#endif + + +// md5_digest 963d6d14dc4bd997fd5d4b9de351745d +// This file was generated automatically from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_table.csv file then build system will generate this header file +// To show efuse_table run the command 'make show_efuse_table'. + + +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY[]; +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY_CRC[]; +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_CRC[]; +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM[]; +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_VER[]; +extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ABS_DONE_0[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_FLASH_KEY[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_CONFIG[]; +extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_ENCRYPT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_DECRYPT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_CACHE[]; +extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_JTAG[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CONSOLE_DEBUG_DISABLE[]; +extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_CRYPT_CNT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK1[]; +extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK2[]; +extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK3[]; +extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK1[]; +extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK2[]; +extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK3[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_APP_CPU[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_BT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[]; +extern const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[]; +extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[]; +extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC_VREF_AND_SDIO_DREF[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_LOW[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_LOW[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_HIGH[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_HIGH[]; + +#ifdef __cplusplus +} +#endif + diff --git a/components/efuse/esp32/sources.cmake b/components/efuse/esp32/sources.cmake new file mode 100644 index 0000000000..492216be21 --- /dev/null +++ b/components/efuse/esp32/sources.cmake @@ -0,0 +1 @@ +set(EFUSE_SOC_SRCS "esp_efuse_table.c") \ No newline at end of file diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h new file mode 100644 index 0000000000..3ea1680ed9 --- /dev/null +++ b/components/efuse/include/esp_efuse.h @@ -0,0 +1,294 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP_EFUSE_MANAGER_H_ +#define _ESP_EFUSE_MANAGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_err.h" +#include "esp_log.h" + +#define ESP_ERR_EFUSE 0x1600 /*!< Base error code for efuse api. */ +#define ESP_OK_EFUSE_CNT (ESP_ERR_EFUSE + 0x01) /*!< OK the required number of bits is set. */ +#define ESP_ERR_EFUSE_CNT_IS_FULL (ESP_ERR_EFUSE + 0x02) /*!< Error field is full. */ +#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. */ + +/** + * @brief Type of eFuse blocks + */ +typedef enum { + EFUSE_BLK0 = 0, /**< Number of eFuse block. Reserved. */ + EFUSE_BLK1 = 1, /**< Number of eFuse block. Used for Flash Encryption. If not using that Flash Encryption feature, they can be used for another purpose. */ + EFUSE_BLK2 = 2, /**< Number of eFuse block. Used for Secure Boot. If not using that Secure Boot feature, they can be used for another purpose. */ + EFUSE_BLK3 = 3 /**< Number of eFuse block. Uses for the purpose of the user. */ +} esp_efuse_block_t; + +/** + * @brief Type of coding scheme + */ +typedef enum { + EFUSE_CODING_SCHEME_NONE = 0, /**< None */ + EFUSE_CODING_SCHEME_3_4 = 1, /**< 3/4 coding */ + EFUSE_CODING_SCHEME_REPEAT = 2, /**< Repeat coding */ +} esp_efuse_coding_scheme_t; + +/** +* @brief Structure eFuse field + */ +typedef struct { + esp_efuse_block_t efuse_block; /**< Block of eFuse */ + uint16_t bit_start; /**< Start bit [0..255] */ + uint16_t bit_count; /**< Length of bit field [1..256]*/ +} esp_efuse_desc_t; + +/** + * @brief Reads bits from EFUSE field and writes it into an array. + * + * The number of read bits will be limited to the minimum value + * from the description of the bits in "field" structure or "dst_size_bits" required size. + * Use "esp_efuse_get_field_size()" function to determine the length of the field. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[out] dst A pointer to array that will contain the result of reading. + * @param[in] dst_size_bits The number of bits required to read. + * If the requested number of bits is greater than the field, + * the number will be limited to the field size. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + */ +esp_err_t esp_efuse_read_field_blob(const esp_efuse_desc_t* field[], void* dst, size_t dst_size_bits); + +/** + * @brief Reads bits from EFUSE field and returns number of bits programmed as "1". + * + * If the bits are set not sequentially, they will still be counted. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[out] out_cnt A pointer that will contain the number of programmed as "1" bits. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + */ +esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_cnt); + +/** + * @brief Writes array to EFUSE field. + * + * The number of write bits will be limited to the minimum value + * from the description of the bits in "field" structure or "src_size_bits" required size. + * Use "esp_efuse_get_field_size()" function to determine the length of the field. + * After the function is completed, the writing registers are cleared. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[in] src A pointer to array that contains the data for writing. + * @param[in] src_size_bits The number of bits required to write. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits is strictly forbidden. + * - ESP_ERR_CODING: Error range of data does not match the coding scheme. + */ +esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void* src, size_t src_size_bits); + +/** + * @brief Writes a required count of bits as "1" to EFUSE field. + * + * If there are no free bits in the field to set the required number of bits to "1", + * ESP_ERR_EFUSE_CNT_IS_FULL error is returned, the field will not be partially recorded. + * After the function is completed, the writing registers are cleared. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[in] cnt Required number of programmed as "1" bits. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_EFUSE_CNT_IS_FULL: Not all requested cnt bits is set. + */ +esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt); + +/** + * @brief Returns the number of bits used by field. + * + * @param[in] field A pointer to the structure describing the fields of efuse. + * + * @return Returns the number of bits used by field. + */ +esp_err_t esp_efuse_get_field_size(const esp_efuse_desc_t* field[]); + +/** + * @brief Returns value of efuse register. + * + * This is a thread-safe implementation. + * Example: EFUSE_BLK2_RDATA3_REG where (blk=2, num_reg=3) + * @param[in] blk Block number of eFuse. + * @param[in] num_reg The register number in the block. + * + * @return Value of register + */ +uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg); + +/** + * @brief Write value to efuse register. + * + * Apply a coding scheme if necessary. + * This is a thread-safe implementation. + * Example: EFUSE_BLK3_WDATA0_REG where (blk=3, num_reg=0) + * @param[in] blk Block number of eFuse. + * @param[in] num_reg The register number in the block. + * @param[in] val Value to write. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits is strictly forbidden. + */ +esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val); + +/** + * @brief Return efuse coding_scheme for blocks. + * + * @param[in] blk Block number of eFuse. + * @return Return efuse coding_scheme for blocks + */ +esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk); + +/** + * @brief Read key to efuse block starting at the offset and the required size. + * + * @param[in] blk Block number of eFuse. + * @param[in] dst_key A pointer to array that will contain the result of reading. + * @param[in] offset_in_bits Start bit in block. + * @param[in] size_bits The number of bits required to read. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_CODING: Error range of data does not match the coding scheme. + */ +esp_err_t esp_efuse_read_block(esp_efuse_block_t blk, void* dst_key, size_t offset_in_bits, size_t size_bits); + +/** + * @brief Write key to efuse block starting at the offset and the required size. + * + * @param[in] blk Block number of eFuse. + * @param[in] src_key A pointer to array that contains the key for writing. + * @param[in] offset_in_bits Start bit in block. + * @param[in] size_bits The number of bits required to write. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_CODING: Error range of data does not match the coding scheme. + * - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits + */ +esp_err_t esp_efuse_write_block(esp_efuse_block_t blk, const void* src_key, size_t offset_in_bits, size_t size_bits); + +/** + * @brief Returns chip version from efuse + * + * @return chip version + */ +uint8_t esp_efuse_get_chip_ver(void); + +/** + * @brief Returns chip package from efuse + * + * @return chip package + */ +uint32_t esp_efuse_get_pkg_ver(void); + +/* @brief Permanently update values written to the efuse write registers + * + * After updating EFUSE_BLKx_WDATAx_REG registers with new values to + * write, call this function to permanently write them to efuse. + * + * @note Setting bits in efuse is permanent, they cannot be unset. + * + * @note Due to this restriction you don't need to copy values to + * Efuse write registers from the matching read registers, bits which + * are set in the read register but unset in the matching write + * register will be unchanged when new values are burned. + * + * @note This function is not threadsafe, if calling code updates + * efuse values from multiple tasks then this is caller's + * responsibility to serialise. + * + * After burning new efuses, the read registers are updated to match + * the new efuse values. + */ +void esp_efuse_burn_new_values(void); + +/* @brief Reset efuse write registers + * + * Efuse write registers are written to zero, to negate + * any changes that have been staged here. + * + * @note This function is not threadsafe, if calling code updates + * efuse values from multiple tasks then this is caller's + * responsibility to serialise. + */ +void esp_efuse_reset(void); + +/* @brief Disable BASIC ROM Console via efuse + * + * By default, if booting from flash fails the ESP32 will boot a + * BASIC console in ROM. + * + * Call this function (from bootloader or app) to permanently + * disable the console on this chip. + */ +void esp_efuse_disable_basic_rom_console(void); + +/* @brief Encode one or more sets of 6 byte sequences into + * 8 bytes suitable for 3/4 Coding Scheme. + * + * This function is only useful if the CODING_SCHEME efuse + * is set to value 1 for 3/4 Coding Scheme. + * + * @param[in] in_bytes Pointer to a sequence of bytes to encode for 3/4 Coding Scheme. Must have length in_bytes_len. After being written to hardware, these bytes will read back as little-endian words. + * @param[out] out_words Pointer to array of words suitable for writing to efuse write registers. Array must contain 2 words (8 bytes) for every 6 bytes in in_bytes_len. Can be a pointer to efuse write registers. + * @param in_bytes_len. Length of array pointed to by in_bytes, in bytes. Must be a multiple of 6. + * + * @return ESP_ERR_INVALID_ARG if either pointer is null or in_bytes_len is not a multiple of 6. ESP_OK otherwise. + */ +esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len); + +/* @brief Write random data to efuse key block write registers + * + * @note Caller is responsible for ensuring efuse + * block is empty and not write protected, before calling. + * + * @note Behaviour depends on coding scheme: a 256-bit key is + * generated and written for Coding Scheme "None", a 192-bit key + * is generated, extended to 256-bits by the Coding Scheme, + * and then writtten for 3/4 Coding Scheme. + * + * @note This function does not burn the new values, caller should + * call esp_efuse_burn_new_values() when ready to do this. + * + * @param blk_wdata0_reg Address of the first data write register + * in the block + */ +void esp_efuse_write_random_key(uint32_t blk_wdata0_reg); + +#ifdef __cplusplus +} +#endif + +#endif // _ESP_EFUSE_MANAGER_H_ diff --git a/components/efuse/src/esp_efuse_api.c b/components/efuse/src/esp_efuse_api.c new file mode 100644 index 0000000000..709985786d --- /dev/null +++ b/components/efuse/src/esp_efuse_api.c @@ -0,0 +1,214 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_efuse.h" +#include "esp_efuse_utility.h" +#include "soc/efuse_reg.h" +#include "assert.h" +#include "sdkconfig.h" + +const static char *TAG = "efuse"; + +#if defined(BOOTLOADER_BUILD) +#define EFUSE_LOCK_ACQUIRE() +#define EFUSE_LOCK_RELEASE() +#else +#include +static _lock_t s_efuse_lock; +#define EFUSE_LOCK_ACQUIRE() _lock_acquire(&s_efuse_lock) +#define EFUSE_LOCK_RELEASE() _lock_release(&s_efuse_lock) +#endif + +// Public API functions + +// 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(); + 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); + } + EFUSE_LOCK_RELEASE(); + return err; +} + +// 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(); + 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); + } + EFUSE_LOCK_RELEASE(); + return err; +} + +// write array to EFUSE +esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void* src, size_t src_size_bits) +{ + EFUSE_LOCK_ACQUIRE(); + esp_err_t err = ESP_OK; + if (field == NULL || src == NULL || src_size_bits == 0) { + err = ESP_ERR_INVALID_ARG; + } else { + esp_efuse_utility_reset(); + err = esp_efuse_utility_process(field, (void*)src, src_size_bits, esp_efuse_utility_write_blob); + + if (err == ESP_OK) { + err = esp_efuse_utility_apply_new_coding_scheme(); + if (err == ESP_OK) { + esp_efuse_utility_burn_efuses(); + } + } + esp_efuse_utility_reset(); + } + EFUSE_LOCK_RELEASE(); + return err; +} + +// program cnt bits to "1" +esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt) +{ + EFUSE_LOCK_ACQUIRE(); + esp_err_t err = ESP_OK; + if (field == NULL || cnt == 0) { + err = ESP_ERR_INVALID_ARG; + } else { + esp_efuse_utility_reset(); + err = esp_efuse_utility_process(field, &cnt, 0, esp_efuse_utility_write_cnt); + + if (cnt != 0) { + ESP_LOGE(TAG, "The required number of bits can not be set. [Not set %d]", cnt); + err = ESP_ERR_EFUSE_CNT_IS_FULL; + } + + if (err == ESP_OK_EFUSE_CNT || err == ESP_OK) { + err = esp_efuse_utility_apply_new_coding_scheme(); + if (err == ESP_OK) { + esp_efuse_utility_burn_efuses(); + } + } + esp_efuse_utility_reset(); + } + EFUSE_LOCK_RELEASE(); + return err; +} + +// get the length of the field in bits +int esp_efuse_get_field_size(const esp_efuse_desc_t* field[]) +{ + assert(field != NULL); + int bits_counter = 0; + int i = 0; + while (field[i] != NULL) { + bits_counter += field[i]->bit_count; + ++i; + } + return bits_counter; +} + +// reading efuse register. +uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg) +{ + EFUSE_LOCK_ACQUIRE(); + uint32_t ret_val = esp_efuse_utility_read_reg(blk, num_reg); + EFUSE_LOCK_RELEASE(); + return ret_val; +} + +// writing efuse register. +esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val) +{ + EFUSE_LOCK_ACQUIRE(); + esp_efuse_utility_reset(); + esp_err_t err = esp_efuse_utility_write_reg(blk, num_reg, val); + if (err == ESP_OK) { + err = esp_efuse_utility_apply_new_coding_scheme(); + if (err == ESP_OK) { + esp_efuse_utility_burn_efuses(); + } + } + esp_efuse_utility_reset(); + EFUSE_LOCK_RELEASE(); + return err; +} + +// get efuse coding_scheme. +esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk) +{ + esp_efuse_coding_scheme_t scheme; + if (blk == EFUSE_BLK0) { + scheme = EFUSE_CODING_SCHEME_NONE; + } else { + uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME); + if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE || + coding_scheme == (EFUSE_CODING_SCHEME_VAL_34 | EFUSE_CODING_SCHEME_VAL_REPEAT)) { + scheme = EFUSE_CODING_SCHEME_NONE; + } else if (coding_scheme == EFUSE_CODING_SCHEME_VAL_34) { + scheme = EFUSE_CODING_SCHEME_3_4; + } else { + scheme = EFUSE_CODING_SCHEME_REPEAT; + } + } + ESP_LOGD(TAG, "coding scheme %d", scheme); + return scheme; +} + +// This function reads the key from the efuse block, starting at the offset and the required size. +esp_err_t esp_efuse_read_block(esp_efuse_block_t blk, void* dst_key, size_t offset_in_bits, size_t size_bits) +{ + esp_err_t err = ESP_OK; + if (blk == EFUSE_BLK0 || blk > EFUSE_BLK3 || dst_key == NULL || size_bits == 0) { + err = ESP_ERR_INVALID_ARG; + } else { + const esp_efuse_desc_t field_desc[] = { + {blk, offset_in_bits, size_bits}, + }; + + const esp_efuse_desc_t* field[] = { + &field_desc[0], + NULL + }; + err = esp_efuse_read_field_blob(field, dst_key, size_bits); + } + return err; +} + +// This function writes the key from the efuse block, starting at the offset and the required size. +esp_err_t esp_efuse_write_block(esp_efuse_block_t blk, const void* src_key, size_t offset_in_bits, size_t size_bits) +{ + esp_err_t err = ESP_OK; + if (blk == EFUSE_BLK0 || blk > EFUSE_BLK3 || src_key == NULL || size_bits == 0) { + err = ESP_ERR_INVALID_ARG; + } else { + const esp_efuse_desc_t field_desc[] = { + {blk, offset_in_bits, size_bits}, + }; + + const esp_efuse_desc_t* field[] = { + &field_desc[0], + NULL + }; + err = esp_efuse_write_field_blob(field, src_key, size_bits); + } + return err; +} diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c new file mode 100644 index 0000000000..2741d0f393 --- /dev/null +++ b/components/efuse/src/esp_efuse_fields.c @@ -0,0 +1,117 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_efuse.h" +#include "esp_efuse_utility.h" +#include "esp_efuse_table.h" +#include "stdlib.h" +#include "esp_types.h" +#include "rom/efuse.h" +#include "assert.h" +#include "esp_err.h" +#include "esp_log.h" +#include "soc/efuse_reg.h" +#include "bootloader_random.h" + +const static char *TAG = "efuse"; + +// Contains functions that provide access to efuse fields which are often used in IDF. + +// Returns chip version from efuse +uint8_t esp_efuse_get_chip_ver(void) +{ + uint8_t chip_ver; + esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &chip_ver, 1); + return chip_ver; +} + +// Returns chip package from efuse +uint32_t esp_efuse_get_pkg_ver(void) +{ + uint32_t pkg_ver; + esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_PKG, &pkg_ver, 3); + return pkg_ver; +} + +// Permanently update values written to the efuse write registers +void esp_efuse_burn_new_values(void) +{ + esp_efuse_utility_burn_efuses(); +} + +// Reset efuse write registers +void esp_efuse_reset(void) +{ + esp_efuse_utility_reset(); +} + +// Disable BASIC ROM Console via efuse +void esp_efuse_disable_basic_rom_console(void) +{ + if (esp_efuse_write_field_cnt(ESP_EFUSE_CONSOLE_DEBUG_DISABLE, 1) == ESP_OK) { + ESP_EARLY_LOGI(TAG, "Disable BASIC ROM Console fallback via efuse..."); + } +} + +esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len) +{ + if (in_bytes == NULL || out_words == NULL || in_bytes_len % 6 != 0) { + return ESP_ERR_INVALID_ARG; + } + + while (in_bytes_len > 0) { + uint8_t out[8]; + uint8_t xor = 0; + uint8_t mul = 0; + for (int i = 0; i < 6; i++) { + xor ^= in_bytes[i]; + mul += (i + 1) * __builtin_popcount(in_bytes[i]); + } + + memcpy(out, in_bytes, 6); // Data bytes + out[6] = xor; + out[7] = mul; + + memcpy(out_words, out, 8); + + in_bytes_len -= 6; + in_bytes += 6; + out_words += 2; + } + + return ESP_OK; +} + +void esp_efuse_write_random_key(uint32_t blk_wdata0_reg) +{ + uint32_t buf[8]; + uint8_t raw[24]; + uint32_t coding_scheme = REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M; + + if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE) { + bootloader_fill_random(buf, sizeof(buf)); + } else { // 3/4 Coding Scheme + bootloader_fill_random(raw, sizeof(raw)); + esp_err_t r = esp_efuse_apply_34_encoding(raw, buf, sizeof(raw)); + assert(r == ESP_OK); + } + + ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg); + for (int i = 0; i < 8; i++) { + ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]); + REG_WRITE(blk_wdata0_reg + 4*i, buf[i]); + } + bzero(buf, sizeof(buf)); + bzero(raw, sizeof(raw)); +} diff --git a/components/efuse/src/esp_efuse_utility.c b/components/efuse/src/esp_efuse_utility.c new file mode 100644 index 0000000000..fa360e46ba --- /dev/null +++ b/components/efuse/src/esp_efuse_utility.c @@ -0,0 +1,512 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_efuse_utility.h" + +#include "soc/efuse_reg.h" +#include "esp_log.h" +#include "assert.h" +#include "sdkconfig.h" +#include + +static const char *TAG = "efuse"; + +#define COUNT_EFUSE_BLOCKS 4 /* The number of blocks. */ +#define COUNT_EFUSE_REG_PER_BLOCK 8 /* The number of registers per block. */ +#define EFUSE_CONF_WRITE 0x5A5A /* eFuse_pgm_op_ena, force no rd/wr disable. */ +#define EFUSE_CONF_READ 0x5AA5 /* eFuse_read_op_ena, release force. */ +#define EFUSE_CMD_PGM 0x02 /* Command to program. */ +#define EFUSE_CMD_READ 0x01 /* Command to read. */ + +// Array for emulate efuse registers. +#ifdef CONFIG_EFUSE_VIRTUAL +static uint32_t virt_blocks[COUNT_EFUSE_BLOCKS][COUNT_EFUSE_REG_PER_BLOCK]; +#endif + +/** + * @brief Structure range address by blocks + */ +typedef struct { + uint32_t start; + uint32_t end; +} esp_efuse_range_addr_t; + +/*Range addresses to read blocks*/ +static const esp_efuse_range_addr_t range_read_addr_blocks[] = { + {EFUSE_BLK0_RDATA0_REG, EFUSE_BLK0_RDATA6_REG}, // range address of EFUSE_BLK0 + {EFUSE_BLK1_RDATA0_REG, EFUSE_BLK1_RDATA7_REG}, // range address of EFUSE_BLK1 + {EFUSE_BLK2_RDATA0_REG, EFUSE_BLK2_RDATA7_REG}, // range address of EFUSE_BLK2 + {EFUSE_BLK3_RDATA0_REG, EFUSE_BLK3_RDATA7_REG} // range address of EFUSE_BLK3 +}; + +/*Range addresses to write blocks*/ +static const esp_efuse_range_addr_t range_write_addr_blocks[] = { + {EFUSE_BLK0_WDATA0_REG, EFUSE_BLK0_WDATA6_REG}, // range address of EFUSE_BLK0 + {EFUSE_BLK1_WDATA0_REG, EFUSE_BLK1_WDATA7_REG}, // range address of EFUSE_BLK1 + {EFUSE_BLK2_WDATA0_REG, EFUSE_BLK2_WDATA7_REG}, // range address of EFUSE_BLK2 + {EFUSE_BLK3_WDATA0_REG, EFUSE_BLK3_WDATA7_REG} // range address of EFUSE_BLK3 +}; + +static int get_reg_num(int bit_start, int bit_count, int i_reg); +static int get_starting_bit_num_in_reg(int bit_start, int i_reg); +static uint32_t get_mask(unsigned int bit_count, unsigned int shift); +static int get_count_bits_in_reg(int bit_start, int bit_count, int i_reg); +static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value); +static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob); +static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt); +static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits); + +// This function processes the field by calling the passed function. +esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, size_t ptr_size_bits, efuse_func_proc_t func_proc) +{ + esp_err_t err = ESP_OK; + int bits_counter = 0; + + // get and check size. + int field_len = esp_efuse_get_field_size(field); + int req_size = (ptr_size_bits == 0) ? field_len : MIN(ptr_size_bits, field_len); + + int i = 0; + 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_LOGE(TAG, "Range of data does not match the coding scheme"); + err = ESP_ERR_CODING; + } + int i_reg = 0; + int num_reg; + while (err == ESP_OK && req_size > bits_counter && + (num_reg = get_reg_num(field[i]->bit_start, field[i]->bit_count, i_reg)) != -1) { + + int start_bit = get_starting_bit_num_in_reg(field[i]->bit_start, i_reg); + int num_bits = get_count_bits_in_reg(field[i]->bit_start, field[i]->bit_count, i_reg); + if ((bits_counter + num_bits) > req_size) { // Limits the length of the field. + num_bits = req_size - bits_counter; + } + ESP_LOGD(TAG, "In EFUSE_BLK%d__DATA%d_REG is used %d bits starting with %d bit", + (int)field[i]->efuse_block, num_reg, num_bits, start_bit); + err = func_proc(num_reg, field[i]->efuse_block, start_bit, num_bits, ptr, &bits_counter); + ++i_reg; + } + i++; + } + assert(bits_counter <= req_size); + return err; +} + + +// Read efuse register and write this value to array. +esp_err_t esp_efuse_utility_fill_buff(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_out, int* bits_counter) +{ + uint8_t* blob = (uint8_t *) arr_out; + uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg); + uint64_t reg_of_aligned_bits = (reg >> bit_start) & get_mask(bit_count, 0); + + int shift_bit = (*bits_counter) % 8; + if (shift_bit != 0) { + blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits << shift_bit); + shift_bit = ((8 - shift_bit) < bit_count) ? (8 - shift_bit) : bit_count; + (*bits_counter) += shift_bit; + bit_count -= shift_bit; + } + + int sum_shift = 0; + while (bit_count > 0) { + sum_shift += shift_bit; + blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits >> sum_shift); + shift_bit = (bit_count > 8) ? 8 : bit_count; + (*bits_counter) += shift_bit; + bit_count -= shift_bit; + }; + return ESP_OK; +} + +// Count a set bits. +esp_err_t esp_efuse_utility_count_once(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* out_cnt, int* bits_counter) +{ + uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg); + *((size_t *)out_cnt) += __builtin_popcount(reg & get_mask(bit_count, bit_start)); // Returns the number of 1-bits in reg. + *bits_counter += bit_count; + return ESP_OK; +} + +// Fill registers from array for writing. +esp_err_t esp_efuse_utility_write_blob(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_in, int* bits_counter) +{ + uint32_t reg_to_write = fill_reg(bit_start, bit_count, (uint8_t *)arr_in, bits_counter); + return esp_efuse_utility_write_reg(efuse_block, num_reg, reg_to_write); +} + +// fill registers with the required number of bits for writing. +esp_err_t esp_efuse_utility_write_cnt(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* cnt, int* bits_counter) +{ + esp_err_t err = ESP_OK; + uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg); + size_t* set_bits = (size_t*)cnt; + uint32_t mask = get_mask(bit_count, bit_start); + uint32_t reg_masked_bits = reg & mask; + if ((reg_masked_bits ^ mask) != 0) {// register has free bits to set them to 1? + uint32_t reg_to_write = set_cnt_in_reg(bit_start, bit_count, reg_masked_bits, set_bits); + write_reg(efuse_block, num_reg, reg_to_write); + } + *bits_counter += bit_count; + if ((*set_bits) == 0) { + err = ESP_OK_EFUSE_CNT; + } + return err; +} + +// Reset efuse write registers +void esp_efuse_utility_reset(void) +{ + REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ); + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; 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); + } + } +} + +// Burn values written to the efuse write registers +void esp_efuse_utility_burn_efuses(void) +{ +#ifdef CONFIG_EFUSE_VIRTUAL + ESP_LOGE(TAG, "Not really burning any efuses!"); + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block); + if (scheme == EFUSE_CODING_SCHEME_3_4) { + uint8_t buf[COUNT_EFUSE_REG_PER_BLOCK * 4] = { 0 }; + int i = 0; + 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, ++i) { + *((uint32_t*)buf + i) = REG_READ(addr_wr_block); + } + int j = 0; + uint32_t out_buf[COUNT_EFUSE_REG_PER_BLOCK] = { 0 }; + for (int k = 0; k < 4; ++k, ++j) { + memcpy((uint8_t*)out_buf + j * 6, &buf[k * 8], 6); + } + for (int k = 0; k < COUNT_EFUSE_REG_PER_BLOCK; ++k) { + REG_WRITE(range_write_addr_blocks[num_block].start + k * 4, out_buf[k]); + } + } + int subblock = 0; + 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) { + virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block); + } + } +#else + // Permanently update values written to the efuse write registers + REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE); + REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM); + while (REG_READ(EFUSE_CMD_REG) != 0) {}; + REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ); + REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_READ); + while (REG_READ(EFUSE_CMD_REG) != 0) {}; +#endif + esp_efuse_utility_reset(); +} + + +// Erase the virt_blocks array. +void esp_efuse_utility_erase_virt_blocks() +{ +#ifdef CONFIG_EFUSE_VIRTUAL + memset(virt_blocks, 0, sizeof(virt_blocks)); +#endif +} + +// Fills the virt_blocks array by values from efuse_Rdata. +void esp_efuse_utility_update_virt_blocks() +{ +#ifdef CONFIG_EFUSE_VIRTUAL + ESP_LOGI(TAG, "Emulate efuse is enabled"); + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + int subblock = 0; + for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) { + virt_blocks[num_block][subblock++] = REG_READ(addr_rd_block); + } + ESP_LOGD(TAG, "virt_blocks[%d] is filled by EFUSE_BLOCK%d", num_block, num_block); + } +#else + ESP_LOGI(TAG, "Emulate efuse is disabled"); +#endif +} + +// Prints efuse values for all registers. +void esp_efuse_utility_debug_dump_blocks() +{ + printf("EFUSE_BLKx:\n"); +#ifdef CONFIG_EFUSE_VIRTUAL + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + int num_reg = 0; + printf("%d) ", num_block); + for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, num_reg++) { + printf("0x%08x ", virt_blocks[num_block][num_reg]); + } + printf("\n"); + } +#else + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + printf("%d) ", num_block); + for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) { + printf("0x%08x ", REG_READ(addr_rd_block)); + } + printf("\n"); + } +#endif + printf("\n"); +} + +// returns the number of array elements for placing these bits in an array with the length of each element equal to size_of_base. +int esp_efuse_utility_get_number_of_items(int bits, int size_of_base) +{ + return bits / size_of_base + (bits % size_of_base > 0 ? 1 : 0); +} + +// Writing efuse register with checking of repeated programming of programmed bits. +esp_err_t esp_efuse_utility_write_reg(esp_efuse_block_t efuse_block, unsigned int num_reg, uint32_t reg_to_write) +{ + esp_err_t err = ESP_OK; + uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg); + if (reg & reg_to_write) { + ESP_LOGE(TAG, "Repeated programming of programmed bits is strictly forbidden 0x%08x", reg & reg_to_write); + err = ESP_ERR_EFUSE_REPEATED_PROG; + } else { + write_reg(efuse_block, num_reg, reg_to_write); + } + return err; +} + +// Reading efuse register. +uint32_t esp_efuse_utility_read_reg(esp_efuse_block_t blk, unsigned int num_reg) +{ + assert(blk >= 0 && blk <= 3); + if (blk == 0) { + assert(num_reg <= 6); + } else { + assert(num_reg <= 7); + } + + uint32_t value; +#ifdef CONFIG_EFUSE_VIRTUAL + value = virt_blocks[blk][num_reg]; +#else + value = REG_READ(range_read_addr_blocks[blk].start + num_reg * 4); +#endif + return value; +} + +// Private functions + +// writing efuse register. +static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value) +{ + assert(blk >= 0 && blk <= 3); + if (blk == 0) { + assert(num_reg <= 6); + } else { + assert(num_reg <= 7); + } + uint32_t addr_wr_reg = range_write_addr_blocks[blk].start + num_reg * 4; + uint32_t reg_to_write = REG_READ(addr_wr_reg) | value; + // The register can be written in parts so we combine the new value with the one already available. + REG_WRITE(addr_wr_reg, reg_to_write); +} + +// return mask with required the number of ones with shift. +static uint32_t get_mask(unsigned int bit_count, unsigned int shift) +{ + uint32_t mask; + if (bit_count != 32) { + mask = (1 << bit_count) - 1; + } else { + mask = 0xFFFFFFFF; + } + return mask << shift; +} + +// return the register number in the array. return -1 if all registers for field was selected. +static int get_reg_num(int bit_start, int bit_count, int i_reg) +{ + int num_reg = i_reg + bit_start / 32; + + if (num_reg > (bit_start + bit_count - 1) / 32) { + return -1; + } + + return num_reg; +} + +// returns the starting bit number in the register. +static int get_starting_bit_num_in_reg(int bit_start, int i_reg) +{ + return (i_reg == 0) ? bit_start % 32 : 0; +} + +// Returns the number of bits in the register. +static int get_count_bits_in_reg(int bit_start, int bit_count, int i_reg) +{ + int ret_count = 0; + int num_reg = 0; + int last_used_bit = (bit_start + bit_count - 1); + for (int num_bit = bit_start; num_bit <= last_used_bit; ++num_bit) { + ++ret_count; + if ((((num_bit + 1) % 32) == 0) || (num_bit == last_used_bit)) { + if (i_reg == num_reg++) { + return ret_count; + } + ret_count = 0; + } + } + return 0; +} + +// fill efuse register from array. +static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob) +{ + uint32_t reg_to_write = 0; + uint32_t temp_blob_32; + int shift_bit = (*filled_bits_blob) % 8; + if (shift_bit != 0) { + temp_blob_32 = blob[(*filled_bits_blob) / 8] >> shift_bit; + shift_bit = ((8 - shift_bit) < bit_count_in_reg) ? (8 - shift_bit) : bit_count_in_reg; + reg_to_write = temp_blob_32 & get_mask(shift_bit, 0); + (*filled_bits_blob) += shift_bit; + bit_count_in_reg -= shift_bit; + } + + int shift_reg = shift_bit; + while (bit_count_in_reg > 0) { + temp_blob_32 = blob[(*filled_bits_blob) / 8]; + shift_bit = (bit_count_in_reg > 8) ? 8 : bit_count_in_reg; + reg_to_write |= (temp_blob_32 & get_mask(shift_bit, 0)) << shift_reg; + (*filled_bits_blob) += shift_bit; + bit_count_in_reg -= shift_bit; + shift_reg += 8; + }; + return reg_to_write << bit_start_in_reg; +} + +// sets a required count of bits as "1". +static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt) +{ + assert((bit_start_in_reg + bit_count_used_in_reg) <= 32); + uint32_t reg_to_write = 0; + for (int i = bit_start_in_reg; i < bit_start_in_reg + bit_count_used_in_reg; ++i) { + if ((reg_masked & (1 << i)) == 0) { + reg_to_write |= (1 << i); + if (--(*cnt) == 0) { + break; + } + } + } + return reg_to_write; +} + +// check range of bits for any coding scheme. +static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits) +{ + esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(blk); + int max_num_bit = offset_in_bits + size_bits; + if ((scheme == EFUSE_CODING_SCHEME_NONE && max_num_bit > 256) || + (scheme == EFUSE_CODING_SCHEME_3_4 && max_num_bit > 192) || + (scheme == EFUSE_CODING_SCHEME_REPEAT && max_num_bit > 128)) { + return false; + } + return true; +} + +static bool read_w_data_and_check_fill(esp_efuse_block_t num_block, uint32_t *buf_w_data) +{ + bool blk_is_filled = false; + int i = 0; + 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, ++i) { + buf_w_data[i] = REG_READ(addr_wr_block); + if (buf_w_data[i] != 0) { + REG_WRITE(addr_wr_block, 0); + blk_is_filled = true; + } + } + return blk_is_filled; +} + +static void read_r_data(esp_efuse_block_t num_block, uint32_t* buf_r_data) +{ + int i = 0; + for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, ++i) { + buf_r_data[i] = REG_READ(addr_rd_block); + } +} + +// After esp_efuse_write.. functions EFUSE_BLKx_WDATAx_REG were filled is not coded values. +// This function reads EFUSE_BLKx_WDATAx_REG registers, applies coding scheme and writes encoded values back to EFUSE_BLKx_WDATAx_REG. +esp_err_t esp_efuse_utility_apply_new_coding_scheme() +{ + uint8_t buf_w_data[COUNT_EFUSE_REG_PER_BLOCK * 4]; + uint8_t buf_r_data[COUNT_EFUSE_REG_PER_BLOCK * 4]; + uint32_t reg[COUNT_EFUSE_REG_PER_BLOCK]; + // start with EFUSE_BLK1. EFUSE_BLK0 - always uses EFUSE_CODING_SCHEME_NONE. + for (int num_block = 1; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block); + // check and apply a new coding scheme. + if (scheme != EFUSE_CODING_SCHEME_NONE) { + memset(buf_w_data, 0, sizeof(buf_w_data)); + memset((uint8_t*)reg, 0, sizeof(reg)); + if (read_w_data_and_check_fill(num_block, (uint32_t*)buf_w_data) == true) { + read_r_data(num_block, (uint32_t*)buf_r_data); + if (scheme == EFUSE_CODING_SCHEME_3_4) { + if (*((uint32_t*)buf_w_data + 6) != 0 || *((uint32_t*)buf_w_data + 7) != 0) { + return ESP_ERR_CODING; + } + for (int i = 0; i < 24; ++i) { + if (buf_w_data[i] != 0) { + int st_offset_buf = (i / 6) * 6; + // check that place is free. + for (int n = st_offset_buf; n < st_offset_buf + 6; ++n) { + if (buf_r_data[n] != 0) { + ESP_LOGE(TAG, "Bits are not empty. Write operation is forbidden."); + return ESP_ERR_CODING; + } + } + + esp_err_t err = esp_efuse_apply_34_encoding(&buf_w_data[st_offset_buf], reg, 6); + if (err != ESP_OK) { + return err; + } + + int num_reg = (st_offset_buf / 6) * 2; + for (int r = 0; r < 2; r++) { + REG_WRITE(range_write_addr_blocks[num_block].start + (num_reg + r) * 4, reg[r]); + } + i = st_offset_buf + 5; + } + } + } else if (scheme == EFUSE_CODING_SCHEME_REPEAT) { + uint32_t* buf_32 = (uint32_t*)buf_w_data; + for (int i = 4; i < 8; ++i) { + if (*(buf_32 + i) != 0) { + return ESP_ERR_CODING; + } + } + for (int i = 0; i < 4; ++i) { + if (buf_32[i] != 0) { + REG_WRITE(range_write_addr_blocks[num_block].start + i * 4, buf_32[i]); + REG_WRITE(range_write_addr_blocks[num_block].start + (i + 4) * 4, buf_32[i]); + } + } + } + } + } + } + return ESP_OK; +} diff --git a/components/efuse/src/esp_efuse_utility.h b/components/efuse/src/esp_efuse_utility.h new file mode 100644 index 0000000000..18d8b58860 --- /dev/null +++ b/components/efuse/src/esp_efuse_utility.h @@ -0,0 +1,140 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP_EFUSE_UTILITY_H_ +#define _ESP_EFUSE_UTILITY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_types.h" +#include "esp_err.h" +#include "esp_efuse.h" + +/** + * @brief This is type of function that will handle the efuse field register. + * + * @param[in] num_reg The register number in the block. + * @param[in] efuse_block Block number. + * @param[in] bit_start Start bit in the register. + * @param[in] bit_count The number of bits used in the register. + * @param[in/out] arr A pointer to an array or variable. + * @param[in/out] bits_counter Counter bits. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - other efuse component errors. + */ +typedef esp_err_t (*efuse_func_proc_t) (unsigned int num_reg, esp_efuse_block_t efuse_block, int starting_bit_num_in_reg, int num_bits_used_in_reg, void* arr, int* bits_counter); + +/** + * @brief This function processes the field by calling the passed function. + * + * This function selects the field, checks the length, and calls the register processing function. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[in/out] ptr A pointer to an array that is used to read / write from / to the efuse field. + * @param[in] ptr_size_bits The size of the data in bits for the efuse field. if = 0 then read all field bits. + * @param[in] func_proc This is the function that will handle the efuse fields. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - other efuse component errors. + */ +esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, size_t ptr_size_bits, efuse_func_proc_t func_proc); + +/** + * @brief Write register with the required number of "1" bits. + * @param[in/out] cnt The number of bits you need to set in the field. + */ +esp_err_t esp_efuse_utility_write_cnt(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* cnt, int* bits_counter); + +/** + * @brief Fill registers from array for writing. + * @param[in] arr_in A pointer to an array in which the data for the writing. + */ +esp_err_t esp_efuse_utility_write_blob(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_in, int* bits_counter); + +/** + * @brief Count a set bits in register. + * @param[in/out] out_cnt A pointer to size_t variable which will contain the number of "1" bits. + */ +esp_err_t esp_efuse_utility_count_once(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* out_cnt, int* bits_counter); + +/** + * @brief Read efuse register and write this value to array. + * @param[out] arr_out A pointer to array that will contain the result of reading. + */ +esp_err_t esp_efuse_utility_fill_buff(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_out, int* bits_counter); + +/** + * @brief Burn values written to the efuse write registers. + * + * 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_efuses(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". + */ +int esp_efuse_utility_get_number_of_items(int bits, int size_of_base); + +/** + * @brief Reading efuse register. + */ +uint32_t esp_efuse_utility_read_reg(esp_efuse_block_t blk, unsigned int num_reg); + +/** + * @brief Writing efuse register with checking of repeated programming of programmed bits. + */ +esp_err_t esp_efuse_utility_write_reg(unsigned int num_reg, esp_efuse_block_t efuse_block, uint32_t reg_to_write); + +/* @brief Reset efuse write registers + * + * Efuse write registers are written to zero, to negate + * any changes that have been staged here. + */ +void esp_efuse_utility_reset(void); + +/** + * @brief Fills the virt_blocks array by values from efuse_Rdata. + */ +void esp_efuse_utility_update_virt_blocks(); + +/** + * @brief Prints efuse values for all registers. + */ +void esp_efuse_utility_debug_dump_blocks(); + +/** + * @brief Erase the virt_blocks array. + */ +void esp_efuse_utility_erase_virt_blocks(); + +/** + * @brief Apply coding_scheme to write registers. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_CODING: Error range of data does not match the coding scheme. + */ +esp_err_t esp_efuse_utility_apply_new_coding_scheme(); + +#ifdef __cplusplus +} +#endif + +#endif // _ESP_EFUSE_UTILITY_H_ diff --git a/components/efuse/test/CMakeLists.txt b/components/efuse/test/CMakeLists.txt new file mode 100644 index 0000000000..28d0b2e7aa --- /dev/null +++ b/components/efuse/test/CMakeLists.txt @@ -0,0 +1,6 @@ +set(COMPONENT_SRCDIRS ".") +set(COMPONENT_ADD_INCLUDEDIRS "." "include") + +set(COMPONENT_REQUIRES unity test_utils efuse bootloader_support) + +register_component() \ No newline at end of file diff --git a/components/efuse/test/component.mk b/components/efuse/test/component.mk new file mode 100644 index 0000000000..5dda86047d --- /dev/null +++ b/components/efuse/test/component.mk @@ -0,0 +1,6 @@ +# +#Component Makefile +# +COMPONENT_ADD_INCLUDEDIRS := include + +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive diff --git a/components/efuse/test/esp_efuse_test_table.c b/components/efuse/test/esp_efuse_test_table.c new file mode 100644 index 0000000000..92977d7c59 --- /dev/null +++ b/components/efuse/test/esp_efuse_test_table.c @@ -0,0 +1,103 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at", +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#include "esp_efuse.h" +#include "esp_efuse_test_table.h" + +// md5_digest dac4d84347dab29412b8b8713b4b0065 +// This file was generated automatically from the file esp_efuse_test_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_test_table.csv file then build system will generate this header file +// To show efuse_table run the command 'make show_efuse_table'. + + +static const esp_efuse_desc_t TEST1_LEN_8[] = { + {EFUSE_BLK3, 0, 8}, // TEST field, +}; + +static const esp_efuse_desc_t TEST2_LEN_16[] = { + {EFUSE_BLK3, 10, 8}, // TEST field, + {EFUSE_BLK3, 80, 8}, // TEST field, +}; + +static const esp_efuse_desc_t TEST3_LEN_6[] = { + {EFUSE_BLK3, 22, 6}, // TEST field, +}; + +static const esp_efuse_desc_t TEST4_LEN_182[] = { + {EFUSE_BLK1, 22, 49}, // TEST field, + {EFUSE_BLK1, 89, 39}, // TEST field, + {EFUSE_BLK1, 71, 18}, // TEST field, + {EFUSE_BLK1, 0, 16}, // TEST field, + {EFUSE_BLK2, 0, 17}, // TEST field, + {EFUSE_BLK2, 60, 43}, // TEST field, +}; + +static const esp_efuse_desc_t TEST5_LEN_1[] = { + {EFUSE_BLK1, 16, 1}, // TEST field, +}; + +static const esp_efuse_desc_t TEST6_LEN_17[] = { + {EFUSE_BLK1, 17, 1}, // TEST field, + {EFUSE_BLK2, 17, 2}, // TEST field, + {EFUSE_BLK3, 29, 4}, // TEST field, + {EFUSE_BLK2, 31, 3}, // TEST field, + {EFUSE_BLK3, 60, 6}, // TEST field, + {EFUSE_BLK2, 127, 1}, // TEST field, +}; + + + + + +const esp_efuse_desc_t* ESP_EFUSE_TEST1_LEN_8[] = { + &TEST1_LEN_8[0], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST2_LEN_16[] = { + &TEST2_LEN_16[0], // TEST field + &TEST2_LEN_16[1], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST3_LEN_6[] = { + &TEST3_LEN_6[0], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST4_LEN_182[] = { + &TEST4_LEN_182[0], // TEST field + &TEST4_LEN_182[1], // TEST field + &TEST4_LEN_182[2], // TEST field + &TEST4_LEN_182[3], // TEST field + &TEST4_LEN_182[4], // TEST field + &TEST4_LEN_182[5], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST5_LEN_1[] = { + &TEST5_LEN_1[0], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST6_LEN_17[] = { + &TEST6_LEN_17[0], // TEST field + &TEST6_LEN_17[1], // TEST field + &TEST6_LEN_17[2], // TEST field + &TEST6_LEN_17[3], // TEST field + &TEST6_LEN_17[4], // TEST field + &TEST6_LEN_17[5], // TEST field + NULL +}; + diff --git a/components/efuse/test/esp_efuse_test_table.csv b/components/efuse/test/esp_efuse_test_table.csv new file mode 100644 index 0000000000..24798c1a3f --- /dev/null +++ b/components/efuse/test/esp_efuse_test_table.csv @@ -0,0 +1,33 @@ +# field_name, | efuse_block, | bit_start, | bit_count, |comment # +# | (EFUSE_BLK0 | (0..255) | (1..256) | # +# | EFUSE_BLK1 | | | # +# | EFUSE_BLK2 | | | # +# | EFUSE_BLK3) | | | # +########################################################################## + +# To generate a new source files. Run two commands: +# cd ~/esp/esp-idf/components/efuse/ +# ./efuse_table_gen.py test/esp_efuse_test_table.csv + +TEST1_LEN_8, EFUSE_BLK3, 0, 8, TEST field + +TEST2_LEN_16, EFUSE_BLK3, 10, 8, TEST field +, EFUSE_BLK3, 80, 8, TEST field + +TEST3_LEN_6, EFUSE_BLK3, 22, 6, TEST field + +TEST4_LEN_182, EFUSE_BLK1, 22, 49, TEST field +, EFUSE_BLK1, 89, 39, TEST field +, EFUSE_BLK1, 71, 18, TEST field +, EFUSE_BLK1, 0, 16, TEST field +, EFUSE_BLK2, 0, 17, TEST field +, EFUSE_BLK2, 60, 43, TEST field + +TEST5_LEN_1, EFUSE_BLK1, 16, 1, TEST field + +TEST6_LEN_17, EFUSE_BLK1, 17, 1, TEST field +, EFUSE_BLK2, 17, 2, TEST field +, EFUSE_BLK3, 29, 4, TEST field +, EFUSE_BLK2, 31, 3, TEST field +, EFUSE_BLK3, 60, 6, TEST field +, EFUSE_BLK2, 127, 1, TEST field diff --git a/components/efuse/test/include/esp_efuse_test_table.h b/components/efuse/test/include/esp_efuse_test_table.h new file mode 100644 index 0000000000..b47ffaf185 --- /dev/null +++ b/components/efuse/test/include/esp_efuse_test_table.h @@ -0,0 +1,36 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at", +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#ifdef __cplusplus +extern "C" { +#endif + + +// md5_digest dac4d84347dab29412b8b8713b4b0065 +// This file was generated automatically from the file esp_efuse_test_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_test_table.csv file then build system will generate this header file +// To show efuse_table run the command 'make show_efuse_table'. + + +extern const esp_efuse_desc_t* ESP_EFUSE_TEST1_LEN_8[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST2_LEN_16[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST3_LEN_6[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST4_LEN_182[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST5_LEN_1[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST6_LEN_17[]; + +#ifdef __cplusplus +} +#endif + diff --git a/components/efuse/test/test_efuse.c b/components/efuse/test/test_efuse.c new file mode 100644 index 0000000000..c41e2b5e16 --- /dev/null +++ b/components/efuse/test/test_efuse.c @@ -0,0 +1,546 @@ +#include +#include +#include +#include +#include +#include "unity.h" +#include "esp_log.h" +#include +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "../src/esp_efuse_utility.h" +#include "esp_efuse_test_table.h" +#include "rom/efuse.h" +#include "bootloader_random.h" +#include "sdkconfig.h" + +static const char* TAG = "efuse_test"; + +static void test_read_blob(void) +{ + esp_efuse_utility_update_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + uint8_t mac[6]; + + ESP_LOGI(TAG, "1. Read MAC address"); + memset(mac, 0, sizeof(mac)); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, sizeof(mac) * 8)); + TEST_ASSERT_EQUAL_INT(sizeof(mac) * 8, esp_efuse_get_field_size(ESP_EFUSE_MAC_FACTORY)); + ESP_LOGI(TAG, "MAC: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + ESP_LOGI(TAG, "2. Check CRC by MAC"); + uint8_t crc; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY_CRC, &crc, 8)); + TEST_ASSERT_EQUAL_HEX8(crc, esp_crc8(mac, sizeof(mac))); + + ESP_LOGI(TAG, "3. Test check args"); + uint32_t test_var; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, NULL, 1)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &test_var, 0)); + + uint8_t half_byte; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &half_byte, 4)); + TEST_ASSERT_EQUAL_HEX8(mac[0]&0x0F, half_byte); + + uint8_t buff[7] = {0x59}; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &buff, sizeof(buff) * 8)); + TEST_ASSERT_TRUE_MESSAGE(memcmp(mac, buff, sizeof(mac)) == 0, "Operation read blob is not success"); + TEST_ASSERT_EQUAL_HEX8(0, buff[6]); +} + +TEST_CASE("efuse test read_field_blob", "[efuse]") +{ + test_read_blob(); +} + +static void test_read_cnt(void) +{ + esp_efuse_utility_update_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "1. Test check args"); + size_t cnt; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_read_field_cnt(ESP_EFUSE_MAC_FACTORY, NULL)); + + ESP_LOGI(TAG, "2. Read MAC address"); + uint8_t mac[6]; + memset(mac, 0, sizeof(mac)); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, 48)); + + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_MAC_FACTORY, &cnt)); + size_t cnt_summ = 0; + for (int i = 0; i < sizeof(mac); ++i) { + cnt_summ += __builtin_popcount(mac[i]); + } + TEST_ASSERT_EQUAL_INT(cnt_summ, cnt); +} + +TEST_CASE("efuse test read_field_cnt", "[efuse]") +{ + test_read_cnt(); +} + +// If using efuse is real, then turn off writing tests. +#ifdef CONFIG_EFUSE_VIRTUAL +static void test_write_blob(void) +{ + esp_efuse_utility_erase_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "1. Test check args"); + uint16_t test1_len_8 = 0x5FAA; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_blob(ESP_EFUSE_MAC_FACTORY, &test1_len_8, 0)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, NULL, 8)); + TEST_ASSERT_EQUAL_HEX16(0x5FAA, test1_len_8); + + ESP_LOGI(TAG, "2. Test write operation"); + + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8, 7)); + TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8, 9)); + uint16_t val_read1 = 0; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST1_LEN_8, &val_read1, 8)); + TEST_ASSERT_EQUAL_HEX16(test1_len_8&((1 << 7) - 1), val_read1); + + uint16_t test1_len_8_hi = test1_len_8 & ~((1 << 7) - 1); + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8_hi, 8)); + TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8, 8)); + val_read1 = 0; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST1_LEN_8, &val_read1, 16)); + TEST_ASSERT_EQUAL_HEX16(test1_len_8&0x00FF, val_read1); + + uint16_t test2_len_16 = 0xAA55; + uint32_t val_32 = test2_len_16; + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST2_LEN_16, &val_32, 17)); + TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST2_LEN_16, &test2_len_16, 16)); + uint16_t test_16 = 0; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST2_LEN_16, &test_16, 16)); + TEST_ASSERT_EQUAL_HEX16(test2_len_16, test_16); + + ESP_LOGI(TAG, "3. Test field with one bit"); + uint8_t test5_len_1; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(0, test5_len_1); + + test5_len_1 = 0; + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(0, test5_len_1); + + test5_len_1 = 1; + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(1, test5_len_1); + + test5_len_1 = 1; + TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + + esp_efuse_utility_debug_dump_blocks(); +} + +TEST_CASE("efuse test write_field_blob", "[efuse]") +{ + test_write_blob(); +} + +static void test_write_cnt(void) +{ + esp_efuse_utility_erase_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "1. Test check args"); + size_t test3_len_6 = 5; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_cnt(ESP_EFUSE_MAC_FACTORY, 0)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_cnt(NULL, 5)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 0)); + + ESP_LOGI(TAG, "2. Test write operation"); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6)); + TEST_ASSERT_EQUAL_INT(0, test3_len_6); + + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 1)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6)); + TEST_ASSERT_EQUAL_INT(1, test3_len_6); + + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 1)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6)); + TEST_ASSERT_EQUAL_INT(2, test3_len_6); + + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 3)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6)); + TEST_ASSERT_EQUAL_INT(5, test3_len_6); + + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "3. Test field is full set"); + int max_bits = esp_efuse_get_field_size(ESP_EFUSE_TEST4_LEN_182); + size_t test4_len_182; + esp_efuse_utility_debug_dump_blocks(); + for (int i = 0; i < max_bits / 26; ++i) { + ESP_LOGD(TAG, "# %d", i); + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST4_LEN_182, 26)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST4_LEN_182, &test4_len_182)); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_EQUAL_INT((i + 1) * 26, test4_len_182); + } + + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "4. Test field ESP_EFUSE_TEST4_LEN_182 is full"); + TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_write_field_cnt(ESP_EFUSE_TEST4_LEN_182, 1)); + + ESP_LOGI(TAG, "3. Test field with one bit"); + size_t test5_len_1; + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST5_LEN_1, &test5_len_1)); + TEST_ASSERT_EQUAL_HEX8(0, test5_len_1); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(0, test5_len_1); + + test5_len_1 = 1; + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST5_LEN_1, test5_len_1)); + + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST5_LEN_1, &test5_len_1)); + TEST_ASSERT_EQUAL_HEX8(1, test5_len_1); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(1, test5_len_1); + + test5_len_1 = 1; + TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_write_field_cnt(ESP_EFUSE_TEST5_LEN_1, test5_len_1)); + + esp_efuse_utility_debug_dump_blocks(); + ESP_LOGI(TAG, "4. Test field test2_len_16"); + size_t test2_len_16 = 11; + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST2_LEN_16, test2_len_16)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST2_LEN_16, &test2_len_16)); + TEST_ASSERT_EQUAL_HEX16(11, test2_len_16); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST2_LEN_16, &test2_len_16, 16)); + TEST_ASSERT_EQUAL_HEX16(0x07FF, test2_len_16); + + esp_efuse_utility_debug_dump_blocks(); +} + +TEST_CASE("efuse test write_field_cnt", "[efuse]") +{ + test_write_cnt(); +} + +void cut_tail_arr(uint8_t *arr, int num_used_bits, size_t count_bits) +{ + if ((num_used_bits + count_bits) % 8) { + int start_used_item = (num_used_bits - 1) / 8; + int last_used_item = ((num_used_bits + count_bits) - 1) / 8; + int shift = 0; + int mask = num_used_bits + count_bits; + if (last_used_item == start_used_item) { + shift = (num_used_bits) % 8; + mask = count_bits; + } + arr[last_used_item] &= ((1 << (mask % 8)) - 1) << shift; + } +} + +void cut_start_arr(uint8_t *arr, size_t num_used_bits) +{ + if (num_used_bits % 8) { + int start_used_item = (num_used_bits - 1) / 8; + arr[start_used_item] &= ~((1 << (num_used_bits % 8)) - 1); + } +} + +void get_part_arr(uint8_t *arr_in, uint8_t *arr_out, int num_used_bits, int count_bits) +{ + int num_items = esp_efuse_utility_get_number_of_items(num_used_bits + count_bits, 8); + memcpy(arr_out, arr_in, num_items); + memset(arr_out, 0, num_used_bits / 8); + cut_start_arr(arr_out, num_used_bits); + cut_tail_arr(arr_out, num_used_bits, count_bits); +} + +void fill_part_arr(uint8_t *arr_in, uint8_t *arr_out, int count_bits) +{ + int num_items = esp_efuse_utility_get_number_of_items(count_bits, 8); + memcpy(arr_out, arr_in, num_items); + cut_tail_arr(arr_out, 0, count_bits); +} + +// Writes a random array to efuse, then reads and compares it. +void test_blob(const esp_efuse_desc_t* field[], uint8_t *arr_w, uint8_t *arr_r, uint8_t *arr_temp, int arr_size, size_t field_size) +{ + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_w, arr_size, ESP_LOG_INFO); + TEST_ESP_OK(esp_efuse_write_field_blob(field, arr_w, field_size)); + memset(arr_r, 0, arr_size); + TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size)); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_r, arr_size, ESP_LOG_INFO); + esp_efuse_utility_debug_dump_blocks(); + + TEST_ASSERT_TRUE_MESSAGE(memcmp(arr_w, arr_r, arr_size) == 0, "Operation write/read blob is not success"); + + int count_once = 0; + for (int i = 0; i < arr_size; ++i) { + count_once += __builtin_popcount(arr_w[i]); + } + + size_t num_bits_r = 0; + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + TEST_ASSERT_EQUAL_INT(count_once, num_bits_r); + + size_t num_bits_w = field_size - count_once; + if (num_bits_w == 0) { + esp_efuse_utility_erase_virt_blocks(); + num_bits_w = field_size; + } + + TEST_ESP_OK(esp_efuse_write_field_cnt(field, num_bits_w)); + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_EQUAL_INT(field_size, num_bits_r); + + memset(arr_r, 0, arr_size); + TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size)); + memset(arr_temp, 0xFF, arr_size); + cut_tail_arr(arr_temp, 0, field_size); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_TRUE_MESSAGE(memcmp(arr_temp, arr_r, arr_size) == 0, "Operation write/read blob is not success"); +} + +// Records a random number of bits (as "1") in the efuse field, then reads and compares. +void test_cnt_part(const esp_efuse_desc_t* field[], uint8_t *arr_r, int arr_size, size_t field_size) +{ + size_t num_bits_r = 0; + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + TEST_ASSERT_EQUAL_INT(0, num_bits_r); + + TEST_ESP_OK(esp_efuse_write_field_cnt(field, field_size)); + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + TEST_ASSERT_EQUAL_INT(field_size, num_bits_r); + + esp_efuse_utility_erase_virt_blocks(); + + int num_bits_summ_r = 0; + int num_bits_w = 0; + while(field_size > num_bits_summ_r) { + num_bits_w = 0; + while(num_bits_w == 0 || (num_bits_summ_r + num_bits_w) > field_size) { + bootloader_random_enable(); + bootloader_fill_random(&num_bits_w, 1); + bootloader_random_disable(); + num_bits_w = num_bits_w * field_size / 255; + if (num_bits_w != 0 && (num_bits_summ_r + num_bits_w) <= field_size) { + break; + } + } + + TEST_ESP_OK(esp_efuse_write_field_cnt(field, num_bits_w)); + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + num_bits_summ_r += num_bits_w; + TEST_ASSERT_EQUAL_INT(num_bits_summ_r, num_bits_r); + + memset(arr_r, 0, arr_size); + TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size)); + int count_once = 0; + for (int i = 0; i < arr_size; ++i) { + count_once += __builtin_popcount(arr_r[i]); + } + TEST_ASSERT_EQUAL_INT(num_bits_summ_r, count_once); + + ESP_LOGI(TAG, "Once bits=%d, step=%d", num_bits_summ_r, num_bits_w); + } + + esp_efuse_utility_debug_dump_blocks(); +} + +// From a random array takes a random number of bits and write to efuse, it repeats until the entire length of the field is written down. +void test_blob_part(const esp_efuse_desc_t* field[], uint8_t *arr_w, uint8_t *arr_r, uint8_t *arr_temp, int arr_size, size_t field_size) +{ + esp_efuse_utility_debug_dump_blocks(); + int num_bits_summ_r = 0; + int num_bits_w = 0; + memset(arr_w, 0, arr_size); + bootloader_random_enable(); + bootloader_fill_random(arr_w, arr_size); + bootloader_random_disable(); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_w, arr_size, ESP_LOG_INFO); + while(field_size > num_bits_summ_r) { + num_bits_w = 0; + while(num_bits_w == 0 || (num_bits_summ_r + num_bits_w) > field_size) { + bootloader_random_enable(); + bootloader_fill_random(&num_bits_w, 1); + bootloader_random_disable(); + num_bits_w = num_bits_w * field_size / 255; + if (num_bits_w != 0 && (num_bits_summ_r + num_bits_w) <= field_size) { + break; + } + } + ESP_LOGI(TAG, "Summ bits=%d, step=%d", num_bits_summ_r, num_bits_w); + memset(arr_temp, 0, arr_size); + get_part_arr(arr_w, arr_temp, num_bits_summ_r, num_bits_w); + + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_temp, arr_size, ESP_LOG_INFO); + TEST_ESP_OK(esp_efuse_write_field_blob(field, arr_temp, field_size)); + memset(arr_r, 0, arr_size); + TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size)); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_r, arr_size, ESP_LOG_INFO); + esp_efuse_utility_debug_dump_blocks(); + + num_bits_summ_r += num_bits_w; + memset(arr_temp, 0, arr_size); + fill_part_arr(arr_w, arr_temp, num_bits_summ_r); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_temp, arr_size, ESP_LOG_INFO); + TEST_ASSERT_TRUE_MESSAGE(memcmp(arr_temp, arr_r, arr_size) == 0, "Operation write/read blob is not success"); + } +} + +void check_efuse_table_test(int cycle) +{ + int num_test = 0; + while(1) { + const esp_efuse_desc_t** field; + switch (num_test++) { + case 0: field = ESP_EFUSE_TEST1_LEN_8; break; + case 1: field = ESP_EFUSE_TEST2_LEN_16; break; + case 2: field = ESP_EFUSE_TEST3_LEN_6; break; + case 3: field = ESP_EFUSE_TEST4_LEN_182; break; + case 4: field = ESP_EFUSE_TEST5_LEN_1; break; + case 5: field = ESP_EFUSE_TEST6_LEN_17; break; + default: + return; + break; + } + size_t field_size = esp_efuse_get_field_size(field); + int arr_size = esp_efuse_utility_get_number_of_items(field_size, 8); + uint8_t *arr_w = (uint8_t *) malloc(arr_size); + uint8_t *arr_r = (uint8_t *) malloc(arr_size); + uint8_t *arr_temp = (uint8_t *) malloc(arr_size); + ESP_LOGI(TAG, "Test#%d", num_test); + for (int c = 1; c <= cycle; ++c) { + ESP_LOGI(TAG, "Cycle#%d/%d", c, cycle); + + memset(arr_w, 0, arr_size); + bootloader_random_enable(); + bootloader_fill_random(arr_w, arr_size); + bootloader_random_disable(); + cut_tail_arr(arr_w, 0, field_size); + + esp_efuse_utility_erase_virt_blocks(); + ESP_LOGI(TAG, "1) blob write/read"); + test_blob(field, arr_w, arr_r, arr_temp, arr_size, field_size); + + esp_efuse_utility_erase_virt_blocks(); + ESP_LOGI(TAG, "2) cnt part write/read"); + test_cnt_part(field, arr_r, arr_size, field_size); + + esp_efuse_utility_erase_virt_blocks(); + ESP_LOGI(TAG, "3) blob part write/read"); + test_blob_part(field, arr_w, arr_r, arr_temp, arr_size, field_size); + } + free(arr_temp); + free(arr_r); + free(arr_w); + } +} + +TEST_CASE("efuse esp_efuse_table_test", "[efuse]") +{ + check_efuse_table_test(2); +} + + +TEST_CASE("Test esp_efuse_read_block esp_efuse_write_block functions", "[efuse]") +{ + int count_useful_reg = 0; + esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK2); + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + printf("EFUSE_CODING_SCHEME_NONE\n"); + count_useful_reg = 8; + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + printf("EFUSE_CODING_SCHEME_3_4\n"); + count_useful_reg = 6; + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + printf("EFUSE_CODING_SCHEME_REPEAT\n"); + count_useful_reg = 4; + } + + esp_efuse_utility_reset(); + esp_efuse_utility_erase_virt_blocks(); + + uint8_t src_key[32] = { 0 }; + uint8_t dst_key[32] = { 0 }; + int offset_in_bits = 0; + for (int i = 0; i < count_useful_reg * 4; ++i) { + src_key[i] = 0xAB + i; + } + + TEST_ESP_OK(esp_efuse_write_block(EFUSE_BLK2, src_key, offset_in_bits, count_useful_reg * 32)); + TEST_ESP_OK(esp_efuse_read_block(EFUSE_BLK2, dst_key, offset_in_bits, count_useful_reg * 32)); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_EQUAL_HEX8_ARRAY(src_key, dst_key, sizeof(src_key)); + + esp_efuse_utility_erase_virt_blocks(); + + memset(src_key, 0, sizeof(src_key)); + memset(dst_key, 0, sizeof(dst_key)); + offset_in_bits = count_useful_reg * 32 / 2; + for (int i = 0; i < count_useful_reg * 4 / 2; ++i) { + src_key[i] = 0xCD + i; + } + TEST_ESP_OK(esp_efuse_write_block(EFUSE_BLK2, src_key, offset_in_bits, count_useful_reg * 32 / 2)); + TEST_ESP_OK(esp_efuse_read_block(EFUSE_BLK2, dst_key, offset_in_bits, count_useful_reg * 32 / 2)); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_EQUAL_HEX8_ARRAY(src_key, dst_key, count_useful_reg * 4 / 2); + + esp_efuse_utility_erase_virt_blocks(); +} + +TEST_CASE("Test Bits are not empty. Write operation is forbidden", "[efuse]") +{ + esp_efuse_utility_update_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + int count_useful_reg = 0; + uint8_t r_buff[32]; + int st_offset = -1; + int num_block; + for (num_block = EFUSE_BLK1; num_block < 4; ++num_block) { + memset(r_buff, 0, sizeof(r_buff)); + esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(num_block); + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + printf("EFUSE_CODING_SCHEME_NONE. The test is not applicable.\n"); + count_useful_reg = 8; + return; + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + printf("EFUSE_CODING_SCHEME_3_4\n"); + count_useful_reg = 6; + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + printf("EFUSE_CODING_SCHEME_REPEAT\n"); + count_useful_reg = 4; + } + TEST_ESP_OK(esp_efuse_read_block(num_block, r_buff, 0, count_useful_reg * 32)); + for (int i = 0; i < count_useful_reg * 4; ++i) { + if (r_buff[i] != 0) { + // found used byte + for (int j = 0; j < 8; ++j) { + if ((r_buff[i] & (1 << j)) == 0) { + // found empty bit into this byte + st_offset = i * 8 + j; + printf("Byte = 0x%02x. offset is = %d\n", r_buff[i], st_offset); + break; + } + } + if (st_offset != -1) { + break; + } + } + } + if (st_offset != -1) { + break; + } + } + if (st_offset != -1) { + // write 1 bit to empty place. + uint8_t val = 1; + TEST_ESP_ERR(ESP_ERR_CODING, esp_efuse_write_block(num_block, &val, st_offset, 1)); + } else { + printf("Test skipped. It is not applicable, the device has no written bits."); + } +} +#endif // #ifdef CONFIG_EFUSE_VIRTUAL diff --git a/components/efuse/test/test_efuse_coding_scheme.c b/components/efuse/test/test_efuse_coding_scheme.c new file mode 100644 index 0000000000..242702d9fd --- /dev/null +++ b/components/efuse/test/test_efuse_coding_scheme.c @@ -0,0 +1,204 @@ +#include +#include +#include "esp_efuse.h" +#include "../src/esp_efuse_utility.h" +#include "soc/efuse_reg.h" +#include "unity.h" +#include "bootloader_random.h" + +typedef struct { + uint8_t unencoded[24]; + uint32_t encoded[8]; +} coding_scheme_test_t; + +/* Randomly generated byte strings, encoded and written to ESP32 + using espefuse algorithm, then verified to have no encoding errors + and correct readback. +*/ +static const coding_scheme_test_t coding_scheme_data[] = { + { + .unencoded = { 0x96, 0xa9, 0xab, 0xb2, 0xda, 0xdd, 0x21, 0xd2, 0x35, 0x22, 0xd3, 0x30, 0x3b, 0xf8, 0xcb, 0x77, 0x8d, 0x8d, 0xf4, 0x96, 0x25, 0xc4, 0xb9, 0x94 }, + .encoded = { 0xb2aba996, 0x6821ddda, 0x2235d221, 0x430730d3, 0x77cbf83b, 0x627f8d8d, 0xc42596f4, 0x4dae94b9 }, + }, + { + .unencoded = { 0x0e, 0x6b, 0x1a, 0x1d, 0xa5, 0x9f, 0x24, 0xcf, 0x91, 0x5b, 0xe7, 0xe1, 0x7c, 0x0a, 0x6e, 0xdc, 0x5e, 0x8e, 0xb1, 0xec, 0xd1, 0xf3, 0x75, 0x48 }, + .encoded = { 0x1d1a6b0e, 0x5e589fa5, 0x5b91cf24, 0x6127e1e7, 0xdc6e0a7c, 0x5d148e5e, 0xf3d1ecb1, 0x57424875 }, + }, + { + .unencoded = { 0x0a, 0x79, 0x5a, 0x1c, 0xb1, 0x45, 0x71, 0x2c, 0xb3, 0xda, 0x9e, 0xdc, 0x76, 0x27, 0xf5, 0xca, 0xe7, 0x00, 0x39, 0x95, 0x6c, 0x53, 0xc2, 0x07 }, + .encoded = { 0x1c5a790a, 0x4ac145b1, 0xdab32c71, 0x6476dc9e, 0xcaf52776, 0x4d8900e7, 0x536c9539, 0x495607c2 }, + }, + { + .unencoded = { 0x76, 0x46, 0x88, 0x2d, 0x4c, 0xe1, 0x50, 0x5d, 0xd6, 0x7c, 0x41, 0x15, 0xc6, 0x1f, 0xd4, 0x60, 0x10, 0x15, 0x2a, 0x72, 0x2d, 0x89, 0x93, 0x13 }, + .encoded = { 0x2d884676, 0x4838e14c, 0x7cd65d50, 0x4bf31541, 0x60d41fc6, 0x39681510, 0x892d722a, 0x497c1393 }, + }, + { + .unencoded = { 0x32, 0xbc, 0x40, 0x92, 0x13, 0x37, 0x1a, 0xae, 0xb6, 0x00, 0xed, 0x30, 0xb8, 0x82, 0xee, 0xfc, 0xcf, 0x6d, 0x7f, 0xc5, 0xfa, 0x0e, 0xdd, 0x84 }, + .encoded = { 0x9240bc32, 0x49783713, 0x00b6ae1a, 0x46df30ed, 0xfcee82b8, 0x6e8a6dcf, 0x0efac57f, 0x571784dd }, + }, + { + .unencoded = { 0x29, 0xb3, 0x04, 0x95, 0xf2, 0x3c, 0x81, 0xe6, 0x5a, 0xf3, 0x42, 0x82, 0xd1, 0x79, 0xe2, 0x12, 0xbe, 0xc3, 0xd4, 0x10, 0x63, 0x66, 0x9f, 0xe3 }, + .encoded = { 0x9504b329, 0x51c53cf2, 0xf35ae681, 0x460e8242, 0x12e279d1, 0x5825c3be, 0x666310d4, 0x5ebde39f }, + }, + { + .unencoded = { 0xda, 0xda, 0x71, 0x4a, 0x62, 0x33, 0xdd, 0x31, 0x87, 0xf3, 0x70, 0x12, 0x33, 0x3b, 0x3b, 0xe9, 0xed, 0xc4, 0x6e, 0x6a, 0xc7, 0xd5, 0x85, 0xfc }, + .encoded = { 0x4a71dada, 0x4e6a3362, 0xf38731dd, 0x4bfa1270, 0xe93b3b33, 0x61f3c4ed, 0xd5c76a6e, 0x636ffc85 }, + }, + { + .unencoded = { 0x45, 0x64, 0x51, 0x34, 0x1c, 0x82, 0x81, 0x77, 0xf8, 0x89, 0xb1, 0x15, 0x82, 0x94, 0xdd, 0x64, 0xa2, 0x46, 0x0e, 0xfb, 0x1a, 0x70, 0x4b, 0x9f }, + .encoded = { 0x34516445, 0x39da821c, 0x89f87781, 0x4f2315b1, 0x64dd9482, 0x474b46a2, 0x701afb0e, 0x5e4b9f4b }, + }, + { + .unencoded = { 0x89, 0x87, 0x15, 0xb6, 0x66, 0x34, 0x49, 0x18, 0x8b, 0x7b, 0xb2, 0xf6, 0x96, 0x1e, 0x2e, 0xf1, 0x03, 0x9d, 0x4e, 0x16, 0x32, 0xd6, 0x23, 0x22 }, + .encoded = { 0xb6158789, 0x4eff3466, 0x7b8b1849, 0x63e5f6b2, 0xf12e1e96, 0x54c99d03, 0xd632164e, 0x42bd2223 }, + }, + { + .unencoded = { 0xa7, 0xa0, 0xb5, 0x21, 0xd2, 0xa3, 0x9f, 0x65, 0xa9, 0xeb, 0x72, 0xa2, 0x2e, 0xa6, 0xfb, 0x9c, 0x48, 0x7e, 0x68, 0x08, 0x7a, 0xb1, 0x4f, 0xbc }, + .encoded = { 0x21b5a0a7, 0x4ce2a3d2, 0xeba9659f, 0x5868a272, 0x9cfba62e, 0x5fd97e48, 0xb17a0868, 0x5b58bc4f }, + }, + { + .unencoded = { 0xf7, 0x05, 0xe3, 0x6c, 0xb1, 0x55, 0xcb, 0x2f, 0x8d, 0x3e, 0x0b, 0x2e, 0x3e, 0xb7, 0x02, 0xf5, 0x91, 0xb1, 0xfe, 0x8b, 0x58, 0x50, 0xb2, 0x40 }, + .encoded = { 0x6ce305f7, 0x569955b1, 0x3e8d2fcb, 0x56722e0b, 0xf502b73e, 0x535eb191, 0x50588bfe, 0x3a8f40b2 }, + }, + { + .unencoded = { 0x0f, 0x93, 0xb0, 0xd5, 0x60, 0xba, 0x40, 0x2a, 0x62, 0xa6, 0x92, 0x82, 0xb8, 0x91, 0x2c, 0xd7, 0x23, 0xdc, 0x6f, 0x7f, 0x2f, 0xbe, 0x41, 0xf5 }, + .encoded = { 0xd5b0930f, 0x5123ba60, 0xa6622a40, 0x3bbe8292, 0xd72c91b8, 0x582ddc23, 0xbe2f7f6f, 0x6935f541 }, + }, + { + .unencoded = { 0x7f, 0x0c, 0x99, 0xde, 0xff, 0x2e, 0xd2, 0x1c, 0x48, 0x98, 0x70, 0x85, 0x15, 0x01, 0x2a, 0xfb, 0xcd, 0xf2, 0xa0, 0xf9, 0x0e, 0xbc, 0x9f, 0x0c }, + .encoded = { 0xde990c7f, 0x6fe52eff, 0x98481cd2, 0x3deb8570, 0xfb2a0115, 0x61faf2cd, 0xbc0ef9a0, 0x55780c9f }, + }, + { + .unencoded = { 0x9a, 0x10, 0x92, 0x03, 0x81, 0xfe, 0x41, 0x57, 0x77, 0x02, 0xcb, 0x20, 0x67, 0xa4, 0x97, 0xf3, 0xf8, 0xc7, 0x0d, 0x65, 0xcd, 0xfc, 0x15, 0xef }, + .encoded = { 0x0392109a, 0x4b64fe81, 0x02775741, 0x418820cb, 0xf397a467, 0x6998c7f8, 0xfccd650d, 0x6ba3ef15 }, + }, +}; + +TEST_CASE("Test 3/4 Coding Scheme Algorithm", "[efuse]") +{ + const int num_tests = sizeof(coding_scheme_data)/sizeof(coding_scheme_test_t); + for (int i = 0; i < num_tests; i++) { + uint32_t result[8]; + const coding_scheme_test_t *t = &coding_scheme_data[i]; + + printf("Test case %d...\n", i); + esp_err_t r = esp_efuse_apply_34_encoding(t->unencoded, result, sizeof(t->unencoded)); + TEST_ASSERT_EQUAL_HEX(ESP_OK, r); + TEST_ASSERT_EQUAL_HEX32_ARRAY(t->encoded, result, 8); + + // Do the same, 6 bytes at a time + for (int offs = 0; offs < sizeof(t->unencoded); offs += 6) { + bzero(result, sizeof(result)); + r = esp_efuse_apply_34_encoding(t->unencoded + offs, result, 6); + TEST_ASSERT_EQUAL_HEX(ESP_OK, r); + TEST_ASSERT_EQUAL_HEX32_ARRAY(t->encoded + (offs / 6 * 2), result, 2); + } + } +} + +TEST_CASE("Test Coding Scheme for efuse manager", "[efuse]") +{ + int count_useful_reg = 0; + int useful_data_in_byte; + uint8_t buf[32]; + uint32_t encoded[8]; + bootloader_random_enable(); + esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK2); + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + printf("EFUSE_CODING_SCHEME_NONE\n"); + count_useful_reg = 8; + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + printf("EFUSE_CODING_SCHEME_3_4\n"); + count_useful_reg = 6; + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + printf("EFUSE_CODING_SCHEME_REPEAT\n"); + count_useful_reg = 4; + } + useful_data_in_byte = count_useful_reg * 4; + + for (int i = 0; i < 10; ++i) { + printf("Test case %d...\n", i); + memset(buf, 0, sizeof(buf)); + memset(encoded, 0, sizeof(encoded)); + // get test data + bootloader_fill_random(buf, useful_data_in_byte); + memset(buf, 0, i); + + esp_efuse_utility_reset(); + + for (int j = 0; j < count_useful_reg; ++j) { + REG_WRITE(EFUSE_BLK2_WDATA0_REG + j * 4, *((uint32_t*)buf + j)); + } + + TEST_ESP_OK(esp_efuse_utility_apply_new_coding_scheme()); + + uint32_t w_data_after_coding[8] = { 0 }; + for (int j = 0; j < 8; ++j) { + w_data_after_coding[j] = REG_READ(EFUSE_BLK2_WDATA0_REG + j * 4); + } + + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + memcpy((uint8_t*)encoded, buf, sizeof(buf)); + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + TEST_ESP_OK(esp_efuse_apply_34_encoding(buf, encoded, useful_data_in_byte)); + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + for (int j = 0; j < count_useful_reg; ++j) { + encoded[j] = *((uint32_t*)buf + j); + encoded[j + 4] = encoded[j]; + } + } +#ifdef CONFIG_EFUSE_VIRTUAL + printf("Data from W reg\n"); + esp_efuse_utility_erase_virt_blocks(); + esp_efuse_utility_burn_efuses(); + esp_efuse_utility_debug_dump_blocks(); + printf("Data from encoded\n"); + for (int j = 0; j < 8; ++j) { + printf("0x%08x ", encoded[j]); + } + printf("\nData from w_data_after_coding\n"); + for (int j = 0; j < 8; ++j) { + printf("0x%08x ", w_data_after_coding[j]); + } + + printf("\nData from buf\n"); + for (int j = 0; j < 8; ++j) { + printf("0x%08x ", *((uint32_t*)buf + j)); + } + printf("\n"); +#endif + TEST_ASSERT_EQUAL_HEX32_ARRAY(encoded, w_data_after_coding, 8); + } + esp_efuse_utility_reset(); + bootloader_random_disable(); +} + +TEST_CASE("Test data does not match the coding scheme", "[efuse]") +{ + int count_useful_reg = 0; + esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK2); + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + printf("EFUSE_CODING_SCHEME_NONE\n"); + count_useful_reg = 8; + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + printf("EFUSE_CODING_SCHEME_3_4\n"); + count_useful_reg = 6 + 1; + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + printf("EFUSE_CODING_SCHEME_REPEAT\n"); + count_useful_reg = 4 + 1; + } + + esp_efuse_utility_reset(); + + for (int i = 0; i < count_useful_reg; ++i) { + REG_WRITE(EFUSE_BLK2_WDATA0_REG + i * 4, 0xABCDEF01 + i); + } + + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + TEST_ESP_OK(esp_efuse_utility_apply_new_coding_scheme()); + } else { + TEST_ESP_ERR(ESP_ERR_CODING, esp_efuse_utility_apply_new_coding_scheme()); + } + + esp_efuse_utility_reset(); +} diff --git a/components/efuse/test_efuse_host/efuse_tests.py b/components/efuse/test_efuse_host/efuse_tests.py new file mode 100644 index 0000000000..e2a546b94d --- /dev/null +++ b/components/efuse/test_efuse_host/efuse_tests.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python +from __future__ import print_function, division +import unittest +import struct +import csv +import sys +import subprocess +import tempfile +import os +import StringIO +sys.path.append("..") +from efuse import * + +''' +To run the test on local PC: +cd ~/esp/esp-idf/components/efuse/test_efuse_host/ + ./efuse_tests.py +''' + + +class CSVParserTests(unittest.TestCase): + + def test_general(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + self.assertEqual(t[0].comment, 'Use for test name 1') + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[1].bit_start, 5) + self.assertEqual(t[1].bit_count, 4) + self.assertEqual(t[1].comment, 'Use for test name 2') + + def test_seq_bit_start1_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK3, , 4, +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].bit_start, 5) + self.assertEqual(t[1].bit_count, 4) + + def test_seq_bit_start2_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].bit_start, 0) + self.assertEqual(t[1].bit_count, 4) + + def test_seq_bit_start3_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, + +name3, EFUSE_BLK2, 5, 4, +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].bit_start, 0) + self.assertEqual(t[1].bit_count, 4) + + self.assertEqual(t[2].field_name, 'name3') + self.assertEqual(t[2].bit_start, 5) + self.assertEqual(t[2].bit_count, 4) + + def test_seq_bit_start4_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, +, EFUSE_BLK2, , 4, +name1, EFUSE_BLK3, , 5, +""" + with self.assertRaisesRegexp(InputError, "Field names must be unique"): + t = FuseTable.from_csv(csv) + + + def test_seq_bit_start5_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, +, EFUSE_BLK2, , 4, +name3, EFUSE_BLK3, 5, 5, +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].bit_start, 0) + self.assertEqual(t[1].bit_count, 4) + + self.assertEqual(t[2].field_name, 'name2') + self.assertEqual(t[2].bit_start, 4) + self.assertEqual(t[2].bit_count, 4) + + self.assertEqual(t[3].field_name, 'name3') + self.assertEqual(t[3].bit_start, 5) + self.assertEqual(t[3].bit_count, 5) + + def test_overlapping_bit_start_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 1, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + t = FuseTable.from_csv(csv) + with self.assertRaisesRegexp(InputError, "overlap"): + t.verify() + + def test_empty_field_name_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, +""" + with self.assertRaisesRegexp(InputError, "missing field name"): + t = FuseTable.from_csv(csv) + + def test_unique_field_name_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, 5, Use for test name 1 +name1, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + with self.assertRaisesRegexp(InputError, "Field names must be unique"): + t = FuseTable.from_csv(csv) + + def test_bit_count_empty_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, , Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + with self.assertRaisesRegexp(InputError, "empty"): + t = FuseTable.from_csv(csv) + + def test_bit_start_num_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, k, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + with self.assertRaisesRegexp(InputError, "Invalid field value"): + t = FuseTable.from_csv(csv) + + def test_join_entry(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK2, 0, 6, Use for test name 1 +name2, EFUSE_BLK2, 6, 5, Use for test name 2 +name3, EFUSE_BLK3, 20, 5, Use for test name 3 +, EFUSE_BLK3, 30, 5, Use for test name 3 +name4, EFUSE_BLK2, 30, 5, Use for test name 4 + """ + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 6) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[1].bit_start, 6) + self.assertEqual(t[1].bit_count, 5) + + self.assertEqual(t[2].field_name, 'name3') + self.assertEqual(t[2].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[2].bit_start, 20) + self.assertEqual(t[2].bit_count, 5) + + self.assertEqual(t[3].field_name, 'name3') + self.assertEqual(t[3].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[3].bit_start, 30) + self.assertEqual(t[3].bit_count, 5) + + self.assertEqual(t[4].field_name, 'name4') + self.assertEqual(t[4].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[4].bit_start, 30) + self.assertEqual(t[4].bit_count, 5) + + def test_block_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK5, 0, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + with self.assertRaisesRegexp(InputError, "'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3"): + t = FuseTable.from_csv(csv) + + def test_field_size_is_ok(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK0, 0, 224, Use for test name 1 +name2, EFUSE_BLK1, 0, 256, Use for test name 2 + """ + t = FuseTable.from_csv(csv) + t.verify() + + def test_field_blk0_size_is_more(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK0, 1, 224, Use for test name 1 +name2, EFUSE_BLK1, 0, 256, Use for test name 2 + """ + t = FuseTable.from_csv(csv) + with self.assertRaisesRegexp(InputError, "The field is outside the boundaries"): + t.verify() + + def test_field_blk1_size_is_more(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK0, 0, 224, Use for test name 1 +name2, EFUSE_BLK1, 1, 256, Use for test name 2 + """ + t = FuseTable.from_csv(csv) + with self.assertRaisesRegexp(InputError, "The field is outside the boundaries"): + t.verify() + +class VerificationTests(unittest.TestCase): + + def test_bit_start_num_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 +name1_1, EFUSE_BLK2, 0, 5, Use for test name 1_1 +name2_1, EFUSE_BLK2, 5, 4, Use for test name 2_1 + """ + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[1].bit_start, 5) + self.assertEqual(t[1].bit_count, 4) + + self.assertEqual(t[2].field_name, 'name1_1') + self.assertEqual(t[2].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[2].bit_start, 0) + self.assertEqual(t[2].bit_count, 5) + + self.assertEqual(t[3].field_name, 'name2_1') + self.assertEqual(t[3].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[3].bit_start, 5) + self.assertEqual(t[3].bit_count, 4) + +if __name__ =="__main__": + unittest.main() From 9822055851ffeb373b145d7549a69b67a326a160 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Wed, 21 Nov 2018 16:09:36 +0800 Subject: [PATCH 07/15] efuse: Add support coding scheme to script Added support using BLK1 and BLK2 in custom table. Added change size key in BLK1 and BLK2 if coding scheme was changed. --- components/efuse/CMakeLists.txt | 52 ++--- components/efuse/Kconfig | 42 ++++- components/efuse/Makefile.projbuild | 63 ++++--- components/efuse/efuse_table_gen.py | 178 +++++++++++++----- components/efuse/esp32/esp_efuse_table.c | 12 +- components/efuse/esp32/esp_efuse_table.csv | 4 + .../efuse/esp32/include/esp_efuse_table.h | 3 +- components/soc/CMakeLists.txt | 2 - make/project.mk | 6 +- 9 files changed, 250 insertions(+), 112 deletions(-) diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt index e11e1e74f3..6077f39269 100644 --- a/components/efuse/CMakeLists.txt +++ b/components/efuse/CMakeLists.txt @@ -16,39 +16,47 @@ set(COMPONENT_REQUIRES) set(COMPONENT_PRIV_REQUIRES bootloader_support) register_component() +set(GEN_EFUSE_TABLE_ARG --coding_scheme ${CONFIG_EFUSE_CODE_SCHEME}) + +if(CONFIG_EFUSE_CUSTOM_TABLE_USE_BLK1) + list(APPEND GEN_EFUSE_TABLE_ARG --custom_table_use_BLK1) +endif() + +if(CONFIG_EFUSE_CUSTOM_TABLE_USE_BLK2) + list(APPEND GEN_EFUSE_TABLE_ARG --custom_table_use_BLK2) +endif() + +if(CONFIG_EFUSE_COMMON_TABLE_FIX_SIZE_BLK1_BLK2_DEP_ON_CODE_SCHEME) + list(APPEND GEN_EFUSE_TABLE_ARG --common_table_fix_size_secure_key_and_encrypt_key) +endif() ################### # Make common files esp_efuse_table.c and include/esp_efuse_table.h files. -# The generated files are used in the bootloader and application space. -# To generate new *.c/*.h files run the command manually "make efuse_common_table". set(EFUSE_COMMON_TABLE_CSV_PATH "${COMPONENT_PATH}/${SOC_NAME}/esp_efuse_table.csv") -add_custom_target(efuse_common_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH}) +set(EFUSE_COMMON_TABLE_OUT_PATH "${COMPONENT_PATH}/${SOC_NAME}/esp_efuse_table.c") - -# custom gen header files +################### +# Make custom files project/main/esp_efuse_custom_table.c and project/main/include/esp_efuse_custom_table.h files. +# Path to CSV file is relative to project path for custom CSV files. if(${CONFIG_EFUSE_CUSTOM_TABLE}) # Custom filename expands any path relative to the project get_filename_component(EFUSE_CUSTOM_TABLE_CSV_PATH "${CONFIG_EFUSE_CUSTOM_TABLE_FILENAME}" ABSOLUTE BASE_DIR "${PROJECT_PATH}") - - add_custom_target(efuse_custom_table ALL - COMMAND ${CMAKE_COMMAND} -E echo "Efuse CSV ${EFUSE_CUSTOM_TABLE_CSV_PATH} does not exist. Either change efuse table file in menuconfig or create this input file." - COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt" - COMMAND ${CMAKE_COMMAND} -P ${IDF_PATH}/tools/cmake/scripts/fail.cmake) - -string(REPLACE ".csv" ".c" HEADER_CUSTOM ${EFUSE_CUSTOM_TABLE_CSV_PATH}) -add_custom_command(OUTPUT ${HEADER_CUSTOM} - COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" - ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} - DEPENDS ${EFUSE_CUSTOM_TABLE_CSV_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" - VERBATIM) - -if(EXISTS ${EFUSE_CUSTOM_TABLE_CSV_PATH}) - add_custom_target(efuse_custom_table ALL DEPENDS ${HEADER_CUSTOM} ${EFUSE_CUSTOM_TABLE_CSV_PATH}) -endif() + string(REPLACE ".csv" ".c" EFUSE_CUSTOM_TABLE_OUT_PATH ${EFUSE_CUSTOM_TABLE_CSV_PATH}) endif()#if(${CONFIG_EFUSE_CUSTOM_TABLE}) +set(GENERATED_SRC ${EFUSE_COMMON_TABLE_OUT_PATH} ${EFUSE_CUSTOM_TABLE_OUT_PATH}) +set_source_files_properties(GENERATED_SRC PROPERTIES SYMBOLIC true) +add_custom_command( + OUTPUT GENERATED_OUTPUT + BYPRODUCTS ${GENERATED_SRC} + COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" + ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG} + DEPENDS "${EFUSE_COMMON_TABLE_CSV_PATH}" "${EFUSE_CUSTOM_TABLE_CSV_PATH}" "${SDKCONFIG_CMAKE}" + VERBATIM) +add_custom_target(GENERATED_SRC DEPENDS GENERATED_OUTPUT ${GENERATED_SRC}) + ################### # Generates files for unit test. This command is run manually. set(EFUSE_TEST_TABLE_CSV_PATH "${COMPONENT_PATH}/test/esp_efuse_test_table.csv") -add_custom_target(efuse_test_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_TEST_TABLE_CSV_PATH}) +add_custom_target(efuse_test_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_TEST_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG}) diff --git a/components/efuse/Kconfig b/components/efuse/Kconfig index d07ae851fd..69697c219c 100644 --- a/components/efuse/Kconfig +++ b/components/efuse/Kconfig @@ -20,18 +20,44 @@ config EFUSE_VIRTUAL If this option is set, all permanent changes (via eFuse) are disabled. Log output will state changes which would be applied, but they will not be. -choice EFUSE_CODE_SCHEME - prompt "eFuse Code Scheme" - default EFUSE_CODE_SCHEME_NONE +choice EFUSE_CODE_SCHEME_SELECTOR + prompt "Coding scheme" + default EFUSE_CODE_SCHEME_STATE_NONE help Selector eFuse code scheme. -config EFUSE_CODE_SCHEME_NONE - bool "None" -config EFUSE_CODE_SCHEME_3_4 +config EFUSE_CODE_SCHEME_STATE_NONE + bool "NONE" +config EFUSE_CODE_SCHEME_STATE_3_4 bool "3/4" -config EFUSE_CODE_SCHEME_REPEAT - bool "Repeat" +config EFUSE_CODE_SCHEME_STATE_REPEAT + bool "REPEAT" endchoice +config EFUSE_CODE_SCHEME + int + default 0 if EFUSE_CODE_SCHEME_STATE_NONE + default 1 if EFUSE_CODE_SCHEME_STATE_3_4 + default 2 if EFUSE_CODE_SCHEME_STATE_REPEAT + +config EFUSE_CUSTOM_TABLE_USE_BLK1 + bool "Use EFUSE_BLK1 for custom purpose" + default n + help + If this option is set then ENCRYPT_FLASH_KEY field from EFUSE_BLK1 [0..192/255] can not be used anymore. + ENCRYPT_FLASH_KEY field will contain 0 bits. + +config EFUSE_CUSTOM_TABLE_USE_BLK2 + bool "Use EFUSE_BLK2 for custom purpose" + default n + help + If this option is set then SECURE_BOOT_KEY field from EFUSE_BLK2 [0..192/255] can not be used anymore. + SECURE_BOOT_KEY field will contain 0 bits. + +config EFUSE_COMMON_TABLE_FIX_SIZE_BLK1_BLK2_DEP_ON_CODE_SCHEME + bool "Limit size BLK1 and BLK2 if coding scheme is changed" + default y + help + efuse_table_gen.py tool will change size two fields: SECURE_BOOT_KEY and ENCRYPT_FLASH_KEY if they have not much coding scheme with a description in csv file. + endmenu diff --git a/components/efuse/Makefile.projbuild b/components/efuse/Makefile.projbuild index 35e0355a92..beebe72ce8 100644 --- a/components/efuse/Makefile.projbuild +++ b/components/efuse/Makefile.projbuild @@ -1,48 +1,59 @@ # # eFuse Manager ganeretes header file. # -# .PHONY: efuse_table efuse_custom_table efuse_common_table efuse_test_table show_efuse_table +# .PHONY: efuse_table efuse_test_table show_efuse_table -GEN_EFUSE_TABLE := $(PYTHON) $(COMPONENT_PATH)/efuse_table_gen.py +GEN_TOOL := $(COMPONENT_PATH)/efuse_table_gen.py +GEN_EFUSE_TABLE := $(PYTHON) $(GEN_TOOL) -efuse_table: efuse_custom_table +GEN_EFUSE_TABLE_ARG := --coding_scheme $(CONFIG_EFUSE_CODE_SCHEME) + +ifdef CONFIG_EFUSE_CUSTOM_TABLE_USE_BLK1 +GEN_EFUSE_TABLE_ARG += --custom_table_use_BLK1 +endif + +ifdef CONFIG_EFUSE_CUSTOM_TABLE_USE_BLK2 +GEN_EFUSE_TABLE_ARG += --custom_table_use_BLK2 +endif + +ifdef CONFIG_EFUSE_COMMON_TABLE_FIX_SIZE_BLK1_BLK2_DEP_ON_CODE_SCHEME +GEN_EFUSE_TABLE_ARG += --common_table_fix_size_secure_key_and_encrypt_key +endif ################### # Make common files esp_efuse_table.c and include/esp_efuse_table.h files. -# The generated files are used in the bootloader and application space. -# To generate new *.c/*.h files run the command manually "make efuse_common_table". SOC_NAME := $(IDF_TARGET) EFUSE_COMMON_TABLE_CSV_PATH := $(COMPONENT_PATH)/$(SOC_NAME)/esp_efuse_table.csv -efuse_common_table: - $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) +EFUSE_COMMON_TABLE_OUT_PATH := $(COMPONENT_PATH)/$(SOC_NAME)/esp_efuse_table.c ################### -# Make custom files -# Changes in esp_efuse_custom_table.csv file lead to regeneration of esp_efuse_custom_table.c and include/esp_efuse_custom_table.h files. -# The generated files are used only in the application. -ifdef IS_BOOTLOADER_BUILD -efuse_custom_table: -else - +# Make custom files project/main/esp_efuse_custom_table.c and project/main/include/esp_efuse_custom_table.h files. ifdef CONFIG_EFUSE_CUSTOM_TABLE # Path to CSV file is relative to project path for custom CSV files. EFUSE_CUSTOM_TABLE_CSV_PATH := $(call dequote,$(abspath $(call dequote, $(PROJECT_PATH))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME)))) -EFUSE_CUSTOM_TABLE_OUT_PATH := $(call dequote,$(abspath $(call dequote, $(BUILD_DIR_BASE))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME)))) -efuse_custom_table: $(EFUSE_CUSTOM_TABLE_OUT_PATH:.csv=.o) - -$(EFUSE_CUSTOM_TABLE_OUT_PATH:.csv=.o): $(EFUSE_CUSTOM_TABLE_CSV_PATH) - @echo "$(EFUSE_CUSTOM_TABLE_OUT_PATH)" - @echo "$(EFUSE_CUSTOM_TABLE_CSV_PATH)" - $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) - +EFUSE_CUSTOM_TABLE_OUT_PATH_CSV := $(call dequote,$(abspath $(call dequote, $(PROJECT_PATH))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME)))) +EFUSE_CUSTOM_TABLE_OUT_PATH := $(EFUSE_CUSTOM_TABLE_OUT_PATH_CSV:.csv=.c) else -efuse_custom_table: -endif +EFUSE_CUSTOM_TABLE_CSV_PATH := +EFUSE_CUSTOM_TABLE_OUT_PATH := +endif # ifdef CONFIG_EFUSE_CUSTOM_TABLE -endif +efuse_table: $(EFUSE_COMMON_TABLE_OUT_PATH) $(EFUSE_CUSTOM_TABLE_OUT_PATH) + +$(EFUSE_COMMON_TABLE_OUT_PATH): $(EFUSE_COMMON_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFILE) + @echo "COMMON_TABLE_CSV: $(EFUSE_COMMON_TABLE_CSV_PATH)" + $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) + +$(EFUSE_CUSTOM_TABLE_OUT_PATH): $(EFUSE_CUSTOM_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFILE) + @echo "CUSTOM_TABLE_CSV: $(EFUSE_CUSTOM_TABLE_CSV_PATH)" + $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) + +# print to console efuse table +show_efuse_table: + $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) --info ################### # Generates files for unit test. This command is run manually. EFUSE_TEST_TABLE_CSV_PATH := $(COMPONENT_PATH)/test/esp_efuse_test_table.csv efuse_test_table: - $(GEN_EFUSE_TABLE) $(EFUSE_TEST_TABLE_CSV_PATH) + $(GEN_EFUSE_TABLE) $(EFUSE_TEST_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) diff --git a/components/efuse/efuse_table_gen.py b/components/efuse/efuse_table_gen.py index a64f2f9495..98be7a6017 100644 --- a/components/efuse/efuse_table_gen.py +++ b/components/efuse/efuse_table_gen.py @@ -30,6 +30,16 @@ import ntpath __version__ = '1.0' quiet = False +coding_scheme = 0 +custom_table_use_BLK1 = False +custom_table_use_BLK2 = False +common_table_fix_size = False + +CODE_SCHEME = { + "NONE" : 0, + "3/4" : 1, + "REPEAT" : 2, +} copyright = '''// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD // @@ -59,12 +69,11 @@ def critical(msg): class FuseTable(list): def __init__(self): super(FuseTable, self).__init__(self) - self.md5_digest = "" + self.md5_digest_table = "" @classmethod - def from_csv(cls, csv_contents): + def from_csv(cls, csv_contents, type_table): res = FuseTable() - res.md5_digest = res.calc_md5(csv_contents) lines = csv_contents.splitlines() def expand_vars(f): f = os.path.expandvars(f) @@ -120,6 +129,16 @@ class FuseTable(list): i_count = 0 res.verify_duplicate_name() + # fix size due to coding scheme + if type_table == "common_table": + if common_table_fix_size == True and (custom_table_use_BLK1 == False or custom_table_use_BLK2 == False): + res.fix_size_fields_from_blk1_blk2(); + if custom_table_use_BLK1 == True or custom_table_use_BLK2 == True: + res.keys_from_blk1_blk2_make_empty(); + + # clac md5 for table + res.calc_md5() + return res def verify_duplicate_name(self): @@ -139,11 +158,9 @@ class FuseTable(list): if fl_error == True: raise InputError("Field names must be unique") - def verify(self): - - '''list_field_names = []''' + def verify(self, type_table = None): for p in self: - p.verify() + p.verify(type_table) self.verify_duplicate_name() @@ -156,8 +173,25 @@ class FuseTable(list): last.field_name, last.efuse_block, last.bit_start, last.bit_count)) last = p - def calc_md5(self, csv_contents): - return hashlib.md5(csv_contents).hexdigest() + def fix_size_fields_from_blk1_blk2(self): + for p in self: + if (p.efuse_block == "EFUSE_BLK1" and custom_table_use_BLK1 == False) or (p.efuse_block == "EFUSE_BLK2" and custom_table_use_BLK2 == False): + max_bits = p.get_max_bits_of_block() + if p.bit_start == 0 and p.bit_count > max_bits: + print("Fix size `%s` field from %d to %d" %(p.field_name, p.bit_count, max_bits)) + p.bit_count = max_bits + + def keys_from_blk1_blk2_make_empty(self): + for p in self: + if (p.efuse_block == "EFUSE_BLK1" and custom_table_use_BLK1 == True) or (p.efuse_block == "EFUSE_BLK2" and custom_table_use_BLK2 == True): + p.bit_count = 0 + print("efuse: `%s` field was changed from %d to 0" %(p.field_name, p.bit_count)) + + def calc_md5(self): + txt_table = '' + for p in self: + txt_table += "%s %s %d %d %s" % (p.field_name, p.efuse_block, p.bit_start, p.bit_count, p.comment) + "\n" + self.md5_digest_table = hashlib.md5(txt_table).hexdigest() def show_range_used_bits(self): # print used and free bits @@ -190,7 +224,7 @@ class FuseTable(list): "#endif", "", "", - "// md5_digest " + self.md5_digest, + "// md5_digest_table " + self.md5_digest_table, "// This file was generated automatically from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", "// If you want to change some fields, you need to change " + file_name + ".csv file then build system will generate this header file", "// To show efuse_table run the command 'make show_efuse_table'.", @@ -215,7 +249,7 @@ class FuseTable(list): rows += [ '#include "esp_efuse.h"', '#include "' + file_name + '.h"', "", - "// md5_digest " + self.md5_digest, + "// md5_digest_table " + self.md5_digest_table, "// This file was generated automatically from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", "// If you want to change some fields, you need to change " + file_name + ".csv file then build system will generate this header file", "// To show efuse_table run the command 'make show_efuse_table'.", @@ -293,18 +327,36 @@ class FuseDefinition(object): raise InputError("Field 'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3") return strval - def verify(self): - '''if self.field_name is None: - raise ValidationError(self, "field_name field is not set")''' + def get_max_bits_of_block(self): + '''common_table: EFUSE_BLK0, EFUSE_BLK1, EFUSE_BLK2, EFUSE_BLK3 + custom_table: ----------, ----------, ----------, EFUSE_BLK3(some reserved in common_table) + ''' + max_bits = 0 + if coding_scheme == CODE_SCHEME["NONE"] or self.efuse_block == "EFUSE_BLK0": + max_bits = 256 + elif coding_scheme == CODE_SCHEME["3/4"]: + max_bits = 192 + elif coding_scheme == CODE_SCHEME["REPEAT"]: + max_bits = 128 + else: + ValidationError(self, "Unknown coding scheme") + return max_bits + + def verify(self, type_table): if self.efuse_block is None: raise ValidationError(self, "efuse_block field is not set") if self.bit_count is None: raise ValidationError(self, "bit_count field is not set") - max_bits = 256 - if self.efuse_block == "EFUSE_BLK0": - max_bits = 224 + if type_table is not None: + if type_table == "custom_table": + if self.efuse_block != "EFUSE_BLK3": + ValidationError(self, "custom_table should use only EFUSE_BLK3") + + max_bits = self.get_max_bits_of_block() + if self.bit_start + self.bit_count > max_bits: + print("(%d + %d) > %d" % (self.bit_start, self.bit_count, max_bits)) raise ValidationError(self, "The field is outside the boundaries of the %s block" % (self.efuse_block)) def get_full_name(self): @@ -324,15 +376,26 @@ class FuseDefinition(object): str(self.bit_start), str(self.bit_count) + "}, \t // " + self.comment]) -def process_input_file(file): +def process_input_file(file, type_table): status("Parsing efuse CSV input file " + file.name + " ...") input = file.read() - table = FuseTable.from_csv(input) - + table = FuseTable.from_csv(input, type_table) status("Verifying efuse table...") - table.verify() + table.verify(type_table) return table +def ckeck_md5_in_file(md5, filename): + if os.path.exists(filename): + with open(filename,'r') as f: + for line in f: + if md5 in line: + return True + return False + +def touch(fname, times=None): + with open(fname, 'a'): + os.utime(fname, times) + def create_output_files(name, output_table, debug): file_name = os.path.splitext(os.path.basename(name))[0] gen_dir = os.path.dirname(name) @@ -346,55 +409,74 @@ def create_output_files(name, output_table, debug): file_h_path = os.path.join(dir_for_file_h, file_name + ".h") file_c_path = os.path.join(gen_dir, file_name + ".c") - status("Creating efuse *.h file " + file_h_path + " ...") - output = output_table.to_header(file_name) - with open(file_h_path, 'w') as f: - f.write(output) - f.close() - - status("Creating efuse *.c file " + file_c_path + " ...") - output = output_table.to_c_file(file_name, debug) - with open(file_c_path, 'w') as f: - f.write(output) - f.close() - + # src files are the same + if ckeck_md5_in_file(output_table.md5_digest_table, file_c_path) == False: + status("Creating efuse *.h file " + file_h_path + " ...") + output = output_table.to_header(file_name) + with open(file_h_path, 'w') as f: + f.write(output) + f.close() + + status("Creating efuse *.c file " + file_c_path + " ...") + output = output_table.to_c_file(file_name, debug) + with open(file_c_path, 'w') as f: + f.write(output) + f.close() + else: + print("touch: %s.c" % (file_name)) + touch(file_c_path) + def main(): global quiet + global coding_scheme + global custom_table_use_BLK1 + global custom_table_use_BLK2 + global common_table_fix_size parser = argparse.ArgumentParser(description='ESP32 eFuse Manager') parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') parser.add_argument('--debug', help='Create header file with debug info', default=False, action="store_false") parser.add_argument('--info', help='Print info about range of used bits', default=False, action="store_true") + parser.add_argument('--custom_table_use_BLK1', help='BLK1 is used for custom purpose', default=False, action="store_true") + parser.add_argument('--custom_table_use_BLK2', help='BLK2 is used for custom purpose', default=False, action="store_true") + parser.add_argument('--common_table_fix_size_secure_key_and_encrypt_key', help='Size of secure_key and encrypt_key will limit to coding scheme', default=False, action="store_true") + parser.add_argument('--coding_scheme', help='Coding scheme', type=int, default=None) parser.add_argument('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('rb')) parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('rb'), nargs='?', default=None) args = parser.parse_args() + coding_scheme = args.coding_scheme + if CODE_SCHEME["NONE"] == coding_scheme: + print("eFuse coding scheme: NONE") + elif CODE_SCHEME["3/4"] == coding_scheme: + print("eFuse coding scheme: 3/4") + elif CODE_SCHEME["REPEAT"] == coding_scheme: + print("eFuse coding scheme: REPEAT") + + custom_table_use_BLK1 = args.custom_table_use_BLK1 + custom_table_use_BLK2 = args.custom_table_use_BLK2 + common_table_fix_size = args.common_table_fix_size_secure_key_and_encrypt_key quiet = args.quiet debug = args.debug info = args.info - common_table = process_input_file(args.common_input) + common_table = process_input_file(args.common_input, "common_table") + two_table = common_table if args.custom_input is not None: - custom_table = process_input_file(args.custom_input) - common_table += custom_table - common_table.verify() - if info == True: - output_table = common_table - else: - output_table = custom_table - name = args.custom_input.name - else: - output_table = common_table - name = args.common_input.name - output_table.verify() + custom_table = process_input_file(args.custom_input, "custom_table") + two_table += custom_table + two_table.verify() # save files. if info == False: - create_output_files(name, output_table, debug) + if args.custom_input is None: + create_output_files(args.common_input.name, common_table, debug) + else: + create_output_files(args.custom_input.name, custom_table, debug) else: - print(output_table.show_range_used_bits()) + print(two_table.show_range_used_bits()) return 0 diff --git a/components/efuse/esp32/esp_efuse_table.c b/components/efuse/esp32/esp_efuse_table.c index 69685c0e89..d4bfeb2854 100644 --- a/components/efuse/esp32/esp_efuse_table.c +++ b/components/efuse/esp32/esp_efuse_table.c @@ -15,8 +15,7 @@ #include "esp_efuse.h" #include "esp_efuse_table.h" - -// md5_digest 963d6d14dc4bd997fd5d4b9de351745d +// md5_digest_table 20db0282fe17fec59ea46716026f5fce // This file was generated automatically from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. // If you want to change some fields, you need to change esp_efuse_table.csv file then build system will generate this header file // To show efuse_table run the command 'make show_efuse_table'. @@ -171,6 +170,10 @@ static const esp_efuse_desc_t ADC2_TP_HIGH[] = { {EFUSE_BLK3, 119, 9}, // TP_REG EFUSE_RD_ADC2_TP_HIGH, }; +static const esp_efuse_desc_t SECURE_VERSION[] = { + {EFUSE_BLK3, 128, 32}, // Secure version for anti-rollback, +}; + @@ -360,3 +363,8 @@ const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_HIGH[] = { NULL }; +const esp_efuse_desc_t* ESP_EFUSE_SECURE_VERSION[] = { + &SECURE_VERSION[0], // Secure version for anti-rollback + NULL +}; + diff --git a/components/efuse/esp32/esp_efuse_table.csv b/components/efuse/esp32/esp_efuse_table.csv index 8c6db79dd4..0c85664f66 100644 --- a/components/efuse/esp32/esp_efuse_table.csv +++ b/components/efuse/esp32/esp_efuse_table.csv @@ -78,3 +78,7 @@ ADC1_TP_LOW, EFUSE_BLK3, 96, 7, TP_REG EFUSE_RD_ADC1_TP_LOW ADC2_TP_LOW, EFUSE_BLK3, 112, 7, TP_REG EFUSE_RD_ADC2_TP_LOW ADC1_TP_HIGH, EFUSE_BLK3, 103, 9, TP_REG EFUSE_RD_ADC1_TP_HIGH ADC2_TP_HIGH, EFUSE_BLK3, 119, 9, TP_REG EFUSE_RD_ADC2_TP_HIGH + +# anti-rollback # +################# +SECURE_VERSION, EFUSE_BLK3, 128, 32, Secure version for anti-rollback diff --git a/components/efuse/esp32/include/esp_efuse_table.h b/components/efuse/esp32/include/esp_efuse_table.h index c7e7c44481..c06e776a0a 100644 --- a/components/efuse/esp32/include/esp_efuse_table.h +++ b/components/efuse/esp32/include/esp_efuse_table.h @@ -17,7 +17,7 @@ extern "C" { #endif -// md5_digest 963d6d14dc4bd997fd5d4b9de351745d +// md5_digest_table 20db0282fe17fec59ea46716026f5fce // This file was generated automatically from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. // If you want to change some fields, you need to change esp_efuse_table.csv file then build system will generate this header file // To show efuse_table run the command 'make show_efuse_table'. @@ -59,6 +59,7 @@ extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_LOW[]; extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_LOW[]; extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_HIGH[]; extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_HIGH[]; +extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_VERSION[]; #ifdef __cplusplus } diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 551063b39c..f377386a42 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -13,6 +13,4 @@ list(APPEND COMPONENT_SRCS "src/memory_layout_utils.c") set(COMPONENT_ADD_LDFRAGMENTS linker.lf) -set(COMPONENT_REQUIRES efuse) - register_component() diff --git a/make/project.mk b/make/project.mk index 6f86cbef07..a0d411496f 100644 --- a/make/project.mk +++ b/make/project.mk @@ -13,7 +13,7 @@ .PHONY: build-components menuconfig defconfig all build clean all_binaries check-submodules size size-components size-files size-symbols list-components MAKECMDGOALS ?= all -all: all_binaries | check_python_dependencies +all: efuse_table all_binaries | check_python_dependencies # see below for recipe of 'all' target # # # other components will add dependencies to 'all_binaries'. The @@ -481,7 +481,7 @@ $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp $(summary) LD $(patsubst $(PWD)/%,%,$@) $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP) -app: $(APP_BIN) partition_table_get_info +app: efuse_table $(APP_BIN) partition_table_get_info ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image @echo "App built but not signed. Signing step via espsecure.py:" @echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)" @@ -521,7 +521,7 @@ endef define GenerateComponentTargets .PHONY: component-$(2)-build component-$(2)-clean -component-$(2)-build: check-submodules efuse_table $(call prereq_if_explicit, component-$(2)-clean) | $(BUILD_DIR_BASE)/$(2) +component-$(2)-build: check-submodules $(call prereq_if_explicit, component-$(2)-clean) | $(BUILD_DIR_BASE)/$(2) $(call ComponentMake,$(1),$(2)) build component-$(2)-clean: | $(BUILD_DIR_BASE)/$(2) $(BUILD_DIR_BASE)/$(2)/component_project_vars.mk From b8141f3ad80b7f7102ddd2643f88c4409f61f01f Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Thu, 6 Dec 2018 17:49:02 +0800 Subject: [PATCH 08/15] efuse: Fix make/cmake build systems and docs --- components/efuse/CMakeLists.txt | 33 +-- components/efuse/Kconfig | 20 -- components/efuse/Makefile.projbuild | 42 ++-- components/efuse/efuse_table_gen.py | 137 +++++------- components/efuse/include/esp_efuse.h | 6 +- components/efuse/test/esp_efuse_test_table.c | 2 +- .../efuse/test/include/esp_efuse_test_table.h | 2 +- .../efuse/test_efuse_host/efuse_tests.py | 211 +++++++++++------- components/soc/CMakeLists.txt | 2 + docs/en/api-reference/system/efuse.rst | 168 +++++++++----- make/project.mk | 4 +- tools/idf.py | 1 + 12 files changed, 325 insertions(+), 303 deletions(-) diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt index 6077f39269..1c91512332 100644 --- a/components/efuse/CMakeLists.txt +++ b/components/efuse/CMakeLists.txt @@ -18,43 +18,24 @@ register_component() set(GEN_EFUSE_TABLE_ARG --coding_scheme ${CONFIG_EFUSE_CODE_SCHEME}) -if(CONFIG_EFUSE_CUSTOM_TABLE_USE_BLK1) - list(APPEND GEN_EFUSE_TABLE_ARG --custom_table_use_BLK1) -endif() - -if(CONFIG_EFUSE_CUSTOM_TABLE_USE_BLK2) - list(APPEND GEN_EFUSE_TABLE_ARG --custom_table_use_BLK2) -endif() - -if(CONFIG_EFUSE_COMMON_TABLE_FIX_SIZE_BLK1_BLK2_DEP_ON_CODE_SCHEME) - list(APPEND GEN_EFUSE_TABLE_ARG --common_table_fix_size_secure_key_and_encrypt_key) -endif() - ################### # Make common files esp_efuse_table.c and include/esp_efuse_table.h files. set(EFUSE_COMMON_TABLE_CSV_PATH "${COMPONENT_PATH}/${SOC_NAME}/esp_efuse_table.csv") -set(EFUSE_COMMON_TABLE_OUT_PATH "${COMPONENT_PATH}/${SOC_NAME}/esp_efuse_table.c") + +add_custom_target(efuse_common_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG}) ################### # Make custom files project/main/esp_efuse_custom_table.c and project/main/include/esp_efuse_custom_table.h files. # Path to CSV file is relative to project path for custom CSV files. if(${CONFIG_EFUSE_CUSTOM_TABLE}) # Custom filename expands any path relative to the project - get_filename_component(EFUSE_CUSTOM_TABLE_CSV_PATH "${CONFIG_EFUSE_CUSTOM_TABLE_FILENAME}" ABSOLUTE BASE_DIR "${PROJECT_PATH}") - string(REPLACE ".csv" ".c" EFUSE_CUSTOM_TABLE_OUT_PATH ${EFUSE_CUSTOM_TABLE_CSV_PATH}) - + get_filename_component(EFUSE_CUSTOM_TABLE_CSV_PATH "${CONFIG_EFUSE_CUSTOM_TABLE_FILENAME}" ABSOLUTE BASE_DIR "${IDF_PROJECT_PATH}") + add_custom_target(efuse_custom_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG}) +else() + add_custom_target(efuse_custom_table COMMAND) endif()#if(${CONFIG_EFUSE_CUSTOM_TABLE}) -set(GENERATED_SRC ${EFUSE_COMMON_TABLE_OUT_PATH} ${EFUSE_CUSTOM_TABLE_OUT_PATH}) -set_source_files_properties(GENERATED_SRC PROPERTIES SYMBOLIC true) -add_custom_command( - OUTPUT GENERATED_OUTPUT - BYPRODUCTS ${GENERATED_SRC} - COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" - ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG} - DEPENDS "${EFUSE_COMMON_TABLE_CSV_PATH}" "${EFUSE_CUSTOM_TABLE_CSV_PATH}" "${SDKCONFIG_CMAKE}" - VERBATIM) -add_custom_target(GENERATED_SRC DEPENDS GENERATED_OUTPUT ${GENERATED_SRC}) +add_custom_target(show_efuse_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG} "--info") ################### # Generates files for unit test. This command is run manually. diff --git a/components/efuse/Kconfig b/components/efuse/Kconfig index 69697c219c..c06b29a1e1 100644 --- a/components/efuse/Kconfig +++ b/components/efuse/Kconfig @@ -40,24 +40,4 @@ config EFUSE_CODE_SCHEME default 1 if EFUSE_CODE_SCHEME_STATE_3_4 default 2 if EFUSE_CODE_SCHEME_STATE_REPEAT -config EFUSE_CUSTOM_TABLE_USE_BLK1 - bool "Use EFUSE_BLK1 for custom purpose" - default n - help - If this option is set then ENCRYPT_FLASH_KEY field from EFUSE_BLK1 [0..192/255] can not be used anymore. - ENCRYPT_FLASH_KEY field will contain 0 bits. - -config EFUSE_CUSTOM_TABLE_USE_BLK2 - bool "Use EFUSE_BLK2 for custom purpose" - default n - help - If this option is set then SECURE_BOOT_KEY field from EFUSE_BLK2 [0..192/255] can not be used anymore. - SECURE_BOOT_KEY field will contain 0 bits. - -config EFUSE_COMMON_TABLE_FIX_SIZE_BLK1_BLK2_DEP_ON_CODE_SCHEME - bool "Limit size BLK1 and BLK2 if coding scheme is changed" - default y - help - efuse_table_gen.py tool will change size two fields: SECURE_BOOT_KEY and ENCRYPT_FLASH_KEY if they have not much coding scheme with a description in csv file. - endmenu diff --git a/components/efuse/Makefile.projbuild b/components/efuse/Makefile.projbuild index beebe72ce8..35eb41d4eb 100644 --- a/components/efuse/Makefile.projbuild +++ b/components/efuse/Makefile.projbuild @@ -1,57 +1,47 @@ # # eFuse Manager ganeretes header file. # -# .PHONY: efuse_table efuse_test_table show_efuse_table +.PHONY: efuse_custom_table efuse_common_table efuse_test_table show_efuse_table -GEN_TOOL := $(COMPONENT_PATH)/efuse_table_gen.py -GEN_EFUSE_TABLE := $(PYTHON) $(GEN_TOOL) +GEN_EFUSE_TABLE := $(PYTHON) $(COMPONENT_PATH)/efuse_table_gen.py GEN_EFUSE_TABLE_ARG := --coding_scheme $(CONFIG_EFUSE_CODE_SCHEME) -ifdef CONFIG_EFUSE_CUSTOM_TABLE_USE_BLK1 -GEN_EFUSE_TABLE_ARG += --custom_table_use_BLK1 -endif - -ifdef CONFIG_EFUSE_CUSTOM_TABLE_USE_BLK2 -GEN_EFUSE_TABLE_ARG += --custom_table_use_BLK2 -endif - -ifdef CONFIG_EFUSE_COMMON_TABLE_FIX_SIZE_BLK1_BLK2_DEP_ON_CODE_SCHEME -GEN_EFUSE_TABLE_ARG += --common_table_fix_size_secure_key_and_encrypt_key -endif ################### # Make common files esp_efuse_table.c and include/esp_efuse_table.h files. SOC_NAME := $(IDF_TARGET) EFUSE_COMMON_TABLE_CSV_PATH := $(COMPONENT_PATH)/$(SOC_NAME)/esp_efuse_table.csv -EFUSE_COMMON_TABLE_OUT_PATH := $(COMPONENT_PATH)/$(SOC_NAME)/esp_efuse_table.c + +efuse_common_table: + @echo "COMMON_TABLE_CSV: $(EFUSE_COMMON_TABLE_CSV_PATH)" + $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) + ################### # Make custom files project/main/esp_efuse_custom_table.c and project/main/include/esp_efuse_custom_table.h files. ifdef CONFIG_EFUSE_CUSTOM_TABLE # Path to CSV file is relative to project path for custom CSV files. EFUSE_CUSTOM_TABLE_CSV_PATH := $(call dequote,$(abspath $(call dequote, $(PROJECT_PATH))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME)))) -EFUSE_CUSTOM_TABLE_OUT_PATH_CSV := $(call dequote,$(abspath $(call dequote, $(PROJECT_PATH))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME)))) -EFUSE_CUSTOM_TABLE_OUT_PATH := $(EFUSE_CUSTOM_TABLE_OUT_PATH_CSV:.csv=.c) + +efuse_custom_table: + @echo "COMMON_TABLE_CSV: $(EFUSE_COMMON_TABLE_CSV_PATH)" + @echo "CUSTOM_TABLE_CSV: $(EFUSE_CUSTOM_TABLE_CSV_PATH)" + $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) + else +efuse_custom_table: EFUSE_CUSTOM_TABLE_CSV_PATH := EFUSE_CUSTOM_TABLE_OUT_PATH := endif # ifdef CONFIG_EFUSE_CUSTOM_TABLE -efuse_table: $(EFUSE_COMMON_TABLE_OUT_PATH) $(EFUSE_CUSTOM_TABLE_OUT_PATH) - -$(EFUSE_COMMON_TABLE_OUT_PATH): $(EFUSE_COMMON_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFILE) - @echo "COMMON_TABLE_CSV: $(EFUSE_COMMON_TABLE_CSV_PATH)" - $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) - -$(EFUSE_CUSTOM_TABLE_OUT_PATH): $(EFUSE_CUSTOM_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFILE) - @echo "CUSTOM_TABLE_CSV: $(EFUSE_CUSTOM_TABLE_CSV_PATH)" - $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) +################### # print to console efuse table show_efuse_table: $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) $(GEN_EFUSE_TABLE_ARG) --info + ################### # Generates files for unit test. This command is run manually. EFUSE_TEST_TABLE_CSV_PATH := $(COMPONENT_PATH)/test/esp_efuse_test_table.csv diff --git a/components/efuse/efuse_table_gen.py b/components/efuse/efuse_table_gen.py index 98be7a6017..368a063891 100644 --- a/components/efuse/efuse_table_gen.py +++ b/components/efuse/efuse_table_gen.py @@ -31,14 +31,11 @@ __version__ = '1.0' quiet = False coding_scheme = 0 -custom_table_use_BLK1 = False -custom_table_use_BLK2 = False -common_table_fix_size = False CODE_SCHEME = { - "NONE" : 0, - "3/4" : 1, - "REPEAT" : 2, + "NONE" : 0, + "3/4" : 1, + "REPEAT" : 2, } copyright = '''// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD @@ -61,25 +58,27 @@ def status(msg): if not quiet: critical(msg) + def critical(msg): """ Print critical message to stderr """ sys.stderr.write(msg) sys.stderr.write('\n') + class FuseTable(list): def __init__(self): super(FuseTable, self).__init__(self) self.md5_digest_table = "" @classmethod - def from_csv(cls, csv_contents, type_table): + def from_csv(cls, csv_contents): res = FuseTable() lines = csv_contents.splitlines() def expand_vars(f): f = os.path.expandvars(f) m = re.match(r'(? 1 ) + names = [p.field_name for p in res] + duplicates = set(n for n in names if names.count(n) > 1) if len(duplicates) != 0: i_count = 0 for p in res: @@ -129,13 +128,6 @@ class FuseTable(list): i_count = 0 res.verify_duplicate_name() - # fix size due to coding scheme - if type_table == "common_table": - if common_table_fix_size == True and (custom_table_use_BLK1 == False or custom_table_use_BLK2 == False): - res.fix_size_fields_from_blk1_blk2(); - if custom_table_use_BLK1 == True or custom_table_use_BLK2 == True: - res.keys_from_blk1_blk2_make_empty(); - # clac md5 for table res.calc_md5() @@ -143,8 +135,8 @@ class FuseTable(list): def verify_duplicate_name(self): # check on duplicate name - names = [ p.field_name for p in self ] - duplicates = set( n for n in names if names.count(n) > 1 ) + names = [p.field_name for p in self] + duplicates = set(n for n in names if names.count(n) > 1) # print sorted duplicate partitions by name if len(duplicates) != 0: @@ -153,8 +145,8 @@ class FuseTable(list): field_name = p.field_name + p.group if field_name != "" and len(duplicates.intersection([field_name])) != 0: fl_error = True - print ("Field at %s, %s, %s, %s have dublicate field_name" - % ( p.field_name, p.efuse_block, p.bit_start, p.bit_count)) + print ("Field at %s, %s, %s, %s have dublicate field_name" % + (p.field_name, p.efuse_block, p.bit_start, p.bit_count)) if fl_error == True: raise InputError("Field names must be unique") @@ -168,9 +160,9 @@ class FuseTable(list): last = None for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): if last is not None and last.efuse_block == p.efuse_block and p.bit_start < last.bit_start + last.bit_count: - raise InputError("Field at %s, %s, %s, %s overlaps %s, %s, %s, %s" - % ( p.field_name, p.efuse_block, p.bit_start, p.bit_count, - last.field_name, last.efuse_block, last.bit_start, last.bit_count)) + raise InputError("Field at %s, %s, %s, %s overlaps %s, %s, %s, %s" % + (p.field_name, p.efuse_block, p.bit_start, p.bit_count, + last.field_name, last.efuse_block, last.bit_start, last.bit_count)) last = p def fix_size_fields_from_blk1_blk2(self): @@ -178,14 +170,14 @@ class FuseTable(list): if (p.efuse_block == "EFUSE_BLK1" and custom_table_use_BLK1 == False) or (p.efuse_block == "EFUSE_BLK2" and custom_table_use_BLK2 == False): max_bits = p.get_max_bits_of_block() if p.bit_start == 0 and p.bit_count > max_bits: - print("Fix size `%s` field from %d to %d" %(p.field_name, p.bit_count, max_bits)) + print("Fix size `%s` field from %d to %d" % (p.field_name, p.bit_count, max_bits)) p.bit_count = max_bits def keys_from_blk1_blk2_make_empty(self): for p in self: if (p.efuse_block == "EFUSE_BLK1" and custom_table_use_BLK1 == True) or (p.efuse_block == "EFUSE_BLK2" and custom_table_use_BLK2 == True): p.bit_count = 0 - print("efuse: `%s` field was changed from %d to 0" %(p.field_name, p.bit_count)) + print("efuse: `%s` field was changed from %d to 0" % (p.field_name, p.bit_count)) def calc_md5(self): txt_table = '' @@ -198,8 +190,9 @@ class FuseTable(list): rows = '' rows += 'Sorted efuse table:\n' num = 1 + rows = "{0} \t{1:<30} \t{2} \t{3} \t{4}".format("#", "field_name", "efuse_block", "bit_start", "bit_count") + "\n" for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): - rows += "#%d \t%s \t\t%s \t\t%d \t\t%d" % (num, p.field_name, p.efuse_block, p.bit_start, p.bit_count) + "\n" + rows += "{0} \t{1:<30} \t{2} \t{3:^8} \t{4:^8}".format(num, p.field_name, p.efuse_block, p.bit_start, p.bit_count) + "\n" num += 1 rows += '\nUsed bits in efuse table:\n' @@ -214,12 +207,12 @@ class FuseTable(list): rows += '%d] [%d ' % (last.bit_start + last.bit_count - 1, p.bit_start) last = p rows += '%d] \n' % (last.bit_start + last.bit_count - 1) - rows += '\nNote: Not printed ranges are free for using.\n' + rows += '\nNote: Not printed ranges are free for using. (bits in EFUSE_BLK0 are reserved for Espressif)\n' return rows def to_header(self, file_name): - rows = [ copyright ] - rows += [ "#ifdef __cplusplus", + rows = [copyright] + rows += ["#ifdef __cplusplus", 'extern "C" {', "#endif", "", @@ -234,19 +227,19 @@ class FuseTable(list): last_field_name = '' for p in self: if (p.field_name != last_field_name): - rows += [ "extern const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[];" ] + rows += ["extern const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[];"] last_field_name = p.field_name - rows += [ "", - "#ifdef __cplusplus", - "}", - "#endif", - ""] + rows += ["", + "#ifdef __cplusplus", + "}", + "#endif", + ""] return '\n'.join(rows) + "\n" def to_c_file(self, file_name, debug): - rows = [ copyright ] - rows += [ '#include "esp_efuse.h"', + rows = [copyright] + rows += ['#include "esp_efuse.h"', '#include "' + file_name + '.h"', "", "// md5_digest_table " + self.md5_digest_table, @@ -260,11 +253,11 @@ class FuseTable(list): for p in self: if (p.field_name != last_name): if last_name != '': - rows += [ "};\n"] - rows += [ "static const esp_efuse_desc_t " + p.field_name + "[] = {" ] + rows += ["};\n"] + rows += ["static const esp_efuse_desc_t " + p.field_name + "[] = {"] last_name = p.field_name - rows += [ p.to_struct(debug) + "," ] - rows += [ "};\n" ] + rows += [p.to_struct(debug) + ","] + rows += ["};\n"] rows += ["\n\n\n"] @@ -273,18 +266,18 @@ class FuseTable(list): if (p.field_name != last_name): if last_name != '': rows += [" NULL", - "};\n" ] - rows += [ "const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[] = {" ] + "};\n"] + rows += ["const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[] = {"] last_name = p.field_name index = str(0) if str(p.group) == "" else str(p.group) - rows += [ " &" + p.field_name + "[" + index + "], \t\t// " + p.comment ] + rows += [" &" + p.field_name + "[" + index + "], \t\t// " + p.comment] rows += [" NULL", "};\n" ] return '\n'.join(rows) + "\n" - -class FuseDefinition(object): + +class FuseDefinition(object): def __init__(self): self.field_name = "" self.group = "" @@ -297,7 +290,7 @@ class FuseDefinition(object): def from_csv(cls, line): """ Parse a line from the CSV """ line_w_defaults = line + ",,,," # lazy way to support default fields - fields = [ f.strip() for f in line_w_defaults.split(",") ] + fields = [f.strip() for f in line_w_defaults.split(",")] res = FuseDefinition() res.field_name = fields[0] @@ -339,7 +332,7 @@ class FuseDefinition(object): elif coding_scheme == CODE_SCHEME["REPEAT"]: max_bits = 128 else: - ValidationError(self, "Unknown coding scheme") + raise ValidationError(self, "Unknown coding scheme") return max_bits def verify(self, type_table): @@ -351,13 +344,12 @@ class FuseDefinition(object): if type_table is not None: if type_table == "custom_table": if self.efuse_block != "EFUSE_BLK3": - ValidationError(self, "custom_table should use only EFUSE_BLK3") + raise ValidationError(self, "custom_table should use only EFUSE_BLK3") max_bits = self.get_max_bits_of_block() if self.bit_start + self.bit_count > max_bits: - print("(%d + %d) > %d" % (self.bit_start, self.bit_count, max_bits)) - raise ValidationError(self, "The field is outside the boundaries of the %s block" % (self.efuse_block)) + raise ValidationError(self, "The field is outside the boundaries(max_bits = %d) of the %s block" % (max_bits, self.efuse_block)) def get_full_name(self): def get_postfix(group): @@ -376,26 +368,25 @@ class FuseDefinition(object): str(self.bit_start), str(self.bit_count) + "}, \t // " + self.comment]) + def process_input_file(file, type_table): status("Parsing efuse CSV input file " + file.name + " ...") input = file.read() - table = FuseTable.from_csv(input, type_table) + table = FuseTable.from_csv(input) status("Verifying efuse table...") table.verify(type_table) return table + def ckeck_md5_in_file(md5, filename): if os.path.exists(filename): - with open(filename,'r') as f: + with open(filename, 'r') as f: for line in f: if md5 in line: return True return False -def touch(fname, times=None): - with open(fname, 'a'): - os.utime(fname, times) - + def create_output_files(name, output_table, debug): file_name = os.path.splitext(os.path.basename(name))[0] gen_dir = os.path.dirname(name) @@ -423,25 +414,19 @@ def create_output_files(name, output_table, debug): f.write(output) f.close() else: - print("touch: %s.c" % (file_name)) - touch(file_c_path) - + print("Source files do not require updating correspond to csv file.") + + def main(): global quiet global coding_scheme - global custom_table_use_BLK1 - global custom_table_use_BLK2 - global common_table_fix_size parser = argparse.ArgumentParser(description='ESP32 eFuse Manager') parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') parser.add_argument('--debug', help='Create header file with debug info', default=False, action="store_false") parser.add_argument('--info', help='Print info about range of used bits', default=False, action="store_true") - parser.add_argument('--custom_table_use_BLK1', help='BLK1 is used for custom purpose', default=False, action="store_true") - parser.add_argument('--custom_table_use_BLK2', help='BLK2 is used for custom purpose', default=False, action="store_true") - parser.add_argument('--common_table_fix_size_secure_key_and_encrypt_key', help='Size of secure_key and encrypt_key will limit to coding scheme', default=False, action="store_true") - parser.add_argument('--coding_scheme', help='Coding scheme', type=int, default=None) + parser.add_argument('--coding_scheme', help='Coding scheme', type=int, default=0) parser.add_argument('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('rb')) parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('rb'), nargs='?', default=None) @@ -454,10 +439,9 @@ def main(): print("eFuse coding scheme: 3/4") elif CODE_SCHEME["REPEAT"] == coding_scheme: print("eFuse coding scheme: REPEAT") - - custom_table_use_BLK1 = args.custom_table_use_BLK1 - custom_table_use_BLK2 = args.custom_table_use_BLK2 - common_table_fix_size = args.common_table_fix_size_secure_key_and_encrypt_key + else: + raise InputError("unknown CODE_SCHEME = %s" % (coding_scheme)) + quiet = args.quiet debug = args.debug info = args.info @@ -486,8 +470,7 @@ class InputError(RuntimeError): class ValidationError(InputError): def __init__(self, p, message): - super(ValidationError, self).__init__( - "Entry %s invalid: %s" % (p.field_name, message)) + super(ValidationError, self).__init__("Entry %s invalid: %s" % (p.field_name, message)) if __name__ == '__main__': try: diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h index 3ea1680ed9..349b6f7923 100644 --- a/components/efuse/include/esp_efuse.h +++ b/components/efuse/include/esp_efuse.h @@ -161,10 +161,12 @@ uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg); esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val); /** - * @brief Return efuse coding_scheme for blocks. + * @brief Return efuse coding scheme for blocks. + * + * Note: The coding scheme is applicable only to 1, 2 and 3 blocks. For 0 block, the coding scheme is always ``NONE``. * * @param[in] blk Block number of eFuse. - * @return Return efuse coding_scheme for blocks + * @return Return efuse coding scheme for blocks */ esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk); diff --git a/components/efuse/test/esp_efuse_test_table.c b/components/efuse/test/esp_efuse_test_table.c index 92977d7c59..7d46e777ca 100644 --- a/components/efuse/test/esp_efuse_test_table.c +++ b/components/efuse/test/esp_efuse_test_table.c @@ -15,7 +15,7 @@ #include "esp_efuse.h" #include "esp_efuse_test_table.h" -// md5_digest dac4d84347dab29412b8b8713b4b0065 +// md5_digest_table 7d587827a6f6134241dce7d3713b3edc // This file was generated automatically from the file esp_efuse_test_table.csv. DO NOT CHANGE THIS FILE MANUALLY. // If you want to change some fields, you need to change esp_efuse_test_table.csv file then build system will generate this header file // To show efuse_table run the command 'make show_efuse_table'. diff --git a/components/efuse/test/include/esp_efuse_test_table.h b/components/efuse/test/include/esp_efuse_test_table.h index b47ffaf185..36669b2cff 100644 --- a/components/efuse/test/include/esp_efuse_test_table.h +++ b/components/efuse/test/include/esp_efuse_test_table.h @@ -17,7 +17,7 @@ extern "C" { #endif -// md5_digest dac4d84347dab29412b8b8713b4b0065 +// md5_digest_table 7d587827a6f6134241dce7d3713b3edc // This file was generated automatically from the file esp_efuse_test_table.csv. DO NOT CHANGE THIS FILE MANUALLY. // If you want to change some fields, you need to change esp_efuse_test_table.csv file then build system will generate this header file // To show efuse_table run the command 'make show_efuse_table'. diff --git a/components/efuse/test_efuse_host/efuse_tests.py b/components/efuse/test_efuse_host/efuse_tests.py index e2a546b94d..aff867e223 100644 --- a/components/efuse/test_efuse_host/efuse_tests.py +++ b/components/efuse/test_efuse_host/efuse_tests.py @@ -8,8 +8,13 @@ import subprocess import tempfile import os import StringIO -sys.path.append("..") -from efuse import * + +try: + import efuse_table_gen +except ImportError: + sys.path.append("..") + import efuse_table_gen + ''' To run the test on local PC: @@ -26,20 +31,20 @@ class CSVParserTests(unittest.TestCase): name1, EFUSE_BLK3, 0, 5, Use for test name 1 name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ - t = FuseTable.from_csv(csv) + t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3') - self.assertEqual(t[0].bit_start, 0) - self.assertEqual(t[0].bit_count, 5) - self.assertEqual(t[0].comment, 'Use for test name 1') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + self.assertEqual(t[0].comment, 'Use for test name 1') self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3') - self.assertEqual(t[1].bit_start, 5) - self.assertEqual(t[1].bit_count, 4) - self.assertEqual(t[1].comment, 'Use for test name 2') + self.assertEqual(t[1].bit_start, 5) + self.assertEqual(t[1].bit_count, 4) + self.assertEqual(t[1].comment, 'Use for test name 2') def test_seq_bit_start1_fill(self): csv = """ @@ -47,16 +52,16 @@ name2, EFUSE_BLK3, 5, name1, EFUSE_BLK3, , 5, name2, EFUSE_BLK3, , 4, """ - t = FuseTable.from_csv(csv) + t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() self.assertEqual(t[0].field_name, 'name1') - self.assertEqual(t[0].bit_start, 0) - self.assertEqual(t[0].bit_count, 5) + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) self.assertEqual(t[1].field_name, 'name2') - self.assertEqual(t[1].bit_start, 5) - self.assertEqual(t[1].bit_count, 4) + self.assertEqual(t[1].bit_start, 5) + self.assertEqual(t[1].bit_count, 4) def test_seq_bit_start2_fill(self): csv = """ @@ -64,16 +69,16 @@ name2, EFUSE_BLK3, , name1, EFUSE_BLK3, , 5, name2, EFUSE_BLK2, , 4, """ - t = FuseTable.from_csv(csv) + t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() self.assertEqual(t[0].field_name, 'name1') - self.assertEqual(t[0].bit_start, 0) - self.assertEqual(t[0].bit_count, 5) + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) self.assertEqual(t[1].field_name, 'name2') - self.assertEqual(t[1].bit_start, 0) - self.assertEqual(t[1].bit_count, 4) + self.assertEqual(t[1].bit_start, 0) + self.assertEqual(t[1].bit_count, 4) def test_seq_bit_start3_fill(self): csv = """ @@ -83,20 +88,20 @@ name2, EFUSE_BLK2, , name3, EFUSE_BLK2, 5, 4, """ - t = FuseTable.from_csv(csv) + t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() self.assertEqual(t[0].field_name, 'name1') - self.assertEqual(t[0].bit_start, 0) - self.assertEqual(t[0].bit_count, 5) + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) self.assertEqual(t[1].field_name, 'name2') - self.assertEqual(t[1].bit_start, 0) - self.assertEqual(t[1].bit_count, 4) + self.assertEqual(t[1].bit_start, 0) + self.assertEqual(t[1].bit_count, 4) self.assertEqual(t[2].field_name, 'name3') - self.assertEqual(t[2].bit_start, 5) - self.assertEqual(t[2].bit_count, 4) + self.assertEqual(t[2].bit_start, 5) + self.assertEqual(t[2].bit_count, 4) def test_seq_bit_start4_fill(self): csv = """ @@ -106,9 +111,8 @@ name2, EFUSE_BLK2, , , EFUSE_BLK2, , 4, name1, EFUSE_BLK3, , 5, """ - with self.assertRaisesRegexp(InputError, "Field names must be unique"): - t = FuseTable.from_csv(csv) - + with self.assertRaisesRegexp(efuse_table_gen.InputError, "Field names must be unique"): + t = efuse_table_gen.FuseTable.from_csv(csv) def test_seq_bit_start5_fill(self): csv = """ @@ -118,33 +122,33 @@ name2, EFUSE_BLK2, , , EFUSE_BLK2, , 4, name3, EFUSE_BLK3, 5, 5, """ - t = FuseTable.from_csv(csv) + t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() self.assertEqual(t[0].field_name, 'name1') - self.assertEqual(t[0].bit_start, 0) - self.assertEqual(t[0].bit_count, 5) + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) self.assertEqual(t[1].field_name, 'name2') - self.assertEqual(t[1].bit_start, 0) - self.assertEqual(t[1].bit_count, 4) + self.assertEqual(t[1].bit_start, 0) + self.assertEqual(t[1].bit_count, 4) self.assertEqual(t[2].field_name, 'name2') - self.assertEqual(t[2].bit_start, 4) - self.assertEqual(t[2].bit_count, 4) + self.assertEqual(t[2].bit_start, 4) + self.assertEqual(t[2].bit_count, 4) self.assertEqual(t[3].field_name, 'name3') - self.assertEqual(t[3].bit_start, 5) - self.assertEqual(t[3].bit_count, 5) - + self.assertEqual(t[3].bit_start, 5) + self.assertEqual(t[3].bit_count, 5) + def test_overlapping_bit_start_fail(self): csv = """ # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment name1, EFUSE_BLK3, 1, 5, Use for test name 1 name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ - t = FuseTable.from_csv(csv) - with self.assertRaisesRegexp(InputError, "overlap"): + t = efuse_table_gen.FuseTable.from_csv(csv) + with self.assertRaisesRegexp(efuse_table_gen.InputError, "overlap"): t.verify() def test_empty_field_name_fail(self): @@ -153,26 +157,26 @@ name2, EFUSE_BLK3, 5, , EFUSE_BLK3, , 5, name2, EFUSE_BLK2, , 4, """ - with self.assertRaisesRegexp(InputError, "missing field name"): - t = FuseTable.from_csv(csv) - + with self.assertRaisesRegexp(efuse_table_gen.InputError, "missing field name"): + t = efuse_table_gen.FuseTable.from_csv(csv) + def test_unique_field_name_fail(self): csv = """ # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment name1, EFUSE_BLK3, 0, 5, Use for test name 1 name1, EFUSE_BLK3, 5, 4, Use for test name 2 """ - with self.assertRaisesRegexp(InputError, "Field names must be unique"): - t = FuseTable.from_csv(csv) - + with self.assertRaisesRegexp(efuse_table_gen.InputError, "Field names must be unique"): + t = efuse_table_gen.FuseTable.from_csv(csv) + def test_bit_count_empty_fail(self): csv = """ # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment name1, EFUSE_BLK3, 0, , Use for test name 1 name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ - with self.assertRaisesRegexp(InputError, "empty"): - t = FuseTable.from_csv(csv) + with self.assertRaisesRegexp(efuse_table_gen.InputError, "empty"): + t = efuse_table_gen.FuseTable.from_csv(csv) def test_bit_start_num_fail(self): csv = """ @@ -180,10 +184,10 @@ name2, EFUSE_BLK3, 5, name1, EFUSE_BLK3, k, 5, Use for test name 1 name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ - with self.assertRaisesRegexp(InputError, "Invalid field value"): - t = FuseTable.from_csv(csv) + with self.assertRaisesRegexp(efuse_table_gen.InputError, "Invalid field value"): + t = efuse_table_gen.FuseTable.from_csv(csv) - def test_join_entry(self): + def test_join_entry(self): csv = """ # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment name1, EFUSE_BLK2, 0, 6, Use for test name 1 @@ -192,33 +196,33 @@ name3, EFUSE_BLK3, 20, , EFUSE_BLK3, 30, 5, Use for test name 3 name4, EFUSE_BLK2, 30, 5, Use for test name 4 """ - t = FuseTable.from_csv(csv) + t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].efuse_block, 'EFUSE_BLK2') - self.assertEqual(t[0].bit_start, 0) - self.assertEqual(t[0].bit_count, 6) + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 6) self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].efuse_block, 'EFUSE_BLK2') - self.assertEqual(t[1].bit_start, 6) - self.assertEqual(t[1].bit_count, 5) + self.assertEqual(t[1].bit_start, 6) + self.assertEqual(t[1].bit_count, 5) self.assertEqual(t[2].field_name, 'name3') self.assertEqual(t[2].efuse_block, 'EFUSE_BLK3') - self.assertEqual(t[2].bit_start, 20) - self.assertEqual(t[2].bit_count, 5) + self.assertEqual(t[2].bit_start, 20) + self.assertEqual(t[2].bit_count, 5) self.assertEqual(t[3].field_name, 'name3') self.assertEqual(t[3].efuse_block, 'EFUSE_BLK3') - self.assertEqual(t[3].bit_start, 30) - self.assertEqual(t[3].bit_count, 5) + self.assertEqual(t[3].bit_start, 30) + self.assertEqual(t[3].bit_count, 5) self.assertEqual(t[4].field_name, 'name4') self.assertEqual(t[4].efuse_block, 'EFUSE_BLK2') - self.assertEqual(t[4].bit_start, 30) - self.assertEqual(t[4].bit_count, 5) + self.assertEqual(t[4].bit_start, 30) + self.assertEqual(t[4].bit_count, 5) def test_block_fail(self): csv = """ @@ -226,8 +230,8 @@ name4, EFUSE_BLK2, 30, name1, EFUSE_BLK5, 0, 5, Use for test name 1 name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ - with self.assertRaisesRegexp(InputError, "'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3"): - t = FuseTable.from_csv(csv) + with self.assertRaisesRegexp(efuse_table_gen.InputError, "'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3"): + t = efuse_table_gen.FuseTable.from_csv(csv) def test_field_size_is_ok(self): csv = """ @@ -235,17 +239,19 @@ name2, EFUSE_BLK3, 5, name1, EFUSE_BLK0, 0, 224, Use for test name 1 name2, EFUSE_BLK1, 0, 256, Use for test name 2 """ - t = FuseTable.from_csv(csv) + efuse_table_gen.coding_scheme = 0 # NONE + t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() - def test_field_blk0_size_is_more(self): + def test_field_blk3_size_is_more(self): csv = """ # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment -name1, EFUSE_BLK0, 1, 224, Use for test name 1 -name2, EFUSE_BLK1, 0, 256, Use for test name 2 +name1, EFUSE_BLK3, 190, 1, Use for test name 1 +name2, EFUSE_BLK3, 191, 5, Use for test name 2 """ - t = FuseTable.from_csv(csv) - with self.assertRaisesRegexp(InputError, "The field is outside the boundaries"): + efuse_table_gen.coding_scheme = 1 #3/4 coding + t = efuse_table_gen.FuseTable.from_csv(csv) + with self.assertRaisesRegexp(efuse_table_gen.InputError, "The field is outside the boundaries"): t.verify() def test_field_blk1_size_is_more(self): @@ -254,13 +260,14 @@ name2, EFUSE_BLK1, 0, name1, EFUSE_BLK0, 0, 224, Use for test name 1 name2, EFUSE_BLK1, 1, 256, Use for test name 2 """ - t = FuseTable.from_csv(csv) - with self.assertRaisesRegexp(InputError, "The field is outside the boundaries"): + t = efuse_table_gen.FuseTable.from_csv(csv) + with self.assertRaisesRegexp(efuse_table_gen.InputError, "The field is outside the boundaries"): t.verify() - + + class VerificationTests(unittest.TestCase): - def test_bit_start_num_fail(self): + def test_general(self): csv = """ # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment name1, EFUSE_BLK3, 0, 5, Use for test name 1 @@ -268,28 +275,60 @@ name2, EFUSE_BLK3, 5, name1_1, EFUSE_BLK2, 0, 5, Use for test name 1_1 name2_1, EFUSE_BLK2, 5, 4, Use for test name 2_1 """ - t = FuseTable.from_csv(csv) + t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3') - self.assertEqual(t[0].bit_start, 0) - self.assertEqual(t[0].bit_count, 5) + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3') - self.assertEqual(t[1].bit_start, 5) - self.assertEqual(t[1].bit_count, 4) + self.assertEqual(t[1].bit_start, 5) + self.assertEqual(t[1].bit_count, 4) self.assertEqual(t[2].field_name, 'name1_1') self.assertEqual(t[2].efuse_block, 'EFUSE_BLK2') - self.assertEqual(t[2].bit_start, 0) - self.assertEqual(t[2].bit_count, 5) + self.assertEqual(t[2].bit_start, 0) + self.assertEqual(t[2].bit_count, 5) self.assertEqual(t[3].field_name, 'name2_1') self.assertEqual(t[3].efuse_block, 'EFUSE_BLK2') - self.assertEqual(t[3].bit_start, 5) - self.assertEqual(t[3].bit_count, 4) - -if __name__ =="__main__": + self.assertEqual(t[3].bit_start, 5) + self.assertEqual(t[3].bit_count, 4) + + def test_custom_use_only_BLK3(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, 5, Use for test name 1 +name2, EFUSE_BLK2, 5, 4, Use for test name 2 + """ + t = efuse_table_gen.FuseTable.from_csv(csv) + with self.assertRaisesRegexp(efuse_table_gen.ValidationError, "custom_table should use only EFUSE_BLK3"): + t.verify("custom_table") + + def test_common_and_custom_table_use_the_same_bits(self): + csv_common = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, 5, Use for test name 1 +name2, EFUSE_BLK2, 5, 4, Use for test name 2 + """ + common_table = efuse_table_gen.FuseTable.from_csv(csv_common) + common_table.verify("common_table") + two_tables = common_table + + csv_custom = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name3, EFUSE_BLK3, 20, 5, Use for test name 1 +name4, EFUSE_BLK3, 4, 1, Use for test name 2 + """ + custom_table = efuse_table_gen.FuseTable.from_csv(csv_custom) + custom_table.verify("custom_table") + + two_tables += custom_table + with self.assertRaisesRegexp(efuse_table_gen.InputError, "overlaps"): + two_tables.verify() + +if __name__ == "__main__": unittest.main() diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index f377386a42..ec532ad872 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -13,4 +13,6 @@ list(APPEND COMPONENT_SRCS "src/memory_layout_utils.c") set(COMPONENT_ADD_LDFRAGMENTS linker.lf) +set(COMPONENT_REQUIRES) + register_component() diff --git a/docs/en/api-reference/system/efuse.rst b/docs/en/api-reference/system/efuse.rst index cf6ac1b67f..bb64bcfc9a 100644 --- a/docs/en/api-reference/system/efuse.rst +++ b/docs/en/api-reference/system/efuse.rst @@ -32,7 +32,7 @@ The component has API functions for reading and writing fields. Access to the fi CSV files: * common (`esp_efuse_table.csv`) - contains efuse fields are used inside the IDF field. C-source generation should be done manually when changing this file (run command 'make efuse_common_table' or `idf.py efuse_common_table`). Note that changes to this file can lead to incorrect IDF operation. Changes are not desirable! -* custom - (may be absent, selected through :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains efuse fields that are used by the user in their application. C-source generation will be done automatically when changing this file. +* custom - (may be absent, selected through :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains efuse fields that are used by the user in their application. C-source generation should be done manually when changing this file (run command 'make efuse_custom_table' or `idf.py efuse_custom_table`). Description CSV file @@ -49,7 +49,7 @@ Table header: Individual params in csv file the following meanings: field_name - Name of field. The prefix `ESP_EFUSE_` will be added to the name, and this field name will be available in the code. This name will be used to access the fields. The name must be unique for all fields. If the line has an empty name, then this line is combined with the previous field. This allows you to set an arbitrary order of bits in the field, and expand the field as well. + Name of field. The prefix `ESP_EFUSE_` will be added to the name, and this field name will be available in the code. This name will be used to access the fields. The name must be unique for all fields. If the line has an empty name, then this line is combined with the previous field. This allows you to set an arbitrary order of bits in the field, and expand the field as well (see ``MAC_FACTORY`` field in the common table). efuse_block Block number. It determines where the efuse bits will be placed for this field. Available EFUSE_BLK0..EFUSE_BLK3. @@ -87,7 +87,8 @@ The tool is designed to generate C-source files from CSV file and validate field To generate a `common` files, use the following command 'make efuse_common_table' or `idf.py efuse_common_table` or: :: - + + cd ~/esp/esp-idf/components/efuse/ ./efuse_table_gen.py esp32/esp_efuse_table.csv After generation in the folder `esp32` create: @@ -95,10 +96,11 @@ After generation in the folder `esp32` create: * `esp_efuse_table.c` file. * In `include` folder `esp_efuse_table.c` file. -To generate custom files, you need to build the project, the build system tracks changes in the csv file and starts the regeneration of the C-source files itself. In this case, the tool will be called with the following parameters: +To generate a `custom` files, use the following command 'make efuse_custom_table' or `idf.py efuse_custom_table` or: :: + cd ~/esp/esp-idf/components/efuse/ ./efuse_table_gen.py esp32/esp_efuse_table.csv PROJECT_PATH/main/esp_efuse_custom_table.csv After generation in the folder PROJECT_PATH/main create: @@ -113,6 +115,37 @@ To use the generated fields, you need to include two files: #include "esp_efuse.h" #include "esp_efuse_table.h" or "esp_efuse_custom_table.h" +Support coding scheme +--------------------- + +eFuse have three coding schemes: + +* ``None`` (value 0). +* ``3/4`` (value 1). +* ``Repeat`` (value 2). + +The coding scheme affects only EFUSE_BLK1, EFUSE_BLK2 and EFUSE_BLK3 blocks. EUSE_BLK0 block always has a coding scheme ``None``. +Coding changes the number of bits that can be written into a block, the block length is constant 256, some of these bits are used for encoding and are not used. + +When using a coding scheme, the length of the payload that can be written is limited (for more detailes ``20.3.1.3 System Parameter coding_scheme``): + +* None 256 bits. +* 3/4 192 bits. +* Repeat 128 bits. + +You can find out the coding scheme of your chip: + +* run a ``espefuse.py -p COM4 summary`` command. +* from ``esptool`` utility logs (during flashing). +* calling the function in the code :cpp:func:`esp_efuse_get_coding_scheme` for the EFUSE_BLK3 block. + +eFuse tables must always comply with the coding scheme in the chip. There is an :envvar:`EFUSE_CODE_SCHEME_SELECTOR` option to select the coding type for tables in a Kconfig. When generating source files, if your tables do not follow the coding scheme, an error message will be displayed. Adjust the length or offset fields. +If your program was compiled with ``None`` encoding and ``3/4`` is used in the chip, then the ``ESP_ERR_CODING`` error may occur when calling the efuse API (the field is outside the block boundaries). If the field matches the new block boundaries, then the API will work without errors. + +Also, 3/4 coding scheme imposes restrictions on writing bits belonging to one coding unit. The whole block with a length of 256 bits is divided into 4 coding units, and in each coding unit there are 6 bytes of useful data and 2 service bytes. These 2 service bytes contain the checksum of the previous 6 data bytes. + +It turns out that only one field can be written into one coding unit. Repeated rewriting in one coding unit is prohibited. But if the record was made in advance or through a :cpp:func:`esp_efuse_write_block` function, then reading the fields belonging to one coding unit is possible. + eFuse API --------- @@ -124,6 +157,10 @@ Access to the fields is via a pointer to the description structure. API function * :cpp:func:`esp_efuse_write_field_cnt` - writes a required count of bits as "1". * :cpp:func:`esp_efuse_get_field_size` - returns the number of bits by the field name. * :cpp:func:`esp_efuse_read_reg` - returns value of efuse register. +* :cpp:func:`esp_efuse_write_reg` - writes value to efuse register. +* :cpp:func:`esp_efuse_get_coding_scheme` - returns efuse coding scheme for blocks. +* :cpp:func:`esp_efuse_read_block` - reads key to efuse block starting at the offset and the required size. +* :cpp:func:`esp_efuse_write_block` - writes key to efuse block starting at the offset and the required size. For frequently used fields, special functions are made, like this :cpp:func:`esp_efuse_get_chip_ver`, :cpp:func:`esp_efuse_get_pkg_ver`. @@ -131,53 +168,55 @@ For frequently used fields, special functions are made, like this :cpp:func:`esp How add a new field ------------------- -1. Find a free bits for field. Show `efuse_table.csv` file or run the next command: +1. Find a free bits for field. Show `esp_efuse_table.csv` file or run ``make show_efuse_table`` or ``idf.py show_efuse_table`` or the next command: :: $ ./efuse_table_gen.py --info esp32/esp_efuse_table.csv - Sorted efuse table: - #1 WR_DIS_FLASH_CRYPT_CNT EFUSE_BLK0 2 1 - #2 WR_DIS_BLK1 EFUSE_BLK0 7 1 - #3 WR_DIS_BLK2 EFUSE_BLK0 8 1 - #4 WR_DIS_BLK3 EFUSE_BLK0 9 1 - #5 RD_DIS_BLK1 EFUSE_BLK0 16 1 - #6 RD_DIS_BLK2 EFUSE_BLK0 17 1 - #7 RD_DIS_BLK3 EFUSE_BLK0 18 1 - #8 FLASH_CRYPT_CNT EFUSE_BLK0 20 8 - #9 MAC_FACTORY EFUSE_BLK0 32 8 - #10 MAC_FACTORY EFUSE_BLK0 40 8 - #11 MAC_FACTORY EFUSE_BLK0 48 8 - #12 MAC_FACTORY EFUSE_BLK0 56 8 - #13 MAC_FACTORY EFUSE_BLK0 64 8 - #14 MAC_FACTORY EFUSE_BLK0 72 8 - #15 MAC_FACTORY_CRC EFUSE_BLK0 80 8 - #16 CHIP_VER_DIS_APP_CPU EFUSE_BLK0 96 1 - #17 CHIP_VER_DIS_BT EFUSE_BLK0 97 1 - #18 CHIP_VER_PKG EFUSE_BLK0 105 3 - #19 CHIP_CPU_FREQ_LOW EFUSE_BLK0 108 1 - #20 CHIP_CPU_FREQ_RATED EFUSE_BLK0 109 1 - #21 CHIP_VER_REV1 EFUSE_BLK0 111 1 - #22 ADC_VREF_AND_SDIO_DREF EFUSE_BLK0 136 6 - #23 XPD_SDIO_REG EFUSE_BLK0 142 1 - #24 SDIO_TIEH EFUSE_BLK0 143 1 - #25 SDIO_FORCE EFUSE_BLK0 144 1 - #26 ENCRYPT_CONFIG EFUSE_BLK0 188 4 - #27 CONSOLE_DEBUG_DISABLE EFUSE_BLK0 194 1 - #28 ABS_DONE_0 EFUSE_BLK0 196 1 - #29 DISABLE_JTAG EFUSE_BLK0 198 1 - #30 DISABLE_DL_ENCRYPT EFUSE_BLK0 199 1 - #31 DISABLE_DL_DECRYPT EFUSE_BLK0 200 1 - #32 DISABLE_DL_CACHE EFUSE_BLK0 201 1 - #33 ENCRYPT_FLASH_KEY EFUSE_BLK1 0 256 - #34 SECURE_BOOT_KEY EFUSE_BLK2 0 256 - #35 MAC_CUSTOM_CRC EFUSE_BLK3 0 8 - #36 MAC_CUSTOM EFUSE_BLK3 8 48 - #37 ADC1_TP_LOW EFUSE_BLK3 96 7 - #38 ADC1_TP_HIGH EFUSE_BLK3 103 9 - #39 ADC2_TP_LOW EFUSE_BLK3 112 7 - #40 ADC2_TP_HIGH EFUSE_BLK3 119 9 - #41 MAC_CUSTOM_VER EFUSE_BLK3 184 8 + eFuse coding scheme: NONE + # field_name efuse_block bit_start bit_count + 1 WR_DIS_FLASH_CRYPT_CNT EFUSE_BLK0 2 1 + 2 WR_DIS_BLK1 EFUSE_BLK0 7 1 + 3 WR_DIS_BLK2 EFUSE_BLK0 8 1 + 4 WR_DIS_BLK3 EFUSE_BLK0 9 1 + 5 RD_DIS_BLK1 EFUSE_BLK0 16 1 + 6 RD_DIS_BLK2 EFUSE_BLK0 17 1 + 7 RD_DIS_BLK3 EFUSE_BLK0 18 1 + 8 FLASH_CRYPT_CNT EFUSE_BLK0 20 8 + 9 MAC_FACTORY EFUSE_BLK0 32 8 + 10 MAC_FACTORY EFUSE_BLK0 40 8 + 11 MAC_FACTORY EFUSE_BLK0 48 8 + 12 MAC_FACTORY EFUSE_BLK0 56 8 + 13 MAC_FACTORY EFUSE_BLK0 64 8 + 14 MAC_FACTORY EFUSE_BLK0 72 8 + 15 MAC_FACTORY_CRC EFUSE_BLK0 80 8 + 16 CHIP_VER_DIS_APP_CPU EFUSE_BLK0 96 1 + 17 CHIP_VER_DIS_BT EFUSE_BLK0 97 1 + 18 CHIP_VER_PKG EFUSE_BLK0 105 3 + 19 CHIP_CPU_FREQ_LOW EFUSE_BLK0 108 1 + 20 CHIP_CPU_FREQ_RATED EFUSE_BLK0 109 1 + 21 CHIP_VER_REV1 EFUSE_BLK0 111 1 + 22 ADC_VREF_AND_SDIO_DREF EFUSE_BLK0 136 6 + 23 XPD_SDIO_REG EFUSE_BLK0 142 1 + 24 SDIO_TIEH EFUSE_BLK0 143 1 + 25 SDIO_FORCE EFUSE_BLK0 144 1 + 26 ENCRYPT_CONFIG EFUSE_BLK0 188 4 + 27 CONSOLE_DEBUG_DISABLE EFUSE_BLK0 194 1 + 28 ABS_DONE_0 EFUSE_BLK0 196 1 + 29 DISABLE_JTAG EFUSE_BLK0 198 1 + 30 DISABLE_DL_ENCRYPT EFUSE_BLK0 199 1 + 31 DISABLE_DL_DECRYPT EFUSE_BLK0 200 1 + 32 DISABLE_DL_CACHE EFUSE_BLK0 201 1 + 33 ENCRYPT_FLASH_KEY EFUSE_BLK1 0 256 + 34 SECURE_BOOT_KEY EFUSE_BLK2 0 256 + 35 MAC_CUSTOM_CRC EFUSE_BLK3 0 8 + 36 MAC_CUSTOM EFUSE_BLK3 8 48 + 37 ADC1_TP_LOW EFUSE_BLK3 96 7 + 38 ADC1_TP_HIGH EFUSE_BLK3 103 9 + 39 ADC2_TP_LOW EFUSE_BLK3 112 7 + 40 ADC2_TP_HIGH EFUSE_BLK3 119 9 + 41 SECURE_VERSION EFUSE_BLK3 128 32 + 42 MAC_CUSTOM_VER EFUSE_BLK3 184 8 Used bits in efuse table: EFUSE_BLK0 @@ -190,18 +229,19 @@ How add a new field [0 255] EFUSE_BLK3 - [0 55] [96 127] [184 191] + [0 55] [96 159] [184 191] - Note: Not printed ranges are free for using. + Note: Not printed ranges are free for using. (bits in EFUSE_BLK0 are reserved for Espressif) - Parsing efuse CSV input file esp32/esp_efuse_table.csv ... + Parsing efuse CSV input file C:/msys32/home/virtpc/esp/esp-idf/components/efuse/esp32/esp_efuse_table.csv ... Verifying efuse table... -The number of bits not included in square brackets is free. All fields are checked for overlapping. + +The number of bits not included in square brackets is free (bits in EFUSE_BLK0 are reserved for Espressif). All fields are checked for overlapping. 2. Fill a line for field: field_name, efuse_block, bit_start, bit_count, comment. -3. Run a command `make show_efuse_table` to check and generate header file. +3. Run a ``show_efuse_table`` command to check efuse table. To generate source files run ``efuse_common_table`` or ``efuse_custom_table`` command. Debug efuse & Unit tests ------------------------ @@ -213,13 +253,13 @@ esptool have an useful tool for reading/writing ESP32 efuse bits - `espefuse.py :: espefuse.py -p COM4 summary - + espefuse.py v2.3.1 Connecting........_ Security fuses: - FLASH_CRYPT_CNT Flash encryption mode counter = 0 R/W (0x4) + FLASH_CRYPT_CNT Flash encryption mode counter = 0 R/W (0x0) FLASH_CRYPT_CONFIG Flash encryption config (key tweak bits) = 0 R/W (0x0) - CONSOLE_DEBUG_DISABLE Disable ROM BASIC interpreter fallback = 0 R/W (0x0) + CONSOLE_DEBUG_DISABLE Disable ROM BASIC interpreter fallback = 1 R/W (0x1) ABS_DONE_0 secure boot enabled for bootloader = 0 R/W (0x0) ABS_DONE_1 secure boot abstract 1 locked = 0 R/W (0x0) JTAG_DISABLE Disable JTAG = 0 R/W (0x0) @@ -231,12 +271,12 @@ esptool have an useful tool for reading/writing ESP32 efuse bits - `espefuse.py BLK2 Secure boot key = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W BLK3 Variable Block 3 - = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa 87 02 91 00 00 00 00 00 00 00 00 00 00 00 00 R/W Efuse fuses: WR_DIS Efuse write disable mask = 0 R/W (0x0) RD_DIS Efuse read disablemask = 0 R/W (0x0) - CODING_SCHEME Efuse variable block length scheme = 0 R/W (0x0) + CODING_SCHEME Efuse variable block length scheme = 1 R/W (0x1) (3/4) KEY_STATUS Usage of efuse block 3 (reserved) = 0 R/W (0x0) Config fuses: @@ -252,14 +292,18 @@ esptool have an useful tool for reading/writing ESP32 efuse bits - `espefuse.py Identity fuses: MAC MAC Address - = 24:0a:c4:03:bb:68 (CRC 82 OK) R/W - CHIP_VER_REV1 Silicon Revision 1 = 0 R/W (0x0) - CHIP_VERSION Reserved for future chip versions = 0 R/W (0x0) + = 84:0d:8e:18:8e:44 (CRC ad OK) R/W + CHIP_VER_REV1 Silicon Revision 1 = 1 R/W (0x1) + CHIP_VERSION Reserved for future chip versions = 2 R/W (0x2) CHIP_PACKAGE Chip package identifier = 0 R/W (0x0) Calibration fuses: - BLK3_PART_RESERVE BLOCK3 partially served for ADC calibration data = 0 R/W (0x0) - ADC_VREF Voltage reference calibration = 1100 R/W (0x0) + BLK3_PART_RESERVE BLOCK3 partially served for ADC calibration data = 1 R/W (0x1) + ADC_VREF Voltage reference calibration = 1114 R/W (0x2) + ADC1_TP_LOW ADC1 150mV reading = 346 R/W (0x11) + ADC1_TP_HIGH ADC1 850mV reading = 3285 R/W (0x5) + ADC2_TP_LOW ADC2 150mV reading = 449 R/W (0x7) + ADC2_TP_HIGH ADC2 850mV reading = 3362 R/W (0x1f5) Flash voltage (VDD_SDIO) determined by GPIO12 on reset (High for 1.8V, Low/NC for 3.3V). diff --git a/make/project.mk b/make/project.mk index a0d411496f..a1307b0454 100644 --- a/make/project.mk +++ b/make/project.mk @@ -13,7 +13,7 @@ .PHONY: build-components menuconfig defconfig all build clean all_binaries check-submodules size size-components size-files size-symbols list-components MAKECMDGOALS ?= all -all: efuse_table all_binaries | check_python_dependencies +all: all_binaries | check_python_dependencies # see below for recipe of 'all' target # # # other components will add dependencies to 'all_binaries'. The @@ -481,7 +481,7 @@ $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp $(summary) LD $(patsubst $(PWD)/%,%,$@) $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP) -app: efuse_table $(APP_BIN) partition_table_get_info +app: $(APP_BIN) partition_table_get_info ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image @echo "App built but not signed. Signing step via espsecure.py:" @echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)" diff --git a/tools/idf.py b/tools/idf.py index 927efca0f6..2d31d66713 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -424,6 +424,7 @@ ACTIONS = { "app-flash": (flash, ["app"], ["erase_flash"]), "efuse_common_table": (build_target, [], ["reconfigure"]), "efuse_custom_table": (build_target, [], ["reconfigure"]), + "show_efuse_table": (build_target, [], ["reconfigure"]), "partition_table": (build_target, [], ["reconfigure"]), "partition_table-flash": (flash, ["partition_table"], ["erase_flash"]), "flash": (flash, ["all"], ["erase_flash"]), From 303d17792a21350d582a1de73ec23793b6aa0f36 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Fri, 7 Dec 2018 17:57:25 +0800 Subject: [PATCH 09/15] efuse: Add a write/read protection --- components/efuse/include/esp_efuse.h | 30 +++++++++++++++++ components/efuse/src/esp_efuse_api.c | 27 ++++++++++++++++ components/efuse/test/test_efuse.c | 48 ++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h index 349b6f7923..22f6879366 100644 --- a/components/efuse/include/esp_efuse.h +++ b/components/efuse/include/esp_efuse.h @@ -123,6 +123,36 @@ esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void */ esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt); +/** + * @brief Sets a write protection for the whole block. + * + * After that, it is impossible to write to this block. + * The write protection does not apply to block 0. + * @param[in] blk Block number of eFuse. (EFUSE_BLK1, EFUSE_BLK2 and EFUSE_BLK3) + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_EFUSE_CNT_IS_FULL: Not all requested cnt bits is set. + * - ESP_ERR_NOT_SUPPORTED: The block does not support this command. + */ +esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk); + +/** + * @brief Sets a read protection for the whole block. + * + * After that, it is impossible to read from this block. + * The read protection does not apply to block 0. + * @param[in] blk Block number of eFuse. (EFUSE_BLK1, EFUSE_BLK2 and EFUSE_BLK3) + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_EFUSE_CNT_IS_FULL: Not all requested cnt bits is set. + * - ESP_ERR_NOT_SUPPORTED: The block does not support this command. + */ +esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk); + /** * @brief Returns the number of bits used by field. * diff --git a/components/efuse/src/esp_efuse_api.c b/components/efuse/src/esp_efuse_api.c index 709985786d..09f6e5b1c0 100644 --- a/components/efuse/src/esp_efuse_api.c +++ b/components/efuse/src/esp_efuse_api.c @@ -17,6 +17,7 @@ #include "soc/efuse_reg.h" #include "assert.h" #include "sdkconfig.h" +#include "esp_efuse_table.h" const static char *TAG = "efuse"; @@ -113,6 +114,32 @@ esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt) return err; } +// Sets a write protection for the whole block. +esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk) +{ + if (blk == EFUSE_BLK1) { + return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK1, 1); + } else if (blk == EFUSE_BLK2) { + return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK2, 1); + } else if (blk == EFUSE_BLK3) { + return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK3, 1); + } + return ESP_ERR_NOT_SUPPORTED; +} + +// read protect for blk. +esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk) +{ + if (blk == EFUSE_BLK1) { + return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_BLK1, 1); + } else if (blk == EFUSE_BLK2) { + return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_BLK2, 1); + } else if (blk == EFUSE_BLK3) { + return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_BLK3, 1); + } + return ESP_ERR_NOT_SUPPORTED; +} + // get the length of the field in bits int esp_efuse_get_field_size(const esp_efuse_desc_t* field[]) { diff --git a/components/efuse/test/test_efuse.c b/components/efuse/test/test_efuse.c index c41e2b5e16..91fe35c85c 100644 --- a/components/efuse/test/test_efuse.c +++ b/components/efuse/test/test_efuse.c @@ -543,4 +543,52 @@ TEST_CASE("Test Bits are not empty. Write operation is forbidden", "[efuse]") printf("Test skipped. It is not applicable, the device has no written bits."); } } + +TEST_CASE("Test a write/read protection", "[efuse]") +{ + esp_efuse_utility_reset(); + esp_efuse_utility_erase_virt_blocks(); + + esp_efuse_utility_debug_dump_blocks(); + + TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_efuse_set_write_protect(EFUSE_BLK0)); + TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_efuse_set_read_protect(EFUSE_BLK0)); + + size_t out_cnt; + esp_efuse_read_field_cnt(ESP_EFUSE_WR_DIS_BLK1, &out_cnt); + TEST_ASSERT_EQUAL_INT(0, out_cnt); + TEST_ESP_OK(esp_efuse_set_write_protect(EFUSE_BLK1)); + esp_efuse_read_field_cnt(ESP_EFUSE_WR_DIS_BLK1, &out_cnt); + TEST_ASSERT_EQUAL_INT(1, out_cnt); + TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_set_write_protect(EFUSE_BLK1)); + + TEST_ESP_OK(esp_efuse_set_write_protect(EFUSE_BLK2)); + esp_efuse_read_field_cnt(ESP_EFUSE_WR_DIS_BLK2, &out_cnt); + TEST_ASSERT_EQUAL_INT(1, out_cnt); + + TEST_ESP_OK(esp_efuse_set_write_protect(EFUSE_BLK3)); + esp_efuse_read_field_cnt(ESP_EFUSE_WR_DIS_BLK3, &out_cnt); + TEST_ASSERT_EQUAL_INT(1, out_cnt); + + esp_efuse_utility_debug_dump_blocks(); + + esp_efuse_read_field_cnt(ESP_EFUSE_RD_DIS_BLK1, &out_cnt); + TEST_ASSERT_EQUAL_INT(0, out_cnt); + TEST_ESP_OK(esp_efuse_set_read_protect(EFUSE_BLK1)); + esp_efuse_read_field_cnt(ESP_EFUSE_RD_DIS_BLK1, &out_cnt); + TEST_ASSERT_EQUAL_INT(1, out_cnt); + TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_set_read_protect(EFUSE_BLK1)); + + TEST_ESP_OK(esp_efuse_set_read_protect(EFUSE_BLK2)); + esp_efuse_read_field_cnt(ESP_EFUSE_RD_DIS_BLK2, &out_cnt); + TEST_ASSERT_EQUAL_INT(1, out_cnt); + + TEST_ESP_OK(esp_efuse_set_read_protect(EFUSE_BLK3)); + esp_efuse_read_field_cnt(ESP_EFUSE_RD_DIS_BLK3, &out_cnt); + TEST_ASSERT_EQUAL_INT(1, out_cnt); + + esp_efuse_utility_debug_dump_blocks(); + esp_efuse_utility_reset(); + esp_efuse_utility_erase_virt_blocks(); +} #endif // #ifdef CONFIG_EFUSE_VIRTUAL From a5fa3b6965e707ccc9e5528b4306baa4f1c2c611 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Fri, 7 Dec 2018 19:28:57 +0800 Subject: [PATCH 10/15] CI: Add host tests --- .gitlab-ci.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a1193c8626..0c55ce4cd5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -593,6 +593,22 @@ test_esp_err_to_name_on_host: - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 ./gen_esp_err_to_name.py - git diff --exit-code -- ../components/esp32/esp_err_to_name.c || { echo 'Differences found between running under Python 2 and 3.'; exit 1; } +test_esp_efuse_table_on_host: + <<: *host_test_template + artifacts: + when: on_failure + paths: + - components/efuse/esp32/esp_efuse_table.c + expire_in: 1 week + script: + - cd ${IDF_PATH}/components/efuse/ + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 2.7.15 ./efuse_table_gen.py ${IDF_PATH}/components/efuse/esp32/esp_efuse_table.csv + - git diff --exit-code -- esp32/esp_efuse_table.c || { echo 'Differences found. Please run make efuse_common_table or idf.py efuse_common_table and commit the changes.'; exit 1; } + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 ./efuse_table_gen.py ${IDF_PATH}/components/efuse/esp32/esp_efuse_table.csv + - git diff --exit-code -- ../components/esp32/esp_efuse_table.c || { echo 'Differences found between running under Python 2 and 3.'; exit 1; } + - cd ${IDF_PATH}/components/efuse/test_efuse_host + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./efuse_tests.py + test_espcoredump: <<: *host_test_template artifacts: From cc094ba789cd4001a5ae81d890d16da9580d28e7 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Fri, 7 Dec 2018 20:32:58 +0800 Subject: [PATCH 11/15] efuse: Fix python coding style Set python's scripts attribute chmod Add compatibility with Python3 for efuse_table_gen.py --- components/efuse/efuse_table_gen.py | 130 ++++++++---------- .../efuse/test_efuse_host/efuse_tests.py | 73 +++++----- 2 files changed, 91 insertions(+), 112 deletions(-) mode change 100644 => 100755 components/efuse/efuse_table_gen.py mode change 100644 => 100755 components/efuse/test_efuse_host/efuse_tests.py diff --git a/components/efuse/efuse_table_gen.py b/components/efuse/efuse_table_gen.py old mode 100644 new mode 100755 index 368a063891..0804f6a6a0 --- a/components/efuse/efuse_table_gen.py +++ b/components/efuse/efuse_table_gen.py @@ -21,11 +21,8 @@ from __future__ import print_function, division import argparse import os import re -import struct import sys import hashlib -import binascii -import ntpath __version__ = '1.0' @@ -33,9 +30,9 @@ quiet = False coding_scheme = 0 CODE_SCHEME = { - "NONE" : 0, - "3/4" : 1, - "REPEAT" : 2, + "NONE": 0, + "3/4": 1, + "REPEAT": 2, } copyright = '''// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD @@ -52,7 +49,8 @@ copyright = '''// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD // See the License for the specific language governing permissions and // limitations under the License ''' - + + def status(msg): """ Print status message to stderr """ if not quiet: @@ -74,6 +72,7 @@ class FuseTable(list): def from_csv(cls, csv_contents): res = FuseTable() lines = csv_contents.splitlines() + def expand_vars(f): f = os.path.expandvars(f) m = re.match(r'(? 1) @@ -127,17 +125,17 @@ class FuseTable(list): else: i_count = 0 res.verify_duplicate_name() - + # clac md5 for table res.calc_md5() - + return res def verify_duplicate_name(self): # check on duplicate name names = [p.field_name for p in self] duplicates = set(n for n in names if names.count(n) > 1) - + # print sorted duplicate partitions by name if len(duplicates) != 0: fl_error = False @@ -145,17 +143,17 @@ class FuseTable(list): field_name = p.field_name + p.group if field_name != "" and len(duplicates.intersection([field_name])) != 0: fl_error = True - print ("Field at %s, %s, %s, %s have dublicate field_name" % - (p.field_name, p.efuse_block, p.bit_start, p.bit_count)) - if fl_error == True: + print("Field at %s, %s, %s, %s have dublicate field_name" % + (p.field_name, p.efuse_block, p.bit_start, p.bit_count)) + if fl_error is True: raise InputError("Field names must be unique") - - def verify(self, type_table = None): + + def verify(self, type_table=None): for p in self: p.verify(type_table) self.verify_duplicate_name() - + # check for overlaps last = None for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): @@ -164,28 +162,14 @@ class FuseTable(list): (p.field_name, p.efuse_block, p.bit_start, p.bit_count, last.field_name, last.efuse_block, last.bit_start, last.bit_count)) last = p - - def fix_size_fields_from_blk1_blk2(self): - for p in self: - if (p.efuse_block == "EFUSE_BLK1" and custom_table_use_BLK1 == False) or (p.efuse_block == "EFUSE_BLK2" and custom_table_use_BLK2 == False): - max_bits = p.get_max_bits_of_block() - if p.bit_start == 0 and p.bit_count > max_bits: - print("Fix size `%s` field from %d to %d" % (p.field_name, p.bit_count, max_bits)) - p.bit_count = max_bits - - def keys_from_blk1_blk2_make_empty(self): - for p in self: - if (p.efuse_block == "EFUSE_BLK1" and custom_table_use_BLK1 == True) or (p.efuse_block == "EFUSE_BLK2" and custom_table_use_BLK2 == True): - p.bit_count = 0 - print("efuse: `%s` field was changed from %d to 0" % (p.field_name, p.bit_count)) - + def calc_md5(self): txt_table = '' for p in self: txt_table += "%s %s %d %d %s" % (p.field_name, p.efuse_block, p.bit_start, p.bit_count, p.comment) + "\n" - self.md5_digest_table = hashlib.md5(txt_table).hexdigest() - - def show_range_used_bits(self): + self.md5_digest_table = hashlib.md5(txt_table.encode('utf-8')).hexdigest() + + def show_range_used_bits(self): # print used and free bits rows = '' rows += 'Sorted efuse table:\n' @@ -194,13 +178,13 @@ class FuseTable(list): for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): rows += "{0} \t{1:<30} \t{2} \t{3:^8} \t{4:^8}".format(num, p.field_name, p.efuse_block, p.bit_start, p.bit_count) + "\n" num += 1 - + rows += '\nUsed bits in efuse table:\n' last = None for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): if last is None: rows += '%s \n[%d ' % (p.efuse_block, p.bit_start) - if last is not None: + if last is not None: if last.efuse_block != p.efuse_block: rows += '%d] \n\n%s \n[%d ' % (last.bit_start + last.bit_count - 1, p.efuse_block, p.bit_start) elif last.bit_start + last.bit_count != p.bit_start: @@ -209,7 +193,7 @@ class FuseTable(list): rows += '%d] \n' % (last.bit_start + last.bit_count - 1) rows += '\nNote: Not printed ranges are free for using. (bits in EFUSE_BLK0 are reserved for Espressif)\n' return rows - + def to_header(self, file_name): rows = [copyright] rows += ["#ifdef __cplusplus", @@ -223,13 +207,13 @@ class FuseTable(list): "// To show efuse_table run the command 'make show_efuse_table'.", "", ""] - + last_field_name = '' for p in self: if (p.field_name != last_field_name): rows += ["extern const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[];"] last_field_name = p.field_name - + rows += ["", "#ifdef __cplusplus", "}", @@ -248,7 +232,7 @@ class FuseTable(list): "// To show efuse_table run the command 'make show_efuse_table'.", "", ""] - + last_name = '' for p in self: if (p.field_name != last_name): @@ -258,9 +242,8 @@ class FuseTable(list): last_name = p.field_name rows += [p.to_struct(debug) + ","] rows += ["};\n"] - rows += ["\n\n\n"] - + last_name = '' for p in self: if (p.field_name != last_name): @@ -272,8 +255,8 @@ class FuseTable(list): index = str(0) if str(p.group) == "" else str(p.group) rows += [" &" + p.field_name + "[" + index + "], \t\t// " + p.comment] rows += [" NULL", - "};\n" ] - + "};\n"] + return '\n'.join(rows) + "\n" @@ -306,13 +289,13 @@ class FuseDefinition(object): if strval == "": return None # Field will fill in default return self.parse_int(strval) - + def parse_int(self, v): try: return int(v, 0) except ValueError: raise InputError("Invalid field value %s" % v) - + def parse_block(self, strval): if strval == "": raise InputError("Field 'efuse_block' can't be left empty.") @@ -334,35 +317,35 @@ class FuseDefinition(object): else: raise ValidationError(self, "Unknown coding scheme") return max_bits - + def verify(self, type_table): if self.efuse_block is None: raise ValidationError(self, "efuse_block field is not set") if self.bit_count is None: raise ValidationError(self, "bit_count field is not set") - + if type_table is not None: if type_table == "custom_table": if self.efuse_block != "EFUSE_BLK3": raise ValidationError(self, "custom_table should use only EFUSE_BLK3") - + max_bits = self.get_max_bits_of_block() if self.bit_start + self.bit_count > max_bits: raise ValidationError(self, "The field is outside the boundaries(max_bits = %d) of the %s block" % (max_bits, self.efuse_block)) - + def get_full_name(self): def get_postfix(group): postfix = "" if group != "": postfix = "_PART_" + group return postfix - + return self.field_name + get_postfix(self.group) - + def to_struct(self, debug): start = " {" - if (debug == True): + if debug is True: start = " {" + '"' + self.field_name + '" ,' return ", ".join([start + self.efuse_block, str(self.bit_start), @@ -390,24 +373,24 @@ def ckeck_md5_in_file(md5, filename): def create_output_files(name, output_table, debug): file_name = os.path.splitext(os.path.basename(name))[0] gen_dir = os.path.dirname(name) - + dir_for_file_h = gen_dir + "/include" try: os.stat(dir_for_file_h) - except: + except Exception: os.mkdir(dir_for_file_h) - + file_h_path = os.path.join(dir_for_file_h, file_name + ".h") file_c_path = os.path.join(gen_dir, file_name + ".c") - + # src files are the same - if ckeck_md5_in_file(output_table.md5_digest_table, file_c_path) == False: + if ckeck_md5_in_file(output_table.md5_digest_table, file_c_path) is False: status("Creating efuse *.h file " + file_h_path + " ...") output = output_table.to_header(file_name) with open(file_h_path, 'w') as f: f.write(output) f.close() - + status("Creating efuse *.c file " + file_c_path + " ...") output = output_table.to_c_file(file_name, debug) with open(file_c_path, 'w') as f: @@ -420,15 +403,14 @@ def create_output_files(name, output_table, debug): def main(): global quiet global coding_scheme - + parser = argparse.ArgumentParser(description='ESP32 eFuse Manager') - parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') parser.add_argument('--debug', help='Create header file with debug info', default=False, action="store_false") parser.add_argument('--info', help='Print info about range of used bits', default=False, action="store_true") parser.add_argument('--coding_scheme', help='Coding scheme', type=int, default=0) - parser.add_argument('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('rb')) - parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('rb'), nargs='?', default=None) + parser.add_argument('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('r')) + parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('r'), nargs='?', default=None) args = parser.parse_args() @@ -441,37 +423,39 @@ def main(): print("eFuse coding scheme: REPEAT") else: raise InputError("unknown CODE_SCHEME = %s" % (coding_scheme)) - + quiet = args.quiet debug = args.debug info = args.info - + common_table = process_input_file(args.common_input, "common_table") two_table = common_table if args.custom_input is not None: custom_table = process_input_file(args.custom_input, "custom_table") two_table += custom_table two_table.verify() - + # save files. - if info == False: + if info is False: if args.custom_input is None: create_output_files(args.common_input.name, common_table, debug) else: create_output_files(args.custom_input.name, custom_table, debug) else: print(two_table.show_range_used_bits()) - return 0 + class InputError(RuntimeError): def __init__(self, e): super(InputError, self).__init__(e) + class ValidationError(InputError): def __init__(self, p, message): super(ValidationError, self).__init__("Entry %s invalid: %s" % (p.field_name, message)) + if __name__ == '__main__': try: main() diff --git a/components/efuse/test_efuse_host/efuse_tests.py b/components/efuse/test_efuse_host/efuse_tests.py old mode 100644 new mode 100755 index aff867e223..45f537326e --- a/components/efuse/test_efuse_host/efuse_tests.py +++ b/components/efuse/test_efuse_host/efuse_tests.py @@ -1,13 +1,7 @@ #!/usr/bin/env python from __future__ import print_function, division import unittest -import struct -import csv import sys -import subprocess -import tempfile -import os -import StringIO try: import efuse_table_gen @@ -33,13 +27,13 @@ name2, EFUSE_BLK3, 5, """ t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() - + self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3') self.assertEqual(t[0].bit_start, 0) self.assertEqual(t[0].bit_count, 5) self.assertEqual(t[0].comment, 'Use for test name 1') - + self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3') self.assertEqual(t[1].bit_start, 5) @@ -54,11 +48,11 @@ name2, EFUSE_BLK3, , """ t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() - + self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].bit_start, 0) self.assertEqual(t[0].bit_count, 5) - + self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].bit_start, 5) self.assertEqual(t[1].bit_count, 4) @@ -71,11 +65,11 @@ name2, EFUSE_BLK2, , """ t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() - + self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].bit_start, 0) self.assertEqual(t[0].bit_count, 5) - + self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].bit_start, 0) self.assertEqual(t[1].bit_count, 4) @@ -90,15 +84,15 @@ name3, EFUSE_BLK2, 5, """ t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() - + self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].bit_start, 0) self.assertEqual(t[0].bit_count, 5) - + self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].bit_start, 0) self.assertEqual(t[1].bit_count, 4) - + self.assertEqual(t[2].field_name, 'name3') self.assertEqual(t[2].bit_start, 5) self.assertEqual(t[2].bit_count, 4) @@ -112,7 +106,7 @@ name2, EFUSE_BLK2, , name1, EFUSE_BLK3, , 5, """ with self.assertRaisesRegexp(efuse_table_gen.InputError, "Field names must be unique"): - t = efuse_table_gen.FuseTable.from_csv(csv) + efuse_table_gen.FuseTable.from_csv(csv) def test_seq_bit_start5_fill(self): csv = """ @@ -124,19 +118,19 @@ name3, EFUSE_BLK3, 5, """ t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() - + self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].bit_start, 0) self.assertEqual(t[0].bit_count, 5) - + self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].bit_start, 0) self.assertEqual(t[1].bit_count, 4) - + self.assertEqual(t[2].field_name, 'name2') self.assertEqual(t[2].bit_start, 4) self.assertEqual(t[2].bit_count, 4) - + self.assertEqual(t[3].field_name, 'name3') self.assertEqual(t[3].bit_start, 5) self.assertEqual(t[3].bit_count, 5) @@ -158,7 +152,7 @@ name2, EFUSE_BLK3, 5, name2, EFUSE_BLK2, , 4, """ with self.assertRaisesRegexp(efuse_table_gen.InputError, "missing field name"): - t = efuse_table_gen.FuseTable.from_csv(csv) + efuse_table_gen.FuseTable.from_csv(csv) def test_unique_field_name_fail(self): csv = """ @@ -167,7 +161,7 @@ name1, EFUSE_BLK3, 0, name1, EFUSE_BLK3, 5, 4, Use for test name 2 """ with self.assertRaisesRegexp(efuse_table_gen.InputError, "Field names must be unique"): - t = efuse_table_gen.FuseTable.from_csv(csv) + efuse_table_gen.FuseTable.from_csv(csv) def test_bit_count_empty_fail(self): csv = """ @@ -176,7 +170,7 @@ name1, EFUSE_BLK3, 0, name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ with self.assertRaisesRegexp(efuse_table_gen.InputError, "empty"): - t = efuse_table_gen.FuseTable.from_csv(csv) + efuse_table_gen.FuseTable.from_csv(csv) def test_bit_start_num_fail(self): csv = """ @@ -185,7 +179,7 @@ name1, EFUSE_BLK3, k, name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ with self.assertRaisesRegexp(efuse_table_gen.InputError, "Invalid field value"): - t = efuse_table_gen.FuseTable.from_csv(csv) + efuse_table_gen.FuseTable.from_csv(csv) def test_join_entry(self): csv = """ @@ -198,27 +192,27 @@ name4, EFUSE_BLK2, 30, """ t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() - + self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].efuse_block, 'EFUSE_BLK2') self.assertEqual(t[0].bit_start, 0) self.assertEqual(t[0].bit_count, 6) - + self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].efuse_block, 'EFUSE_BLK2') self.assertEqual(t[1].bit_start, 6) self.assertEqual(t[1].bit_count, 5) - + self.assertEqual(t[2].field_name, 'name3') self.assertEqual(t[2].efuse_block, 'EFUSE_BLK3') self.assertEqual(t[2].bit_start, 20) self.assertEqual(t[2].bit_count, 5) - + self.assertEqual(t[3].field_name, 'name3') self.assertEqual(t[3].efuse_block, 'EFUSE_BLK3') self.assertEqual(t[3].bit_start, 30) self.assertEqual(t[3].bit_count, 5) - + self.assertEqual(t[4].field_name, 'name4') self.assertEqual(t[4].efuse_block, 'EFUSE_BLK2') self.assertEqual(t[4].bit_start, 30) @@ -231,7 +225,7 @@ name1, EFUSE_BLK5, 0, name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ with self.assertRaisesRegexp(efuse_table_gen.InputError, "'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3"): - t = efuse_table_gen.FuseTable.from_csv(csv) + efuse_table_gen.FuseTable.from_csv(csv) def test_field_size_is_ok(self): csv = """ @@ -239,7 +233,7 @@ name2, EFUSE_BLK3, 5, name1, EFUSE_BLK0, 0, 224, Use for test name 1 name2, EFUSE_BLK1, 0, 256, Use for test name 2 """ - efuse_table_gen.coding_scheme = 0 # NONE + efuse_table_gen.coding_scheme = 0 # NONE t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() @@ -249,7 +243,7 @@ name2, EFUSE_BLK1, 0, name1, EFUSE_BLK3, 190, 1, Use for test name 1 name2, EFUSE_BLK3, 191, 5, Use for test name 2 """ - efuse_table_gen.coding_scheme = 1 #3/4 coding + efuse_table_gen.coding_scheme = 1 # 3/4 coding t = efuse_table_gen.FuseTable.from_csv(csv) with self.assertRaisesRegexp(efuse_table_gen.InputError, "The field is outside the boundaries"): t.verify() @@ -266,7 +260,7 @@ name2, EFUSE_BLK1, 1, class VerificationTests(unittest.TestCase): - + def test_general(self): csv = """ # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment @@ -277,22 +271,22 @@ name2_1, EFUSE_BLK2, 5, """ t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() - + self.assertEqual(t[0].field_name, 'name1') self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3') self.assertEqual(t[0].bit_start, 0) self.assertEqual(t[0].bit_count, 5) - + self.assertEqual(t[1].field_name, 'name2') self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3') self.assertEqual(t[1].bit_start, 5) self.assertEqual(t[1].bit_count, 4) - + self.assertEqual(t[2].field_name, 'name1_1') self.assertEqual(t[2].efuse_block, 'EFUSE_BLK2') self.assertEqual(t[2].bit_start, 0) self.assertEqual(t[2].bit_count, 5) - + self.assertEqual(t[3].field_name, 'name2_1') self.assertEqual(t[3].efuse_block, 'EFUSE_BLK2') self.assertEqual(t[3].bit_start, 5) @@ -317,7 +311,7 @@ name2, EFUSE_BLK2, 5, common_table = efuse_table_gen.FuseTable.from_csv(csv_common) common_table.verify("common_table") two_tables = common_table - + csv_custom = """ # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment name3, EFUSE_BLK3, 20, 5, Use for test name 1 @@ -325,10 +319,11 @@ name4, EFUSE_BLK3, 4, """ custom_table = efuse_table_gen.FuseTable.from_csv(csv_custom) custom_table.verify("custom_table") - + two_tables += custom_table with self.assertRaisesRegexp(efuse_table_gen.InputError, "overlaps"): two_tables.verify() + if __name__ == "__main__": unittest.main() From 95b6273c7cfc1acf2a60267f9c4f4fdec673d6b2 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Tue, 11 Dec 2018 14:39:32 +0800 Subject: [PATCH 12/15] efuse: Fix docs and script --- components/efuse/Kconfig | 7 ++-- components/efuse/efuse_table_gen.py | 6 +-- components/efuse/include/esp_efuse.h | 2 +- docs/en/api-reference/system/efuse.rst | 54 +++++++++++++------------- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/components/efuse/Kconfig b/components/efuse/Kconfig index c06b29a1e1..9125a781ff 100644 --- a/components/efuse/Kconfig +++ b/components/efuse/Kconfig @@ -14,11 +14,12 @@ config EFUSE_CUSTOM_TABLE_FILENAME relative to the project root directory. config EFUSE_VIRTUAL - bool "Emulate eFuse work" + bool "Simulate eFuse operations in RAM" default n help - If this option is set, all permanent changes (via eFuse) are disabled. - Log output will state changes which would be applied, but they will not be. + All read and writes operations are redirected to RAM instead of eFuse registers. + If this option is set, all permanent changes (via eFuse) are disabled. + Log output will state changes which would be applied, but they will not be. choice EFUSE_CODE_SCHEME_SELECTOR prompt "Coding scheme" diff --git a/components/efuse/efuse_table_gen.py b/components/efuse/efuse_table_gen.py index 0804f6a6a0..28d39edf53 100755 --- a/components/efuse/efuse_table_gen.py +++ b/components/efuse/efuse_table_gen.py @@ -174,7 +174,7 @@ class FuseTable(list): rows = '' rows += 'Sorted efuse table:\n' num = 1 - rows = "{0} \t{1:<30} \t{2} \t{3} \t{4}".format("#", "field_name", "efuse_block", "bit_start", "bit_count") + "\n" + rows += "{0} \t{1:<30} \t{2} \t{3} \t{4}".format("#", "field_name", "efuse_block", "bit_start", "bit_count") + "\n" for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): rows += "{0} \t{1:<30} \t{2} \t{3:^8} \t{4:^8}".format(num, p.field_name, p.efuse_block, p.bit_start, p.bit_count) + "\n" num += 1 @@ -299,7 +299,7 @@ class FuseDefinition(object): def parse_block(self, strval): if strval == "": raise InputError("Field 'efuse_block' can't be left empty.") - if strval != "EFUSE_BLK0" and strval != "EFUSE_BLK1" and strval != "EFUSE_BLK2" and strval != "EFUSE_BLK3": + if strval not in ["EFUSE_BLK0", "EFUSE_BLK1", "EFUSE_BLK2", "EFUSE_BLK3"]: raise InputError("Field 'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3") return strval @@ -389,13 +389,11 @@ def create_output_files(name, output_table, debug): output = output_table.to_header(file_name) with open(file_h_path, 'w') as f: f.write(output) - f.close() status("Creating efuse *.c file " + file_c_path + " ...") output = output_table.to_c_file(file_name, debug) with open(file_c_path, 'w') as f: f.write(output) - f.close() else: print("Source files do not require updating correspond to csv file.") diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h index 22f6879366..b0c8bc08ea 100644 --- a/components/efuse/include/esp_efuse.h +++ b/components/efuse/include/esp_efuse.h @@ -54,7 +54,7 @@ typedef enum { typedef struct { esp_efuse_block_t efuse_block; /**< Block of eFuse */ uint16_t bit_start; /**< Start bit [0..255] */ - uint16_t bit_count; /**< Length of bit field [1..256]*/ + uint16_t bit_count; /**< Length of bit field [1..-]*/ } esp_efuse_desc_t; /** diff --git a/docs/en/api-reference/system/efuse.rst b/docs/en/api-reference/system/efuse.rst index bb64bcfc9a..833da43623 100644 --- a/docs/en/api-reference/system/efuse.rst +++ b/docs/en/api-reference/system/efuse.rst @@ -11,15 +11,15 @@ The eFuse Manager library is designed to structure access to eFuse bits and make Hardware description -------------------- -The ESP32 has a number of eFuses which can store system and user parameters. Each eFuse this is one bit wich can programmed to 1, after this it can never be reverted to 0. +The ESP32 has a number of eFuses which can store system and user parameters. Each eFuse is a one-bit field which can be programmed to 1 after which it cannot be reverted back to 0. Some of system parameters are using these eFuse bits directly by hardware modules and have special place (for example EFUSE_BLK0). For more details see `ESP32 Technical Reference Manual `_ in part 20 eFuse controller. Some eFuse bits are available for user applications. -ESP32 has 4 eFuse bit blocks of 256 bits each (not all bits are available): +ESP32 has 4 eFuse blocks each of the size of 256 bits (not all bits are available): * EFUSE_BLK0 is used entirely for system purposes; * EFUSE_BLK1 is used for flash encrypt key. If not using that Flash Encryption feature, they can be used for another purpose; * EFUSE_BLK2 is used for security boot key. If not using that Secure Boot feature, they can be used for another purpose; -* EFUSE_BLK3 is used for a custom MAC address, some bits are free and can be used for user applications, note that some bits are already used in idf. +* EFUSE_BLK3 can be partially reserved for the custom MAC address, or used entirely for user application. Note that some bits are already used in IDF. Each block is divided into 8 32-bits registers. @@ -27,18 +27,18 @@ Each block is divided into 8 32-bits registers. eFuse Manager component ----------------------- -The component has API functions for reading and writing fields. Access to the fields is carried out through the structures that describe the location of the efuse bits in the blocks. The component provides the ability to form fields of any length and from any number of individual bits. The description of the fields is made in a csv file in a table form. To generate from a tabular form (csv file) in the C-source uses the tool `efuse_table_gen.py`. The tool checks the csv file for uniqueness of field names and bit intersection, in case of using a `custom` file from the user's project directory, the utility will check with the `common` csv file. +The component has API functions for reading and writing fields. Access to the fields is carried out through the structures that describe the location of the eFuse bits in the blocks. The component provides the ability to form fields of any length and from any number of individual bits. The description of the fields is made in a CSV file in a table form. To generate from a tabular form (CSV file) in the C-source uses the tool `efuse_table_gen.py`. The tool checks the CSV file for uniqueness of field names and bit intersection, in case of using a `custom` file from the user's project directory, the utility will check with the `common` CSV file. CSV files: -* common (`esp_efuse_table.csv`) - contains efuse fields are used inside the IDF field. C-source generation should be done manually when changing this file (run command 'make efuse_common_table' or `idf.py efuse_common_table`). Note that changes to this file can lead to incorrect IDF operation. Changes are not desirable! -* custom - (may be absent, selected through :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains efuse fields that are used by the user in their application. C-source generation should be done manually when changing this file (run command 'make efuse_custom_table' or `idf.py efuse_custom_table`). +* common (`esp_efuse_table.csv`) - contains eFuse fields which are used inside the IDF. C-source generation should be done manually when changing this file (run command 'make efuse_common_table' or `idf.py efuse_common_table`). Note that changes in this file can lead to incorrect operation. +* custom - (optional and can be enabled by :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains eFuse fields that are used by the user in their application. C-source generation should be done manually when changing this file (run command 'make efuse_custom_table' or `idf.py efuse_custom_table`). Description CSV file -------------------- -The CSV file contains a description of the efuse fields. In the simple case, one field has one line of description. +The CSV file contains a description of the eFuse fields. In the simple case, one field has one line of description. Table header: :: @@ -46,13 +46,13 @@ Table header: # field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count(1..256), comment -Individual params in csv file the following meanings: +Individual params in CSV file the following meanings: field_name Name of field. The prefix `ESP_EFUSE_` will be added to the name, and this field name will be available in the code. This name will be used to access the fields. The name must be unique for all fields. If the line has an empty name, then this line is combined with the previous field. This allows you to set an arbitrary order of bits in the field, and expand the field as well (see ``MAC_FACTORY`` field in the common table). efuse_block - Block number. It determines where the efuse bits will be placed for this field. Available EFUSE_BLK0..EFUSE_BLK3. + Block number. It determines where the eFuse bits will be placed for this field. Available EFUSE_BLK0..EFUSE_BLK3. bit_start Start bit number (0..255). The bit_start field can be omitted. In this case, it will be set to bit_start + bit_count from the previous record, if it has the same efuse_block. Otherwise (if efuse_block is different, or this is the first entry), an error will be generated. @@ -88,7 +88,7 @@ To generate a `common` files, use the following command 'make efuse_common_table :: - cd ~/esp/esp-idf/components/efuse/ + cd $IDF_PATH/components/efuse/ ./efuse_table_gen.py esp32/esp_efuse_table.csv After generation in the folder `esp32` create: @@ -100,7 +100,7 @@ To generate a `custom` files, use the following command 'make efuse_custom_table :: - cd ~/esp/esp-idf/components/efuse/ + cd $IDF_PATH/components/efuse/ ./efuse_table_gen.py esp32/esp_efuse_table.csv PROJECT_PATH/main/esp_efuse_custom_table.csv After generation in the folder PROJECT_PATH/main create: @@ -127,7 +127,7 @@ eFuse have three coding schemes: The coding scheme affects only EFUSE_BLK1, EFUSE_BLK2 and EFUSE_BLK3 blocks. EUSE_BLK0 block always has a coding scheme ``None``. Coding changes the number of bits that can be written into a block, the block length is constant 256, some of these bits are used for encoding and are not used. -When using a coding scheme, the length of the payload that can be written is limited (for more detailes ``20.3.1.3 System Parameter coding_scheme``): +When using a coding scheme, the length of the payload that can be written is limited (for more details ``20.3.1.3 System Parameter coding_scheme``): * None 256 bits. * 3/4 192 bits. @@ -140,7 +140,7 @@ You can find out the coding scheme of your chip: * calling the function in the code :cpp:func:`esp_efuse_get_coding_scheme` for the EFUSE_BLK3 block. eFuse tables must always comply with the coding scheme in the chip. There is an :envvar:`EFUSE_CODE_SCHEME_SELECTOR` option to select the coding type for tables in a Kconfig. When generating source files, if your tables do not follow the coding scheme, an error message will be displayed. Adjust the length or offset fields. -If your program was compiled with ``None`` encoding and ``3/4`` is used in the chip, then the ``ESP_ERR_CODING`` error may occur when calling the efuse API (the field is outside the block boundaries). If the field matches the new block boundaries, then the API will work without errors. +If your program was compiled with ``None`` encoding and ``3/4`` is used in the chip, then the ``ESP_ERR_CODING`` error may occur when calling the eFuse API (the field is outside the block boundaries). If the field matches the new block boundaries, then the API will work without errors. Also, 3/4 coding scheme imposes restrictions on writing bits belonging to one coding unit. The whole block with a length of 256 bits is divided into 4 coding units, and in each coding unit there are 6 bytes of useful data and 2 service bytes. These 2 service bytes contain the checksum of the previous 6 data bytes. @@ -151,16 +151,16 @@ eFuse API Access to the fields is via a pointer to the description structure. API functions have some basic operation: -* :cpp:func:`esp_efuse_read_field_blob` - returns an array of read efuse bits. +* :cpp:func:`esp_efuse_read_field_blob` - returns an array of read eFuse bits. * :cpp:func:`esp_efuse_read_field_cnt` - returns the number of bits programmed as "1". * :cpp:func:`esp_efuse_write_field_blob` - writes an array. * :cpp:func:`esp_efuse_write_field_cnt` - writes a required count of bits as "1". * :cpp:func:`esp_efuse_get_field_size` - returns the number of bits by the field name. -* :cpp:func:`esp_efuse_read_reg` - returns value of efuse register. -* :cpp:func:`esp_efuse_write_reg` - writes value to efuse register. -* :cpp:func:`esp_efuse_get_coding_scheme` - returns efuse coding scheme for blocks. -* :cpp:func:`esp_efuse_read_block` - reads key to efuse block starting at the offset and the required size. -* :cpp:func:`esp_efuse_write_block` - writes key to efuse block starting at the offset and the required size. +* :cpp:func:`esp_efuse_read_reg` - returns value of eFuse register. +* :cpp:func:`esp_efuse_write_reg` - writes value to eFuse register. +* :cpp:func:`esp_efuse_get_coding_scheme` - returns eFuse coding scheme for blocks. +* :cpp:func:`esp_efuse_read_block` - reads key to eFuse block starting at the offset and the required size. +* :cpp:func:`esp_efuse_write_block` - writes key to eFuse block starting at the offset and the required size. For frequently used fields, special functions are made, like this :cpp:func:`esp_efuse_get_chip_ver`, :cpp:func:`esp_efuse_get_pkg_ver`. @@ -172,7 +172,7 @@ How add a new field :: - $ ./efuse_table_gen.py --info esp32/esp_efuse_table.csv + $ ./efuse_table_gen.py esp32/esp_efuse_table.csv --info eFuse coding scheme: NONE # field_name efuse_block bit_start bit_count 1 WR_DIS_FLASH_CRYPT_CNT EFUSE_BLK0 2 1 @@ -218,7 +218,7 @@ How add a new field 41 SECURE_VERSION EFUSE_BLK3 128 32 42 MAC_CUSTOM_VER EFUSE_BLK3 184 8 - Used bits in efuse table: + Used bits in eFuse table: EFUSE_BLK0 [2 2] [7 9] [16 18] [20 27] [32 87] [96 97] [105 109] [111 111] [136 144] [188 191] [194 194] [196 196] [198 201] @@ -233,22 +233,22 @@ How add a new field Note: Not printed ranges are free for using. (bits in EFUSE_BLK0 are reserved for Espressif) - Parsing efuse CSV input file C:/msys32/home/virtpc/esp/esp-idf/components/efuse/esp32/esp_efuse_table.csv ... - Verifying efuse table... + Parsing eFuse CSV input file $IDF_PATH/components/efuse/esp32/esp_efuse_table.csv ... + Verifying eFuse table... The number of bits not included in square brackets is free (bits in EFUSE_BLK0 are reserved for Espressif). All fields are checked for overlapping. 2. Fill a line for field: field_name, efuse_block, bit_start, bit_count, comment. -3. Run a ``show_efuse_table`` command to check efuse table. To generate source files run ``efuse_common_table`` or ``efuse_custom_table`` command. +3. Run a ``show_efuse_table`` command to check eFuse table. To generate source files run ``efuse_common_table`` or ``efuse_custom_table`` command. -Debug efuse & Unit tests +Debug eFuse & Unit tests ------------------------ eFuse manager have option :envvar:`CONFIG_EFUSE_VIRTUAL` in Kconfig which will make an operation write is virtual. It can help to debug app and unit tests. -esptool have an useful tool for reading/writing ESP32 efuse bits - `espefuse.py `_. +esptool have an useful tool for reading/writing ESP32 eFuse bits - `espefuse.py `_. :: @@ -307,7 +307,7 @@ esptool have an useful tool for reading/writing ESP32 efuse bits - `espefuse.py Flash voltage (VDD_SDIO) determined by GPIO12 on reset (High for 1.8V, Low/NC for 3.3V). -To get a dump for all efuse registers. +To get a dump for all eFuse registers. :: From 1d7b901aebba6191df70baaaf33d71c5343fa8d0 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Wed, 12 Dec 2018 15:50:31 +0800 Subject: [PATCH 13/15] efuse: Add MAX_BLK_LEN define for changing len of field Added docs, improved efuse_table_gen.py, and minor fixes Checking the generated files for compliance with the coding scheme. --- components/efuse/efuse_table_gen.py | 91 ++++++++++++++++--- components/efuse/esp32/esp_efuse_table.c | 35 +++++-- components/efuse/esp32/esp_efuse_table.csv | 9 +- .../efuse/esp32/include/esp_efuse_table.h | 9 +- components/efuse/include/esp_efuse.h | 2 +- components/efuse/src/esp_efuse_api.c | 11 ++- docs/en/api-reference/system/efuse.rst | 4 +- 7 files changed, 126 insertions(+), 35 deletions(-) diff --git a/components/efuse/efuse_table_gen.py b/components/efuse/efuse_table_gen.py index 28d39edf53..dfa338fe02 100755 --- a/components/efuse/efuse_table_gen.py +++ b/components/efuse/efuse_table_gen.py @@ -166,7 +166,7 @@ class FuseTable(list): def calc_md5(self): txt_table = '' for p in self: - txt_table += "%s %s %d %d %s" % (p.field_name, p.efuse_block, p.bit_start, p.bit_count, p.comment) + "\n" + txt_table += "%s %s %d %s %s" % (p.field_name, p.efuse_block, p.bit_start, str(p.get_bit_count()), p.comment) + "\n" self.md5_digest_table = hashlib.md5(txt_table.encode('utf-8')).hexdigest() def show_range_used_bits(self): @@ -194,6 +194,19 @@ class FuseTable(list): rows += '\nNote: Not printed ranges are free for using. (bits in EFUSE_BLK0 are reserved for Espressif)\n' return rows + def get_str_position_last_free_bit_in_blk(self, blk): + last_used_bit = 0 + for p in self: + if p.efuse_block == blk: + if p.define is not None: + return p.get_bit_count() + else: + if last_used_bit < p.bit_start + p.bit_count: + last_used_bit = p.bit_start + p.bit_count + if last_used_bit == 0: + return None + return str(last_used_bit) + def to_header(self, file_name): rows = [copyright] rows += ["#ifdef __cplusplus", @@ -202,9 +215,10 @@ class FuseTable(list): "", "", "// md5_digest_table " + self.md5_digest_table, - "// This file was generated automatically from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", - "// If you want to change some fields, you need to change " + file_name + ".csv file then build system will generate this header file", - "// To show efuse_table run the command 'make show_efuse_table'.", + "// This file was generated from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", + "// If you want to change some fields, you need to change " + file_name + ".csv file", + "// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.", + "// To show efuse_table run the command 'show_efuse_table'.", "", ""] @@ -223,15 +237,54 @@ class FuseTable(list): def to_c_file(self, file_name, debug): rows = [copyright] - rows += ['#include "esp_efuse.h"', + rows += ['#include "sdkconfig.h"', + '#include "esp_efuse.h"', + '#include ', '#include "' + file_name + '.h"', "", "// md5_digest_table " + self.md5_digest_table, - "// This file was generated automatically from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", - "// If you want to change some fields, you need to change " + file_name + ".csv file then build system will generate this header file", - "// To show efuse_table run the command 'make show_efuse_table'.", - "", - ""] + "// This file was generated from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", + "// If you want to change some fields, you need to change " + file_name + ".csv file", + "// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.", + "// To show efuse_table run the command 'show_efuse_table'."] + + rows += [""] + + rows += ["#if (CONFIG_EFUSE_CODE_SCHEME == 0)", + "#define MAX_BLK_LEN 256", + "#elif (CONFIG_EFUSE_CODE_SCHEME == 1)", + "#define MAX_BLK_LEN 192", + "#elif (CONFIG_EFUSE_CODE_SCHEME == 2)", + "#define MAX_BLK_LEN 128", + "#endif"] + + rows += [""] + + last_free_bit_blk1 = self.get_str_position_last_free_bit_in_blk("EFUSE_BLK1") + last_free_bit_blk2 = self.get_str_position_last_free_bit_in_blk("EFUSE_BLK2") + last_free_bit_blk3 = self.get_str_position_last_free_bit_in_blk("EFUSE_BLK3") + + rows += ["// The last free bit in the block is counted over the entire file."] + if last_free_bit_blk1 is not None: + rows += ["#define LAST_FREE_BIT_BLK1 " + last_free_bit_blk1] + if last_free_bit_blk2 is not None: + rows += ["#define LAST_FREE_BIT_BLK2 " + last_free_bit_blk2] + if last_free_bit_blk3 is not None: + rows += ["#define LAST_FREE_BIT_BLK3 " + last_free_bit_blk3] + + rows += [""] + + if last_free_bit_blk1 is not None: + rows += ['_Static_assert(LAST_FREE_BIT_BLK1 <= MAX_BLK_LEN, "The eFuse table does not match the coding scheme. ' + 'Edit the table and restart the efuse_common_table or efuse_custom_table command to regenerate the new files.");'] + if last_free_bit_blk2 is not None: + rows += ['_Static_assert(LAST_FREE_BIT_BLK2 <= MAX_BLK_LEN, "The eFuse table does not match the coding scheme. ' + 'Edit the table and restart the efuse_common_table or efuse_custom_table command to regenerate the new files.");'] + if last_free_bit_blk3 is not None: + rows += ['_Static_assert(LAST_FREE_BIT_BLK3 <= MAX_BLK_LEN, "The eFuse table does not match the coding scheme. ' + 'Edit the table and restart the efuse_common_table or efuse_custom_table command to regenerate the new files.");'] + + rows += [""] last_name = '' for p in self: @@ -267,6 +320,7 @@ class FuseDefinition(object): self.efuse_block = "" self.bit_start = None self.bit_count = None + self.define = None self.comment = "" @classmethod @@ -279,7 +333,7 @@ class FuseDefinition(object): res.field_name = fields[0] res.efuse_block = res.parse_block(fields[1]) res.bit_start = res.parse_num(fields[2]) - res.bit_count = res.parse_num(fields[3]) + res.bit_count = res.parse_bit_count(fields[3]) if res.bit_count is None or res.bit_count == 0: raise InputError("Field bit_count can't be empty") res.comment = fields[4] @@ -290,6 +344,13 @@ class FuseDefinition(object): return None # Field will fill in default return self.parse_int(strval) + def parse_bit_count(self, strval): + if strval == "MAX_BLK_LEN": + self.define = strval + return self.get_max_bits_of_block() + else: + return self.parse_num(strval) + def parse_int(self, v): try: return int(v, 0) @@ -343,13 +404,19 @@ class FuseDefinition(object): return self.field_name + get_postfix(self.group) + def get_bit_count(self, check_define=True): + if check_define is True and self.define is not None: + return self.define + else: + return self.bit_count + def to_struct(self, debug): start = " {" if debug is True: start = " {" + '"' + self.field_name + '" ,' return ", ".join([start + self.efuse_block, str(self.bit_start), - str(self.bit_count) + "}, \t // " + self.comment]) + str(self.get_bit_count()) + "}, \t // " + self.comment]) def process_input_file(file, type_table): diff --git a/components/efuse/esp32/esp_efuse_table.c b/components/efuse/esp32/esp_efuse_table.c index d4bfeb2854..1741121290 100644 --- a/components/efuse/esp32/esp_efuse_table.c +++ b/components/efuse/esp32/esp_efuse_table.c @@ -12,14 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License +#include "sdkconfig.h" #include "esp_efuse.h" +#include #include "esp_efuse_table.h" -// md5_digest_table 20db0282fe17fec59ea46716026f5fce -// This file was generated automatically from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. -// If you want to change some fields, you need to change esp_efuse_table.csv file then build system will generate this header file -// To show efuse_table run the command 'make show_efuse_table'. +// md5_digest_table 840523b9e1313240e6102615e3a497a5 +// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_table.csv file +// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file. +// To show efuse_table run the command 'show_efuse_table'. +#if (CONFIG_EFUSE_CODE_SCHEME == 0) +#define MAX_BLK_LEN 256 +#elif (CONFIG_EFUSE_CODE_SCHEME == 1) +#define MAX_BLK_LEN 192 +#elif (CONFIG_EFUSE_CODE_SCHEME == 2) +#define MAX_BLK_LEN 128 +#endif + +// The last free bit in the block is counted over the entire file. +#define LAST_FREE_BIT_BLK1 MAX_BLK_LEN +#define LAST_FREE_BIT_BLK2 MAX_BLK_LEN +#define LAST_FREE_BIT_BLK3 192 + +_Static_assert(LAST_FREE_BIT_BLK1 <= MAX_BLK_LEN, "The eFuse table does not match the coding scheme. Edit the table and restart the efuse_common_table or efuse_custom_table command to regenerate the new files."); +_Static_assert(LAST_FREE_BIT_BLK2 <= MAX_BLK_LEN, "The eFuse table does not match the coding scheme. Edit the table and restart the efuse_common_table or efuse_custom_table command to regenerate the new files."); +_Static_assert(LAST_FREE_BIT_BLK3 <= MAX_BLK_LEN, "The eFuse table does not match the coding scheme. Edit the table and restart the efuse_common_table or efuse_custom_table command to regenerate the new files."); static const esp_efuse_desc_t MAC_FACTORY[] = { {EFUSE_BLK0, 72, 8}, // Factory MAC addr [0], @@ -47,7 +66,7 @@ static const esp_efuse_desc_t MAC_CUSTOM_VER[] = { }; static const esp_efuse_desc_t SECURE_BOOT_KEY[] = { - {EFUSE_BLK2, 0, 256}, // Security boot. Key., + {EFUSE_BLK2, 0, MAX_BLK_LEN}, // Security boot. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128), }; static const esp_efuse_desc_t ABS_DONE_0[] = { @@ -55,7 +74,7 @@ static const esp_efuse_desc_t ABS_DONE_0[] = { }; static const esp_efuse_desc_t ENCRYPT_FLASH_KEY[] = { - {EFUSE_BLK1, 0, 256}, // Flash encrypt. Key., + {EFUSE_BLK1, 0, MAX_BLK_LEN}, // Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128), }; static const esp_efuse_desc_t ENCRYPT_CONFIG[] = { @@ -209,7 +228,7 @@ const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_VER[] = { }; const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY[] = { - &SECURE_BOOT_KEY[0], // Security boot. Key. + &SECURE_BOOT_KEY[0], // Security boot. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128) NULL }; @@ -219,7 +238,7 @@ const esp_efuse_desc_t* ESP_EFUSE_ABS_DONE_0[] = { }; const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_FLASH_KEY[] = { - &ENCRYPT_FLASH_KEY[0], // Flash encrypt. Key. + &ENCRYPT_FLASH_KEY[0], // Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128) NULL }; diff --git a/components/efuse/esp32/esp_efuse_table.csv b/components/efuse/esp32/esp_efuse_table.csv index 0c85664f66..6b131350de 100644 --- a/components/efuse/esp32/esp_efuse_table.csv +++ b/components/efuse/esp32/esp_efuse_table.csv @@ -1,9 +1,10 @@ # field_name, | efuse_block, | bit_start, | bit_count, |comment # -# | (EFUSE_BLK0 | (0..255) | (1..256) | # -# | EFUSE_BLK1 | | | # +# | (EFUSE_BLK0 | (0..255) | (1..-) | # +# | EFUSE_BLK1 | |MAX_BLK_LEN*| # # | EFUSE_BLK2 | | | # # | EFUSE_BLK3) | | | # ########################################################################## +# *) The value MAX_BLK_LEN depends on CONFIG_EFUSE_CODE_SCHEME, will be replaced with "None" - 256. "3/4" - 192. "REPEAT" - 128. # !!!!!!!!!!! # # After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table" # this will generate new source files, next rebuild all the sources. @@ -27,12 +28,12 @@ MAC_CUSTOM_VER, EFUSE_BLK3, 184, 8, Custom MAC version # Security boot # ################# -SECURE_BOOT_KEY, EFUSE_BLK2, 0, 256, Security boot. Key. +SECURE_BOOT_KEY, EFUSE_BLK2, 0, MAX_BLK_LEN, Security boot. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128) ABS_DONE_0, EFUSE_BLK0, 196, 1, Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0 # Flash encrypt # ################# -ENCRYPT_FLASH_KEY, EFUSE_BLK1, 0, 256, Flash encrypt. Key. +ENCRYPT_FLASH_KEY, EFUSE_BLK1, 0, MAX_BLK_LEN, Flash encrypt. Key. (length = "None" - 256. "3/4" - 192. "REPEAT" - 128) ENCRYPT_CONFIG, EFUSE_BLK0, 188, 4, Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT. diff --git a/components/efuse/esp32/include/esp_efuse_table.h b/components/efuse/esp32/include/esp_efuse_table.h index c06e776a0a..ad67ae2216 100644 --- a/components/efuse/esp32/include/esp_efuse_table.h +++ b/components/efuse/esp32/include/esp_efuse_table.h @@ -17,10 +17,11 @@ extern "C" { #endif -// md5_digest_table 20db0282fe17fec59ea46716026f5fce -// This file was generated automatically from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. -// If you want to change some fields, you need to change esp_efuse_table.csv file then build system will generate this header file -// To show efuse_table run the command 'make show_efuse_table'. +// md5_digest_table 840523b9e1313240e6102615e3a497a5 +// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_table.csv file +// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file. +// To show efuse_table run the command 'show_efuse_table'. extern const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY[]; diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h index b0c8bc08ea..7c6b370023 100644 --- a/components/efuse/include/esp_efuse.h +++ b/components/efuse/include/esp_efuse.h @@ -160,7 +160,7 @@ esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk); * * @return Returns the number of bits used by field. */ -esp_err_t esp_efuse_get_field_size(const esp_efuse_desc_t* field[]); +int esp_efuse_get_field_size(const esp_efuse_desc_t* field[]); /** * @brief Returns value of efuse register. diff --git a/components/efuse/src/esp_efuse_api.c b/components/efuse/src/esp_efuse_api.c index 09f6e5b1c0..d697a0d4c0 100644 --- a/components/efuse/src/esp_efuse_api.c +++ b/components/efuse/src/esp_efuse_api.c @@ -143,12 +143,13 @@ esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk) // get the length of the field in bits int esp_efuse_get_field_size(const esp_efuse_desc_t* field[]) { - assert(field != NULL); int bits_counter = 0; - int i = 0; - while (field[i] != NULL) { - bits_counter += field[i]->bit_count; - ++i; + if (field != NULL) { + int i = 0; + while (field[i] != NULL) { + bits_counter += field[i]->bit_count; + ++i; + } } return bits_counter; } diff --git a/docs/en/api-reference/system/efuse.rst b/docs/en/api-reference/system/efuse.rst index 833da43623..afeffd60a7 100644 --- a/docs/en/api-reference/system/efuse.rst +++ b/docs/en/api-reference/system/efuse.rst @@ -58,7 +58,7 @@ bit_start Start bit number (0..255). The bit_start field can be omitted. In this case, it will be set to bit_start + bit_count from the previous record, if it has the same efuse_block. Otherwise (if efuse_block is different, or this is the first entry), an error will be generated. bit_count - The number of bits to use in this field (1..256). This parameter can not be omitted. + The number of bits to use in this field (1..-). This parameter can not be omitted. This field also may be ``MAX_BLK_LEN`` in this case, the field length will have the maximum block length, taking into account the coding scheme (applicable for ``ESP_EFUSE_SECURE_BOOT_KEY`` and ``ESP_EFUSE_ENCRYPT_FLASH_KEY`` fields). The value ``MAX_BLK_LEN`` depends on :envvar:`CONFIG_EFUSE_CODE_SCHEME`, will be replaced with "None" - 256, "3/4" - 192, "REPEAT" - 128. comment This param is using for comment field, it also move to C-header file. The comment field can be omitted. @@ -146,6 +146,8 @@ Also, 3/4 coding scheme imposes restrictions on writing bits belonging to one co It turns out that only one field can be written into one coding unit. Repeated rewriting in one coding unit is prohibited. But if the record was made in advance or through a :cpp:func:`esp_efuse_write_block` function, then reading the fields belonging to one coding unit is possible. +After changing the coding scheme, run ``efuse_common_table`` and ``efuse_custom_table`` commands to check the tables of the new coding scheme. + eFuse API --------- From c9cd06c886839176d06fb113c183a1a83c8e4461 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Fri, 14 Dec 2018 14:00:59 +0800 Subject: [PATCH 14/15] efuse: Reduce the size of esp_efuse_desc_t to 4 bytes --- components/efuse/include/esp_efuse.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h index 7c6b370023..84fd63e53f 100644 --- a/components/efuse/include/esp_efuse.h +++ b/components/efuse/include/esp_efuse.h @@ -52,8 +52,8 @@ typedef enum { * @brief Structure eFuse field */ typedef struct { - esp_efuse_block_t efuse_block; /**< Block of eFuse */ - uint16_t bit_start; /**< Start bit [0..255] */ + esp_efuse_block_t efuse_block: 8; /**< Block of eFuse */ + uint8_t bit_start; /**< Start bit [0..255] */ uint16_t bit_count; /**< Length of bit field [1..-]*/ } esp_efuse_desc_t; From 509e1264b9895768424d587f493ae59278942674 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Tue, 18 Dec 2018 22:42:10 +0800 Subject: [PATCH 15/15] efuse: Fix to pass CI tests --- .../bootloader_support/include/esp_efuse.h | 136 ---------- components/bootloader_support/src/efuse.c | 235 ------------------ components/efuse/CMakeLists.txt | 2 +- components/efuse/Kconfig | 73 +++--- components/efuse/Makefile.projbuild | 2 +- components/efuse/efuse_table_gen.py | 45 +--- components/efuse/esp32/esp_efuse_table.c | 8 +- components/efuse/esp32/esp_efuse_table.csv | 2 +- components/efuse/include/esp_efuse.h | 36 +++ components/efuse/src/esp_efuse_fields.c | 120 +++++++++ .../efuse/test_efuse_host/efuse_tests.py | 42 ++-- components/esp32/esp_err_to_name.c | 17 ++ docs/en/api-reference/system/efuse.rst | 2 +- 13 files changed, 253 insertions(+), 467 deletions(-) delete mode 100644 components/bootloader_support/include/esp_efuse.h delete mode 100644 components/bootloader_support/src/efuse.c diff --git a/components/bootloader_support/include/esp_efuse.h b/components/bootloader_support/include/esp_efuse.h deleted file mode 100644 index 3f446cb939..0000000000 --- a/components/bootloader_support/include/esp_efuse.h +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef _ESP_EFUSE_H -#define _ESP_EFUSE_H - -#include "soc/efuse_reg.h" -#include "esp_err.h" -#include "stdbool.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* @brief Permanently update values written to the efuse write registers - * - * After updating EFUSE_BLKx_WDATAx_REG registers with new values to - * write, call this function to permanently write them to efuse. - * - * @note Setting bits in efuse is permanent, they cannot be unset. - * - * @note Due to this restriction you don't need to copy values to - * Efuse write registers from the matching read registers, bits which - * are set in the read register but unset in the matching write - * register will be unchanged when new values are burned. - * - * @note This function is not threadsafe, if calling code updates - * efuse values from multiple tasks then this is caller's - * responsibility to serialise. - * - * After burning new efuses, the read registers are updated to match - * the new efuse values. - */ -void esp_efuse_burn_new_values(void); - -/* @brief Reset efuse write registers - * - * Efuse write registers are written to zero, to negate - * any changes that have been staged here. - */ -void esp_efuse_reset(void); - -/* @brief Disable BASIC ROM Console via efuse - * - * By default, if booting from flash fails the ESP32 will boot a - * BASIC console in ROM. - * - * Call this function (from bootloader or app) to permanently - * disable the console on this chip. - */ -void esp_efuse_disable_basic_rom_console(void); - -/* @brief Encode one or more sets of 6 byte sequences into - * 8 bytes suitable for 3/4 Coding Scheme. - * - * This function is only useful if the CODING_SCHEME efuse - * is set to value 1 for 3/4 Coding Scheme. - * - * @param[in] in_bytes Pointer to a sequence of bytes to encode for 3/4 Coding Scheme. Must have length in_bytes_len. After being written to hardware, these bytes will read back as little-endian words. - * @param[out] out_words Pointer to array of words suitable for writing to efuse write registers. Array must contain 2 words (8 bytes) for every 6 bytes in in_bytes_len. Can be a pointer to efuse write registers. - * @param in_bytes_len. Length of array pointed to by in_bytes, in bytes. Must be a multiple of 6. - * - * @return ESP_ERR_INVALID_ARG if either pointer is null or in_bytes_len is not a multiple of 6. ESP_OK otherwise. - */ -esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len); - -/* @brief Write random data to efuse key block write registers - * - * @note Caller is responsible for ensuring efuse - * block is empty and not write protected, before calling. - * - * @note Behaviour depends on coding scheme: a 256-bit key is - * generated and written for Coding Scheme "None", a 192-bit key - * is generated, extended to 256-bits by the Coding Scheme, - * and then writtten for 3/4 Coding Scheme. - * - * @note This function does not burn the new values, caller should - * call esp_efuse_burn_new_values() when ready to do this. - * - * @param blk_wdata0_reg Address of the first data write register - * in the block - */ -void esp_efuse_write_random_key(uint32_t blk_wdata0_reg); - -/* @brief Return secure_version from efuse field. - * @return Secure version from efuse field - */ -uint32_t esp_efuse_read_secure_version(); - -/* @brief Check secure_version from app and secure_version and from efuse field. - * - * @param secure_version Secure version from app. - * @return - * - True: If version of app is equal or more then secure_version from efuse. - */ -bool esp_efuse_check_secure_version(uint32_t secure_version); - -/* @brief Write efuse field by secure_version value. - * - * Update the secure_version value is available if the coding scheme is None. - * Note: Do not use this function in your applications. This function is called as part of the other API. - * - * @param[in] secure_version Secure version from app. - * @return - * - ESP_OK: Successful. - * - ESP_FAIL: secure version of app cannot be set to efuse field. - * - ESP_ERR_NOT_SUPPORTED: Anti rollback is not supported with the 3/4 and Repeat coding scheme. - */ -esp_err_t esp_efuse_update_secure_version(uint32_t secure_version); - -/* @brief Initializes variables: offset and size to simulate the work of an eFuse. - * - * Note: To simulate the work of an eFuse need to set CONFIG_EFUSE_SECURE_VERSION_EMULATE option - * and to add in the partition.csv file a line `efuse_em, data, efuse, , 0x2000,`. - * - * @param[in] offset The starting address of the partition where the eFuse data will be located. - * @param[in] size The size of the partition. - */ -void esp_efuse_init(uint32_t offset, uint32_t size); - -#ifdef __cplusplus -} -#endif - -#endif /* __ESP_EFUSE_H */ - diff --git a/components/bootloader_support/src/efuse.c b/components/bootloader_support/src/efuse.c deleted file mode 100644 index 637d6e4947..0000000000 --- a/components/bootloader_support/src/efuse.c +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "esp_efuse.h" -#include "esp_log.h" -#include -#include "bootloader_random.h" - -#define EFUSE_CONF_WRITE 0x5A5A /* efuse_pgm_op_ena, force no rd/wr disable */ -#define EFUSE_CONF_READ 0x5AA5 /* efuse_read_op_ena, release force */ - -#define EFUSE_CMD_PGM 0x02 -#define EFUSE_CMD_READ 0x01 - -static const char *TAG = "efuse"; - -void esp_efuse_burn_new_values(void) -{ - REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE); - REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM); - while (REG_READ(EFUSE_CMD_REG) != 0) { - } - REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ); - REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_READ); - while (REG_READ(EFUSE_CMD_REG) != 0) { - } - esp_efuse_reset(); -} - -void esp_efuse_reset(void) -{ - REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ); - const uint32_t block_start[4] = { EFUSE_BLK0_WDATA0_REG, EFUSE_BLK1_WDATA0_REG, - EFUSE_BLK2_WDATA0_REG, EFUSE_BLK3_WDATA0_REG }; - const uint32_t block_end[4] = { EFUSE_BLK0_WDATA6_REG, EFUSE_BLK1_WDATA7_REG, - EFUSE_BLK2_WDATA7_REG, EFUSE_BLK3_WDATA7_REG }; - for (int i = 0; i < 4; i++) { - for (uint32_t r = block_start[i]; r <= block_end[i]; r+= 4) { - REG_WRITE(r, 0); - } - } -} - -void esp_efuse_disable_basic_rom_console(void) -{ - if ((REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_CONSOLE_DEBUG_DISABLE) == 0) { - ESP_EARLY_LOGI(TAG, "Disable BASIC ROM Console fallback via efuse..."); - esp_efuse_reset(); - REG_WRITE(EFUSE_BLK0_WDATA6_REG, EFUSE_RD_CONSOLE_DEBUG_DISABLE); - esp_efuse_burn_new_values(); - } -} - -esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len) -{ - if (in_bytes == NULL || out_words == NULL || in_bytes_len % 6 != 0) { - return ESP_ERR_INVALID_ARG; - } - - while (in_bytes_len > 0) { - uint8_t out[8]; - uint8_t xor = 0; - uint8_t mul = 0; - for (int i = 0; i < 6; i++) { - xor ^= in_bytes[i]; - mul += (i + 1) * __builtin_popcount(in_bytes[i]); - } - - memcpy(out, in_bytes, 6); // Data bytes - out[6] = xor; - out[7] = mul; - - memcpy(out_words, out, 8); - - in_bytes_len -= 6; - in_bytes += 6; - out_words += 2; - } - - return ESP_OK; -} - -void esp_efuse_write_random_key(uint32_t blk_wdata0_reg) -{ - uint32_t buf[8]; - uint8_t raw[24]; - uint32_t coding_scheme = REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M; - - if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE) { - bootloader_fill_random(buf, sizeof(buf)); - } else { // 3/4 Coding Scheme - bootloader_fill_random(raw, sizeof(raw)); - esp_err_t r = esp_efuse_apply_34_encoding(raw, buf, sizeof(raw)); - assert(r == ESP_OK); - } - - ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg); - for (int i = 0; i < 8; i++) { - ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]); - REG_WRITE(blk_wdata0_reg + 4*i, buf[i]); - } - bzero(buf, sizeof(buf)); - bzero(raw, sizeof(raw)); -} - - -#ifdef CONFIG_EFUSE_SECURE_VERSION_EMULATE - -#include "bootloader_flash.h" -#include "esp_flash_encrypt.h" - -static uint32_t esp_efuse_flash_offset = 0; -static uint32_t esp_efuse_flash_size = 0; -void esp_efuse_init(uint32_t offset, uint32_t size) -{ - esp_efuse_flash_offset = offset; - esp_efuse_flash_size = size; -} - -static uint32_t emulate_secure_version_read() -{ - uint32_t secure_version; - uint32_t offset = esp_efuse_flash_offset; - if (offset == 0) { - ESP_LOGE(TAG, "emulate secure_version can not be used"); - return 0; - } - const uint32_t *efuse_place_in_flash = bootloader_mmap(offset, esp_efuse_flash_size); - if (!efuse_place_in_flash) { - ESP_LOGE(TAG, "secure_version can not be read from (0x%x, 0x%x) flash", offset, esp_efuse_flash_size); - return 0; - } - memcpy(&secure_version, efuse_place_in_flash, sizeof(uint32_t)); - bootloader_munmap(efuse_place_in_flash); - secure_version = ~secure_version; - ESP_LOGV(TAG, "Read 0x%08x secure_version from flash", secure_version); - return secure_version; -} - -static void emulate_secure_version_write(uint32_t secure_version) -{ - uint32_t secure_version_wr = ~secure_version; - uint32_t offset = esp_efuse_flash_offset; - if (offset == 0) { - ESP_LOGE(TAG, "emulate secure_version can not be used"); - return; - } - esp_err_t err = bootloader_flash_write(offset, &secure_version_wr, sizeof(secure_version_wr), false); - if (err != ESP_OK) { - ESP_LOGE(TAG, "secure_version can not be written to flash. err = 0x%x", err); - } - ESP_LOGV(TAG, "Write 0x%08x secure_version into flash", secure_version); -} -#endif - -// This efuse register is used whole for secure version (32 bits). -#define EFUSE_BLK_RD_ANTI_ROLLBACK EFUSE_BLK3_RDATA4_REG -#define EFUSE_BLK_WR_ANTI_ROLLBACK EFUSE_BLK3_WDATA4_REG - -uint32_t esp_efuse_read_secure_version() -{ -#ifdef CONFIG_APP_ANTI_ROLLBACK - uint32_t secure_version; - -#ifdef CONFIG_EFUSE_SECURE_VERSION_EMULATE - secure_version = emulate_secure_version_read(); -#else - secure_version = REG_READ(EFUSE_BLK_RD_ANTI_ROLLBACK); -#endif // CONFIG_EFUSE_SECURE_VERSION_EMULATE - - return __builtin_popcount(secure_version & ((1ULL << CONFIG_APP_SECURE_VERSION_SIZE_EFUSE_FIELD) - 1)); -#else - return 0; -#endif -} - -#ifdef CONFIG_APP_ANTI_ROLLBACK -static void write_anti_rollback(uint32_t new_bits) -{ -#ifdef CONFIG_EFUSE_SECURE_VERSION_EMULATE - emulate_secure_version_write(new_bits); -#else - esp_efuse_reset(); - REG_WRITE(EFUSE_BLK_WR_ANTI_ROLLBACK, new_bits); - esp_efuse_burn_new_values(); -#endif -} -#endif - -bool esp_efuse_check_secure_version(uint32_t secure_version) -{ - uint32_t sec_ver_hw = esp_efuse_read_secure_version(); - return secure_version >= sec_ver_hw; -} - -esp_err_t esp_efuse_update_secure_version(uint32_t secure_version) -{ -#ifdef CONFIG_APP_ANTI_ROLLBACK - if (CONFIG_APP_SECURE_VERSION_SIZE_EFUSE_FIELD < secure_version) { - ESP_LOGE(TAG, "Max secure version is %d. Given %d version can not be written.", CONFIG_APP_SECURE_VERSION_SIZE_EFUSE_FIELD, secure_version); - return ESP_ERR_INVALID_ARG; - } -#ifndef CONFIG_EFUSE_SECURE_VERSION_EMULATE - uint32_t coding_scheme = REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M; - if (coding_scheme != EFUSE_CODING_SCHEME_VAL_NONE) { - ESP_LOGE(TAG, "Anti rollback is not supported with a 3/4 coding scheme."); - return ESP_ERR_NOT_SUPPORTED; - } -#endif - uint32_t sec_ver_hw = esp_efuse_read_secure_version(); - // If secure_version is the same as in eFuse field than it is ok just go out. - if (sec_ver_hw < secure_version) { - uint32_t num_bit_hw = (1ULL << sec_ver_hw) - 1; - uint32_t num_bit_app = (1ULL << secure_version) - 1; - // Repeated programming of programmed bits is strictly forbidden - uint32_t new_bits = num_bit_app - num_bit_hw; // get only new bits - write_anti_rollback(new_bits); - ESP_LOGI(TAG, "Anti-rollback is set. eFuse field is updated(%d).", secure_version); - } else if (sec_ver_hw > secure_version) { - ESP_LOGE(TAG, "Anti-rollback is not set. secure_version of app is lower that eFuse field(%d).", sec_ver_hw); - return ESP_FAIL; - } -#endif - return ESP_OK; -} diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt index 1c91512332..6528dd2ccc 100644 --- a/components/efuse/CMakeLists.txt +++ b/components/efuse/CMakeLists.txt @@ -16,7 +16,7 @@ set(COMPONENT_REQUIRES) set(COMPONENT_PRIV_REQUIRES bootloader_support) register_component() -set(GEN_EFUSE_TABLE_ARG --coding_scheme ${CONFIG_EFUSE_CODE_SCHEME}) +set(GEN_EFUSE_TABLE_ARG --max_blk_len ${CONFIG_EFUSE_MAX_BLK_LEN}) ################### # Make common files esp_efuse_table.c and include/esp_efuse_table.h files. diff --git a/components/efuse/Kconfig b/components/efuse/Kconfig index 9125a781ff..bf40e2dfc2 100644 --- a/components/efuse/Kconfig +++ b/components/efuse/Kconfig @@ -1,44 +1,45 @@ -menu "eFuse bit Manager" +menu "eFuse Bit Manager" -config EFUSE_CUSTOM_TABLE - bool "Use custom eFuse table" - default n - help - Allows to generate a structure for eFuse from the CSV file. + config EFUSE_CUSTOM_TABLE + bool "Use custom eFuse table" + default n + help + Allows to generate a structure for eFuse from the CSV file. -config EFUSE_CUSTOM_TABLE_FILENAME - string "Custom eFuse CSV file" if EFUSE_CUSTOM_TABLE - default main/esp_efuse_custom_table.csv - help - Name of the custom eFuse CSV filename. This path is evaluated - relative to the project root directory. + config EFUSE_CUSTOM_TABLE_FILENAME + string "Custom eFuse CSV file" + depends on EFUSE_CUSTOM_TABLE + default main/esp_efuse_custom_table.csv + help + Name of the custom eFuse CSV filename. This path is evaluated + relative to the project root directory. -config EFUSE_VIRTUAL - bool "Simulate eFuse operations in RAM" - default n - help - All read and writes operations are redirected to RAM instead of eFuse registers. - If this option is set, all permanent changes (via eFuse) are disabled. - Log output will state changes which would be applied, but they will not be. + config EFUSE_VIRTUAL + bool "Simulate eFuse operations in RAM" + default n + help + All read and writes operations are redirected to RAM instead of eFuse registers. + If this option is set, all permanent changes (via eFuse) are disabled. + Log output will state changes which would be applied, but they will not be. -choice EFUSE_CODE_SCHEME_SELECTOR - prompt "Coding scheme" - default EFUSE_CODE_SCHEME_STATE_NONE - help - Selector eFuse code scheme. + choice EFUSE_CODE_SCHEME_SELECTOR + prompt "Coding Scheme Compatibility" + default EFUSE_CODE_SCHEME_COMPAT_3_4 + help + Selector eFuse code scheme. -config EFUSE_CODE_SCHEME_STATE_NONE - bool "NONE" -config EFUSE_CODE_SCHEME_STATE_3_4 - bool "3/4" -config EFUSE_CODE_SCHEME_STATE_REPEAT - bool "REPEAT" -endchoice + config EFUSE_CODE_SCHEME_COMPAT_NONE + bool "None Only" + config EFUSE_CODE_SCHEME_COMPAT_3_4 + bool "3/4 and None" + config EFUSE_CODE_SCHEME_COMPAT_REPEAT + bool "Repeat, 3/4 and None (common table does not support it)" + endchoice -config EFUSE_CODE_SCHEME - int - default 0 if EFUSE_CODE_SCHEME_STATE_NONE - default 1 if EFUSE_CODE_SCHEME_STATE_3_4 - default 2 if EFUSE_CODE_SCHEME_STATE_REPEAT + config EFUSE_MAX_BLK_LEN + int + default 256 if EFUSE_CODE_SCHEME_COMPAT_NONE + default 192 if EFUSE_CODE_SCHEME_COMPAT_3_4 + default 128 if EFUSE_CODE_SCHEME_COMPAT_REPEAT endmenu diff --git a/components/efuse/Makefile.projbuild b/components/efuse/Makefile.projbuild index 35eb41d4eb..5f552ebb67 100644 --- a/components/efuse/Makefile.projbuild +++ b/components/efuse/Makefile.projbuild @@ -5,7 +5,7 @@ GEN_EFUSE_TABLE := $(PYTHON) $(COMPONENT_PATH)/efuse_table_gen.py -GEN_EFUSE_TABLE_ARG := --coding_scheme $(CONFIG_EFUSE_CODE_SCHEME) +GEN_EFUSE_TABLE_ARG := --max_blk_len $(CONFIG_EFUSE_MAX_BLK_LEN) ################### diff --git a/components/efuse/efuse_table_gen.py b/components/efuse/efuse_table_gen.py index dfa338fe02..02940c27a5 100755 --- a/components/efuse/efuse_table_gen.py +++ b/components/efuse/efuse_table_gen.py @@ -27,13 +27,7 @@ import hashlib __version__ = '1.0' quiet = False -coding_scheme = 0 - -CODE_SCHEME = { - "NONE": 0, - "3/4": 1, - "REPEAT": 2, -} +max_blk_len = 256 copyright = '''// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD // @@ -250,13 +244,7 @@ class FuseTable(list): rows += [""] - rows += ["#if (CONFIG_EFUSE_CODE_SCHEME == 0)", - "#define MAX_BLK_LEN 256", - "#elif (CONFIG_EFUSE_CODE_SCHEME == 1)", - "#define MAX_BLK_LEN 192", - "#elif (CONFIG_EFUSE_CODE_SCHEME == 2)", - "#define MAX_BLK_LEN 128", - "#endif"] + rows += ["#define MAX_BLK_LEN CONFIG_EFUSE_MAX_BLK_LEN"] rows += [""] @@ -368,16 +356,10 @@ class FuseDefinition(object): '''common_table: EFUSE_BLK0, EFUSE_BLK1, EFUSE_BLK2, EFUSE_BLK3 custom_table: ----------, ----------, ----------, EFUSE_BLK3(some reserved in common_table) ''' - max_bits = 0 - if coding_scheme == CODE_SCHEME["NONE"] or self.efuse_block == "EFUSE_BLK0": - max_bits = 256 - elif coding_scheme == CODE_SCHEME["3/4"]: - max_bits = 192 - elif coding_scheme == CODE_SCHEME["REPEAT"]: - max_bits = 128 + if self.efuse_block == "EFUSE_BLK0": + return 256 else: - raise ValidationError(self, "Unknown coding scheme") - return max_bits + return max_blk_len def verify(self, type_table): if self.efuse_block is None: @@ -467,27 +449,22 @@ def create_output_files(name, output_table, debug): def main(): global quiet - global coding_scheme + global max_blk_len parser = argparse.ArgumentParser(description='ESP32 eFuse Manager') parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') parser.add_argument('--debug', help='Create header file with debug info', default=False, action="store_false") parser.add_argument('--info', help='Print info about range of used bits', default=False, action="store_true") - parser.add_argument('--coding_scheme', help='Coding scheme', type=int, default=0) + parser.add_argument('--max_blk_len', help='Max number of bits in BLK1, BLK2 and BLK3', type=int, default=256) parser.add_argument('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('r')) parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('r'), nargs='?', default=None) args = parser.parse_args() - coding_scheme = args.coding_scheme - if CODE_SCHEME["NONE"] == coding_scheme: - print("eFuse coding scheme: NONE") - elif CODE_SCHEME["3/4"] == coding_scheme: - print("eFuse coding scheme: 3/4") - elif CODE_SCHEME["REPEAT"] == coding_scheme: - print("eFuse coding scheme: REPEAT") - else: - raise InputError("unknown CODE_SCHEME = %s" % (coding_scheme)) + max_blk_len = args.max_blk_len + print("Max number of bits in BLK %d" % (max_blk_len)) + if max_blk_len not in [256, 192, 128]: + raise InputError("Unsupported block length = %d" % (max_blk_len)) quiet = args.quiet debug = args.debug diff --git a/components/efuse/esp32/esp_efuse_table.c b/components/efuse/esp32/esp_efuse_table.c index 1741121290..0e390c6d13 100644 --- a/components/efuse/esp32/esp_efuse_table.c +++ b/components/efuse/esp32/esp_efuse_table.c @@ -23,13 +23,7 @@ // then run `efuse_common_table` or `efuse_custom_table` command it will generate this file. // To show efuse_table run the command 'show_efuse_table'. -#if (CONFIG_EFUSE_CODE_SCHEME == 0) -#define MAX_BLK_LEN 256 -#elif (CONFIG_EFUSE_CODE_SCHEME == 1) -#define MAX_BLK_LEN 192 -#elif (CONFIG_EFUSE_CODE_SCHEME == 2) -#define MAX_BLK_LEN 128 -#endif +#define MAX_BLK_LEN CONFIG_EFUSE_MAX_BLK_LEN // The last free bit in the block is counted over the entire file. #define LAST_FREE_BIT_BLK1 MAX_BLK_LEN diff --git a/components/efuse/esp32/esp_efuse_table.csv b/components/efuse/esp32/esp_efuse_table.csv index 6b131350de..9d8381413b 100644 --- a/components/efuse/esp32/esp_efuse_table.csv +++ b/components/efuse/esp32/esp_efuse_table.csv @@ -4,7 +4,7 @@ # | EFUSE_BLK2 | | | # # | EFUSE_BLK3) | | | # ########################################################################## -# *) The value MAX_BLK_LEN depends on CONFIG_EFUSE_CODE_SCHEME, will be replaced with "None" - 256. "3/4" - 192. "REPEAT" - 128. +# *) The value MAX_BLK_LEN depends on CONFIG_EFUSE_MAX_BLK_LEN, will be replaced with "None" - 256. "3/4" - 192. "REPEAT" - 128. # !!!!!!!!!!! # # After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table" # this will generate new source files, next rebuild all the sources. diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h index 84fd63e53f..68f8491e49 100644 --- a/components/efuse/include/esp_efuse.h +++ b/components/efuse/include/esp_efuse.h @@ -319,6 +319,42 @@ esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_wor */ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg); +/* @brief Return secure_version from efuse field. + * @return Secure version from efuse field + */ +uint32_t esp_efuse_read_secure_version(); + +/* @brief Check secure_version from app and secure_version and from efuse field. + * + * @param secure_version Secure version from app. + * @return + * - True: If version of app is equal or more then secure_version from efuse. + */ +bool esp_efuse_check_secure_version(uint32_t secure_version); + +/* @brief Write efuse field by secure_version value. + * + * Update the secure_version value is available if the coding scheme is None. + * Note: Do not use this function in your applications. This function is called as part of the other API. + * + * @param[in] secure_version Secure version from app. + * @return + * - ESP_OK: Successful. + * - ESP_FAIL: secure version of app cannot be set to efuse field. + * - ESP_ERR_NOT_SUPPORTED: Anti rollback is not supported with the 3/4 and Repeat coding scheme. + */ +esp_err_t esp_efuse_update_secure_version(uint32_t secure_version); + +/* @brief Initializes variables: offset and size to simulate the work of an eFuse. + * + * Note: To simulate the work of an eFuse need to set CONFIG_EFUSE_SECURE_VERSION_EMULATE option + * and to add in the partition.csv file a line `efuse_em, data, efuse, , 0x2000,`. + * + * @param[in] offset The starting address of the partition where the eFuse data will be located. + * @param[in] size The size of the partition. + */ +void esp_efuse_init(uint32_t offset, uint32_t size); + #ifdef __cplusplus } #endif diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c index 2741d0f393..ad4843937d 100644 --- a/components/efuse/src/esp_efuse_fields.c +++ b/components/efuse/src/esp_efuse_fields.c @@ -115,3 +115,123 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg) bzero(buf, sizeof(buf)); bzero(raw, sizeof(raw)); } + +#ifdef CONFIG_EFUSE_SECURE_VERSION_EMULATE + +#include "../include_bootloader/bootloader_flash.h" +#include "esp_flash_encrypt.h" + +static uint32_t esp_efuse_flash_offset = 0; +static uint32_t esp_efuse_flash_size = 0; +void esp_efuse_init(uint32_t offset, uint32_t size) +{ + esp_efuse_flash_offset = offset; + esp_efuse_flash_size = size; +} + +static uint32_t emulate_secure_version_read() +{ + uint32_t secure_version; + uint32_t offset = esp_efuse_flash_offset; + if (offset == 0) { + ESP_LOGE(TAG, "emulate secure_version can not be used"); + return 0; + } + const uint32_t *efuse_place_in_flash = bootloader_mmap(offset, esp_efuse_flash_size); + if (!efuse_place_in_flash) { + ESP_LOGE(TAG, "secure_version can not be read from (0x%x, 0x%x) flash", offset, esp_efuse_flash_size); + return 0; + } + memcpy(&secure_version, efuse_place_in_flash, sizeof(uint32_t)); + bootloader_munmap(efuse_place_in_flash); + secure_version = ~secure_version; + ESP_LOGV(TAG, "Read 0x%08x secure_version from flash", secure_version); + return secure_version; +} + +static void emulate_secure_version_write(uint32_t secure_version) +{ + uint32_t secure_version_wr = ~secure_version; + uint32_t offset = esp_efuse_flash_offset; + if (offset == 0) { + ESP_LOGE(TAG, "emulate secure_version can not be used"); + return; + } + esp_err_t err = bootloader_flash_write(offset, &secure_version_wr, sizeof(secure_version_wr), false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "secure_version can not be written to flash. err = 0x%x", err); + } + ESP_LOGV(TAG, "Write 0x%08x secure_version into flash", secure_version); +} +#endif + +// This efuse register is used whole for secure version (32 bits). +#define EFUSE_BLK_RD_ANTI_ROLLBACK EFUSE_BLK3_RDATA4_REG +#define EFUSE_BLK_WR_ANTI_ROLLBACK EFUSE_BLK3_WDATA4_REG + +uint32_t esp_efuse_read_secure_version() +{ +#ifdef CONFIG_APP_ANTI_ROLLBACK + uint32_t secure_version; + +#ifdef CONFIG_EFUSE_SECURE_VERSION_EMULATE + secure_version = emulate_secure_version_read(); +#else + secure_version = REG_READ(EFUSE_BLK_RD_ANTI_ROLLBACK); +#endif // CONFIG_EFUSE_SECURE_VERSION_EMULATE + + return __builtin_popcount(secure_version & ((1ULL << CONFIG_APP_SECURE_VERSION_SIZE_EFUSE_FIELD) - 1)); +#else + return 0; +#endif +} + +#ifdef CONFIG_APP_ANTI_ROLLBACK +static void write_anti_rollback(uint32_t new_bits) +{ +#ifdef CONFIG_EFUSE_SECURE_VERSION_EMULATE + emulate_secure_version_write(new_bits); +#else + esp_efuse_reset(); + REG_WRITE(EFUSE_BLK_WR_ANTI_ROLLBACK, new_bits); + esp_efuse_burn_new_values(); +#endif +} +#endif + +bool esp_efuse_check_secure_version(uint32_t secure_version) +{ + uint32_t sec_ver_hw = esp_efuse_read_secure_version(); + return secure_version >= sec_ver_hw; +} + +esp_err_t esp_efuse_update_secure_version(uint32_t secure_version) +{ +#ifdef CONFIG_APP_ANTI_ROLLBACK + if (CONFIG_APP_SECURE_VERSION_SIZE_EFUSE_FIELD < secure_version) { + ESP_LOGE(TAG, "Max secure version is %d. Given %d version can not be written.", CONFIG_APP_SECURE_VERSION_SIZE_EFUSE_FIELD, secure_version); + return ESP_ERR_INVALID_ARG; + } +#ifndef CONFIG_EFUSE_SECURE_VERSION_EMULATE + uint32_t coding_scheme = REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M; + if (coding_scheme != EFUSE_CODING_SCHEME_VAL_NONE) { + ESP_LOGE(TAG, "Anti rollback is not supported with a 3/4 coding scheme."); + return ESP_ERR_NOT_SUPPORTED; + } +#endif + uint32_t sec_ver_hw = esp_efuse_read_secure_version(); + // If secure_version is the same as in eFuse field than it is ok just go out. + if (sec_ver_hw < secure_version) { + uint32_t num_bit_hw = (1ULL << sec_ver_hw) - 1; + uint32_t num_bit_app = (1ULL << secure_version) - 1; + // Repeated programming of programmed bits is strictly forbidden + uint32_t new_bits = num_bit_app - num_bit_hw; // get only new bits + write_anti_rollback(new_bits); + ESP_LOGI(TAG, "Anti-rollback is set. eFuse field is updated(%d).", secure_version); + } else if (sec_ver_hw > secure_version) { + ESP_LOGE(TAG, "Anti-rollback is not set. secure_version of app is lower that eFuse field(%d).", sec_ver_hw); + return ESP_FAIL; + } +#endif + return ESP_OK; +} diff --git a/components/efuse/test_efuse_host/efuse_tests.py b/components/efuse/test_efuse_host/efuse_tests.py index 45f537326e..b94092451f 100755 --- a/components/efuse/test_efuse_host/efuse_tests.py +++ b/components/efuse/test_efuse_host/efuse_tests.py @@ -17,7 +17,19 @@ cd ~/esp/esp-idf/components/efuse/test_efuse_host/ ''' -class CSVParserTests(unittest.TestCase): +class Py23TestCase(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(Py23TestCase, self).__init__(*args, **kwargs) + try: + self.assertRaisesRegex + except AttributeError: + # assertRaisesRegexp is deprecated in Python3 but assertRaisesRegex doesn't exist in Python2 + # This fix is used in order to avoid using the alias from the six library + self.assertRaisesRegex = self.assertRaisesRegexp + + +class CSVParserTests(Py23TestCase): def test_general(self): csv = """ @@ -105,7 +117,7 @@ name2, EFUSE_BLK2, , , EFUSE_BLK2, , 4, name1, EFUSE_BLK3, , 5, """ - with self.assertRaisesRegexp(efuse_table_gen.InputError, "Field names must be unique"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "Field names must be unique"): efuse_table_gen.FuseTable.from_csv(csv) def test_seq_bit_start5_fill(self): @@ -142,7 +154,7 @@ name1, EFUSE_BLK3, 1, name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ t = efuse_table_gen.FuseTable.from_csv(csv) - with self.assertRaisesRegexp(efuse_table_gen.InputError, "overlap"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "overlap"): t.verify() def test_empty_field_name_fail(self): @@ -151,7 +163,7 @@ name2, EFUSE_BLK3, 5, , EFUSE_BLK3, , 5, name2, EFUSE_BLK2, , 4, """ - with self.assertRaisesRegexp(efuse_table_gen.InputError, "missing field name"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "missing field name"): efuse_table_gen.FuseTable.from_csv(csv) def test_unique_field_name_fail(self): @@ -160,7 +172,7 @@ name2, EFUSE_BLK2, , name1, EFUSE_BLK3, 0, 5, Use for test name 1 name1, EFUSE_BLK3, 5, 4, Use for test name 2 """ - with self.assertRaisesRegexp(efuse_table_gen.InputError, "Field names must be unique"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "Field names must be unique"): efuse_table_gen.FuseTable.from_csv(csv) def test_bit_count_empty_fail(self): @@ -169,7 +181,7 @@ name1, EFUSE_BLK3, 5, name1, EFUSE_BLK3, 0, , Use for test name 1 name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ - with self.assertRaisesRegexp(efuse_table_gen.InputError, "empty"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "empty"): efuse_table_gen.FuseTable.from_csv(csv) def test_bit_start_num_fail(self): @@ -178,7 +190,7 @@ name2, EFUSE_BLK3, 5, name1, EFUSE_BLK3, k, 5, Use for test name 1 name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ - with self.assertRaisesRegexp(efuse_table_gen.InputError, "Invalid field value"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "Invalid field value"): efuse_table_gen.FuseTable.from_csv(csv) def test_join_entry(self): @@ -224,7 +236,7 @@ name4, EFUSE_BLK2, 30, name1, EFUSE_BLK5, 0, 5, Use for test name 1 name2, EFUSE_BLK3, 5, 4, Use for test name 2 """ - with self.assertRaisesRegexp(efuse_table_gen.InputError, "'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3"): efuse_table_gen.FuseTable.from_csv(csv) def test_field_size_is_ok(self): @@ -233,7 +245,7 @@ name2, EFUSE_BLK3, 5, name1, EFUSE_BLK0, 0, 224, Use for test name 1 name2, EFUSE_BLK1, 0, 256, Use for test name 2 """ - efuse_table_gen.coding_scheme = 0 # NONE + efuse_table_gen.max_blk_len = 256 t = efuse_table_gen.FuseTable.from_csv(csv) t.verify() @@ -243,9 +255,9 @@ name2, EFUSE_BLK1, 0, name1, EFUSE_BLK3, 190, 1, Use for test name 1 name2, EFUSE_BLK3, 191, 5, Use for test name 2 """ - efuse_table_gen.coding_scheme = 1 # 3/4 coding + efuse_table_gen.max_blk_len = 192 t = efuse_table_gen.FuseTable.from_csv(csv) - with self.assertRaisesRegexp(efuse_table_gen.InputError, "The field is outside the boundaries"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "The field is outside the boundaries"): t.verify() def test_field_blk1_size_is_more(self): @@ -255,11 +267,11 @@ name1, EFUSE_BLK0, 0, name2, EFUSE_BLK1, 1, 256, Use for test name 2 """ t = efuse_table_gen.FuseTable.from_csv(csv) - with self.assertRaisesRegexp(efuse_table_gen.InputError, "The field is outside the boundaries"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "The field is outside the boundaries"): t.verify() -class VerificationTests(unittest.TestCase): +class VerificationTests(Py23TestCase): def test_general(self): csv = """ @@ -299,7 +311,7 @@ name1, EFUSE_BLK3, 0, name2, EFUSE_BLK2, 5, 4, Use for test name 2 """ t = efuse_table_gen.FuseTable.from_csv(csv) - with self.assertRaisesRegexp(efuse_table_gen.ValidationError, "custom_table should use only EFUSE_BLK3"): + with self.assertRaisesRegex(efuse_table_gen.ValidationError, "custom_table should use only EFUSE_BLK3"): t.verify("custom_table") def test_common_and_custom_table_use_the_same_bits(self): @@ -321,7 +333,7 @@ name4, EFUSE_BLK3, 4, custom_table.verify("custom_table") two_tables += custom_table - with self.assertRaisesRegexp(efuse_table_gen.InputError, "overlaps"): + with self.assertRaisesRegex(efuse_table_gen.InputError, "overlaps"): two_tables.verify() diff --git a/components/esp32/esp_err_to_name.c b/components/esp32/esp_err_to_name.c index 8172f9efe7..2f33b3ab96 100644 --- a/components/esp32/esp_err_to_name.c +++ b/components/esp32/esp_err_to_name.c @@ -243,6 +243,23 @@ static const esp_err_msg_t esp_err_msg_table[] = { (ESP_OTA_IMG_PENDING_VERIFY), essentially first boot of firmware image post upgrade and hence firmware upgrade is not possible */ +# endif + // components/efuse/include/esp_efuse.h +# ifdef ESP_ERR_EFUSE + ERR_TBL_IT(ESP_ERR_EFUSE), /* 5632 0x1600 Base error code for efuse api. */ +# endif +# ifdef ESP_OK_EFUSE_CNT + ERR_TBL_IT(ESP_OK_EFUSE_CNT), /* 5633 0x1601 OK the required number of bits is set. */ +# endif +# ifdef ESP_ERR_EFUSE_CNT_IS_FULL + ERR_TBL_IT(ESP_ERR_EFUSE_CNT_IS_FULL), /* 5634 0x1602 Error field is full. */ +# endif +# ifdef ESP_ERR_EFUSE_REPEATED_PROG + ERR_TBL_IT(ESP_ERR_EFUSE_REPEATED_PROG), /* 5635 0x1603 Error repeated programming of programmed + bits is strictly forbidden. */ +# endif +# ifdef ESP_ERR_CODING + ERR_TBL_IT(ESP_ERR_CODING), /* 5636 0x1604 Error while a encoding operation. */ # endif // components/bootloader_support/include/esp_image_format.h # ifdef ESP_ERR_IMAGE_BASE diff --git a/docs/en/api-reference/system/efuse.rst b/docs/en/api-reference/system/efuse.rst index afeffd60a7..e1fd2bebc0 100644 --- a/docs/en/api-reference/system/efuse.rst +++ b/docs/en/api-reference/system/efuse.rst @@ -58,7 +58,7 @@ bit_start Start bit number (0..255). The bit_start field can be omitted. In this case, it will be set to bit_start + bit_count from the previous record, if it has the same efuse_block. Otherwise (if efuse_block is different, or this is the first entry), an error will be generated. bit_count - The number of bits to use in this field (1..-). This parameter can not be omitted. This field also may be ``MAX_BLK_LEN`` in this case, the field length will have the maximum block length, taking into account the coding scheme (applicable for ``ESP_EFUSE_SECURE_BOOT_KEY`` and ``ESP_EFUSE_ENCRYPT_FLASH_KEY`` fields). The value ``MAX_BLK_LEN`` depends on :envvar:`CONFIG_EFUSE_CODE_SCHEME`, will be replaced with "None" - 256, "3/4" - 192, "REPEAT" - 128. + The number of bits to use in this field (1..-). This parameter can not be omitted. This field also may be ``MAX_BLK_LEN`` in this case, the field length will have the maximum block length, taking into account the coding scheme (applicable for ``ESP_EFUSE_SECURE_BOOT_KEY`` and ``ESP_EFUSE_ENCRYPT_FLASH_KEY`` fields). The value ``MAX_BLK_LEN`` depends on :envvar:`CONFIG_EFUSE_MAX_BLK_LEN`, will be replaced with "None" - 256, "3/4" - 192, "REPEAT" - 128. comment This param is using for comment field, it also move to C-header file. The comment field can be omitted.