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,19 +1,20 @@
menu "eFuse bit Manager"
menu "eFuse Bit Manager"
config EFUSE_CUSTOM_TABLE
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
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
config EFUSE_VIRTUAL
bool "Simulate eFuse operations in RAM"
default n
help
@@ -21,24 +22,24 @@ 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_SELECTOR
prompt "Coding scheme"
default EFUSE_CODE_SCHEME_STATE_NONE
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
config EFUSE_MAX_BLK_LEN
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
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.