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