efuse: Fix to pass CI tests

This commit is contained in:
Konstantin Kondrashov 2018-12-18 22:42:10 +08:00 committed by bot
parent c9cd06c886
commit 509e1264b9
13 changed files with 253 additions and 467 deletions

View File

@ -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 */

View File

@ -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 <string.h>
#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;
}

View File

@ -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.

View File

@ -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

View File

@ -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)
###################

View File

@ -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

View File

@ -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

View File

@ -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.

Can't render this file because it contains an unexpected character in line 7 and column 87.

View File

@ -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

View File

@ -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;
}

View File

@ -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()

View File

@ -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

View File

@ -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.