在引导程序中使用 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/nvs 目录下的 storage/nvs/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_flashcomponent. To declare that your component depends on- nvs_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 the- read_listarray. 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 the- result_codemember of each element of the- read_listarray.- 参数:
- partition_name -- The name of the NVS partition to read from. 
- read_list_count -- The number of elements in the - read_listarray.
- read_list -- An array of - nvs_bootloader_read_list_tstructures 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 individual- result_codein- read_listindicates the result of the lookup for a particular requested key.
- ESP_ERR_INVALID_ARG: The validity of all- read_listinput parameters was checked and failed for at least one of the parameters. The individual- result_codein- read_listprovides 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 given- nvs_sec_cfg_tsecurity config, until- nvs_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_readfunction, populate the namespace_name, key_name and value_type members. If string value has to be read, provide also buffer and its length in the- value.str_valmember.- 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_readwas 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 NVS
- ESP_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 long
- ESP_ERR_NVS_KEY_TOO_LONG: key_name NULL or too long
- ESP_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_SIZE
- ESP_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)