# NVS Bootloader

[中文]

## Overview

This guide provides an overview of the NVS (Non-Volatile Storage) functionality available for custom bootloader code, along with its limitations.

Due to the constraints of the bootloader runtime environment, custom bootloader code cannot use the full NVS API directly. Instead, NVS provides a simplified API that offers read-only access to NVS data.

The API supports reading all NVS datatypes except for blobs. One call to the API can read multiple NVS entries at once. Values can be read from different namespaces within the same NVS partition. The array of input-output structures serves as placeholders for the data read from NVS, with a fixed size of up to 8 bytes.

To read string entries, the API requires the caller to provide a buffer and its size, due to the heap memory allocation restriction in the bootloader.

### Reading encrypted NVS partitions

The API also supports decrypting NVS data, if the NVS partition is encrypted using one of the schemes as mentioned in the NVS Encryption guide.

Applications are expected to follow the steps below in order to enable decryption of a NVS partition using the `nvs_bootloader_read()` API:

> 1. Populate the NVS security configuration structure `nvs_sec_cfg_t` according to the selected NVS encryption scheme (Please refer to NVS Encryption for more details).

> 2. Read NVS security configuration set by the specified security scheme using the `nvs_bootloader_read_security_cfg()` API.

> 3. Initialise the NVS flash partition with the above read security configuration using the `nvs_bootloader_secure_init()` API.

> 4. Perform NVS read operations using the `nvs_bootloader_read()` API.

> 5. Deinitialise and clear the security configuration of the NVS flash partition using the `nvs_bootloader_secure_deinit()` API.

Note

While using the HMAC-based scheme, the above workflow can be used without enabling any of the config options for NVS encryption - CONFIG_NVS_ENCRYPTION, CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME -> `CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC` and CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID to encrypt the default as well as custom NVS partitions with `nvs_flash_secure_init()` API.

## Application Example

You can find code examples in storage/nvs/nvs_bootloader (in the storage/nvs directory of ESP-IDF examples).

This section demonstrates how to prepare data in the input-output structure for various data types, namespaces, and keys. It includes an example of reading string data from NVS.

The example also shows how to check if a read operation was successful, or if there were inconsistencies in the data or if certain values were not found in NVS. The example prints the values (or error codes) returned by the API to the console.

## API Reference

### Header File

- components/nvs_flash/include/nvs_bootloader.h

- 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 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_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 the `result_code` member of each element of the `read_list` array.

  Parameters:

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

  Returns:

    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_code` in `read_list` indicates the result of the lookup for a particular requested key.

    - `ESP_ERR_INVALID_ARG`: The validity of all `read_list` input parameters was checked and failed for at least one of the parameters. The individual `result_code` in `read_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.

  Note

  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_t` security config, until `nvs_bootloader_secure_deinit()` clears the internal NVS security context.

  Parameters:

    sec_cfg -- NVS security key that would be used for decrypting the NVS partition

  Returns:

    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.

  Parameters:

    - scheme_cfg -- [in] Security scheme specific configuration

    - cfg -- [out] Security configuration (encryption keys)

  Returns:

    - 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

### Structures

struct nvs_bootloader_str_value_placeholder_t

  Placeholders for buffer pointer and length of string type.

  Public Members

  char *buff_ptr

    Pointer to the buffer where string and terminating zero character will be read

  size_t buff_len

    Buffer length in bytes

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 the `value.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 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)

Was this page helpful?

- Thank you! We received your feedback.
- If you have any comments, fill in Espressif Documentation Feedback Form.

- We value your feedback.
- Let us know how we can improve this page by filling in Espressif Documentation Feedback Form.