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