mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
NVS: using esp_partition API
* partition api changed from spi_flash* API to esp_partition* API and is abstracted as a C++ interface. * The old nvs encryption is still possible * changed default unit test app partition table * Partitions coming from esp_partition API are checked for generic flash encryption. If yes, an error is returned since generic flash encryption isn't compatible with nvs encryption * esp32, esp32s2 tests don't require nvs_flash but mbedtls now Closes IDF-1340 Closes IDF-858
This commit is contained in:
parent
153c2e7406
commit
aca9ec28b3
@ -1,7 +1,7 @@
|
||||
if(IDF_TARGET STREQUAL "esp32")
|
||||
idf_component_register(SRC_DIRS .
|
||||
PRIV_INCLUDE_DIRS .
|
||||
PRIV_REQUIRES cmock test_utils nvs_flash ulp esp_common
|
||||
PRIV_REQUIRES cmock test_utils mbedtls ulp esp_common
|
||||
)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_test_dport_xt_highint5")
|
||||
endif()
|
||||
|
@ -1,7 +1,7 @@
|
||||
if(IDF_TARGET STREQUAL "esp32s2")
|
||||
idf_component_register(SRC_DIRS .
|
||||
PRIV_INCLUDE_DIRS .
|
||||
PRIV_REQUIRES cmock test_utils nvs_flash ulp esp_common
|
||||
PRIV_REQUIRES cmock test_utils nvs_flash mbedtls ulp esp_common
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -212,6 +212,12 @@ static const esp_err_msg_t esp_err_msg_table[] = {
|
||||
ERR_TBL_IT(ESP_ERR_NVS_CONTENT_DIFFERS), /* 4376 0x1118 Internal error; never returned by nvs
|
||||
API functions. NVS key is different in
|
||||
comparison */
|
||||
# endif
|
||||
# ifdef ESP_ERR_NVS_WRONG_ENCRYPTION
|
||||
ERR_TBL_IT(ESP_ERR_NVS_WRONG_ENCRYPTION), /* 4377 0x1119 NVS partition is marked as encrypted
|
||||
with generic flash encryption. This is
|
||||
forbidden since the NVS encryption works
|
||||
differently. */
|
||||
# endif
|
||||
// components/ulp/include/ulp_common.h
|
||||
# ifdef ESP_ERR_ULP_BASE
|
||||
|
@ -1,16 +1,18 @@
|
||||
set(srcs "src/nvs_api.cpp"
|
||||
"src/nvs_cxx_api.cpp"
|
||||
"src/nvs_item_hash_list.cpp"
|
||||
"src/nvs_ops.cpp"
|
||||
"src/nvs_page.cpp"
|
||||
"src/nvs_pagemanager.cpp"
|
||||
"src/nvs_storage.cpp"
|
||||
"src/nvs_handle_simple.cpp"
|
||||
"src/nvs_handle_locked.cpp"
|
||||
"src/nvs_partition.cpp"
|
||||
"src/nvs_partition_lookup.cpp"
|
||||
"src/nvs_partition_manager.cpp"
|
||||
"src/nvs_types.cpp")
|
||||
|
||||
if(CONFIG_NVS_ENCRYPTION)
|
||||
list(APPEND srcs "src/nvs_encr.cpp")
|
||||
list(APPEND srcs "src/nvs_encrypted_partition.cpp")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
|
@ -59,6 +59,7 @@ typedef nvs_handle_t nvs_handle IDF_DEPRECATED("Replace with nvs_handle_t");
|
||||
#define ESP_ERR_NVS_ENCR_NOT_SUPPORTED (ESP_ERR_NVS_BASE + 0x15) /*!< NVS encryption is not supported in this version */
|
||||
#define ESP_ERR_NVS_KEYS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x16) /*!< NVS key partition is uninitialized */
|
||||
#define ESP_ERR_NVS_CORRUPT_KEY_PART (ESP_ERR_NVS_BASE + 0x17) /*!< NVS key partition is corrupt */
|
||||
#define ESP_ERR_NVS_WRONG_ENCRYPTION (ESP_ERR_NVS_BASE + 0x19) /*!< NVS partition is marked as encrypted with generic flash encryption. This is forbidden since the NVS encryption works differently. */
|
||||
|
||||
#define ESP_ERR_NVS_CONTENT_DIFFERS (ESP_ERR_NVS_BASE + 0x18) /*!< Internal error; never returned by nvs API functions. NVS key is different in comparison */
|
||||
|
||||
|
@ -20,9 +20,6 @@
|
||||
#include "esp_partition.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#include "nvs_encr.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp32/rom/crc.h>
|
||||
@ -57,14 +54,9 @@ private:
|
||||
uint32_t NVSHandleEntry::s_nvs_next_handle;
|
||||
|
||||
extern "C" void nvs_dump(const char *partName);
|
||||
extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount);
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
extern "C" esp_err_t nvs_flash_secure_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg);
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
SemaphoreHandle_t nvs::Lock::mSemaphore = NULL;
|
||||
SemaphoreHandle_t nvs::Lock::mSemaphore = nullptr;
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
@ -83,41 +75,13 @@ extern "C" void nvs_dump(const char *partName)
|
||||
nvs::Storage* pStorage;
|
||||
|
||||
pStorage = lookup_storage_from_name(partName);
|
||||
if (pStorage == NULL) {
|
||||
if (pStorage == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
pStorage->debugDump();
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount)
|
||||
{
|
||||
ESP_LOGD(TAG, "nvs_flash_init_custom partition=%s start=%d count=%d", partName, baseSector, sectorCount);
|
||||
|
||||
return NVSPartitionManager::get_instance()->init_custom(partName, baseSector, sectorCount);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
extern "C" esp_err_t nvs_flash_secure_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
ESP_LOGD(TAG, "nvs_flash_secure_init_custom partition=%s start=%d count=%d", partName, baseSector, sectorCount);
|
||||
|
||||
if(cfg) {
|
||||
auto encrMgr = EncrMgr::getInstance();
|
||||
|
||||
if (!encrMgr) return ESP_ERR_NO_MEM;
|
||||
|
||||
auto err = encrMgr->setSecurityContext(baseSector, sectorCount, cfg);
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return nvs_flash_init_custom(partName, baseSector, sectorCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
static esp_err_t close_handles_and_deinit(const char* part_name)
|
||||
{
|
||||
// Delete all corresponding open handles
|
||||
@ -132,13 +96,24 @@ extern "C" esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partiti
|
||||
Lock::init();
|
||||
Lock lock;
|
||||
|
||||
if (!partition) {
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return nvs_flash_init_custom(partition->label,
|
||||
partition->address / SPI_FLASH_SEC_SIZE,
|
||||
partition->size / SPI_FLASH_SEC_SIZE);
|
||||
NVSPartition *part = new (std::nothrow) NVSPartition(partition);
|
||||
if (part == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t init_res = NVSPartitionManager::get_instance()->init_custom(part,
|
||||
partition->address / SPI_FLASH_SEC_SIZE,
|
||||
partition->size / SPI_FLASH_SEC_SIZE);
|
||||
|
||||
if (init_res != ESP_OK) {
|
||||
delete part;
|
||||
}
|
||||
|
||||
return init_res;
|
||||
}
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
@ -160,21 +135,8 @@ extern "C" esp_err_t nvs_flash_secure_init_partition(const char *part_name, nvs_
|
||||
{
|
||||
Lock::init();
|
||||
Lock lock;
|
||||
nvs::Storage* mStorage;
|
||||
|
||||
mStorage = lookup_storage_from_name(part_name);
|
||||
if (mStorage) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const esp_partition_t* partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name);
|
||||
if (partition == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return nvs_flash_secure_init_custom(part_name, partition->address / SPI_FLASH_SEC_SIZE,
|
||||
partition->size / SPI_FLASH_SEC_SIZE, cfg);
|
||||
return NVSPartitionManager::get_instance()->secure_init_partition(part_name, cfg);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_flash_secure_init(nvs_sec_cfg_t* cfg)
|
||||
@ -200,7 +162,7 @@ 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 == NULL) {
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
@ -212,7 +174,7 @@ extern "C" esp_err_t nvs_flash_erase_partition_ptr(const esp_partition_t *partit
|
||||
Lock::init();
|
||||
Lock lock;
|
||||
|
||||
if (!partition) {
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
@ -515,7 +477,7 @@ extern "C" esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats
|
||||
Lock lock;
|
||||
nvs::Storage* pStorage;
|
||||
|
||||
if (nvs_stats == NULL) {
|
||||
if (nvs_stats == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
nvs_stats->used_entries = 0;
|
||||
@ -523,8 +485,8 @@ extern "C" esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats
|
||||
nvs_stats->total_entries = 0;
|
||||
nvs_stats->namespace_count = 0;
|
||||
|
||||
pStorage = lookup_storage_from_name((part_name == NULL) ? NVS_DEFAULT_PART_NAME : part_name);
|
||||
if (pStorage == NULL) {
|
||||
pStorage = lookup_storage_from_name((part_name == nullptr) ? NVS_DEFAULT_PART_NAME : part_name);
|
||||
if (pStorage == nullptr) {
|
||||
return ESP_ERR_NVS_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
@ -538,7 +500,7 @@ extern "C" esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats
|
||||
extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle_t c_handle, size_t* used_entries)
|
||||
{
|
||||
Lock lock;
|
||||
if(used_entries == NULL){
|
||||
if(used_entries == nullptr){
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
*used_entries = 0;
|
||||
@ -571,12 +533,12 @@ extern "C" esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, n
|
||||
cfg->tky[cnt] = 0xee;
|
||||
}
|
||||
|
||||
err = spi_flash_write(partition->address, cfg->eky, NVS_KEY_SIZE);
|
||||
err = esp_partition_write(partition, 0, cfg->eky, NVS_KEY_SIZE);
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = spi_flash_write(partition->address + NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE);
|
||||
err = esp_partition_write(partition, NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE);
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
@ -622,17 +584,17 @@ extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partitio
|
||||
return true;
|
||||
};
|
||||
|
||||
auto err = spi_flash_read(partition->address, eky_raw, NVS_KEY_SIZE);
|
||||
auto err = esp_partition_read_raw(partition, 0, eky_raw, NVS_KEY_SIZE);
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = spi_flash_read(partition->address + NVS_KEY_SIZE, tky_raw, NVS_KEY_SIZE);
|
||||
err = esp_partition_read_raw(partition, NVS_KEY_SIZE, tky_raw, NVS_KEY_SIZE);
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = spi_flash_read(partition->address + 2 * NVS_KEY_SIZE, &crc_raw, 4);
|
||||
err = esp_partition_read_raw(partition, 2 * NVS_KEY_SIZE, &crc_raw, 4);
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
@ -679,8 +641,8 @@ extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partitio
|
||||
static nvs_iterator_t create_iterator(nvs::Storage *storage, nvs_type_t type)
|
||||
{
|
||||
nvs_iterator_t it = (nvs_iterator_t)calloc(1, sizeof(nvs_opaque_iterator_t));
|
||||
if (it == NULL) {
|
||||
return NULL;
|
||||
if (it == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
it->storage = storage;
|
||||
@ -695,19 +657,19 @@ extern "C" nvs_iterator_t nvs_entry_find(const char *part_name, const char *name
|
||||
nvs::Storage *pStorage;
|
||||
|
||||
pStorage = lookup_storage_from_name(part_name);
|
||||
if (pStorage == NULL) {
|
||||
return NULL;
|
||||
if (pStorage == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nvs_iterator_t it = create_iterator(pStorage, type);
|
||||
if (it == NULL) {
|
||||
return NULL;
|
||||
if (it == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool entryFound = pStorage->findEntry(it, namespace_name);
|
||||
if (!entryFound) {
|
||||
free(it);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return it;
|
||||
@ -721,7 +683,7 @@ extern "C" nvs_iterator_t nvs_entry_next(nvs_iterator_t it)
|
||||
bool entryFound = it->storage->nextEntry(it);
|
||||
if (!entryFound) {
|
||||
free(it);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return it;
|
||||
|
@ -1,155 +0,0 @@
|
||||
// Copyright 2015-2018 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 "nvs_encr.hpp"
|
||||
#include "nvs_types.hpp"
|
||||
#include <string.h>
|
||||
|
||||
namespace nvs
|
||||
{
|
||||
|
||||
bool EncrMgr::isActive = false;
|
||||
EncrMgr* EncrMgr::instance = nullptr;
|
||||
|
||||
|
||||
EncrMgr* EncrMgr::getInstance()
|
||||
{
|
||||
if(!isActive)
|
||||
{
|
||||
instance = new (std::nothrow) EncrMgr();
|
||||
if (instance) {
|
||||
isActive = true;
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
void EncrMgr::resetInstance()
|
||||
{
|
||||
if(isActive) {
|
||||
delete instance;
|
||||
instance = nullptr;
|
||||
isActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EncrMgr::isEncrActive() {
|
||||
return isActive;
|
||||
}
|
||||
|
||||
XtsCtxt* EncrMgr::findXtsCtxtFromAddr(uint32_t addr) {
|
||||
|
||||
auto it = find_if(std::begin(xtsCtxtList), std::end(xtsCtxtList), [=](XtsCtxt& ctx) -> bool
|
||||
{ return (ctx.baseSector * SPI_FLASH_SEC_SIZE <= addr)
|
||||
&& (addr < (ctx.baseSector + ctx.sectorCount) * SPI_FLASH_SEC_SIZE); });
|
||||
|
||||
if (it == std::end(xtsCtxtList)) {
|
||||
return nullptr;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
esp_err_t EncrMgr::setSecurityContext(uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg) {
|
||||
|
||||
uint8_t* eky = reinterpret_cast<uint8_t*>(cfg);
|
||||
|
||||
auto ctxt = new (std::nothrow) XtsCtxt();
|
||||
|
||||
if (!ctxt) return ESP_ERR_NO_MEM;
|
||||
|
||||
ctxt->baseSector = baseSector;
|
||||
ctxt->sectorCount = sectorCount;
|
||||
|
||||
mbedtls_aes_xts_init(ctxt->ectxt);
|
||||
mbedtls_aes_xts_init(ctxt->dctxt);
|
||||
|
||||
if(mbedtls_aes_xts_setkey_enc(ctxt->ectxt, eky, 2 * NVS_KEY_SIZE * 8)) {
|
||||
return ESP_ERR_NVS_XTS_CFG_FAILED;
|
||||
}
|
||||
|
||||
if(mbedtls_aes_xts_setkey_dec(ctxt->dctxt, eky, 2 * NVS_KEY_SIZE * 8)) {
|
||||
return ESP_ERR_NVS_XTS_CFG_FAILED;
|
||||
}
|
||||
|
||||
xtsCtxtList.push_back(ctxt);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t EncrMgr::removeSecurityContext(uint32_t baseSector) {
|
||||
auto xtsCtxt = findXtsCtxtFromAddr(baseSector * SPI_FLASH_SEC_SIZE);
|
||||
if(!xtsCtxt) {
|
||||
return ESP_ERR_NVS_XTS_CFG_NOT_FOUND;
|
||||
}
|
||||
xtsCtxtList.erase(xtsCtxt);
|
||||
delete xtsCtxt;
|
||||
|
||||
if(!xtsCtxtList.size()) {
|
||||
resetInstance();
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t EncrMgr::encryptNvsData(uint8_t* ptxt, uint32_t addr, uint32_t ptxtLen, XtsCtxt* xtsCtxt) {
|
||||
|
||||
uint8_t entrySize = sizeof(Item);
|
||||
|
||||
//sector num required as an arr by mbedtls. Should have been just uint64/32.
|
||||
uint8_t data_unit[16];
|
||||
|
||||
assert(ptxtLen % entrySize == 0);
|
||||
|
||||
/* Use relative address instead of absolute address (relocatable), so that host-generated
|
||||
* encrypted nvs images can be used*/
|
||||
uint32_t relAddr = addr - (xtsCtxt->baseSector * SPI_FLASH_SEC_SIZE);
|
||||
|
||||
memset(data_unit, 0, sizeof(data_unit));
|
||||
|
||||
for(uint8_t entry = 0; entry < (ptxtLen/entrySize); entry++)
|
||||
{
|
||||
uint32_t offset = entry * entrySize;
|
||||
uint32_t *addr_loc = (uint32_t*) &data_unit[0];
|
||||
|
||||
*addr_loc = relAddr + offset;
|
||||
if(mbedtls_aes_crypt_xts(xtsCtxt->ectxt, MBEDTLS_AES_ENCRYPT, entrySize, data_unit, ptxt + offset, ptxt + offset)) {
|
||||
return ESP_ERR_NVS_XTS_ENCR_FAILED;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t EncrMgr::decryptNvsData(uint8_t* ctxt, uint32_t addr, uint32_t ctxtLen, XtsCtxt* xtsCtxt) {
|
||||
|
||||
//sector num required as an arr by mbedtls. Should have been just uint64/32.
|
||||
uint8_t data_unit[16];
|
||||
|
||||
|
||||
/** 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.*/
|
||||
assert(ctxtLen == sizeof(Item));
|
||||
|
||||
uint32_t relAddr = addr - (xtsCtxt->baseSector * SPI_FLASH_SEC_SIZE);
|
||||
|
||||
memset(data_unit, 0, sizeof(data_unit));
|
||||
|
||||
memcpy(data_unit, &relAddr, sizeof(relAddr));
|
||||
|
||||
if(mbedtls_aes_crypt_xts(xtsCtxt->dctxt, MBEDTLS_AES_DECRYPT, ctxtLen, data_unit, ctxt, ctxt)) {
|
||||
return ESP_ERR_NVS_XTS_DECR_FAILED;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
} // namespace nvs
|
@ -1,63 +0,0 @@
|
||||
// Copyright 2015-2018 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 nvs_encr_hpp
|
||||
#define nvs_encr_hpp
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "intrusive_list.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
namespace nvs
|
||||
{
|
||||
|
||||
struct XtsCtxt : public intrusive_list_node<XtsCtxt> {
|
||||
public:
|
||||
mbedtls_aes_xts_context ectxt[1];
|
||||
mbedtls_aes_xts_context dctxt[1];
|
||||
uint32_t baseSector;
|
||||
uint32_t sectorCount;
|
||||
};
|
||||
|
||||
|
||||
/* A singleton class for managing nvs encryption*/
|
||||
class EncrMgr
|
||||
{
|
||||
public:
|
||||
static EncrMgr* getInstance();
|
||||
static void resetInstance();
|
||||
static bool isEncrActive();
|
||||
esp_err_t setSecurityContext(uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg);
|
||||
esp_err_t removeSecurityContext(uint32_t baseSector);
|
||||
esp_err_t encryptNvsData(uint8_t* ptxt, uint32_t addr, uint32_t ptxtLen, XtsCtxt* xtsCtxt);
|
||||
esp_err_t decryptNvsData(uint8_t* ctxt, uint32_t addr, uint32_t ctxtLen, XtsCtxt* xtsCtxt);
|
||||
XtsCtxt* findXtsCtxtFromAddr(uint32_t addr);
|
||||
~EncrMgr() {}
|
||||
|
||||
protected:
|
||||
static bool isActive;
|
||||
static EncrMgr* instance;
|
||||
intrusive_list<XtsCtxt> xtsCtxtList;
|
||||
EncrMgr() {}
|
||||
|
||||
}; // class EncrMgr
|
||||
|
||||
esp_err_t nvs_flash_write(size_t destAddr, const void *srcAddr, size_t size);
|
||||
esp_err_t nvs_flash_read(size_t srcAddr, void *destAddr, size_t size);
|
||||
|
||||
|
||||
} // namespace nvs
|
||||
|
||||
|
||||
#endif /* nvs_encr_hpp */
|
122
components/nvs_flash/src/nvs_encrypted_partition.cpp
Normal file
122
components/nvs_flash/src/nvs_encrypted_partition.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
// Copyright 2019 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 <cstring>
|
||||
#include "nvs_encrypted_partition.hpp"
|
||||
#include "nvs_types.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
NVSEncryptedPartition::NVSEncryptedPartition(const esp_partition_t *partition)
|
||||
: NVSPartition(partition) { }
|
||||
|
||||
esp_err_t NVSEncryptedPartition::init(nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
uint8_t* eky = reinterpret_cast<uint8_t*>(cfg);
|
||||
|
||||
mbedtls_aes_xts_init(&mEctxt);
|
||||
mbedtls_aes_xts_init(&mDctxt);
|
||||
|
||||
if (mbedtls_aes_xts_setkey_enc(&mEctxt, eky, 2 * NVS_KEY_SIZE * 8) != 0) {
|
||||
return ESP_ERR_NVS_XTS_CFG_FAILED;
|
||||
}
|
||||
|
||||
if (mbedtls_aes_xts_setkey_dec(&mDctxt, eky, 2 * NVS_KEY_SIZE * 8) != 0) {
|
||||
return ESP_ERR_NVS_XTS_CFG_FAILED;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// read data
|
||||
esp_err_t read_result = esp_partition_read(mESPPartition, 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];
|
||||
|
||||
uint32_t relAddr = src_offset;
|
||||
|
||||
memset(data_unit, 0, sizeof(data_unit));
|
||||
|
||||
memcpy(data_unit, &relAddr, sizeof(relAddr));
|
||||
|
||||
uint8_t *destination = reinterpret_cast<uint8_t*>(dst);
|
||||
|
||||
if (mbedtls_aes_crypt_xts(&mDctxt, MBEDTLS_AES_DECRYPT, size, data_unit, destination, destination) != 0) {
|
||||
return ESP_ERR_NVS_XTS_DECR_FAILED;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// copy data to buffer for encryption
|
||||
uint8_t* buf = new (std::nothrow) uint8_t [size];
|
||||
|
||||
if (!buf) return ESP_ERR_NO_MEM;
|
||||
|
||||
memcpy(buf, src, size);
|
||||
|
||||
// encrypt data
|
||||
uint8_t entrySize = sizeof(Item);
|
||||
|
||||
//sector num required as an arr by mbedtls. Should have been just uint64/32.
|
||||
uint8_t data_unit[16];
|
||||
|
||||
/* Use relative address instead of absolute address (relocatable), so that host-generated
|
||||
* encrypted nvs images can be used*/
|
||||
uint32_t relAddr = addr;
|
||||
|
||||
memset(data_unit, 0, sizeof(data_unit));
|
||||
|
||||
for(uint8_t entry = 0; entry < (size/entrySize); entry++)
|
||||
{
|
||||
uint32_t offset = entry * entrySize;
|
||||
uint32_t *addr_loc = (uint32_t*) &data_unit[0];
|
||||
|
||||
*addr_loc = relAddr + offset;
|
||||
if (mbedtls_aes_crypt_xts(&mEctxt,
|
||||
MBEDTLS_AES_ENCRYPT,
|
||||
entrySize,
|
||||
data_unit,
|
||||
buf + offset,
|
||||
buf + offset) != 0) {
|
||||
delete buf;
|
||||
return ESP_ERR_NVS_XTS_ENCR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
// write data
|
||||
esp_err_t result = esp_partition_write(mESPPartition, addr, buf, size);
|
||||
|
||||
delete buf;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // nvs
|
||||
|
44
components/nvs_flash/src/nvs_encrypted_partition.hpp
Normal file
44
components/nvs_flash/src/nvs_encrypted_partition.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2019 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 NVS_ENCRYPTED_PARTITION_HPP_
|
||||
#define NVS_ENCRYPTED_PARTITION_HPP_
|
||||
|
||||
#include "mbedtls/aes.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs_partition.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
class NVSEncryptedPartition : public NVSPartition {
|
||||
public:
|
||||
NVSEncryptedPartition(const esp_partition_t *partition);
|
||||
|
||||
virtual ~NVSEncryptedPartition() { }
|
||||
|
||||
esp_err_t init(nvs_sec_cfg_t* cfg);
|
||||
|
||||
esp_err_t read(size_t src_offset, void* dst, size_t size) override;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
||||
#endif // NVS_ENCRYPTED_PARTITION_HPP_
|
||||
|
@ -1,79 +0,0 @@
|
||||
// Copyright 2015-2018 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_spi_flash.h"
|
||||
#include "nvs_ops.hpp"
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#include "nvs_encr.hpp"
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
namespace nvs
|
||||
{
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
esp_err_t nvs_flash_write(size_t destAddr, const void *srcAddr, size_t size) {
|
||||
|
||||
if(EncrMgr::isEncrActive()) {
|
||||
auto encrMgr = EncrMgr::getInstance();
|
||||
|
||||
if (!encrMgr) return ESP_ERR_NO_MEM;
|
||||
|
||||
auto xtsCtxt = encrMgr->findXtsCtxtFromAddr(destAddr);
|
||||
|
||||
if(xtsCtxt) {
|
||||
uint8_t* buf = static_cast<uint8_t*>(malloc(size));
|
||||
memcpy(buf, srcAddr, size);
|
||||
auto err = encrMgr->encryptNvsData(buf, destAddr, size, xtsCtxt);
|
||||
if( err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
err = spi_flash_write(destAddr, buf, size);
|
||||
delete buf;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return spi_flash_write(destAddr, srcAddr, size);
|
||||
}
|
||||
|
||||
esp_err_t nvs_flash_read(size_t srcAddr, void *destAddr, size_t size) {
|
||||
|
||||
auto err = spi_flash_read(srcAddr, destAddr, size);
|
||||
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if(EncrMgr::isEncrActive()) {
|
||||
auto encrMgr = EncrMgr::getInstance();
|
||||
|
||||
if (!encrMgr) return ESP_ERR_NO_MEM;
|
||||
|
||||
auto xtsCtxt = encrMgr->findXtsCtxtFromAddr(srcAddr);
|
||||
if(xtsCtxt) {
|
||||
return encrMgr->decryptNvsData(static_cast<uint8_t*>(destAddr),
|
||||
srcAddr, size, xtsCtxt);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#else
|
||||
esp_err_t nvs_flash_write(size_t destAddr, const void *srcAddr, size_t size) {
|
||||
return spi_flash_write(destAddr, srcAddr, size);
|
||||
}
|
||||
|
||||
esp_err_t nvs_flash_read(size_t srcAddr, void *destAddr, size_t size) {
|
||||
return spi_flash_read(srcAddr, destAddr, size);
|
||||
}
|
||||
#endif
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
// Copyright 2015-2018 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 nvs_ops_hpp
|
||||
#define nvs_ops_hpp
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
namespace nvs
|
||||
{
|
||||
esp_err_t nvs_flash_write(size_t destAddr, const void *srcAddr, size_t size);
|
||||
esp_err_t nvs_flash_read(size_t srcAddr, void *destAddr, size_t size);
|
||||
|
||||
} // namespace nvs
|
||||
|
||||
|
||||
#endif /* nvs_ops_hpp */
|
@ -20,11 +20,11 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "nvs_ops.hpp"
|
||||
|
||||
namespace nvs
|
||||
{
|
||||
|
||||
Page::Page() : mPartition(nullptr) { }
|
||||
|
||||
uint32_t Page::Header::calculateCrc32()
|
||||
{
|
||||
return crc32_le(0xffffffff,
|
||||
@ -32,14 +32,19 @@ uint32_t Page::Header::calculateCrc32()
|
||||
offsetof(Header, mCrc32) - offsetof(Header, mSeqNumber));
|
||||
}
|
||||
|
||||
esp_err_t Page::load(uint32_t sectorNumber)
|
||||
esp_err_t Page::load(Partition *partition, uint32_t sectorNumber)
|
||||
{
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mPartition = partition;
|
||||
mBaseAddress = sectorNumber * SEC_SIZE;
|
||||
mUsedEntryCount = 0;
|
||||
mErasedEntryCount = 0;
|
||||
|
||||
Header header;
|
||||
auto rc = spi_flash_read(mBaseAddress, &header, sizeof(header));
|
||||
auto rc = mPartition->read_raw(mBaseAddress, &header, sizeof(header));
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
return rc;
|
||||
@ -54,7 +59,7 @@ esp_err_t Page::load(uint32_t sectorNumber)
|
||||
if (!block) return ESP_ERR_NO_MEM;
|
||||
|
||||
for (uint32_t i = 0; i < SPI_FLASH_SEC_SIZE; i += 4 * BLOCK_SIZE) {
|
||||
rc = spi_flash_read(mBaseAddress + i, block, 4 * BLOCK_SIZE);
|
||||
rc = mPartition->read_raw(mBaseAddress + i, block, 4 * BLOCK_SIZE);
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
delete[] block;
|
||||
@ -101,7 +106,7 @@ esp_err_t Page::writeEntry(const Item& item)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
err = nvs_flash_write(getEntryAddress(mNextFreeEntry), &item, sizeof(item));
|
||||
err = mPartition->write(getEntryAddress(mNextFreeEntry), &item, sizeof(item));
|
||||
|
||||
if (err != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
@ -133,6 +138,7 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size)
|
||||
const uint8_t* buf = data;
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
// TODO: check whether still necessary with esp_partition* API
|
||||
/* On the ESP32, data can come from DROM, which is not accessible by spi_flash_write
|
||||
* function. To work around this, we copy the data to heap if it came from DROM.
|
||||
* Hopefully this won't happen very often in practice. For data from DRAM, we should
|
||||
@ -149,7 +155,7 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size)
|
||||
}
|
||||
#endif //ESP_PLATFORM
|
||||
|
||||
auto rc = nvs_flash_write(getEntryAddress(mNextFreeEntry), buf, size);
|
||||
auto rc = mPartition->write(getEntryAddress(mNextFreeEntry), buf, size);
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
if (buf != data) {
|
||||
@ -518,7 +524,7 @@ esp_err_t Page::mLoadEntryTable()
|
||||
if (mState == PageState::ACTIVE ||
|
||||
mState == PageState::FULL ||
|
||||
mState == PageState::FREEING) {
|
||||
auto rc = spi_flash_read(mBaseAddress + ENTRY_TABLE_OFFSET, mEntryTable.data(),
|
||||
auto rc = mPartition->read_raw(mBaseAddress + ENTRY_TABLE_OFFSET, mEntryTable.data(),
|
||||
mEntryTable.byteSize());
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
@ -557,7 +563,7 @@ esp_err_t Page::mLoadEntryTable()
|
||||
while (mNextFreeEntry < ENTRY_COUNT) {
|
||||
uint32_t entryAddress = getEntryAddress(mNextFreeEntry);
|
||||
uint32_t header;
|
||||
auto rc = spi_flash_read(entryAddress, &header, sizeof(header));
|
||||
auto rc = mPartition->read_raw(entryAddress, &header, sizeof(header));
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
return rc;
|
||||
@ -722,7 +728,7 @@ esp_err_t Page::initialize()
|
||||
header.mVersion = mVersion;
|
||||
header.mCrc32 = header.calculateCrc32();
|
||||
|
||||
auto rc = spi_flash_write(mBaseAddress, &header, sizeof(header));
|
||||
auto rc = mPartition->write_raw(mBaseAddress, &header, sizeof(header));
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
return rc;
|
||||
@ -739,7 +745,7 @@ esp_err_t Page::alterEntryState(size_t index, EntryState state)
|
||||
mEntryTable.set(index, state);
|
||||
size_t wordToWrite = mEntryTable.getWordIndex(index);
|
||||
uint32_t word = mEntryTable.data()[wordToWrite];
|
||||
auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast<uint32_t>(wordToWrite) * 4,
|
||||
auto rc = mPartition->write_raw(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast<uint32_t>(wordToWrite) * 4,
|
||||
&word, sizeof(word));
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
@ -763,7 +769,7 @@ esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state)
|
||||
}
|
||||
if (nextWordIndex != wordIndex) {
|
||||
uint32_t word = mEntryTable.data()[wordIndex];
|
||||
auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast<uint32_t>(wordIndex) * 4,
|
||||
auto rc = mPartition->write_raw(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast<uint32_t>(wordIndex) * 4,
|
||||
&word, 4);
|
||||
if (rc != ESP_OK) {
|
||||
return rc;
|
||||
@ -777,7 +783,7 @@ esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state)
|
||||
esp_err_t Page::alterPageState(PageState state)
|
||||
{
|
||||
uint32_t state_val = static_cast<uint32_t>(state);
|
||||
auto rc = spi_flash_write(mBaseAddress, &state_val, sizeof(state));
|
||||
auto rc = mPartition->write_raw(mBaseAddress, &state_val, sizeof(state));
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
return rc;
|
||||
@ -788,7 +794,7 @@ esp_err_t Page::alterPageState(PageState state)
|
||||
|
||||
esp_err_t Page::readEntry(size_t index, Item& dst) const
|
||||
{
|
||||
auto rc = nvs_flash_read(getEntryAddress(index), &dst, sizeof(dst));
|
||||
auto rc = mPartition->read(getEntryAddress(index), &dst, sizeof(dst));
|
||||
if (rc != ESP_OK) {
|
||||
return rc;
|
||||
}
|
||||
@ -925,8 +931,7 @@ esp_err_t Page::setVersion(uint8_t ver)
|
||||
|
||||
esp_err_t Page::erase()
|
||||
{
|
||||
auto sector = mBaseAddress / SPI_FLASH_SEC_SIZE;
|
||||
auto rc = spi_flash_erase_sector(sector);
|
||||
auto rc = mPartition->erase_range(mBaseAddress, SPI_FLASH_SEC_SIZE);
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
return rc;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "compressed_enum_table.hpp"
|
||||
#include "intrusive_list.h"
|
||||
#include "nvs_item_hash_list.hpp"
|
||||
#include "partition.hpp"
|
||||
|
||||
namespace nvs
|
||||
{
|
||||
@ -77,17 +78,19 @@ public:
|
||||
INVALID = 0
|
||||
};
|
||||
|
||||
Page();
|
||||
|
||||
PageState state() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
esp_err_t load(uint32_t sectorNumber);
|
||||
esp_err_t load(Partition *partition, uint32_t sectorNumber);
|
||||
|
||||
esp_err_t getSeqNumber(uint32_t& seqNumber) const;
|
||||
|
||||
esp_err_t setSeqNumber(uint32_t seqNumber);
|
||||
|
||||
|
||||
esp_err_t setVersion(uint8_t version);
|
||||
|
||||
esp_err_t writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize, uint8_t chunkIdx = CHUNK_ANY);
|
||||
@ -188,7 +191,7 @@ protected:
|
||||
esp_err_t readEntry(size_t index, Item& dst) const;
|
||||
|
||||
esp_err_t writeEntry(const Item& item);
|
||||
|
||||
|
||||
esp_err_t writeEntryData(const uint8_t* data, size_t size);
|
||||
|
||||
esp_err_t eraseEntryAndSpan(size_t index);
|
||||
@ -205,7 +208,7 @@ protected:
|
||||
assert(entry < ENTRY_COUNT);
|
||||
return mBaseAddress + ENTRY_DATA_OFFSET + static_cast<uint32_t>(entry) * ENTRY_SIZE;
|
||||
}
|
||||
|
||||
|
||||
static const char* pageStateToName(PageState ps);
|
||||
|
||||
|
||||
@ -223,6 +226,8 @@ protected:
|
||||
|
||||
HashList mHashList;
|
||||
|
||||
Partition *mPartition;
|
||||
|
||||
static const uint32_t HEADER_OFFSET = 0;
|
||||
static const uint32_t ENTRY_TABLE_OFFSET = HEADER_OFFSET + 32;
|
||||
static const uint32_t ENTRY_DATA_OFFSET = ENTRY_TABLE_OFFSET + 32;
|
||||
|
@ -15,8 +15,12 @@
|
||||
|
||||
namespace nvs
|
||||
{
|
||||
esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount)
|
||||
esp_err_t PageManager::load(Partition *partition, uint32_t baseSector, uint32_t sectorCount)
|
||||
{
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mBaseSector = baseSector;
|
||||
mPageCount = sectorCount;
|
||||
mPageList.clear();
|
||||
@ -26,7 +30,7 @@ esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount)
|
||||
if (!mPages) return ESP_ERR_NO_MEM;
|
||||
|
||||
for (uint32_t i = 0; i < sectorCount; ++i) {
|
||||
auto err = mPages[i].load(baseSector + i);
|
||||
auto err = mPages[i].load(partition, baseSector + i);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
@ -126,7 +130,7 @@ esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount)
|
||||
}
|
||||
|
||||
// partition should have at least one free page
|
||||
if (mFreePageList.size() == 0) {
|
||||
if (mFreePageList.empty()) {
|
||||
return ESP_ERR_NVS_NO_FREE_PAGES;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <list>
|
||||
#include "nvs_types.hpp"
|
||||
#include "nvs_page.hpp"
|
||||
#include "nvs_pagemanager.hpp"
|
||||
#include "partition.hpp"
|
||||
#include "intrusive_list.h"
|
||||
|
||||
namespace nvs
|
||||
@ -31,7 +31,7 @@ public:
|
||||
|
||||
PageManager() {}
|
||||
|
||||
esp_err_t load(uint32_t baseSector, uint32_t sectorCount);
|
||||
esp_err_t load(Partition *partition, uint32_t baseSector, uint32_t sectorCount);
|
||||
|
||||
TPageListIterator begin()
|
||||
{
|
||||
|
78
components/nvs_flash/src/nvs_partition.cpp
Normal file
78
components/nvs_flash/src/nvs_partition.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2019 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 "string.h"
|
||||
#include "nvs_partition.hpp"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
NVSPartition::NVSPartition(const esp_partition_t* partition)
|
||||
: mESPPartition(partition)
|
||||
{
|
||||
// ensure the class is in a valid state
|
||||
if (partition == nullptr) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
const char *NVSPartition::get_partition_name()
|
||||
{
|
||||
return mESPPartition->label;
|
||||
}
|
||||
|
||||
esp_err_t NVSPartition::read_raw(size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
return esp_partition_read_raw(mESPPartition, src_offset, dst, 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);
|
||||
}
|
||||
|
||||
esp_err_t NVSPartition::write_raw(size_t dst_offset, const void* src, size_t size)
|
||||
{
|
||||
return esp_partition_write_raw(mESPPartition, dst_offset, src, size);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
esp_err_t NVSPartition::erase_range(size_t dst_offset, size_t size)
|
||||
{
|
||||
return esp_partition_erase_range(mESPPartition, dst_offset, size);
|
||||
}
|
||||
|
||||
uint32_t NVSPartition::get_address()
|
||||
{
|
||||
return mESPPartition->address;
|
||||
}
|
||||
|
||||
uint32_t NVSPartition::get_size()
|
||||
{
|
||||
return mESPPartition->size;
|
||||
}
|
||||
|
||||
} // nvs
|
||||
|
116
components/nvs_flash/src/nvs_partition.hpp
Normal file
116
components/nvs_flash/src/nvs_partition.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2019 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_PARTITION_HPP_
|
||||
#define ESP_PARTITION_HPP_
|
||||
|
||||
#include "esp_partition.h"
|
||||
#include "intrusive_list.h"
|
||||
#include "partition.hpp"
|
||||
|
||||
#define ESP_ENCRYPT_BLOCK_SIZE 16
|
||||
|
||||
#define PART_NAME_MAX_SIZE 16 /*!< maximum length of partition name (excluding null terminator) */
|
||||
|
||||
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.
|
||||
*/
|
||||
class NVSPartition : public Partition, public intrusive_list_node<NVSPartition> {
|
||||
public:
|
||||
/**
|
||||
* Copy partition_name to mPartitionName and initialize mESPPartition.
|
||||
*
|
||||
* @param partition_name the name of the partition as in the partition table, must be non-NULL!
|
||||
* @param partition an already initialized partition structure
|
||||
*/
|
||||
NVSPartition(const esp_partition_t* partition);
|
||||
|
||||
/**
|
||||
* No need to de-initialize mESPPartition here, if you used esp_partition_find_first.
|
||||
* Otherwise, the user is responsible for de-initializing it.
|
||||
*/
|
||||
virtual ~NVSPartition() { }
|
||||
|
||||
const char *get_partition_name() override;
|
||||
|
||||
/**
|
||||
* Look into \c esp_partition_read_raw for more details.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - other error codes from the esp_partition 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.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
esp_err_t read(size_t src_offset, void* dst, size_t size) override;
|
||||
|
||||
/**
|
||||
* Look into \c esp_partition_write_raw for more details.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - error codes from the esp_partition 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.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - error codes from the esp_partition API
|
||||
*/
|
||||
esp_err_t erase_range(size_t dst_offset, size_t size) override;
|
||||
|
||||
/**
|
||||
* @return the base address of the partition.
|
||||
*/
|
||||
uint32_t get_address() override;
|
||||
|
||||
/**
|
||||
* @return the size of the partition in bytes.
|
||||
*/
|
||||
uint32_t get_size() override;
|
||||
|
||||
protected:
|
||||
const esp_partition_t* mESPPartition;
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
||||
#endif // ESP_PARTITION_HPP_
|
||||
|
65
components/nvs_flash/src/nvs_partition_lookup.cpp
Normal file
65
components/nvs_flash/src/nvs_partition_lookup.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include "esp_partition.h"
|
||||
#include "nvs_partition_lookup.hpp"
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#include "nvs_encrypted_partition.hpp"
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
|
||||
namespace nvs {
|
||||
|
||||
esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p)
|
||||
{
|
||||
const esp_partition_t* esp_partition = esp_partition_find_first(
|
||||
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;
|
||||
}
|
||||
|
||||
NVSPartition *partition = new (std::nothrow) NVSPartition(esp_partition);
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
*p = partition;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p)
|
||||
{
|
||||
const esp_partition_t* esp_partition = esp_partition_find_first(
|
||||
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;
|
||||
}
|
||||
|
||||
NVSEncryptedPartition *enc_p = new (std::nothrow) NVSEncryptedPartition(esp_partition);
|
||||
if (enc_p == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t result = enc_p->init(cfg);
|
||||
if (result != ESP_OK) {
|
||||
delete enc_p;
|
||||
return result;
|
||||
}
|
||||
|
||||
*p = enc_p;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
|
||||
} // nvs
|
18
components/nvs_flash/src/nvs_partition_lookup.hpp
Normal file
18
components/nvs_flash/src/nvs_partition_lookup.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "esp_err.h"
|
||||
#include "nvs_partition.hpp"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#ifndef NVS_PARTITION_LOOKUP_HPP_
|
||||
#define NVS_PARTITION_LOOKUP_HPP_
|
||||
|
||||
namespace nvs {
|
||||
|
||||
esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p);
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p);
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
|
||||
} // nvs
|
||||
|
||||
#endif // NVS_PARTITION_LOOKUP_HPP_
|
@ -13,6 +13,11 @@
|
||||
// limitations under the License.
|
||||
#include "esp_partition.h"
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "nvs_partition_lookup.hpp"
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#include "nvs_encrypted_partition.hpp"
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
|
||||
namespace nvs {
|
||||
|
||||
@ -30,6 +35,11 @@ NVSPartitionManager* NVSPartitionManager::get_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;
|
||||
Storage* mStorage;
|
||||
|
||||
mStorage = lookup_storage_from_name(partition_label);
|
||||
@ -39,33 +49,55 @@ esp_err_t NVSPartitionManager::init_partition(const char *partition_label)
|
||||
|
||||
assert(SPI_FLASH_SEC_SIZE != 0);
|
||||
|
||||
const esp_partition_t* partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, partition_label);
|
||||
if (partition == nullptr) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
NVSPartition *p = nullptr;
|
||||
esp_err_t result = lookup_nvs_partition(partition_label, &p);
|
||||
|
||||
if (result != ESP_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return init_custom(partition_label, partition->address / SPI_FLASH_SEC_SIZE,
|
||||
partition->size / SPI_FLASH_SEC_SIZE);
|
||||
size = p->get_size();
|
||||
|
||||
result = init_custom(p, 0, size / SPI_FLASH_SEC_SIZE);
|
||||
if (result != ESP_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
nvs_partition_list.push_back(p);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
error:
|
||||
delete p;
|
||||
return result;
|
||||
}
|
||||
#endif // ESP_PLATFORM
|
||||
|
||||
esp_err_t NVSPartitionManager::init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount)
|
||||
esp_err_t NVSPartitionManager::init_custom(Partition *partition, uint32_t baseSector, uint32_t sectorCount)
|
||||
{
|
||||
if (strlen(partName) > NVS_PART_NAME_MAX_SIZE) return ESP_ERR_INVALID_ARG;
|
||||
Storage* new_storage = nullptr;
|
||||
Storage* storage = lookup_storage_from_name(partition->get_partition_name());
|
||||
if (storage == nullptr) {
|
||||
new_storage = new (std::nothrow) Storage(partition);
|
||||
|
||||
Storage* new_storage = NULL;
|
||||
Storage* storage = lookup_storage_from_name(partName);
|
||||
if (storage == NULL) {
|
||||
new_storage = new (std::nothrow) Storage((const char *)partName);
|
||||
|
||||
if (!new_storage) return ESP_ERR_NO_MEM;
|
||||
if (new_storage == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
storage = new_storage;
|
||||
} else {
|
||||
// if storage was initialized already, we don't need partition and hence delete it
|
||||
for (auto it = nvs_partition_list.begin(); it != nvs_partition_list.end(); ++it) {
|
||||
if (partition == it) {
|
||||
nvs_partition_list.erase(it);
|
||||
delete partition;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t err = storage->init(baseSector, sectorCount);
|
||||
if (new_storage != NULL) {
|
||||
if (new_storage != nullptr) {
|
||||
if (err == ESP_OK) {
|
||||
nvs_storage_list.push_back(new_storage);
|
||||
} else {
|
||||
@ -75,41 +107,47 @@ esp_err_t NVSPartitionManager::init_custom(const char *partName, uint32_t baseSe
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
if (strlen(part_name) > NVS_PART_NAME_MAX_SIZE) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
Storage* mStorage;
|
||||
|
||||
mStorage = lookup_storage_from_name(part_name);
|
||||
if (mStorage) {
|
||||
if (mStorage != nullptr) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const esp_partition_t* partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name);
|
||||
if (partition == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
NVSPartition *p;
|
||||
esp_err_t result;
|
||||
if (cfg != nullptr) {
|
||||
result = lookup_nvs_encrypted_partition(part_name, cfg, &p);
|
||||
} else {
|
||||
result = lookup_nvs_partition(part_name, &p);
|
||||
}
|
||||
|
||||
return secure_init_custom(part_name, partition->address / SPI_FLASH_SEC_SIZE,
|
||||
partition->size / SPI_FLASH_SEC_SIZE, cfg);
|
||||
}
|
||||
|
||||
esp_err_t NVSPartitionManager::secure_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
if(cfg) {
|
||||
auto encrMgr = EncrMgr::getInstance();
|
||||
auto err = encrMgr->setSecurityContext(baseSector, sectorCount, cfg);
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (result != ESP_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return init_custom(partName, baseSector, sectorCount);
|
||||
uint32_t size = p->get_size();
|
||||
|
||||
result = init_custom(p, 0, size / SPI_FLASH_SEC_SIZE);
|
||||
if (result != ESP_OK) {
|
||||
delete p;
|
||||
return result;
|
||||
}
|
||||
|
||||
nvs_partition_list.push_back(p);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
#endif // ESP_PLATFORM
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
|
||||
esp_err_t NVSPartitionManager::deinit_partition(const char *partition_label)
|
||||
{
|
||||
@ -118,13 +156,6 @@ esp_err_t NVSPartitionManager::deinit_partition(const char *partition_label)
|
||||
return ESP_ERR_NVS_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
if(EncrMgr::isEncrActive()) {
|
||||
auto encrMgr = EncrMgr::getInstance();
|
||||
encrMgr->removeSecurityContext(storage->getBaseSector());
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clean up handles related to the storage being deinitialized */
|
||||
for (auto it = nvs_handles.begin(); it != nvs_handles.end(); ++it) {
|
||||
if (it->mStoragePtr == storage) {
|
||||
@ -133,10 +164,19 @@ esp_err_t NVSPartitionManager::deinit_partition(const char *partition_label)
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally delete the storage itself */
|
||||
/* Finally delete the storage and its partition */
|
||||
nvs_storage_list.erase(storage);
|
||||
delete storage;
|
||||
|
||||
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;
|
||||
nvs_partition_list.erase(it);
|
||||
delete p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -148,12 +188,12 @@ esp_err_t NVSPartitionManager::open_handle(const char *part_name,
|
||||
uint8_t nsIndex;
|
||||
Storage* sHandle;
|
||||
|
||||
if (nvs_storage_list.size() == 0) {
|
||||
if (nvs_storage_list.empty()) {
|
||||
return ESP_ERR_NVS_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
sHandle = lookup_storage_from_name(part_name);
|
||||
if (sHandle == NULL) {
|
||||
if (sHandle == nullptr) {
|
||||
return ESP_ERR_NVS_PART_NOT_FOUND;
|
||||
}
|
||||
|
||||
@ -164,7 +204,9 @@ esp_err_t NVSPartitionManager::open_handle(const char *part_name,
|
||||
|
||||
*handle = new (std::nothrow) NVSHandleSimple(open_mode==NVS_READONLY, nsIndex, sHandle);
|
||||
|
||||
if (!handle) return ESP_ERR_NO_MEM;
|
||||
if (handle == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
nvs_handles.push_back(*handle);
|
||||
|
||||
@ -194,7 +236,7 @@ Storage* NVSPartitionManager::lookup_storage_from_name(const char* name)
|
||||
});
|
||||
|
||||
if (it == end(nvs_storage_list)) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
@ -16,10 +16,8 @@
|
||||
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_storage.hpp"
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#include "nvs_encr.hpp"
|
||||
#endif
|
||||
#include "nvs_partition.hpp"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
@ -31,12 +29,10 @@ public:
|
||||
|
||||
esp_err_t init_partition(const char *partition_label);
|
||||
|
||||
esp_err_t init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount);
|
||||
esp_err_t init_custom(Partition *partition, uint32_t baseSector, uint32_t sectorCount);
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
esp_err_t secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg);
|
||||
|
||||
esp_err_t secure_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg);
|
||||
#endif
|
||||
|
||||
esp_err_t deinit_partition(const char *partition_label);
|
||||
@ -57,6 +53,8 @@ protected:
|
||||
intrusive_list<NVSHandleSimple> nvs_handles;
|
||||
|
||||
intrusive_list<nvs::Storage> nvs_storage_list;
|
||||
|
||||
intrusive_list<nvs::NVSPartition> nvs_partition_list;
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
@ -90,7 +90,7 @@ void Storage::eraseOrphanDataBlobs(TBlobIndexList& blobIdxList)
|
||||
|
||||
esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount)
|
||||
{
|
||||
auto err = mPageManager.load(baseSector, sectorCount);
|
||||
auto err = mPageManager.load(mPartition, baseSector, sectorCount);
|
||||
if (err != ESP_OK) {
|
||||
mState = StorageState::INVALID;
|
||||
return err;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "nvs_types.hpp"
|
||||
#include "nvs_page.hpp"
|
||||
#include "nvs_pagemanager.hpp"
|
||||
#include "partition.hpp"
|
||||
|
||||
//extern void dumpBytes(const uint8_t* data, size_t count);
|
||||
|
||||
@ -60,9 +61,10 @@ class Storage : public intrusive_list_node<Storage>
|
||||
public:
|
||||
~Storage();
|
||||
|
||||
Storage(const char *pName = NVS_DEFAULT_PART_NAME)
|
||||
{
|
||||
strncpy(mPartitionName, pName, NVS_PART_NAME_MAX_SIZE);
|
||||
Storage(Partition *partition) : mPartition(partition) {
|
||||
if (partition == nullptr) {
|
||||
abort();
|
||||
}
|
||||
};
|
||||
|
||||
esp_err_t init(uint32_t baseSector, uint32_t sectorCount);
|
||||
@ -98,10 +100,16 @@ public:
|
||||
|
||||
esp_err_t eraseNamespace(uint8_t nsIndex);
|
||||
|
||||
const Partition *getPart() const
|
||||
{
|
||||
return mPartition;
|
||||
}
|
||||
|
||||
const char *getPartName() const
|
||||
{
|
||||
return mPartitionName;
|
||||
return mPartition->get_partition_name();
|
||||
}
|
||||
|
||||
uint32_t getBaseSector()
|
||||
{
|
||||
return mPageManager.getBaseSector();
|
||||
@ -145,7 +153,7 @@ protected:
|
||||
esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item, uint8_t chunkIdx = Page::CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY);
|
||||
|
||||
protected:
|
||||
char mPartitionName [NVS_PART_NAME_MAX_SIZE + 1];
|
||||
Partition *mPartition;
|
||||
size_t mPageCount;
|
||||
PageManager mPageManager;
|
||||
TNamespaces mNamespaces;
|
||||
|
60
components/nvs_flash/src/partition.hpp
Normal file
60
components/nvs_flash/src/partition.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2019 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 PARTITION_HPP_
|
||||
#define PARTITION_HPP_
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
namespace nvs {
|
||||
|
||||
/**
|
||||
* @brief Abstract interface for partition related operations, currently in NVS.
|
||||
*
|
||||
* It resembles the main operations according to esp_partition.h.
|
||||
*/
|
||||
class Partition {
|
||||
public:
|
||||
virtual ~Partition() { }
|
||||
|
||||
/**
|
||||
* Return the partition name as in the partition table.
|
||||
*/
|
||||
virtual const char *get_partition_name() = 0;
|
||||
|
||||
virtual esp_err_t read_raw(size_t src_offset, void* dst, size_t size) = 0;
|
||||
|
||||
virtual esp_err_t read(size_t src_offset, void* dst, size_t size) = 0;
|
||||
|
||||
virtual esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) = 0;
|
||||
|
||||
virtual esp_err_t write(size_t dst_offset, const void* src, size_t size) = 0;
|
||||
|
||||
virtual esp_err_t erase_range(size_t dst_offset, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Return the address of the beginning of the partition.
|
||||
*/
|
||||
virtual uint32_t get_address() = 0;
|
||||
|
||||
/**
|
||||
* Return the partition size in bytes.
|
||||
*/
|
||||
virtual uint32_t get_size() = 0;
|
||||
};
|
||||
|
||||
} // nvs
|
||||
|
||||
#endif // PARTITION_HPP_
|
||||
|
@ -1,3 +1,4 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES cmock test_utils nvs_flash bootloader_support)
|
||||
PRIV_REQUIRES cmock test_utils nvs_flash bootloader_support
|
||||
EMBED_TXTFILES encryption_keys.bin partition_encrypted.bin sample.bin)
|
||||
|
@ -18,6 +18,15 @@
|
||||
|
||||
static const char* TAG = "test_nvs";
|
||||
|
||||
TEST_CASE("Partition name no longer than 16 characters", "[nvs]")
|
||||
{
|
||||
const char *TOO_LONG_NAME = "0123456789abcdefg";
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, nvs_flash_init_partition(TOO_LONG_NAME));
|
||||
|
||||
nvs_flash_deinit_partition(TOO_LONG_NAME); // just in case
|
||||
}
|
||||
|
||||
TEST_CASE("flash erase deinitializes initialized partition", "[nvs]")
|
||||
{
|
||||
nvs_handle_t handle;
|
||||
@ -26,7 +35,7 @@ TEST_CASE("flash erase deinitializes initialized partition", "[nvs]")
|
||||
nvs_flash_erase();
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( err );
|
||||
TEST_ESP_OK( err );
|
||||
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
TEST_ESP_OK(nvs_open("uninit_ns", NVS_READWRITE, &handle));
|
||||
@ -468,7 +477,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena
|
||||
}
|
||||
|
||||
for (int i = 0; i < nvs_part->size; i+= SPI_FLASH_SEC_SIZE) {
|
||||
ESP_ERROR_CHECK( spi_flash_write(nvs_part->address + i, nvs_data_start + i, SPI_FLASH_SEC_SIZE) );
|
||||
ESP_ERROR_CHECK( esp_partition_write(nvs_part, i, nvs_data_start + i, SPI_FLASH_SEC_SIZE) );
|
||||
}
|
||||
|
||||
esp_err_t err = nvs_flash_read_security_cfg(key_part, &xts_cfg);
|
||||
|
@ -10,11 +10,11 @@ SOURCE_FILES = \
|
||||
nvs_pagemanager.cpp \
|
||||
nvs_storage.cpp \
|
||||
nvs_item_hash_list.cpp \
|
||||
nvs_encr.cpp \
|
||||
nvs_ops.cpp \
|
||||
nvs_handle_simple.cpp \
|
||||
nvs_handle_locked.cpp \
|
||||
nvs_partition_manager.cpp \
|
||||
nvs_partition.cpp \
|
||||
nvs_encrypted_partition.cpp \
|
||||
nvs_cxx_api.cpp \
|
||||
) \
|
||||
spi_flash_emulation.cpp \
|
||||
@ -25,6 +25,7 @@ SOURCE_FILES = \
|
||||
test_partition_manager.cpp \
|
||||
test_nvs_handle.cpp \
|
||||
test_nvs_storage.cpp \
|
||||
test_nvs_partition.cpp \
|
||||
test_nvs_cxx_api.cpp \
|
||||
test_nvs_initialization.cpp \
|
||||
crc.cpp \
|
||||
@ -36,7 +37,7 @@ else
|
||||
COMPILER := gcc
|
||||
endif
|
||||
|
||||
CPPFLAGS += -I../include -I../src -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../hal/include -I ../../xtensa/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage
|
||||
CPPFLAGS += -I../include -I../src -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../hal/include -I ../../xtensa/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -g2 -ggdb
|
||||
CFLAGS += -fprofile-arcs -ftest-coverage
|
||||
CXXFLAGS += -std=c++11 -Wall -Werror
|
||||
LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage
|
||||
@ -89,6 +90,8 @@ clean: clean-coverage
|
||||
rm -f ../nvs_partition_generator/partition_encrypted.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keygen.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keyfile.bin
|
||||
rm -f ../nvs_partition_generator/partition_decrypted.bin
|
||||
rm -f ../nvs_partition_generator/partition_encoded.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition-encrypted.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition.bin
|
||||
rm -f ../../../tools/mass_mfg/samples/sample_values_multipage_blob_created.csv
|
||||
|
@ -11,7 +11,7 @@
|
||||
// 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_spi_flash.h"
|
||||
#include "esp_partition.h"
|
||||
#include "spi_flash_emulation.h"
|
||||
|
||||
|
||||
@ -22,39 +22,82 @@ void spi_flash_emulator_set(SpiFlashEmulator* e)
|
||||
s_emulator = e;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_erase_sector(size_t sec)
|
||||
esp_err_t esp_partition_erase_range(const esp_partition_t* partition,
|
||||
size_t offset, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!s_emulator->erase(sec)) {
|
||||
if (size % SPI_FLASH_SEC_SIZE != 0) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (offset % SPI_FLASH_SEC_SIZE != 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
size_t start_sector = offset / SPI_FLASH_SEC_SIZE;
|
||||
size_t num_sectors = size / SPI_FLASH_SEC_SIZE;
|
||||
for (size_t sector = start_sector; sector < (start_sector + num_sectors); sector++) {
|
||||
if (!s_emulator->erase(sector)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_read(const esp_partition_t* partition,
|
||||
size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!s_emulator->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_write(size_t des_addr, const void *src_addr, size_t size)
|
||||
esp_err_t esp_partition_read_raw(const esp_partition_t* partition,
|
||||
size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!s_emulator->write(des_addr, reinterpret_cast<const uint32_t*>(src_addr), size)) {
|
||||
if (!s_emulator->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_read(size_t src_addr, void *des_addr, size_t size)
|
||||
esp_err_t esp_partition_write(const esp_partition_t* partition,
|
||||
size_t dst_offset, const void* src, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!s_emulator->read(reinterpret_cast<uint32_t*>(des_addr), src_addr, size)) {
|
||||
if (!s_emulator->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_write_raw(const esp_partition_t* partition,
|
||||
size_t dst_offset, const void* src, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!s_emulator->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
|
149
components/nvs_flash/test_nvs_host/test_fixtures.hpp
Normal file
149
components/nvs_flash/test_nvs_host/test_fixtures.hpp
Normal file
@ -0,0 +1,149 @@
|
||||
// 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 "nvs_partition.hpp"
|
||||
#include "nvs_encrypted_partition.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
#include "nvs.h"
|
||||
|
||||
class PartitionEmulation : public nvs::Partition {
|
||||
public:
|
||||
PartitionEmulation(SpiFlashEmulator *spi_flash_emulator,
|
||||
uint32_t address,
|
||||
uint32_t size,
|
||||
const char *partition_name = NVS_DEFAULT_PART_NAME)
|
||||
: partition_name(partition_name), flash_emu(spi_flash_emulator), address(address), size(size)
|
||||
{
|
||||
assert(partition_name);
|
||||
assert(flash_emu);
|
||||
assert(size);
|
||||
}
|
||||
|
||||
const char *get_partition_name() override
|
||||
{
|
||||
return partition_name;
|
||||
}
|
||||
|
||||
esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override
|
||||
{
|
||||
if (!flash_emu->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t read(size_t src_offset, void* dst, size_t size) override
|
||||
{
|
||||
if (!flash_emu->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override
|
||||
{
|
||||
if (!flash_emu->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t write(size_t dst_offset, const void* src, size_t size) override
|
||||
{
|
||||
if (!flash_emu->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t erase_range(size_t dst_offset, size_t size) override
|
||||
{
|
||||
if (size % SPI_FLASH_SEC_SIZE != 0) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (dst_offset % SPI_FLASH_SEC_SIZE != 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
size_t start_sector = dst_offset / SPI_FLASH_SEC_SIZE;
|
||||
size_t num_sectors = size / SPI_FLASH_SEC_SIZE;
|
||||
for (size_t sector = start_sector; sector < (start_sector + num_sectors); sector++) {
|
||||
if (!flash_emu->erase(sector)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint32_t get_address() override
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
uint32_t get_size() override
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
private:
|
||||
const char *partition_name;
|
||||
|
||||
SpiFlashEmulator *flash_emu;
|
||||
|
||||
uint32_t address;
|
||||
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct PartitionEmulationFixture {
|
||||
PartitionEmulationFixture(uint32_t start_sector = 0,
|
||||
uint32_t sector_size = 1,
|
||||
const char *partition_name = NVS_DEFAULT_PART_NAME)
|
||||
: emu(start_sector + sector_size),
|
||||
part(&emu, start_sector * SPI_FLASH_SEC_SIZE, sector_size * SPI_FLASH_SEC_SIZE, partition_name) {
|
||||
}
|
||||
|
||||
~PartitionEmulationFixture() { }
|
||||
|
||||
SpiFlashEmulator emu;
|
||||
|
||||
PartitionEmulation part;
|
||||
};
|
||||
|
||||
struct EncryptedPartitionFixture {
|
||||
EncryptedPartitionFixture(nvs_sec_cfg_t *cfg,
|
||||
uint32_t start_sector = 0,
|
||||
uint32_t sector_size = 1,
|
||||
const char *partition_name = NVS_DEFAULT_PART_NAME)
|
||||
: esp_partition(), emu(start_sector + sector_size),
|
||||
part(&esp_partition) {
|
||||
esp_partition.address = start_sector * SPI_FLASH_SEC_SIZE;
|
||||
esp_partition.size = sector_size * SPI_FLASH_SEC_SIZE;
|
||||
strncpy(esp_partition.label, partition_name, PART_NAME_MAX_SIZE);
|
||||
assert(part.init(cfg) == ESP_OK);
|
||||
}
|
||||
|
||||
~EncryptedPartitionFixture() { }
|
||||
|
||||
esp_partition_t esp_partition;
|
||||
|
||||
SpiFlashEmulator emu;
|
||||
|
||||
nvs::NVSEncryptedPartition part;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,8 @@
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
|
||||
#include "test_fixtures.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
@ -27,12 +29,12 @@ TEST_CASE("NVSHandleSimple CXX api open invalid arguments", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10, "test");
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->
|
||||
init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
|
||||
handle = nvs::open_nvs_handle_from_partition(nullptr, "ns_1", NVS_READWRITE, &result);
|
||||
CHECK(result == ESP_ERR_INVALID_ARG);
|
||||
@ -61,11 +63,11 @@ TEST_CASE("NVSHandleSimple CXX api open successful", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10, "test");
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
@ -87,11 +89,11 @@ TEST_CASE("NVSHandleSimple CXX api open default part successful", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom("nvs", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
@ -113,11 +115,11 @@ TEST_CASE("NVSHandleSimple CXX api open default part ns NULL", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom("nvs", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
@ -135,12 +137,12 @@ TEST_CASE("NVSHandleSimple CXX api read/write string", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
char read_buffer [256];
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom("nvs", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
@ -164,13 +166,13 @@ TEST_CASE("NVSHandleSimple CXX api read/write blob", "[nvs cxx]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
const char blob [6] = {15, 16, 17, 18, 19};
|
||||
char read_blob[6] = {0};
|
||||
esp_err_t result;
|
||||
shared_ptr<nvs::NVSHandle> handle;
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom("nvs", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
|
||||
#include "test_fixtures.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@ -29,9 +31,9 @@ TEST_CASE("NVSHandleSimple closes its reference in PartitionManager", "[partitio
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10, "test");
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
@ -53,9 +55,9 @@ TEST_CASE("NVSHandleSimple multiple open and closes with PartitionManager", "[pa
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10, "test");
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
@ -83,18 +85,18 @@ TEST_CASE("NVSHandleSimple multiple open and closes with PartitionManager", "[pa
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("nvshandle readonly fails", "[partition_mgr]")
|
||||
TEST_CASE("NVSHandleSimple readonly fails", "[partition_mgr]")
|
||||
{
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
|
||||
NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME);
|
||||
NVSHandleSimple *handle_1;
|
||||
NVSHandleSimple *handle_2;
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
|
||||
CHECK(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||
|
||||
// first, creating namespace...
|
||||
@ -123,13 +125,13 @@ TEST_CASE("NVSHandleSimple set/get char", "[partition_mgr]")
|
||||
BAR
|
||||
};
|
||||
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
NVSHandleSimple *handle;
|
||||
@ -155,13 +157,13 @@ TEST_CASE("NVSHandleSimple correctly sets/gets int enum", "[partition_mgr]")
|
||||
BAR
|
||||
};
|
||||
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
NVSHandleSimple *handle;
|
||||
@ -188,13 +190,13 @@ TEST_CASE("NVSHandleSimple correctly sets/gets int enum with negative values", "
|
||||
BAR
|
||||
};
|
||||
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
NVSHandleSimple *handle;
|
||||
@ -220,13 +222,13 @@ TEST_CASE("NVSHandleSimple correctly sets/gets uint8_t enum", "[partition_mgr]")
|
||||
BAR
|
||||
};
|
||||
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
NVSHandleSimple *handle;
|
||||
@ -253,13 +255,13 @@ TEST_CASE("NVSHandleSimple correctly sets/gets char enum", "[partition_mgr]")
|
||||
BAR
|
||||
};
|
||||
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
NVSHandleSimple *handle;
|
||||
|
55
components/nvs_flash/test_nvs_host/test_nvs_partition.cpp
Normal file
55
components/nvs_flash/test_nvs_host/test_nvs_partition.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
// 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 "catch.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "nvs_test_api.h"
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_partition.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
|
||||
#include "test_fixtures.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace nvs;
|
||||
|
||||
TEST_CASE("encrypted partition read size must be item size", "[nvs]")
|
||||
{
|
||||
char foo [32] = { };
|
||||
nvs_sec_cfg_t xts_cfg;
|
||||
for(int count = 0; count < NVS_KEY_SIZE; count++) {
|
||||
xts_cfg.eky[count] = 0x11;
|
||||
xts_cfg.tky[count] = 0x22;
|
||||
}
|
||||
EncryptedPartitionFixture fix(&xts_cfg);
|
||||
|
||||
CHECK(fix.part.read(0, foo, sizeof (foo) -1) == ESP_ERR_INVALID_SIZE);
|
||||
}
|
||||
|
||||
TEST_CASE("encrypted partition write size must be mod item size", "[nvs]")
|
||||
{
|
||||
char foo [64] = { };
|
||||
nvs_sec_cfg_t xts_cfg;
|
||||
for(int count = 0; count < NVS_KEY_SIZE; count++) {
|
||||
xts_cfg.eky[count] = 0x11;
|
||||
xts_cfg.tky[count] = 0x22;
|
||||
}
|
||||
EncryptedPartitionFixture fix(&xts_cfg);
|
||||
|
||||
CHECK(fix.part.write(0, foo, sizeof (foo) -1) == ESP_ERR_INVALID_SIZE);
|
||||
CHECK(fix.part.write(0, foo, sizeof (foo)) == ESP_OK);
|
||||
CHECK(fix.part.write(0, foo, sizeof (foo) * 2) == ESP_OK);
|
||||
}
|
@ -18,6 +18,8 @@
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
|
||||
#include "test_fixtures.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
@ -27,9 +29,9 @@ TEST_CASE("Storage iterator recognizes blob with VerOffset::VER_1_OFFSET", "[nvs
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10, "test");
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
uint8_t blob [] = {0x0, 0x1, 0x2, 0x3};
|
||||
|
@ -20,25 +20,28 @@
|
||||
#include "spi_flash_emulation.h"
|
||||
#include "nvs_test_api.h"
|
||||
|
||||
#include "test_fixtures.hpp"
|
||||
|
||||
using namespace nvs;
|
||||
|
||||
TEST_CASE("Partition manager initializes storage", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10, "test");
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr);
|
||||
REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(f.part.get_partition_name()) == ESP_OK);
|
||||
}
|
||||
|
||||
TEST_CASE("Partition manager de-initializes storage", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10, "test");
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr);
|
||||
CHECK(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
||||
CHECK(NVSPartitionManager::get_instance()->lookup_storage_from_name("test") == nullptr);
|
||||
@ -49,11 +52,13 @@ TEST_CASE("Partition manager initializes multiple partitions", "[partition_mgr]"
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulation part_0(&emu, NVS_FLASH_SECTOR * SPI_FLASH_SEC_SIZE, NVS_FLASH_SECTOR_COUNT_MIN * SPI_FLASH_SEC_SIZE, "test1");
|
||||
PartitionEmulation part_1(&emu, NVS_FLASH_SECTOR * SPI_FLASH_SEC_SIZE, NVS_FLASH_SECTOR_COUNT_MIN * SPI_FLASH_SEC_SIZE, "test2");
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test1", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&part_0, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
// TODO: why does this work, actually? same sectors used as above
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test2", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&part_1, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
Storage *storage1 = NVSPartitionManager::get_instance()->lookup_storage_from_name("test1");
|
||||
REQUIRE(storage1 != nullptr);
|
||||
@ -61,15 +66,17 @@ TEST_CASE("Partition manager initializes multiple partitions", "[partition_mgr]"
|
||||
REQUIRE(storage2 != nullptr);
|
||||
|
||||
CHECK(storage1 != storage2);
|
||||
REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(part_0.get_partition_name()) == ESP_OK);
|
||||
REQUIRE(NVSPartitionManager::get_instance()->deinit_partition(part_1.get_partition_name()) == ESP_OK);
|
||||
}
|
||||
|
||||
TEST_CASE("Partition manager invalidates handle on partition de-init", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
PartitionEmulationFixture f(0, 10, "test");
|
||||
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom("test", NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
REQUIRE(NVSPartitionManager::get_instance()->init_custom(&f.part, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
|
||||
NVSHandleSimple *handle;
|
||||
|
@ -11,9 +11,9 @@
|
||||
// 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 <functional>
|
||||
#include "catch.hpp"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_partition.h"
|
||||
#include "spi_flash_emulation.h"
|
||||
#include <functional>
|
||||
|
||||
@ -25,14 +25,21 @@ bool range_empty_n(Tit it_begin, size_t n)
|
||||
return all_of(it_begin, it_begin + n, bind(equal_to<uint32_t>(), placeholders::_1, 0xffffffff));
|
||||
}
|
||||
|
||||
struct FlashEmuFixture {
|
||||
FlashEmuFixture(size_t sectors) : esp_part(), emu(sectors) { }
|
||||
|
||||
esp_partition_t esp_part;
|
||||
SpiFlashEmulator emu;
|
||||
};
|
||||
|
||||
TEST_CASE("flash starts with all bytes == 0xff", "[spi_flash_emu]")
|
||||
{
|
||||
SpiFlashEmulator emu(4);
|
||||
FlashEmuFixture f(4);
|
||||
|
||||
uint8_t sector[SPI_FLASH_SEC_SIZE];
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
CHECK(spi_flash_read(0, sector, sizeof(sector)) == ESP_OK);
|
||||
CHECK(esp_partition_read(&f.esp_part, 0, sector, sizeof(sector)) == ESP_OK);
|
||||
for (auto v: sector) {
|
||||
CHECK(v == 0xff);
|
||||
}
|
||||
@ -41,116 +48,139 @@ TEST_CASE("flash starts with all bytes == 0xff", "[spi_flash_emu]")
|
||||
|
||||
TEST_CASE("invalid writes are checked", "[spi_flash_emu]")
|
||||
{
|
||||
SpiFlashEmulator emu(1);
|
||||
FlashEmuFixture f(1);
|
||||
|
||||
uint32_t val = 0;
|
||||
CHECK(spi_flash_write(0, &val, 4) == ESP_OK);
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &val, 4) == ESP_OK);
|
||||
val = 1;
|
||||
CHECK(spi_flash_write(0, &val, 4) == ESP_ERR_FLASH_OP_FAIL);
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &val, 4) == ESP_ERR_FLASH_OP_FAIL);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("out of bounds writes fail", "[spi_flash_emu]")
|
||||
{
|
||||
SpiFlashEmulator emu(4);
|
||||
FlashEmuFixture f(4);
|
||||
uint32_t vals[8];
|
||||
std::fill_n(vals, 8, 0);
|
||||
CHECK(spi_flash_write(0, vals, sizeof(vals)) == ESP_OK);
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &vals, sizeof(vals)) == ESP_OK);
|
||||
|
||||
CHECK(spi_flash_write(4*4096 - sizeof(vals), vals, sizeof(vals)) == ESP_OK);
|
||||
CHECK(esp_partition_write(&f.esp_part, 4*4096 - sizeof(vals), &vals, sizeof(vals)) == ESP_OK);
|
||||
|
||||
CHECK(spi_flash_write(4*4096 - sizeof(vals) + 4, vals, sizeof(vals)) == ESP_ERR_FLASH_OP_FAIL);
|
||||
CHECK(esp_partition_write(&f.esp_part, 4*4096 - sizeof(vals) + 4, &vals, sizeof(vals)) == ESP_ERR_FLASH_OP_FAIL);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("after erase the sector is set to 0xff", "[spi_flash_emu]")
|
||||
{
|
||||
SpiFlashEmulator emu(4);
|
||||
FlashEmuFixture f(4);
|
||||
uint32_t val1 = 0xab00cd12;
|
||||
CHECK(spi_flash_write(0, &val1, sizeof(val1)) == ESP_OK);
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &val1, sizeof(val1)) == ESP_OK);
|
||||
uint32_t val2 = 0x5678efab;
|
||||
CHECK(spi_flash_write(4096 - 4, &val2, sizeof(val2)) == ESP_OK);
|
||||
CHECK(esp_partition_write(&f.esp_part, 4096 - 4, &val2, sizeof(val2)) == ESP_OK);
|
||||
|
||||
CHECK(emu.words()[0] == val1);
|
||||
CHECK(range_empty_n(emu.words() + 1, 4096 / 4 - 2));
|
||||
CHECK(emu.words()[4096 / 4 - 1] == val2);
|
||||
CHECK(f.emu.words()[0] == val1);
|
||||
CHECK(range_empty_n(f.emu.words() + 1, 4096 / 4 - 2));
|
||||
CHECK(f.emu.words()[4096 / 4 - 1] == val2);
|
||||
|
||||
CHECK(spi_flash_erase_sector(0) == ESP_OK);
|
||||
CHECK(esp_partition_erase_range(&f.esp_part, 0, SPI_FLASH_SEC_SIZE) == ESP_OK);
|
||||
|
||||
CHECK(emu.words()[0] == 0xffffffff);
|
||||
CHECK(range_empty_n(emu.words() + 1, 4096 / 4 - 2));
|
||||
CHECK(emu.words()[4096 / 4 - 1] == 0xffffffff);
|
||||
CHECK(f.emu.words()[0] == 0xffffffff);
|
||||
CHECK(range_empty_n(f.emu.words() + 1, 4096 / 4 - 2));
|
||||
CHECK(f.emu.words()[4096 / 4 - 1] == 0xffffffff);
|
||||
}
|
||||
|
||||
TEST_CASE("EMU raw read function works", "[spi_flash_emu]")
|
||||
{
|
||||
FlashEmuFixture f(4);
|
||||
uint32_t value = 0xdeadbeef;
|
||||
uint32_t read_value = 0;
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK);
|
||||
|
||||
CHECK(esp_partition_read_raw(&f.esp_part, 0, &read_value, sizeof(&read_value)) == ESP_OK);
|
||||
|
||||
CHECK(read_value == 0xdeadbeef);
|
||||
}
|
||||
|
||||
TEST_CASE("EMU raw write function works", "[spi_flash_emu]")
|
||||
{
|
||||
FlashEmuFixture f(4);
|
||||
uint32_t value = 0xdeadbeef;
|
||||
uint32_t read_value = 0;
|
||||
CHECK(esp_partition_write_raw(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK);
|
||||
|
||||
CHECK(esp_partition_read(&f.esp_part, 0, &read_value, sizeof(&read_value)) == ESP_OK);
|
||||
|
||||
CHECK(read_value == 0xdeadbeef);
|
||||
}
|
||||
|
||||
TEST_CASE("read/write/erase operation times are calculated correctly", "[spi_flash_emu]")
|
||||
{
|
||||
SpiFlashEmulator emu(1);
|
||||
FlashEmuFixture f(1);
|
||||
uint8_t data[512];
|
||||
spi_flash_read(0, data, 4);
|
||||
CHECK(emu.getTotalTime() == 7);
|
||||
CHECK(emu.getReadOps() == 1);
|
||||
CHECK(emu.getReadBytes() == 4);
|
||||
emu.clearStats();
|
||||
spi_flash_read(0, data, 8);
|
||||
CHECK(emu.getTotalTime() == 5);
|
||||
CHECK(emu.getReadOps() == 1);
|
||||
CHECK(emu.getReadBytes() == 8);
|
||||
emu.clearStats();
|
||||
spi_flash_read(0, data, 16);
|
||||
CHECK(emu.getTotalTime() == 6);
|
||||
CHECK(emu.getReadOps() == 1);
|
||||
CHECK(emu.getReadBytes() == 16);
|
||||
emu.clearStats();
|
||||
spi_flash_read(0, data, 128);
|
||||
CHECK(emu.getTotalTime() == 18);
|
||||
CHECK(emu.getReadOps() == 1);
|
||||
CHECK(emu.getReadBytes() == 128);
|
||||
emu.clearStats();
|
||||
spi_flash_read(0, data, 256);
|
||||
CHECK(emu.getTotalTime() == 32);
|
||||
emu.clearStats();
|
||||
spi_flash_read(0, data, (128+256)/2);
|
||||
CHECK(emu.getTotalTime() == (18+32)/2);
|
||||
emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, 4);
|
||||
CHECK(f.emu.getTotalTime() == 7);
|
||||
CHECK(f.emu.getReadOps() == 1);
|
||||
CHECK(f.emu.getReadBytes() == 4);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, 8);
|
||||
CHECK(f.emu.getTotalTime() == 5);
|
||||
CHECK(f.emu.getReadOps() == 1);
|
||||
CHECK(f.emu.getReadBytes() == 8);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, 16);
|
||||
CHECK(f.emu.getTotalTime() == 6);
|
||||
CHECK(f.emu.getReadOps() == 1);
|
||||
CHECK(f.emu.getReadBytes() == 16);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, 128);
|
||||
CHECK(f.emu.getTotalTime() == 18);
|
||||
CHECK(f.emu.getReadOps() == 1);
|
||||
CHECK(f.emu.getReadBytes() == 128);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, 256);
|
||||
CHECK(f.emu.getTotalTime() == 32);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, (128+256)/2);
|
||||
CHECK(f.emu.getTotalTime() == (18+32)/2);
|
||||
f.emu.clearStats();
|
||||
|
||||
spi_flash_write(0, data, 4);
|
||||
CHECK(emu.getTotalTime() == 19);
|
||||
CHECK(emu.getWriteOps() == 1);
|
||||
CHECK(emu.getWriteBytes() == 4);
|
||||
emu.clearStats();
|
||||
CHECK(emu.getWriteOps() == 0);
|
||||
CHECK(emu.getWriteBytes() == 0);
|
||||
spi_flash_write(0, data, 8);
|
||||
CHECK(emu.getTotalTime() == 23);
|
||||
emu.clearStats();
|
||||
spi_flash_write(0, data, 16);
|
||||
CHECK(emu.getTotalTime() == 35);
|
||||
CHECK(emu.getWriteOps() == 1);
|
||||
CHECK(emu.getWriteBytes() == 16);
|
||||
emu.clearStats();
|
||||
spi_flash_write(0, data, 128);
|
||||
CHECK(emu.getTotalTime() == 205);
|
||||
emu.clearStats();
|
||||
spi_flash_write(0, data, 256);
|
||||
CHECK(emu.getTotalTime() == 417);
|
||||
emu.clearStats();
|
||||
spi_flash_write(0, data, (128+256)/2);
|
||||
CHECK(emu.getTotalTime() == (205+417)/2);
|
||||
emu.clearStats();
|
||||
esp_partition_write(&f.esp_part, 0, data, 4);
|
||||
CHECK(f.emu.getTotalTime() == 19);
|
||||
CHECK(f.emu.getWriteOps() == 1);
|
||||
CHECK(f.emu.getWriteBytes() == 4);
|
||||
f.emu.clearStats();
|
||||
CHECK(f.emu.getWriteOps() == 0);
|
||||
CHECK(f.emu.getWriteBytes() == 0);
|
||||
esp_partition_write(&f.esp_part, 0, data, 8);
|
||||
CHECK(f.emu.getTotalTime() == 23);
|
||||
f.emu.clearStats();
|
||||
esp_partition_write(&f.esp_part, 0, data, 16);
|
||||
CHECK(f.emu.getTotalTime() == 35);
|
||||
CHECK(f.emu.getWriteOps() == 1);
|
||||
CHECK(f.emu.getWriteBytes() == 16);
|
||||
f.emu.clearStats();
|
||||
esp_partition_write(&f.esp_part, 0, data, 128);
|
||||
CHECK(f.emu.getTotalTime() == 205);
|
||||
f.emu.clearStats();
|
||||
esp_partition_write(&f.esp_part, 0, data, 256);
|
||||
CHECK(f.emu.getTotalTime() == 417);
|
||||
f.emu.clearStats();
|
||||
esp_partition_write(&f.esp_part, 0, data, (128+256)/2);
|
||||
CHECK(f.emu.getTotalTime() == (205+417)/2);
|
||||
f.emu.clearStats();
|
||||
|
||||
spi_flash_erase_sector(0);
|
||||
CHECK(emu.getEraseOps() == 1);
|
||||
CHECK(emu.getTotalTime() == 37142);
|
||||
esp_partition_erase_range(&f.esp_part, 0, SPI_FLASH_SEC_SIZE);
|
||||
CHECK(f.emu.getEraseOps() == 1);
|
||||
CHECK(f.emu.getTotalTime() == 37142);
|
||||
}
|
||||
|
||||
TEST_CASE("data is randomized predictably", "[spi_flash_emu]")
|
||||
{
|
||||
SpiFlashEmulator emu1(3);
|
||||
emu1.randomize(0x12345678);
|
||||
|
||||
|
||||
SpiFlashEmulator emu2(3);
|
||||
emu2.randomize(0x12345678);
|
||||
|
||||
|
||||
CHECK(std::equal(emu1.bytes(), emu1.bytes() + emu1.size(), emu2.bytes()));
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ TEST_CASE("Can read partition table", "[partition]")
|
||||
|
||||
const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||
TEST_ASSERT_NOT_NULL(p);
|
||||
TEST_ASSERT_EQUAL(0x10000, p->address);
|
||||
TEST_ASSERT_EQUAL(0x20000, p->address);
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, p->subtype);
|
||||
|
||||
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||
|
@ -202,6 +202,9 @@ const esp_partition_t *esp_partition_verify(const esp_partition_t *partition);
|
||||
/**
|
||||
* @brief Read data from the partition
|
||||
*
|
||||
* Partitions marked with an encryption flag will automatically be
|
||||
* be read and decrypted via a cache mapping.
|
||||
*
|
||||
* @param partition Pointer to partition structure obtained using
|
||||
* esp_partition_find_first or esp_partition_get.
|
||||
* Must be non-NULL.
|
||||
@ -250,7 +253,59 @@ esp_err_t esp_partition_read(const esp_partition_t* partition,
|
||||
* or one of error codes from lower-level flash driver.
|
||||
*/
|
||||
esp_err_t esp_partition_write(const esp_partition_t* partition,
|
||||
size_t dst_offset, const void* src, size_t size);
|
||||
size_t dst_offset, const void* src, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Read data from the partition
|
||||
*
|
||||
* @note This function is essentially the same as \c esp_partition_write() above.
|
||||
* It just never decrypts data but returns it as is.
|
||||
*
|
||||
* @param partition Pointer to partition structure obtained using
|
||||
* esp_partition_find_first or esp_partition_get.
|
||||
* Must be non-NULL.
|
||||
* @param dst Pointer to the buffer where data should be stored.
|
||||
* Pointer must be non-NULL and buffer must be at least 'size' bytes long.
|
||||
* @param src_offset Address of the data to be read, relative to the
|
||||
* beginning of the partition.
|
||||
* @param size Size of data to be read, in bytes.
|
||||
*
|
||||
* @return ESP_OK, if data was read successfully;
|
||||
* ESP_ERR_INVALID_ARG, if src_offset exceeds partition size;
|
||||
* ESP_ERR_INVALID_SIZE, if read would go out of bounds of the partition;
|
||||
* or one of error codes from lower-level flash driver.
|
||||
*/
|
||||
esp_err_t esp_partition_read_raw(const esp_partition_t* partition,
|
||||
size_t src_offset, void* dst, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Write data to the partition without any transformation/encryption.
|
||||
*
|
||||
* @note This function is essentially the same as \c esp_partition_write() above.
|
||||
* It just never encrypts data but writes it as is.
|
||||
*
|
||||
* Before writing data to flash, corresponding region of flash needs to be erased.
|
||||
* This can be done using esp_partition_erase_range function.
|
||||
*
|
||||
* @param partition Pointer to partition structure obtained using
|
||||
* esp_partition_find_first or esp_partition_get.
|
||||
* Must be non-NULL.
|
||||
* @param dst_offset Address where the data should be written, relative to the
|
||||
* beginning of the partition.
|
||||
* @param src Pointer to the source buffer. Pointer must be non-NULL and
|
||||
* buffer must be at least 'size' bytes long.
|
||||
* @param size Size of data to be written, in bytes.
|
||||
*
|
||||
* @note Prior to writing to flash memory, make sure it has been erased with
|
||||
* esp_partition_erase_range call.
|
||||
*
|
||||
* @return ESP_OK, if data was written successfully;
|
||||
* ESP_ERR_INVALID_ARG, if dst_offset exceeds partition size;
|
||||
* ESP_ERR_INVALID_SIZE, if write would go out of bounds of the partition;
|
||||
* or one of the error codes from lower-level flash driver.
|
||||
*/
|
||||
esp_err_t esp_partition_write_raw(const esp_partition_t* partition,
|
||||
size_t dst_offset, const void* src, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Erase part of the partition
|
||||
|
@ -402,6 +402,43 @@ esp_err_t esp_partition_write(const esp_partition_t* partition,
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_read_raw(const esp_partition_t* partition,
|
||||
size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
assert(partition != NULL);
|
||||
if (src_offset > partition->size) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (src_offset + size > partition->size) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
|
||||
return esp_flash_read(partition->flash_chip, dst, partition->address + src_offset, size);
|
||||
#else
|
||||
return spi_flash_read(partition->address + src_offset, dst, size);
|
||||
#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_write_raw(const esp_partition_t* partition,
|
||||
size_t dst_offset, const void* src, size_t size)
|
||||
{
|
||||
assert(partition != NULL);
|
||||
if (dst_offset > partition->size) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (dst_offset + size > partition->size) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
dst_offset = partition->address + dst_offset;
|
||||
|
||||
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
|
||||
return esp_flash_write(partition->flash_chip, src, dst_offset, size);
|
||||
#else
|
||||
return spi_flash_write(dst_offset, src, size);
|
||||
#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_erase_range(const esp_partition_t* partition,
|
||||
size_t offset, size_t size)
|
||||
{
|
||||
|
@ -2,10 +2,10 @@
|
||||
#
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0x9000, 0x4000
|
||||
otadata, data, ota, 0xd000, 0x2000
|
||||
phy_init, data, phy, 0xf000, 0x1000
|
||||
factory, 0, 0, 0x10000, 0x260000
|
||||
nvs, data, nvs, 0xb000, 0x5000
|
||||
otadata, data, ota, 0x10000, 0x2000
|
||||
phy_init, data, phy, 0x12000, 0x1000
|
||||
factory, 0, 0, 0x20000, 0x260000
|
||||
# these OTA partitions are used for tests, but can't fit real OTA apps in them
|
||||
# (done this way to reduce total flash usage.)
|
||||
ota_0, 0, ota_0, , 64K
|
||||
|
|
Loading…
Reference in New Issue
Block a user