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) set(COMPONENT_PRIV_REQUIRES bootloader_support)
register_component() 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. # 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 config EFUSE_CUSTOM_TABLE
bool "Use custom eFuse table" bool "Use custom eFuse table"
default n default n
help help
Allows to generate a structure for eFuse from the CSV file. Allows to generate a structure for eFuse from the CSV file.
config EFUSE_CUSTOM_TABLE_FILENAME config EFUSE_CUSTOM_TABLE_FILENAME
string "Custom eFuse CSV file" if EFUSE_CUSTOM_TABLE string "Custom eFuse CSV file"
default main/esp_efuse_custom_table.csv depends on EFUSE_CUSTOM_TABLE
help default main/esp_efuse_custom_table.csv
Name of the custom eFuse CSV filename. This path is evaluated help
relative to the project root directory. 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" bool "Simulate eFuse operations in RAM"
default n default n
help help
All read and writes operations are redirected to RAM instead of eFuse registers. 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. 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. Log output will state changes which would be applied, but they will not be.
choice EFUSE_CODE_SCHEME_SELECTOR choice EFUSE_CODE_SCHEME_SELECTOR
prompt "Coding scheme" prompt "Coding Scheme Compatibility"
default EFUSE_CODE_SCHEME_STATE_NONE default EFUSE_CODE_SCHEME_COMPAT_3_4
help help
Selector eFuse code scheme. Selector eFuse code scheme.
config EFUSE_CODE_SCHEME_STATE_NONE config EFUSE_CODE_SCHEME_COMPAT_NONE
bool "NONE" bool "None Only"
config EFUSE_CODE_SCHEME_STATE_3_4 config EFUSE_CODE_SCHEME_COMPAT_3_4
bool "3/4" bool "3/4 and None"
config EFUSE_CODE_SCHEME_STATE_REPEAT config EFUSE_CODE_SCHEME_COMPAT_REPEAT
bool "REPEAT" bool "Repeat, 3/4 and None (common table does not support it)"
endchoice endchoice
config EFUSE_CODE_SCHEME config EFUSE_MAX_BLK_LEN
int int
default 0 if EFUSE_CODE_SCHEME_STATE_NONE default 256 if EFUSE_CODE_SCHEME_COMPAT_NONE
default 1 if EFUSE_CODE_SCHEME_STATE_3_4 default 192 if EFUSE_CODE_SCHEME_COMPAT_3_4
default 2 if EFUSE_CODE_SCHEME_STATE_REPEAT default 128 if EFUSE_CODE_SCHEME_COMPAT_REPEAT
endmenu endmenu

View File

@@ -5,7 +5,7 @@
GEN_EFUSE_TABLE := $(PYTHON) $(COMPONENT_PATH)/efuse_table_gen.py 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' __version__ = '1.0'
quiet = False quiet = False
coding_scheme = 0 max_blk_len = 256
CODE_SCHEME = {
"NONE": 0,
"3/4": 1,
"REPEAT": 2,
}
copyright = '''// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD copyright = '''// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
// //
@@ -250,13 +244,7 @@ class FuseTable(list):
rows += [""] rows += [""]
rows += ["#if (CONFIG_EFUSE_CODE_SCHEME == 0)", rows += ["#define MAX_BLK_LEN CONFIG_EFUSE_MAX_BLK_LEN"]
"#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 += [""] rows += [""]
@@ -368,16 +356,10 @@ class FuseDefinition(object):
'''common_table: EFUSE_BLK0, EFUSE_BLK1, EFUSE_BLK2, EFUSE_BLK3 '''common_table: EFUSE_BLK0, EFUSE_BLK1, EFUSE_BLK2, EFUSE_BLK3
custom_table: ----------, ----------, ----------, EFUSE_BLK3(some reserved in common_table) custom_table: ----------, ----------, ----------, EFUSE_BLK3(some reserved in common_table)
''' '''
max_bits = 0 if self.efuse_block == "EFUSE_BLK0":
if coding_scheme == CODE_SCHEME["NONE"] or self.efuse_block == "EFUSE_BLK0": return 256
max_bits = 256
elif coding_scheme == CODE_SCHEME["3/4"]:
max_bits = 192
elif coding_scheme == CODE_SCHEME["REPEAT"]:
max_bits = 128
else: else:
raise ValidationError(self, "Unknown coding scheme") return max_blk_len
return max_bits
def verify(self, type_table): def verify(self, type_table):
if self.efuse_block is None: if self.efuse_block is None:
@@ -467,27 +449,22 @@ def create_output_files(name, output_table, debug):
def main(): def main():
global quiet global quiet
global coding_scheme global max_blk_len
parser = argparse.ArgumentParser(description='ESP32 eFuse Manager') 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('--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('--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('--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('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) parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('r'), nargs='?', default=None)
args = parser.parse_args() args = parser.parse_args()
coding_scheme = args.coding_scheme max_blk_len = args.max_blk_len
if CODE_SCHEME["NONE"] == coding_scheme: print("Max number of bits in BLK %d" % (max_blk_len))
print("eFuse coding scheme: NONE") if max_blk_len not in [256, 192, 128]:
elif CODE_SCHEME["3/4"] == coding_scheme: raise InputError("Unsupported block length = %d" % (max_blk_len))
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))
quiet = args.quiet quiet = args.quiet
debug = args.debug debug = args.debug

View File

