在引导程序中使用 NVS
概述
本指南概述了可用于自定义引导加载程序代码的 NVS(非易失性存储)功能及其限制。
由于引导加载程序运行环境的限制,自定义引导加载程序代码无法直接使用完整的 NVS API。为此,NVS 提供了一个简化 API,仅支持只读访问 NVS 数据。
该 API 支持读取除 blob 之外的所有 NVS 数据类型。一次 API 调用可以同时读取多个 NVS 条目。可以从同一 NVS 分区的不同命名空间读取值,读取结果存储在输入/输出结构数组中,每个数据项的固定大小最多为 8 字节。
由于引导加载程序中的堆内存分配限制,读取字符串条目时,API 要求调用者提供缓冲区及其大小。
读取加密的 NVS 分区
如果 NVS 分区使用 NVS 加密 指南中的加密方案,该 API 还支持解密 NVS 数据。
应用程序应按照以下步骤使用 nvs_bootloader_read()
API 读取加密 NVS 分区数据:
根据所选的 NVS 加密方案填充 NVS 安全配置结构
nvs_sec_cfg_t
(详情请参阅 NVS 加密)。使用
nvs_bootloader_read_security_cfg()
API 从指定的安全方案中读取 NVS 安全配置。获取安全配置后,使用
nvs_bootloader_secure_init()
API 初始化 NVS flash 分区。使用
nvs_bootloader_read()
API 执行 NVS 读取操作。使用
nvs_bootloader_secure_deinit()
API 反初始化 NVS flash 分区,并清除安全配置。
备注
在使用基于 HMAC 的方案进行上述流程时,可以直接调用 nvs_flash_secure_init()
API 对默认和自定义 NVS 分区进行加密,而无需启用 NVS 加密相关配置选项(如 CONFIG_NVS_ENCRYPTION, CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME -> CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC
, CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID)。
应用示例
代码示例请参阅 ESP-IDF 示例 storage 目录下的 storage/nvs_bootloader。
本节演示了如何在输入/输出结构中准备数据,以支持不同的数据类型、命名空间和键。此外,还包含从 NVS 读取字符串数据的示例。
示例还演示了如何检查读取操作是否成功,数据是否存在不一致,或是否在 NVS 中找不到某些值的情形。该示例能够将 API 返回的值(或错误码)打印到控制台。
API 参考
Header File
This header file can be included with:
#include "nvs_bootloader.h"
This header file is a part of the API provided by the
nvs_flash
component. To declare that your component depends onnvs_flash
, add the following to your CMakeLists.txt:REQUIRES nvs_flash
or
PRIV_REQUIRES nvs_flash
Functions
-
esp_err_t nvs_bootloader_read(const char *partition_name, const size_t read_list_count, nvs_bootloader_read_list_t read_list[])
Reads data specified from the specified NVS partition.
This function reads data from the NVS partition specified by
partition_name
. Multiple NVS entries can be read in a single call. The list of entries to read is specified in theread_list
array. Function indicates overall success or failure by its return value. In case it is ESP_OK or ESP_ERR_INVALID_ARG, result of validation / reading of individual entry is returned in theresult_code
member of each element of theread_list
array.- 参数:
partition_name -- The name of the NVS partition to read from.
read_list_count -- The number of elements in the
read_list
array.read_list -- An array of
nvs_bootloader_read_list_t
structures specifying the keys and buffers for reading data.
- 返回:
The return value of the function in this file can be one of the following:
ESP_OK
: The function successfully checked all input parameters and executed successfully. The individualresult_code
inread_list
indicates the result of the lookup for a particular requested key.ESP_ERR_INVALID_ARG
: The validity of allread_list
input parameters was checked and failed for at least one of the parameters. The individualresult_code
inread_list
provides the detailed reason. This error code is also returned when read_list is null or read_list_count is 0.ESP_ERR_NVS_INVALID_NAME
: The partition name specified is too long or is null.ESP_ERR_NVS_PART_NOT_FOUND
: The partition was not found in the partition table.ESP_ERR_NVS_CORRUPT_KEY_PART
: Encryption-related problems.ESP_ERR_NVS_WRONG_ENCRYPTION
: Encryption-related problems.ESP_ERR_INVALID_STATE
: NVS partition or pages related errors - wrong size of partition, header inconsistent / entries inconsistencies, multiple active pages, page in state INVALID.ESP_ERR_NO_MEM
: Cannot allocate memory required to perform the function.Technical errors in underlying storage.
-
esp_err_t nvs_bootloader_secure_init(const nvs_sec_cfg_t *sec_cfg)
Initialize internal NVS security context, thus, enabling the NVS bootloader read API to decrypt encrypted NVS partitions.
备注
Once
nvs_bootloader_secure_init()
is performed,nvs_bootloader_read()
can correctly read only those NVS partitions that are encrypted using the givennvs_sec_cfg_t
security config, untilnvs_bootloader_secure_deinit()
clears the internal NVS security context.- 参数:
sec_cfg -- NVS security key that would be used for decrypting the NVS partition
- 返回:
ESP_OK if security initialization is successful
-
void nvs_bootloader_secure_deinit(void)
Clear the internal NVS security context.
-
esp_err_t nvs_bootloader_read_security_cfg(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t *cfg)
Reads NVS bootloader security configuration set by the specified security scheme.
- 参数:
scheme_cfg -- [in] Security scheme specific configuration
cfg -- [out] Security configuration (encryption keys)
- 返回:
ESP_OK, if cfg was read successfully;
ESP_ERR_INVALID_ARG, if scheme_cfg or cfg is NULL;
ESP_FAIL, if the key reading process fails
Unions
-
union nvs_bootloader_value_placeholder_t
- #include <nvs_bootloader.h>
Union of value placeholders for all nvs_type_t supported by bootloader code.
Public Members
-
uint8_t u8_val
Placeholder for unsigned 8 bit integer variable
-
int8_t i8_val
Placeholder for signed 8 bit integer variable
-
uint16_t u16_val
Placeholder for unsigned 16 bit integer variable
-
int16_t i16_val
Placeholder for signed 16 bit integer variable
-
uint32_t u32_val
Placeholder for unsigned 32 bit integer variable
-
int32_t i32_val
Placeholder for signed 32 bit integer variable
-
uint64_t u64_val
Placeholder for unsigned 64 bit integer variable
-
int64_t i64_val
Placeholder for signed 64 bit integer variable
-
nvs_bootloader_str_value_placeholder_t str_val
Placeholder for string buffer information
-
uint8_t u8_val
Structures
-
struct nvs_bootloader_str_value_placeholder_t
Placeholders for buffer pointer and length of string type.
-
struct nvs_bootloader_read_list_t
Structure representing one NVS bootloader entry.
This structure serves as read operation input parameters and result value and status placeholder. Before calling the
nvs_bootloader_read
function, populate the namespace_name, key_name and value_type members. If string value has to be read, provide also buffer and its length in thevalue.str_val
member.The result_code member will be populated by the function with the result of the read operation. There are 2 possible situations and interpretations of the result_code: If the return value of the
nvs_bootloader_read
was ESP_OK, the result_code will be one of the following:ESP_OK
: Entry found, value member contains the data. This is the only case when the value member is populated.ESP_ERR_NVS_TYPE_MISMATCH
: Entry was found, but requested datatype doesn't match datatype found in NVSESP_ERR_NVS_NOT_FOUND
: Data was not found.ESP_ERR_INVALID_SIZE
: the value found for string is longer than the space provided in placeholder (str_val.buff_len) If the return value of the function was ESP_ERR_INVALID_ARG, the result_code will be one of the following:ESP_ERR_NVS_NOT_FOUND
: Check of this parameters was successful.ESP_ERR_NVS_INVALID_NAME
: namespace_name is NULL or too longESP_ERR_NVS_KEY_TOO_LONG
: key_name NULL or too longESP_ERR_INVALID_SIZE
: the size of the buffer provided for NVS_TYPE_STR in placeholder (str_val.buff_len) is zero or exceeds maximum value NVS_CONST_STR_LEN_MAX_SIZEESP_ERR_INVALID_ARG
: Invalid datatype requested
Public Members
-
const char *namespace_name
Namespace of the entry
-
const char *key_name
Key of the entry
-
nvs_type_t value_type
Expected datatype to be read, can be any of NVS_TYPE_U*, NVS_TYPE_I* or NVS_TYPE_STR
-
esp_err_t result_code
Result code of this entry. Explanation is in general description of the struct nvs_bootloader_read_list_t
-
nvs_bootloader_value_placeholder_t value
Placeholder for value read
-
uint8_t namespace_index
Index of the namespace (internal variable, do not use)