1 /*
2  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "esp_partition.h"
7 #include "nvs_partition_manager.hpp"
8 #include "nvs_partition_lookup.hpp"
9 
10 #ifdef CONFIG_NVS_ENCRYPTION
11 #include "nvs_encrypted_partition.hpp"
12 #endif // CONFIG_NVS_ENCRYPTION
13 
14 namespace nvs {
15 
16 NVSPartitionManager* NVSPartitionManager::instance = nullptr;
17 
get_instance()18 NVSPartitionManager* NVSPartitionManager::get_instance()
19 {
20     if (!instance) {
21         instance = new (std::nothrow) NVSPartitionManager();
22     }
23 
24     return instance;
25 }
26 
27 #ifdef ESP_PLATFORM
init_partition(const char * partition_label)28 esp_err_t NVSPartitionManager::init_partition(const char *partition_label)
29 {
30     if (strlen(partition_label) > NVS_PART_NAME_MAX_SIZE) {
31         return ESP_ERR_INVALID_ARG;
32     }
33 
34     uint32_t size;
35     Storage* mStorage;
36 
37     mStorage = lookup_storage_from_name(partition_label);
38     if (mStorage) {
39         return ESP_OK;
40     }
41 
42     assert(SPI_FLASH_SEC_SIZE != 0);
43 
44     NVSPartition *p = nullptr;
45     esp_err_t result = partition_lookup::lookup_nvs_partition(partition_label, &p);
46 
47     if (result != ESP_OK) {
48         goto error;
49     }
50 
51     size = p->get_size();
52 
53     result = init_custom(p, 0, size / SPI_FLASH_SEC_SIZE);
54     if (result != ESP_OK) {
55         goto error;
56     }
57 
58     nvs_partition_list.push_back(p);
59 
60     return ESP_OK;
61 
62 error:
63     delete p;
64     return result;
65 }
66 #endif // ESP_PLATFORM
67 
init_custom(Partition * partition,uint32_t baseSector,uint32_t sectorCount)68 esp_err_t NVSPartitionManager::init_custom(Partition *partition, uint32_t baseSector, uint32_t sectorCount)
69 {
70     Storage* new_storage = nullptr;
71     Storage* storage = lookup_storage_from_name(partition->get_partition_name());
72     if (storage == nullptr) {
73         new_storage = new (std::nothrow) Storage(partition);
74 
75         if (new_storage == nullptr) {
76             return ESP_ERR_NO_MEM;
77         }
78 
79         storage = new_storage;
80     } else {
81         // if storage was initialized already, we don't need partition and hence delete it
82         for (auto it = nvs_partition_list.begin(); it != nvs_partition_list.end(); ++it) {
83             if (partition == it) {
84                 nvs_partition_list.erase(it);
85                 delete partition;
86                 break;
87             }
88         }
89     }
90 
91     esp_err_t err = storage->init(baseSector, sectorCount);
92     if (new_storage != nullptr) {
93         if (err == ESP_OK) {
94             nvs_storage_list.push_back(new_storage);
95         } else {
96             delete new_storage;
97         }
98     }
99     return err;
100 }
101 
102 #ifdef CONFIG_NVS_ENCRYPTION
103 #ifdef ESP_PLATFORM
secure_init_partition(const char * part_name,nvs_sec_cfg_t * cfg)104 esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg)
105 {
106     if (strlen(part_name) > NVS_PART_NAME_MAX_SIZE) {
107         return ESP_ERR_INVALID_ARG;
108     }
109 
110     Storage* mStorage;
111 
112     mStorage = lookup_storage_from_name(part_name);
113     if (mStorage != nullptr) {
114         return ESP_OK;
115     }
116 
117     NVSPartition *p;
118     esp_err_t result;
119     if (cfg != nullptr) {
120         result = partition_lookup::lookup_nvs_encrypted_partition(part_name, cfg, &p);
121     } else {
122         result = partition_lookup::lookup_nvs_partition(part_name, &p);
123     }
124 
125     if (result != ESP_OK) {
126         return result;
127     }
128 
129     uint32_t size = p->get_size();
130 
131     result = init_custom(p, 0, size / SPI_FLASH_SEC_SIZE);
132     if (result != ESP_OK) {
133         delete p;
134         return result;
135     }
136 
137     nvs_partition_list.push_back(p);
138 
139     return ESP_OK;
140 }
141 #endif // ESP_PLATFORM
142 #endif // CONFIG_NVS_ENCRYPTION
143 
deinit_partition(const char * partition_label)144 esp_err_t NVSPartitionManager::deinit_partition(const char *partition_label)
145 {
146     Storage* storage = lookup_storage_from_name(partition_label);
147     if (!storage) {
148         return ESP_ERR_NVS_NOT_INITIALIZED;
149     }
150 
151     /* Clean up handles related to the storage being deinitialized */
152     for (auto it = nvs_handles.begin(); it != nvs_handles.end(); ++it) {
153         if (it->mStoragePtr == storage) {
154             it->valid = false;
155             nvs_handles.erase(it);
156         }
157     }
158 
159     /* Finally delete the storage and its partition */
160     nvs_storage_list.erase(storage);
161     delete storage;
162 
163     for (auto it = nvs_partition_list.begin(); it != nvs_partition_list.end(); ++it) {
164         if (strcmp(it->get_partition_name(), partition_label) == 0) {
165             NVSPartition *p = it;
166             nvs_partition_list.erase(it);
167             delete p;
168             break;
169         }
170     }
171 
172     return ESP_OK;
173 }
174 
open_handle(const char * part_name,const char * ns_name,nvs_open_mode_t open_mode,NVSHandleSimple ** handle)175 esp_err_t NVSPartitionManager::open_handle(const char *part_name,
176         const char *ns_name,
177         nvs_open_mode_t open_mode,
178         NVSHandleSimple** handle)
179 {
180     uint8_t nsIndex;
181     Storage* sHandle;
182 
183     if (handle == nullptr) {
184         return ESP_ERR_INVALID_ARG;
185     }
186 
187     if (nvs_storage_list.empty()) {
188         return ESP_ERR_NVS_NOT_INITIALIZED;
189     }
190 
191     sHandle = lookup_storage_from_name(part_name);
192     if (sHandle == nullptr) {
193         return ESP_ERR_NVS_PART_NOT_FOUND;
194     }
195 
196     esp_err_t err = sHandle->createOrOpenNamespace(ns_name, open_mode == NVS_READWRITE, nsIndex);
197     if (err != ESP_OK) {
198         return err;
199     }
200 
201     NVSHandleSimple* new_handle = new (std::nothrow) NVSHandleSimple(open_mode==NVS_READONLY, nsIndex, sHandle);
202     if (new_handle == nullptr) {
203         return ESP_ERR_NO_MEM;
204     }
205 
206     nvs_handles.push_back(new_handle);
207 
208     *handle = new_handle;
209     return ESP_OK;
210 }
211 
close_handle(NVSHandleSimple * handle)212 esp_err_t NVSPartitionManager::close_handle(NVSHandleSimple* handle) {
213     for (auto it = nvs_handles.begin(); it != nvs_handles.end(); ++it) {
214         if (it == intrusive_list<NVSHandleSimple>::iterator(handle)) {
215             nvs_handles.erase(it);
216             return ESP_OK;
217         }
218     }
219 
220     return ESP_ERR_NVS_INVALID_HANDLE;
221 }
222 
open_handles_size()223 size_t NVSPartitionManager::open_handles_size()
224 {
225     return nvs_handles.size();
226 }
227 
lookup_storage_from_name(const char * name)228 Storage* NVSPartitionManager::lookup_storage_from_name(const char* name)
229 {
230     auto it = find_if(begin(nvs_storage_list), end(nvs_storage_list), [=](Storage& e) -> bool {
231         return (strcmp(e.getPartName(), name) == 0);
232     });
233 
234     if (it == end(nvs_storage_list)) {
235         return nullptr;
236     }
237     return it;
238 }
239 
240 } // nvs
241