@@ -23,13 +23,7 @@
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file. // then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
// To show efuse_table run the command 'show_efuse_table'. // To show efuse_table run the command 'show_efuse_table'.
#if (CONFIG_EFUSE_CODE_SCHEME == 0) #define MAX_BLK_LEN CONFIG_EFUSE_MAX_BLK_LEN
#define MAX_BLK_LEN 256
#elif (CONFIG_EFUSE_CODE_SCHEME == 1)
#define MAX_BLK_LEN 192
#elif (CONFIG_EFUSE_CODE_SCHEME == 2)
#define MAX_BLK_LEN 128
#endif
// The last free bit in the block is counted over the entire file. // The last free bit in the block is counted over the entire file.
#define LAST_FREE_BIT_BLK1 MAX_BLK_LEN #define LAST_FREE_BIT_BLK1 MAX_BLK_LEN

View File

@@ -4,7 +4,7 @@
# | EFUSE_BLK2 | | | # # | EFUSE_BLK2 | | | #
# | EFUSE_BLK3) | | | # # | 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" # 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. # 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); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -115,3 +115,123 @@ void esp_efuse_write_random_key(uint32_t blk_wdata0_reg)
bzero(buf, sizeof(buf)); bzero(buf, sizeof(buf));
bzero(raw, sizeof(raw)); 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): def test_general(self):
csv = """ csv = """
@@ -105,7 +117,7 @@ name2, EFUSE_BLK2, ,
, EFUSE_BLK2, , 4, , EFUSE_BLK2, , 4,
name1, EFUSE_BLK3, , 5, 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) efuse_table_gen.FuseTable.from_csv(csv)
def test_seq_bit_start5_fill(self): 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 name2, EFUSE_BLK3, 5, 4, Use for test name 2
""" """
t = efuse_table_gen.FuseTable.from_csv(csv) 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() t.verify()
def test_empty_field_name_fail(self): def test_empty_field_name_fail(self):
@@ -151,7 +163,7 @@ name2, EFUSE_BLK3, 5,
, EFUSE_BLK3, , 5, , EFUSE_BLK3, , 5,
name2, EFUSE_BLK2, , 4, 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) efuse_table_gen.FuseTable.from_csv(csv)
def test_unique_field_name_fail(self): 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, 0, 5, Use for test name 1
name1, EFUSE_BLK3, 5, 4, Use for test name 2 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) efuse_table_gen.FuseTable.from_csv(csv)
def test_bit_count_empty_fail(self): def test_bit_count_empty_fail(self):
@@ -169,7 +181,7 @@ name1, EFUSE_BLK3, 5,
name1, EFUSE_BLK3, 0, , Use for test name 1 name1, EFUSE_BLK3, 0, , Use for test name 1
name2, EFUSE_BLK3, 5, 4, Use for test name 2 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) efuse_table_gen.FuseTable.from_csv(csv)
def test_bit_start_num_fail(self): 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 name1, EFUSE_BLK3, k, 5, Use for test name 1
name2, EFUSE_BLK3, 5, 4, Use for test name 2 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) efuse_table_gen.FuseTable.from_csv(csv)
def test_join_entry(self): def test_join_entry(self):
@@ -224,7 +236,7 @@ name4, EFUSE_BLK2, 30,
name1, EFUSE_BLK5, 0, 5, Use for test name 1 name1, EFUSE_BLK5, 0, 5, Use for test name 1
name2, EFUSE_BLK3, 5, 4, Use for test name 2 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) efuse_table_gen.FuseTable.from_csv(csv)
def test_field_size_is_ok(self): 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 name1, EFUSE_BLK0, 0, 224, Use for test name 1
name2, EFUSE_BLK1, 0, 256, Use for test name 2 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 = efuse_table_gen.FuseTable.from_csv(csv)
t.verify() t.verify()
@@ -243,9 +255,9 @@ name2, EFUSE_BLK1, 0,
name1, EFUSE_BLK3, 190, 1, Use for test name 1 name1, EFUSE_BLK3, 190, 1, Use for test name 1
name2, EFUSE_BLK3, 191, 5, Use for test name 2 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) 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() t.verify()
def test_field_blk1_size_is_more(self): 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 name2, EFUSE_BLK1, 1, 256, Use for test name 2
""" """
t = efuse_table_gen.FuseTable.from_csv(csv) 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() t.verify()
class VerificationTests(unittest.TestCase): class VerificationTests(Py23TestCase):
def test_general(self): def test_general(self):
csv = """ csv = """
@@ -299,7 +311,7 @@ name1, EFUSE_BLK3, 0,
name2, EFUSE_BLK2, 5, 4, Use for test name 2 name2, EFUSE_BLK2, 5, 4, Use for test name 2
""" """
t = efuse_table_gen.FuseTable.from_csv(csv) 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") t.verify("custom_table")
def test_common_and_custom_table_use_the_same_bits(self): def test_common_and_custom_table_use_the_same_bits(self):
@@ -321,7 +333,7 @@ name4, EFUSE_BLK3, 4,
custom_table.verify("custom_table") custom_table.verify("custom_table")
two_tables += 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() 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 (ESP_OTA_IMG_PENDING_VERIFY), essentially
first boot of firmware image post upgrade first boot of firmware image post upgrade
and hence firmware upgrade is not possible */ 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 # endif
// components/bootloader_support/include/esp_image_format.h // components/bootloader_support/include/esp_image_format.h
# ifdef ESP_ERR_IMAGE_BASE # 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. 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 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 comment
This param is using for comment field, it also move to C-header file. The comment field can be omitted. This param is using for comment field, it also move to C-header file. The comment field can be omitted.