ソースを参照

Merge branch 'feature/nvs_encryption_s2' into 'master'

NVS: using esp_partition API

Closes IDF-1340 and IDF-858

See merge request espressif/esp-idf!8683
Ivan Grokhotkov 5 年 前
コミット
96db25c861
41 ファイル変更1464 行追加845 行削除
  1. 1 1
      components/esp32/test/CMakeLists.txt
  2. 1 1
      components/esp32s2/test/CMakeLists.txt
  3. 6 0
      components/esp_common/src/esp_err_to_name.c
  4. 4 2
      components/nvs_flash/CMakeLists.txt
  5. 1 0
      components/nvs_flash/include/nvs.h
  6. 37 75
      components/nvs_flash/src/nvs_api.cpp
  7. 0 155
      components/nvs_flash/src/nvs_encr.cpp
  8. 0 63
      components/nvs_flash/src/nvs_encr.hpp
  9. 122 0
      components/nvs_flash/src/nvs_encrypted_partition.cpp
  10. 44 0
      components/nvs_flash/src/nvs_encrypted_partition.hpp
  11. 0 79
      components/nvs_flash/src/nvs_ops.cpp
  12. 0 27
      components/nvs_flash/src/nvs_ops.hpp
  13. 21 16
      components/nvs_flash/src/nvs_page.cpp
  14. 9 4
      components/nvs_flash/src/nvs_page.hpp
  15. 7 3
      components/nvs_flash/src/nvs_pagemanager.cpp
  16. 2 2
      components/nvs_flash/src/nvs_pagemanager.hpp
  17. 78 0
      components/nvs_flash/src/nvs_partition.cpp
  18. 116 0
      components/nvs_flash/src/nvs_partition.hpp
  19. 65 0
      components/nvs_flash/src/nvs_partition_lookup.cpp
  20. 18 0
      components/nvs_flash/src/nvs_partition_lookup.hpp
  21. 88 46
      components/nvs_flash/src/nvs_partition_manager.cpp
  22. 5 7
      components/nvs_flash/src/nvs_partition_manager.hpp
  23. 1 1
      components/nvs_flash/src/nvs_storage.cpp
  24. 13 5
      components/nvs_flash/src/nvs_storage.hpp
  25. 60 0
      components/nvs_flash/src/partition.hpp
  26. 2 1
      components/nvs_flash/test/CMakeLists.txt
  27. 11 2
      components/nvs_flash/test/test_nvs.c
  28. 6 3
      components/nvs_flash/test_nvs_host/Makefile
  29. 50 7
      components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp
  30. 149 0
      components/nvs_flash/test_nvs_host/test_fixtures.hpp
  31. 227 215
      components/nvs_flash/test_nvs_host/test_nvs.cpp
  32. 14 12
      components/nvs_flash/test_nvs_host/test_nvs_cxx_api.cpp
  33. 25 23
      components/nvs_flash/test_nvs_host/test_nvs_handle.cpp
  34. 55 0
      components/nvs_flash/test_nvs_host/test_nvs_partition.cpp
  35. 4 2
      components/nvs_flash/test_nvs_host/test_nvs_storage.cpp
  36. 15 8
      components/nvs_flash/test_nvs_host/test_partition_manager.cpp
  37. 109 79
      components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp
  38. 1 1
      components/partition_table/test/test_partition.c
  39. 56 1
      components/spi_flash/include/esp_partition.h
  40. 37 0
      components/spi_flash/partition.c
  41. 4 4
      tools/unit-test-app/partition_table_unit_test_app.csv

+ 1 - 1
components/esp32/test/CMakeLists.txt

@@ -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 - 1
components/esp32s2/test/CMakeLists.txt

@@ -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()
 

+ 6 - 0
components/esp_common/src/esp_err_to_name.c

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

+ 4 - 2
components/nvs_flash/CMakeLists.txt

@@ -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}"

+ 1 - 0
components/nvs_flash/include/nvs.h

@@ -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 */
 

+ 37 - 75
components/nvs_flash/src/nvs_api.cpp

@@ -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,40 +75,12 @@ 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)
 {
@@ -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;

+ 0 - 155
components/nvs_flash/src/nvs_encr.cpp

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

+ 0 - 63
components/nvs_flash/src/nvs_encr.hpp

@@ -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 - 0
components/nvs_flash/src/nvs_encrypted_partition.cpp

@@ -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 - 0
components/nvs_flash/src/nvs_encrypted_partition.hpp

@@ -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_
+

+ 0 - 79
components/nvs_flash/src/nvs_ops.cpp

@@ -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
-}

+ 0 - 27
components/nvs_flash/src/nvs_ops.hpp

