mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
feat(nvs_flash): Added support for Block Data Layer storage provider
- BDL provider can be enabled vor NVS in the menuconfig option NVS_BDL_STACK - Hierarchy of Partition class tree was adjusted and all operations were documented - Class Partition is now derived from intrusive_list_node and ExceptionlessAllocable - Class NVSPartition implements only the dual support for esp_partition and BDL - Class NVSEncryptedPartition implements only encryption related extensions
This commit is contained in:
@@ -4,6 +4,7 @@ components/nvs_flash/host_test:
|
||||
- nvs_flash
|
||||
- nvs_sec_provider
|
||||
- esp_partition
|
||||
- esp_blockdev
|
||||
enable:
|
||||
- if: IDF_TARGET == "linux"
|
||||
|
||||
@@ -12,6 +13,7 @@ components/nvs_flash/test_apps:
|
||||
- spi_flash
|
||||
- nvs_flash
|
||||
- nvs_sec_provider
|
||||
- esp_blockdev
|
||||
- esp_partition
|
||||
disable_test:
|
||||
- if: IDF_TARGET not in ["esp32", "esp32c3"]
|
||||
|
||||
@@ -32,7 +32,7 @@ elseif(esp_tee_build)
|
||||
"src/nvs_types.cpp"
|
||||
"src/nvs_platform.cpp")
|
||||
|
||||
set(requires esp_partition mbedtls)
|
||||
set(requires esp_partition esp_blockdev mbedtls)
|
||||
set(priv_requires spi_flash esp_libc cxx)
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
@@ -60,7 +60,7 @@ else()
|
||||
"src/nvs_platform.cpp"
|
||||
"src/nvs_bootloader.c")
|
||||
|
||||
set(requires esp_partition)
|
||||
set(requires esp_partition esp_blockdev)
|
||||
set(priv_requires spi_flash)
|
||||
if(NOT ${target} STREQUAL "linux")
|
||||
list(APPEND priv_requires esp_libc esptool_py nvs_sec_provider)
|
||||
|
||||
@@ -45,4 +45,10 @@ menu "NVS"
|
||||
instead of internal RAM. It can help applications using large nvs partitions or large number
|
||||
of keys to save heap space in internal RAM. SPIRAM heap allocation negatively impacts speed
|
||||
of NVS operations as the CPU accesses NVS cache via SPI instead of direct access to the internal RAM.
|
||||
|
||||
config NVS_BDL_STACK
|
||||
bool "Run NVS on BDL instead of ESP_Partition"
|
||||
default n
|
||||
help
|
||||
This option enforces internal use of Block Device Layer instead ESP_Partition.
|
||||
endmenu
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "nvs.hpp"
|
||||
#include "nvs_partition_manager.hpp"
|
||||
|
||||
@@ -92,7 +92,11 @@ esp_err_t nvs_flash_init(void);
|
||||
esp_err_t nvs_flash_init_partition(const char *partition_label);
|
||||
|
||||
/**
|
||||
* @brief Initialize NVS flash storage for the partition specified by partition pointer.
|
||||
* @brief Initialize NVS flash storage on the partition specified by esp_partition pointer.
|
||||
*
|
||||
* This API initialises the NVS storage on an esp_partition. The storage is identified
|
||||
* by the label of the respective partition.
|
||||
* Note: this API is only available when the block device support is disabled in the menuconfig.
|
||||
*
|
||||
* @param[in] partition pointer to a partition obtained by the ESP partition API.
|
||||
*
|
||||
@@ -106,6 +110,30 @@ esp_err_t nvs_flash_init_partition(const char *partition_label);
|
||||
*/
|
||||
esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partition);
|
||||
|
||||
/**
|
||||
* @brief Initialize NVS flash storage on the specified block device handle.
|
||||
*
|
||||
* This API initialises the NVS storage on a bdl device and identifies it with the given label.
|
||||
* Caller of this API is responsible for creating and managing the lifetime of the block device handle.
|
||||
* NVS component will stop using the handle when nvs_flash_deinit_partition() is called for the last
|
||||
* partition label using this block device handle.
|
||||
*
|
||||
* Note: to use this API, the block device support must be enabled in the menuconfig option NVS_BDL_STACK
|
||||
*
|
||||
* @param[in] partition_label label of the partition to initialize
|
||||
* @param[in] bdl block device handle for the partition
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if storage was successfully initialized
|
||||
* - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages
|
||||
* (which may happen if NVS partition was truncated)
|
||||
* - ESP_ERR_INVALID_ARG in case partition_label or bdl is NULL
|
||||
* - ESP_ERR_NO_MEM in case memory could not be allocated for the internal structures
|
||||
* - ESP_ERR_NOT_SUPPORTED if the bdl handle does not fulfill the NVS compliance requirements
|
||||
* - one of the error codes from the underlying flash storage driver
|
||||
*/
|
||||
esp_err_t nvs_flash_init_partition_bdl(const char* partition_label, esp_blockdev_handle_t bdl);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize NVS storage for the default NVS partition
|
||||
*
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "esp_err.h"
|
||||
#include <esp_rom_crc.h>
|
||||
#include "nvs_internal.h"
|
||||
#include "nvs_partition_lookup.hpp"
|
||||
|
||||
// Uncomment this line to force output from this module
|
||||
// #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
||||
@@ -91,6 +92,7 @@ static esp_err_t close_handles_and_deinit(const char* part_name)
|
||||
return NVSPartitionManager::get_instance()->deinit_partition(part_name);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NVS_BDL_STACK
|
||||
extern "C" esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partition)
|
||||
{
|
||||
esp_err_t lock_result = Lock::init();
|
||||
@@ -108,10 +110,12 @@ extern "C" esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partiti
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
uint32_t sec_size = NVS_CONST_PAGE_SIZE;
|
||||
uint32_t size = part->get_size();
|
||||
|
||||
esp_err_t init_res = NVSPartitionManager::get_instance()->init_custom(part,
|
||||
0,
|
||||
partition->size / sec_size);
|
||||
size / sec_size);
|
||||
|
||||
if (init_res != ESP_OK) {
|
||||
delete part;
|
||||
@@ -119,6 +123,46 @@ extern "C" esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partiti
|
||||
|
||||
return init_res;
|
||||
}
|
||||
#else
|
||||
extern "C" esp_err_t nvs_flash_init_partition_bdl(const char* partition_label, esp_blockdev_handle_t bdl)
|
||||
{
|
||||
esp_err_t lock_result = Lock::init();
|
||||
if (lock_result != ESP_OK) {
|
||||
return lock_result;
|
||||
}
|
||||
Lock lock;
|
||||
|
||||
if (partition_label == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (bdl == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!NVSPartition::is_bdl_nvs_compliant(partition_label, bdl)) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NVSPartition *part = new (std::nothrow) NVSPartition(partition_label, bdl, false);
|
||||
if (part == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
uint32_t sec_size = NVS_CONST_PAGE_SIZE;
|
||||
uint32_t size = part->get_size();
|
||||
|
||||
esp_err_t init_res = NVSPartitionManager::get_instance()->init_custom(part,
|
||||
0,
|
||||
size / sec_size);
|
||||
|
||||
if (init_res != ESP_OK) {
|
||||
delete part;
|
||||
}
|
||||
|
||||
return init_res;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LINUX_HOST_LEGACY_TEST
|
||||
extern "C" esp_err_t nvs_flash_init_partition(const char *part_name)
|
||||
@@ -129,7 +173,6 @@ extern "C" esp_err_t nvs_flash_init_partition(const char *part_name)
|
||||
}
|
||||
Lock lock;
|
||||
|
||||
assert(nvs::Page::SEC_SIZE == esp_partition_get_main_flash_sector_size());
|
||||
return NVSPartitionManager::get_instance()->init_partition(part_name);
|
||||
}
|
||||
|
||||
@@ -170,7 +213,6 @@ extern "C" esp_err_t nvs_flash_secure_init_partition(const char *part_name, nvs_
|
||||
}
|
||||
Lock lock;
|
||||
|
||||
assert(nvs::Page::SEC_SIZE == esp_partition_get_main_flash_sector_size());
|
||||
return NVSPartitionManager::get_instance()->secure_init_partition(part_name, cfg);
|
||||
}
|
||||
|
||||
@@ -197,38 +239,23 @@ extern "C" esp_err_t nvs_flash_erase_partition(const char *part_name)
|
||||
}
|
||||
}
|
||||
|
||||
const esp_partition_t* partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name);
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
// reuse the partition lookup code to find the NVS partition to streamline the BDL and non-BDL code paths
|
||||
nvs::Partition* part = nullptr;
|
||||
esp_err_t err = nvs::partition_lookup::lookup_nvs_partition(part_name, &part);
|
||||
if (err != ESP_OK || part == nullptr) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return esp_partition_erase_range(partition, 0, partition->size);
|
||||
// erase the partition
|
||||
err = part->erase_range(0, part->get_size());
|
||||
|
||||
// No need to delete the partition here, as it is managed by the NVSPartitionManager.
|
||||
return err;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_flash_erase_partition_ptr(const esp_partition_t *partition)
|
||||
{
|
||||
esp_err_t lock_result = Lock::init();
|
||||
if (lock_result != ESP_OK) {
|
||||
return lock_result;
|
||||
}
|
||||
Lock lock;
|
||||
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// if the partition is initialized, uninitialize it first
|
||||
if (NVSPartitionManager::get_instance()->lookup_storage_from_name(partition->label)) {
|
||||
const esp_err_t err = close_handles_and_deinit(partition->label);
|
||||
|
||||
// only hypothetical/future case, deinit_partition() only fails if partition is uninitialized
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return esp_partition_erase_range(partition, 0, partition->size);
|
||||
return nvs_flash_erase_partition(partition->label);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_flash_erase(void)
|
||||
|
||||
@@ -3,15 +3,20 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "nvs_encrypted_partition.hpp"
|
||||
#include "nvs_types.hpp"
|
||||
#include "nvs_constants.h"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
#ifdef CONFIG_NVS_BDL_STACK
|
||||
NVSEncryptedPartition::NVSEncryptedPartition(const char* label, const esp_blockdev_handle_t bdl, const bool managed_bdl)
|
||||
: NVSPartition(label, bdl, managed_bdl) { }
|
||||
#else
|
||||
NVSEncryptedPartition::NVSEncryptedPartition(const esp_partition_t *partition)
|
||||
: NVSPartition(partition) { }
|
||||
#endif // CONFIG_NVS_BDL_STACK
|
||||
|
||||
esp_err_t NVSEncryptedPartition::init(nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
@@ -33,19 +38,20 @@ esp_err_t NVSEncryptedPartition::init(nvs_sec_cfg_t* cfg)
|
||||
|
||||
esp_err_t NVSEncryptedPartition::read(size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
/** Currently upper layer of NVS reads entries one by one even for variable size
|
||||
* multi-entry data types. So length should always be equal to size of an entry.*/
|
||||
if (size != sizeof(Item)) return ESP_ERR_INVALID_SIZE;
|
||||
// Currently upper layer of NVS reads entries one by one even for variable size
|
||||
// multi-entry data types. So length should always be equal to size of an entry.
|
||||
// here we make sure that the size is really compliant with the minimal encryption block size.
|
||||
if (size % NVS_ENCRYPT_BLOCK_SIZE != 0) return ESP_ERR_INVALID_SIZE;
|
||||
|
||||
// read data
|
||||
esp_err_t read_result = esp_partition_read(mESPPartition, src_offset, dst, size);
|
||||
esp_err_t read_result = NVSPartition::read(src_offset, dst, size);
|
||||
if (read_result != ESP_OK) {
|
||||
return read_result;
|
||||
}
|
||||
|
||||
// decrypt data
|
||||
//sector num required as an arr by mbedtls. Should have been just uint64/32.
|
||||
uint8_t data_unit[16];
|
||||
uint8_t data_unit[NVS_ENCRYPT_BLOCK_SIZE];
|
||||
|
||||
uint32_t relAddr = src_offset;
|
||||
|
||||
@@ -64,7 +70,7 @@ esp_err_t NVSEncryptedPartition::read(size_t src_offset, void* dst, size_t size)
|
||||
|
||||
esp_err_t NVSEncryptedPartition::write(size_t addr, const void* src, size_t size)
|
||||
{
|
||||
if (size % ESP_ENCRYPT_BLOCK_SIZE != 0) return ESP_ERR_INVALID_SIZE;
|
||||
if (size % NVS_ENCRYPT_BLOCK_SIZE != 0) return ESP_ERR_INVALID_SIZE;
|
||||
|
||||
// copy data to buffer for encryption
|
||||
uint8_t* buf = new (std::nothrow) uint8_t [size];
|
||||
@@ -77,7 +83,7 @@ esp_err_t NVSEncryptedPartition::write(size_t addr, const void* src, size_t size
|
||||
uint8_t entrySize = sizeof(Item);
|
||||
|
||||
//sector num required as an arr by mbedtls. Should have been just uint64/32.
|
||||
uint8_t data_unit[16];
|
||||
uint8_t data_unit[NVS_ENCRYPT_BLOCK_SIZE];
|
||||
|
||||
/* Use relative address instead of absolute address (relocatable), so that host-generated
|
||||
* encrypted nvs images can be used*/
|
||||
@@ -103,7 +109,7 @@ esp_err_t NVSEncryptedPartition::write(size_t addr, const void* src, size_t size
|
||||
}
|
||||
|
||||
// write data
|
||||
esp_err_t result = esp_partition_write(mESPPartition, addr, buf, size);
|
||||
esp_err_t result = NVSPartition::write(addr, buf, size);
|
||||
|
||||
delete [] buf;
|
||||
|
||||
|
||||
@@ -5,27 +5,70 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h" // For CONFIG_NVS_BDL_STACK
|
||||
#include "mbedtls/aes.h" // For mbedtls_aes_xts_context
|
||||
#include "nvs_flash.h" // For nvs_sec_cfg_t
|
||||
#include "nvs_partition.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
/**
|
||||
* Implementation of encrypted esp_partition or bdl storage wrapper for NVS.
|
||||
*/
|
||||
class NVSEncryptedPartition : public NVSPartition {
|
||||
public:
|
||||
#ifdef CONFIG_NVS_BDL_STACK
|
||||
NVSEncryptedPartition(const char* label, const esp_blockdev_handle_t bdl, const bool managed_bdl = true);
|
||||
#else
|
||||
NVSEncryptedPartition(const esp_partition_t *partition);
|
||||
#endif
|
||||
|
||||
virtual ~NVSEncryptedPartition() { }
|
||||
|
||||
/**
|
||||
* Initializes the AES encryption components with the provided configuration.
|
||||
*
|
||||
* @param cfg the configuration for the AES encryption
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the AES component initialization
|
||||
* - ESP_ERR_NVS_XTS_CFG_FAILED if the AES key configuration is invalid
|
||||
*/
|
||||
esp_err_t init(nvs_sec_cfg_t* cfg);
|
||||
|
||||
/**
|
||||
* Reads and decrypts the data from the storage
|
||||
* This function is intended for reading data aligned to the size of NVS entry.
|
||||
*
|
||||
* @param src_offset the offset in the storage to read from
|
||||
* @param dst an already allocated buffer to read data into
|
||||
* @param size the size of the data to read in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the esp_partition or BDL API
|
||||
*/
|
||||
esp_err_t read(size_t src_offset, void* dst, size_t size) override;
|
||||
|
||||
/**
|
||||
* Encrypts the data from the src buffer and writes it to the storage.
|
||||
* This function is intended for writing data aligned to the size of NVS entry.
|
||||
* Repeated writes to the same address are not expected to be called.
|
||||
*
|
||||
* @param dst_offset the offset in the storage to write to
|
||||
* @param src pointer to the buffer to write data from
|
||||
* @param size the size of the data to write in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the esp_partition or BDL API
|
||||
*/
|
||||
esp_err_t write(size_t dst_offset, const void* src, size_t size) override;
|
||||
|
||||
protected:
|
||||
mbedtls_aes_xts_context mEctxt;
|
||||
mbedtls_aes_xts_context mDctxt;
|
||||
mbedtls_aes_xts_context mEctxt; // AES context for encryption
|
||||
mbedtls_aes_xts_context mDctxt; // AES context for decryption
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
||||
@@ -3,12 +3,20 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include "nvs_partition.hpp"
|
||||
#include <cstdlib>
|
||||
#include "esp_log.h"
|
||||
#include "nvs_constants.h" // For NVS_CONST_PAGE_SIZE
|
||||
|
||||
#ifdef CONFIG_NVS_BDL_STACK
|
||||
#include "esp_partition.h" // For esp_blockdev_handle_t
|
||||
#endif // CONFIG_NVS_BDL_STACK
|
||||
|
||||
#define TAG "NVSPartition"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
#ifndef CONFIG_NVS_BDL_STACK
|
||||
NVSPartition::NVSPartition(const esp_partition_t* partition)
|
||||
: mESPPartition(partition)
|
||||
{
|
||||
@@ -18,6 +26,11 @@ NVSPartition::NVSPartition(const esp_partition_t* partition)
|
||||
}
|
||||
}
|
||||
|
||||
NVSPartition::~NVSPartition()
|
||||
{
|
||||
// No need to de-initialize mESPPartition here, if you used esp_partition_find_first.
|
||||
}
|
||||
|
||||
const char *NVSPartition::get_partition_name()
|
||||
{
|
||||
return mESPPartition->label;
|
||||
@@ -30,10 +43,6 @@ esp_err_t NVSPartition::read_raw(size_t src_offset, void* dst, size_t size)
|
||||
|
||||
esp_err_t NVSPartition::read(size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
if (size % ESP_ENCRYPT_BLOCK_SIZE != 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return esp_partition_read(mESPPartition, src_offset, dst, size);
|
||||
}
|
||||
|
||||
@@ -44,10 +53,6 @@ esp_err_t NVSPartition::write_raw(size_t dst_offset, const void* src, size_t siz
|
||||
|
||||
esp_err_t NVSPartition::write(size_t dst_offset, const void* src, size_t size)
|
||||
{
|
||||
if (size % ESP_ENCRYPT_BLOCK_SIZE != 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return esp_partition_write(mESPPartition, dst_offset, src, size);
|
||||
}
|
||||
|
||||
@@ -71,4 +76,141 @@ bool NVSPartition::get_readonly()
|
||||
return mESPPartition->readonly;
|
||||
}
|
||||
|
||||
#else // CONFIG_NVS_BDL_STACK
|
||||
// BDL implementation of NVSPartition
|
||||
NVSPartition::NVSPartition(const char* label, const esp_blockdev_handle_t bdl, const bool managed_bdl)
|
||||
: mBDL(bdl), mManagedBDLbyInstance(managed_bdl)
|
||||
{
|
||||
if (bdl == nullptr || label == nullptr) {
|
||||
std::abort();
|
||||
}
|
||||
strlcpy(mLabel, label, NVS_PART_NAME_MAX_SIZE);
|
||||
mLabel[NVS_PART_NAME_MAX_SIZE] = '\0';
|
||||
}
|
||||
|
||||
NVSPartition::~NVSPartition()
|
||||
{
|
||||
if(mManagedBDLbyInstance) {
|
||||
// If the BDL was managed by this instance, we need to de-initialize it.
|
||||
if (mBDL != nullptr) {
|
||||
mBDL->ops->release(mBDL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* NVSPartition::get_partition_name()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
esp_err_t NVSPartition::read_raw(size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
return mBDL->ops->read(mBDL, (uint8_t*) dst, size, src_offset, size);
|
||||
}
|
||||
|
||||
esp_err_t NVSPartition::read(size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
return mBDL->ops->read(mBDL, (uint8_t*) dst, size, src_offset, size);
|
||||
}
|
||||
|
||||
esp_err_t NVSPartition::write_raw(size_t dst_offset, const void* src, size_t size)
|
||||
{
|
||||
return mBDL->ops->write(mBDL, (const uint8_t*) src, dst_offset, size);
|
||||
}
|
||||
|
||||
esp_err_t NVSPartition::write(size_t dst_offset, const void* src, size_t size)
|
||||
{
|
||||
return mBDL->ops->write(mBDL, (const uint8_t*) src, dst_offset, size);
|
||||
}
|
||||
|
||||
esp_err_t NVSPartition::erase_range(size_t dst_offset, size_t size)
|
||||
{
|
||||
return mBDL->ops->erase(mBDL, dst_offset, size);
|
||||
}
|
||||
|
||||
uint32_t NVSPartition::get_address()
|
||||
{
|
||||
// BDL cannot be used directly to get the address, as it is not a partition in the traditional sense.
|
||||
ESP_LOGE(TAG, "get_address() is not supported");
|
||||
std::abort();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t NVSPartition::get_size()
|
||||
{
|
||||
return mBDL->geometry.disk_size;
|
||||
}
|
||||
|
||||
bool NVSPartition::get_readonly()
|
||||
{
|
||||
return mBDL->device_flags.read_only;
|
||||
}
|
||||
|
||||
bool NVSPartition::is_bdl_nvs_compliant(const char* label, const esp_blockdev_handle_t bdl)
|
||||
{
|
||||
if (bdl == nullptr) {
|
||||
ESP_LOGV(TAG, "Block device layer handle is null for label %s", label);
|
||||
return false;
|
||||
}
|
||||
bool is_compliant = true;
|
||||
|
||||
if(label == nullptr) {
|
||||
ESP_LOGV(TAG, "Label is null, cannot check compliance");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strlen(label) >= NVS_PART_NAME_MAX_SIZE) {
|
||||
ESP_LOGV(TAG, "Label %s is too long, it must be less than %d characters", label, NVS_PART_NAME_MAX_SIZE);
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
if(bdl->geometry.read_size != 1){
|
||||
ESP_LOGV(TAG, "Block device read size is not 1, it is %zu", bdl->geometry.read_size);
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
if(bdl->geometry.write_size != 1) {
|
||||
ESP_LOGV(TAG, "Block device write size is not 1, it is %zu", bdl->geometry.write_size);
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
if(bdl->geometry.erase_size % NVS_CONST_PAGE_SIZE != 0) {
|
||||
ESP_LOGV(TAG, "Block device erase size is not a multiple of %d, it is %zu", NVS_CONST_PAGE_SIZE, bdl->geometry.erase_size);
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
if(bdl->geometry.disk_size % NVS_CONST_PAGE_SIZE != 0) {
|
||||
ESP_LOGV(TAG, "Block device size is not a multiple of %d, it is %zu", NVS_CONST_PAGE_SIZE, bdl->geometry.disk_size);
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
if(bdl->ops->read == nullptr) {
|
||||
ESP_LOGV(TAG, "Block device read operation is not present");
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
if(bdl->ops->write == nullptr) {
|
||||
ESP_LOGV(TAG, "Block device write operation is not present");
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
if(bdl->ops->erase == nullptr) {
|
||||
ESP_LOGV(TAG, "Block device erase operation is not present");
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
if(bdl->device_flags.default_val_after_erase != 1) {
|
||||
ESP_LOGV(TAG, "Block device default value after erase has to be 1, it is %d", bdl->device_flags.default_val_after_erase);
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
if(bdl->device_flags.encrypted) {
|
||||
ESP_LOGV(TAG, "Block device is encrypted, NVS does not support encrypted BDLs");
|
||||
is_compliant = false;
|
||||
}
|
||||
|
||||
return is_compliant;
|
||||
}
|
||||
|
||||
#endif // CONFIG_NVS_BDL_STACK
|
||||
} // nvs
|
||||
|
||||
@@ -5,106 +5,188 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "esp_partition.h"
|
||||
#include "intrusive_list.h"
|
||||
#include "sdkconfig.h" // For CONFIG_NVS_BDL_STACK
|
||||
#include "partition.hpp"
|
||||
#include "nvs_memory_management.hpp"
|
||||
|
||||
#define ESP_ENCRYPT_BLOCK_SIZE 16
|
||||
|
||||
#define PART_NAME_MAX_SIZE 16 /*!< maximum length of partition name (excluding null terminator) */
|
||||
#ifdef CONFIG_NVS_BDL_STACK
|
||||
#include "esp_blockdev.h" // For esp_blockdev_handle_t
|
||||
#include "nvs.h" // For NVS_PART_NAME_MAX_SIZE
|
||||
#else
|
||||
#include "esp_partition.h"
|
||||
#endif // CONFIG_NVS_BDL_STACK
|
||||
|
||||
namespace nvs {
|
||||
|
||||
/**
|
||||
* Implementation of Partition for NVS.
|
||||
*
|
||||
* It is implemented as an intrusive_list_node to easily store instances of it. NVSStorage and NVSPage take pointer
|
||||
* references of this class to abstract their partition operations.
|
||||
* Implementation of non-encrypted esp_partition or bdl storage wrapper for NVS.
|
||||
*/
|
||||
class NVSPartition : public Partition, public intrusive_list_node<NVSPartition>, public ExceptionlessAllocatable {
|
||||
class NVSPartition : public Partition {
|
||||
public:
|
||||
#ifdef CONFIG_NVS_BDL_STACK
|
||||
/**
|
||||
* Copy partition_name to mPartitionName and initialize mESPPartition.
|
||||
* Constructor copies storage name to mLabel and initializes BDL reference.
|
||||
* See function is_bdl_nvs_compliant for the requirements on the BDL.
|
||||
*
|
||||
* @param partition_name the name of the partition as in the partition table, must be non-NULL!
|
||||
* @param partition an already initialized partition structure
|
||||
* @param label the label of the partition corresponding to the referenced BDL handle.
|
||||
* @param bdl an already initialized bdl handle
|
||||
* @param managed_bdl if true, the BDL handle will be released in the destructor of this class.
|
||||
*/
|
||||
NVSPartition(const char* label, const esp_blockdev_handle_t bdl, const bool managed_bdl = true);
|
||||
|
||||
/**
|
||||
* Function allowing to check if the block device is compliant with NVS requirements.
|
||||
* This static function shall be called prior to creating an instance of NVSPartition.
|
||||
* Following checks are performed:
|
||||
* 1. The block device handle must not be null
|
||||
* 2. The block device label must not be null
|
||||
* 3. The block device label must fit to the statically allocated buffer (NVS_PART_NAME_MAX_SIZE)
|
||||
* 4. The block device read block size must be 1
|
||||
* 5. The block device write block size must be 1
|
||||
* 6. The block device erase block size must be a multiple of NVS_CONST_PAGE_SIZE (NVS_CONST_PAGE_SIZE is 4kB)
|
||||
* 7. The size of the block device must be a multiple of the NVS_CONST_PAGE_SIZE (NVS_CONST_PAGE_SIZE is 4kB)
|
||||
* 8. BDL operations read / write / erase must be supported
|
||||
* 9. The block device write operation type must be at least NOR flash compliant. Regular write, or write setting to zero are supported.
|
||||
* 10. The block device must not be encrypted
|
||||
*
|
||||
* @param label the label of the storage corresponding to the referenced BDL handle.
|
||||
* @param bdl an already initialized bdl handle
|
||||
*
|
||||
* @return true if the block device is NVS compliant and can be used for NVS operations, false otherwise.
|
||||
*/
|
||||
static bool is_bdl_nvs_compliant(const char* label, const esp_blockdev_handle_t bdl);
|
||||
|
||||
#else
|
||||
/**
|
||||
* Constructor initializes the mPartition.
|
||||
*
|
||||
* @param partition an already initialized esp_partition structure
|
||||
*/
|
||||
NVSPartition(const esp_partition_t* partition);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* No need to de-initialize mESPPartition here, if you used esp_partition_find_first.
|
||||
* Otherwise, the user is responsible for de-initializing it.
|
||||
* Destructor cleans up the wrapper.
|
||||
* If BDL is used and constructor was called with managed_bdl = true,
|
||||
* the BDL handle will be released.
|
||||
*/
|
||||
virtual ~NVSPartition() { }
|
||||
virtual ~NVSPartition();
|
||||
|
||||
/**
|
||||
* Return the name (label) of the storage.
|
||||
* In esp_partition implementation it returns the partition label.
|
||||
* In BDL implementation it returns the BDL label handed over to the constructor.
|
||||
*
|
||||
* @return
|
||||
* - the label of the storage
|
||||
*/
|
||||
const char *get_partition_name() override;
|
||||
|
||||
/**
|
||||
* Look into \c esp_partition_read_raw for more details.
|
||||
* Reads data from the storage.
|
||||
* Raw read is used for reading data aligned down to the size of 1 byte
|
||||
*
|
||||
* @param src_offset the offset in the storage to read from
|
||||
* @param dst an already allocated buffer to read data into
|
||||
* @param size the size of the data to read in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the esp_partition API
|
||||
* - other error codes from the esp_partition or BDL API
|
||||
*/
|
||||
esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override;
|
||||
|
||||
/**
|
||||
* Look into \c esp_partition_read for more details.
|
||||
* Reads data from the storage
|
||||
* This function is intended for reading data aligned to the size of NVS entry.
|
||||
* This, not encrypted, implementation does not require the size to be aligned to the NVS entry size though.
|
||||
*
|
||||
* @param src_offset the offset in the storage to read from
|
||||
* @param dst an already allocated buffer to read data into
|
||||
* @param size the size of the data to read in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_ARG if size isn't a multiple of ESP_ENCRYPT_BLOCK_SIZE
|
||||
* - other error codes from the esp_partition API
|
||||
* - other error codes from the esp_partition or BDL API
|
||||
*/
|
||||
esp_err_t read(size_t src_offset, void* dst, size_t size) override;
|
||||
|
||||
/**
|
||||
* Look into \c esp_partition_write_raw for more details.
|
||||
* Writes data from the src buffer to the storage.
|
||||
* Raw write is used for writing data aligned down to the size of 1 byte
|
||||
* Even repeated writes to the same address can be called.
|
||||
*
|
||||
* @param dst_offset the offset in the storage to write to
|
||||
* @param src pointer to the buffer to write data from
|
||||
* @param size the size of the data to write in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - error codes from the esp_partition API
|
||||
* - other error codes from the esp_partition or BDL API
|
||||
*/
|
||||
esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override;
|
||||
|
||||
/**
|
||||
* Look into \c esp_partition_write for more details.
|
||||
* Writes data from the src buffer to the storage.
|
||||
* This function is intended for writing data aligned to the size of NVS entry.
|
||||
* This, not encrypted, implementation does not require the size to be aligned to the NVS entry size though.
|
||||
* Repeated writes to the same address are not expected to be called.
|
||||
*
|
||||
* @param dst_offset the offset in the storage to write to
|
||||
* @param src pointer to the buffer to write data from
|
||||
* @param size the size of the data to write in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_ARG if size isn't a multiple of ESP_ENCRYPT_BLOCK_SIZE
|
||||
* - other error codes from the esp_partition API
|
||||
* - other error codes from the esp_partition or BDL API
|
||||
*/
|
||||
esp_err_t write(size_t dst_offset, const void* src, size_t size) override;
|
||||
|
||||
/**
|
||||
* Look into \c esp_partition_erase_range for more details.
|
||||
* Erases the address range in the storage.
|
||||
* Erased data is set to 0xFF.
|
||||
*
|
||||
* @param dst_offset the offset in the storage to erase
|
||||
* @param size the size of the data to erase in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - error codes from the esp_partition API
|
||||
* - other error codes from the esp_partition or BDL API
|
||||
*/
|
||||
esp_err_t erase_range(size_t dst_offset, size_t size) override;
|
||||
|
||||
/**
|
||||
* @return the base address of the partition.
|
||||
* Returns the RAM address of the beginning of the memory mapped storage.
|
||||
* Not available if the block device layer is enabled.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the esp_partition or BDL API
|
||||
*/
|
||||
uint32_t get_address() override;
|
||||
|
||||
/**
|
||||
* @return the size of the partition in bytes.
|
||||
* Returns total size of the storage in bytes.
|
||||
*
|
||||
* @return size of the storage in bytes.
|
||||
*/
|
||||
uint32_t get_size() override;
|
||||
|
||||
/**
|
||||
* @return true if the partition is read-only.
|
||||
* Returns the read-only status of the storage.
|
||||
*
|
||||
* @return true if the storage is read-only.
|
||||
*/
|
||||
bool get_readonly() override;
|
||||
|
||||
protected:
|
||||
const esp_partition_t* mESPPartition;
|
||||
|
||||
#ifdef CONFIG_NVS_BDL_STACK
|
||||
esp_blockdev_handle_t mBDL; // Block Device Layer handle for the storage
|
||||
char mLabel[NVS_PART_NAME_MAX_SIZE + 1]; // Label of the storage, used for matching in NVS open operations
|
||||
bool mManagedBDLbyInstance; // True if the BDL is managed by this instance, false if it is managed externally
|
||||
#else
|
||||
const esp_partition_t* mESPPartition; // Pointer to the ESP partition structure for the storage
|
||||
#endif // CONFIG_NVS_BDL_STACK
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
||||
@@ -11,18 +11,17 @@
|
||||
#endif // ! LINUX_TARGET
|
||||
|
||||
namespace nvs {
|
||||
|
||||
namespace partition_lookup {
|
||||
|
||||
esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p)
|
||||
esp_err_t lookup_nvs_partition(const char* label, Partition **p)
|
||||
{
|
||||
#ifndef CONFIG_NVS_BDL_STACK
|
||||
const esp_partition_t* esp_partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, label);
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, label);
|
||||
|
||||
if (esp_partition == nullptr) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (esp_partition->encrypted) {
|
||||
return ESP_ERR_NVS_WRONG_ENCRYPTION;
|
||||
}
|
||||
@@ -33,15 +32,36 @@ esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p)
|
||||
}
|
||||
|
||||
*p = partition;
|
||||
|
||||
return ESP_OK;
|
||||
#else
|
||||
esp_blockdev_handle_t bdl = NULL;
|
||||
esp_err_t err = esp_partition_get_blockdev(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, label, &bdl);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
if (!NVSPartition::is_bdl_nvs_compliant(label, bdl)) {
|
||||
if(bdl->ops->release) bdl->ops->release(bdl);
|
||||
return ESP_ERR_NVS_PART_NOT_FOUND;
|
||||
}
|
||||
|
||||
NVSPartition *partition = new (std::nothrow) NVSPartition(label, bdl);
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
*p = partition;
|
||||
return ESP_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef LINUX_TARGET
|
||||
esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p)
|
||||
esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, Partition **p)
|
||||
{
|
||||
#ifndef CONFIG_NVS_BDL_STACK
|
||||
const esp_partition_t* esp_partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, label);
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, label);
|
||||
|
||||
if (esp_partition == nullptr) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
@@ -51,23 +71,47 @@ esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg,
|
||||
return ESP_ERR_NVS_WRONG_ENCRYPTION;
|
||||
}
|
||||
|
||||
NVSEncryptedPartition *enc_p = new (std::nothrow) NVSEncryptedPartition(esp_partition);
|
||||
if (enc_p == nullptr) {
|
||||
NVSEncryptedPartition *partition = new (std::nothrow) NVSEncryptedPartition(esp_partition);
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t result = enc_p->init(cfg);
|
||||
esp_err_t result = partition->init(cfg);
|
||||
if (result != ESP_OK) {
|
||||
delete enc_p;
|
||||
delete partition;
|
||||
return result;
|
||||
}
|
||||
|
||||
*p = enc_p;
|
||||
|
||||
*p = partition;
|
||||
return ESP_OK;
|
||||
#else
|
||||
esp_blockdev_handle_t bdl = NULL;
|
||||
esp_err_t err = esp_partition_get_blockdev(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, label, &bdl);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!NVSPartition::is_bdl_nvs_compliant(label, bdl)) {
|
||||
if(bdl->ops->release) bdl->ops->release(bdl);
|
||||
return ESP_ERR_NVS_PART_NOT_FOUND;
|
||||
}
|
||||
|
||||
NVSEncryptedPartition *partition = new (std::nothrow) NVSEncryptedPartition(label, bdl);
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t result = partition->init(cfg);
|
||||
if (result != ESP_OK) {
|
||||
delete partition;
|
||||
return result;
|
||||
}
|
||||
*p = partition;
|
||||
return ESP_OK;
|
||||
#endif
|
||||
}
|
||||
#endif // ! LINUX_TARGET
|
||||
#endif // !LINUX_TARGET
|
||||
|
||||
} // partition_lookup
|
||||
|
||||
} // nvs
|
||||
} // namespace partition_lookup
|
||||
} // namespace nvs
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace nvs {
|
||||
|
||||
namespace partition_lookup {
|
||||
|
||||
esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p);
|
||||
esp_err_t lookup_nvs_partition(const char* label, Partition **p);
|
||||
|
||||
esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p);
|
||||
esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, Partition **p);
|
||||
|
||||
} // partition_lookup
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_partition.h"
|
||||
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "nvs_partition_lookup.hpp"
|
||||
#include "nvs_internal.h"
|
||||
@@ -27,15 +27,12 @@ NVSPartitionManager* NVSPartitionManager::get_instance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_err_t NVSPartitionManager::init_partition(const char *partition_label)
|
||||
{
|
||||
if (strlen(partition_label) > NVS_PART_NAME_MAX_SIZE) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
uint32_t size;
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
Storage* mStorage;
|
||||
|
||||
mStorage = lookup_storage_from_name(partition_label);
|
||||
@@ -43,17 +40,20 @@ esp_err_t NVSPartitionManager::init_partition(const char *partition_label)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
NVS_ASSERT_OR_RETURN(sec_size != 0, ESP_FAIL);
|
||||
|
||||
NVSPartition *p = nullptr;
|
||||
Partition *p = nullptr;
|
||||
esp_err_t result = partition_lookup::lookup_nvs_partition(partition_label, &p);
|
||||
|
||||
if (result != ESP_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t size = p->get_size();
|
||||
uint32_t sec_size = NVS_CONST_PAGE_SIZE;
|
||||
|
||||
if (result != ESP_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
size = p->get_size();
|
||||
|
||||
result = init_custom(p, 0, size / sec_size);
|
||||
if (result != ESP_OK) {
|
||||
goto error;
|
||||
@@ -67,7 +67,6 @@ error:
|
||||
delete p;
|
||||
return result;
|
||||
}
|
||||
#endif // ESP_PLATFORM
|
||||
|
||||
esp_err_t NVSPartitionManager::init_custom(Partition *partition, uint32_t baseSector, uint32_t sectorCount)
|
||||
{
|
||||
@@ -117,7 +116,7 @@ esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
NVSPartition *p;
|
||||
Partition *p;
|
||||
esp_err_t result;
|
||||
if (cfg != nullptr) {
|
||||
result = partition_lookup::lookup_nvs_encrypted_partition(part_name, cfg, &p);
|
||||
@@ -130,7 +129,7 @@ esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_
|
||||
}
|
||||
|
||||
uint32_t size = p->get_size();
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
uint32_t sec_size = NVS_CONST_PAGE_SIZE;
|
||||
|
||||
result = init_custom(p, 0, size / sec_size);
|
||||
if (result != ESP_OK) {
|
||||
@@ -165,7 +164,7 @@ esp_err_t NVSPartitionManager::deinit_partition(const char *partition_label)
|
||||
|
||||
for (auto it = nvs_partition_list.begin(); it != nvs_partition_list.end(); ++it) {
|
||||
if (strcmp(it->get_partition_name(), partition_label) == 0) {
|
||||
NVSPartition *p = it;
|
||||
Partition *p = it;
|
||||
nvs_partition_list.erase(it);
|
||||
delete p;
|
||||
break;
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_storage.hpp"
|
||||
#include "nvs_partition.hpp"
|
||||
#include "nvs_memory_management.hpp"
|
||||
#include "partition.hpp"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
namespace nvs {
|
||||
@@ -44,7 +42,7 @@ protected:
|
||||
|
||||
intrusive_list<nvs::Storage> nvs_storage_list;
|
||||
|
||||
intrusive_list<nvs::NVSPartition> nvs_partition_list;
|
||||
intrusive_list<nvs::Partition> nvs_partition_list;
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
||||
@@ -6,45 +6,127 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "intrusive_list.h"
|
||||
#include "nvs_memory_management.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
/**
|
||||
* @brief Abstract interface for partition related operations, currently in NVS.
|
||||
* @brief Abstract interface for permanent storage (partition) related operations, currently in NVS.
|
||||
*
|
||||
* It resembles the main operations according to esp_partition.h.
|
||||
* It resembles the main operations required by NVS to operate on permanent storage.
|
||||
* It is implemented as an intrusive_list_node to easily store instances of it.
|
||||
* It also allows to create instances of this class without throwing exceptions using custom heap allocator
|
||||
*/
|
||||
class Partition {
|
||||
class Partition : public intrusive_list_node<Partition>, public ExceptionlessAllocatable {
|
||||
public:
|
||||
virtual ~Partition() { }
|
||||
|
||||
/**
|
||||
* Return the partition name as in the partition table.
|
||||
* Return the name (label) of the storage.
|
||||
*
|
||||
* @return
|
||||
* - the name of the storage, e.g. "nvs".
|
||||
*/
|
||||
virtual const char *get_partition_name() = 0;
|
||||
|
||||
/**
|
||||
* Reads data from the storage.
|
||||
* Raw read is used for reading data aligned down to the size of 1 byte
|
||||
* No decryption is applied.
|
||||
*
|
||||
* @param src_offset the offset in the storage to read from
|
||||
* @param dst an already allocated buffer to read data into
|
||||
* @param size the size of the data to read in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the implementation of the storage
|
||||
*/
|
||||
virtual esp_err_t read_raw(size_t src_offset, void* dst, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Reads data from the storage
|
||||
* This function is intended for reading data aligned to the size of NVS entry.
|
||||
* Implementations of this function may leverage the minimal size to read efficiently.
|
||||
* For implementation with encryption, this function will decrypt the data.
|
||||
*
|
||||
* @param src_offset the offset in the storage to read from
|
||||
* @param dst an already allocated buffer to read data into
|
||||
* @param size the size of the data to read in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the implementation of the storage
|
||||
*/
|
||||
virtual esp_err_t read(size_t src_offset, void* dst, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Writes data from the src buffer to the storage.
|
||||
* Raw write is used for writing data aligned down to the size of 1 byte
|
||||
* Repeated writes to the same address can be called thus no encryption is applied.
|
||||
*
|
||||
* @param dst_offset the offset in the storage to write to
|
||||
* @param src pointer to the buffer to write data from
|
||||
* @param size the size of the data to write in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the implementation of the storage
|
||||
*/
|
||||
virtual esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Writes data from the src buffer to the storage.
|
||||
* This function is intended for writing data aligned to the size of NVS entry.
|
||||
* This, not encrypted, implementation does not require the size to be aligned to the NVS entry size though.
|
||||
* Repeated writes to the same address are not expected to be called.
|
||||
* For implementation with encryption, this function will encrypt the data.
|
||||
*
|
||||
* @param dst_offset the offset in the storage to write to
|
||||
* @param src pointer to the buffer to write data from
|
||||
* @param size the size of the data to write in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the implementation of the storage
|
||||
*/
|
||||
virtual esp_err_t write(size_t dst_offset, const void* src, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Erases the address range in the storage.
|
||||
* Erased data is set to 0xFF.
|
||||
*
|
||||
* @param dst_offset the offset in the storage to erase
|
||||
* @param size the size of the data to erase in bytes
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the implementation of the storage
|
||||
*/
|
||||
virtual esp_err_t erase_range(size_t dst_offset, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Return the address of the beginning of the partition.
|
||||
* Returns the RAM address of the beginning of the memory mapped storage.
|
||||
* Not available if the block device layer is enabled.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the implementation of the storage
|
||||
*/
|
||||
virtual uint32_t get_address() = 0;
|
||||
|
||||
/**
|
||||
* Return the partition size in bytes.
|
||||
* Returns total size of the storage in bytes.
|
||||
*
|
||||
* @return size of the storage in bytes.
|
||||
*/
|
||||
virtual uint32_t get_size() = 0;
|
||||
|
||||
/**
|
||||
* Return true if the partition is read-only.
|
||||
* Returns the read-only status of the storage.
|
||||
*
|
||||
* @return true if the storage is read-only.
|
||||
*/
|
||||
virtual bool get_readonly() = 0;
|
||||
};
|
||||
|
||||
@@ -136,7 +136,8 @@ TEST_CASE("flash erase deinitializes initialized partition", "[nvs]")
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NVS_ENCRYPTION
|
||||
// NOTE: `nvs_flash_init_partition_ptr` does not support NVS encryption
|
||||
#ifndef CONFIG_NVS_BDL_STACK
|
||||
// NOTE: `nvs_flash_init_partition_ptr` does not support NVS encryption nor BDL stack
|
||||
TEST_CASE("nvs_flash_init_partition_ptr() works correctly", "[nvs]")
|
||||
{
|
||||
// First, open and write to partition using normal initialization
|
||||
@@ -165,6 +166,7 @@ TEST_CASE("nvs_flash_init_partition_ptr() works correctly", "[nvs]")
|
||||
|
||||
nvs_flash_deinit();
|
||||
}
|
||||
#endif // !CONFIG_NVS_BDL_STACK
|
||||
|
||||
#ifdef CONFIG_SOC_HMAC_SUPPORTED
|
||||
TEST_CASE("test nvs encryption with HMAC-based scheme without toggling any config options", "[nvs_encr_hmac]")
|
||||
|
||||
Reference in New Issue
Block a user