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.