@@ -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 */

+ 21 - 16
components/nvs_flash/src/nvs_page.cpp

@@ -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;

+ 9 - 4
components/nvs_flash/src/nvs_page.hpp

@@ -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;

+ 7 - 3
components/nvs_flash/src/nvs_pagemanager.cpp

@@ -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;
     }
 

+ 2 - 2
components/nvs_flash/src/nvs_pagemanager.hpp

@@ -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 - 0
components/nvs_flash/src/nvs_partition.cpp

@@ -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 - 0
components/nvs_flash/src/nvs_partition.hpp

@@ -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 - 0
components/nvs_flash/src/nvs_partition_lookup.cpp

@@ -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 - 0
components/nvs_flash/src/nvs_partition_lookup.hpp

@@ -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_

+ 88 - 46
components/nvs_flash/src/nvs_partition_manager.cpp

@@ -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;
+    }
+
+    size = p->get_size();
+
+    result = init_custom(p, 0, size / SPI_FLASH_SEC_SIZE);
+    if (result != ESP_OK) {
+        goto error;
     }
 
-    return init_custom(partition_label, partition->address / SPI_FLASH_SEC_SIZE,
-            partition->size / SPI_FLASH_SEC_SIZE);
+    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);
-}
+    if (result != ESP_OK) {
+        return result;
+    }
 
-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;
-        }
+    uint32_t size = p->get_size();
+
+    result = init_custom(p, 0, size / SPI_FLASH_SEC_SIZE);
+    if (result != ESP_OK) {
+        delete p;
+        return result;
     }
 
-    return init_custom(partName, baseSector, sectorCount);
+    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;
 }

+ 5 - 7
components/nvs_flash/src/nvs_partition_manager.hpp

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

+ 1 - 1
components/nvs_flash/src/nvs_storage.cpp

@@ -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;

+ 13 - 5
components/nvs_flash/src/nvs_storage.hpp

@@ -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 - 0
components/nvs_flash/src/partition.hpp

@@ -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_
+

+ 2 - 1
components/nvs_flash/test/CMakeLists.txt

@@ -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)

+ 11 - 2
components/nvs_flash/test/test_nvs.c

@@ -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);

+ 6 - 3
components/nvs_flash/test_nvs_host/Makefile

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

+ 50 - 7
components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp

@@ -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 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->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_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->write(des_addr, reinterpret_cast<const uint32_t*>(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 spi_flash_read(size_t src_addr, void *des_addr, size_t size)
+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->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;
     }
 

+ 149 - 0
components/nvs_flash/test_nvs_host/test_fixtures.hpp

@@ -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;
+};

ファイルの差分が大きいため隠しています
+ 227 - 215
components/nvs_flash/test_nvs_host/test_nvs.cpp


+ 14 - 12
components/nvs_flash/test_nvs_host/test_nvs_cxx_api.cpp

@@ -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);

+ 25 - 23
components/nvs_flash/test_nvs_host/test_nvs_handle.cpp

@@ -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 - 0
components/nvs_flash/test_nvs_host/test_nvs_partition.cpp

@@ -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);
+}

+ 4 - 2
components/nvs_flash/test_nvs_host/test_nvs_storage.cpp

@@ -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};

+ 15 - 8
components/nvs_flash/test_nvs_host/test_partition_manager.cpp

@@ -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;

+ 109 - 79
components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp

@@ -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(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(esp_partition_erase_range(&f.esp_part, 0, SPI_FLASH_SEC_SIZE) == ESP_OK);
+
+    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);
+}
 
-    CHECK(emu.words()[0] == val1);
-    CHECK(range_empty_n(emu.words() + 1, 4096 / 4 - 2));
-    CHECK(emu.words()[4096 / 4 - 1] == val2);
+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);
+}
 
-    CHECK(spi_flash_erase_sector(0) == ESP_OK);
+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(emu.words()[0] == 0xffffffff);
-    CHECK(range_empty_n(emu.words() + 1, 4096 / 4 - 2));
-    CHECK(emu.words()[4096 / 4 - 1] == 0xffffffff);
+    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();
-
-    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();
-
-    spi_flash_erase_sector(0);
-    CHECK(emu.getEraseOps() == 1);
-    CHECK(emu.getTotalTime() == 37142);
+    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();
+
+    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();
+
+    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()));
 }
 

+ 1 - 1
components/partition_table/test/test_partition.c

@@ -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);

+ 56 - 1
components/spi_flash/include/esp_partition.h

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

+ 37 - 0
components/spi_flash/partition.c

@@ -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)
 {

+ 4 - 4
tools/unit-test-app/partition_table_unit_test_app.csv

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

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません