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 "sdkconfig.h"
15 #include "nvs.hpp"
16 #include "nvs_flash.h"
17 #include "nvs_storage.hpp"
18 #include "intrusive_list.h"
19 #include "nvs_platform.hpp"
20 #include "nvs_partition_manager.hpp"
21 #include "esp_partition.h"
22 #include <functional>
23 #include "nvs_handle_simple.hpp"
24 #include "esp_err.h"
25 #include <esp_rom_crc.h>
26
27 // Uncomment this line to force output from this module
28 // #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
29 #include "esp_log.h"
30 static const char* TAG = "nvs";
31
32 class NVSHandleEntry : public intrusive_list_node<NVSHandleEntry> {
33 public:
NVSHandleEntry(nvs::NVSHandleSimple * handle,const char * part_name)34 NVSHandleEntry(nvs::NVSHandleSimple *handle, const char* part_name)
35 : nvs_handle(handle),
36 mHandle(++s_nvs_next_handle),
37 handle_part_name(part_name) { }
38
~NVSHandleEntry()39 ~NVSHandleEntry() {
40 delete nvs_handle;
41 }
42
43 nvs::NVSHandleSimple *nvs_handle;
44 nvs_handle_t mHandle;
45 const char* handle_part_name;
46 private:
47 static uint32_t s_nvs_next_handle;
48 };
49
50 uint32_t NVSHandleEntry::s_nvs_next_handle;
51
52 extern "C" void nvs_dump(const char *partName);
53
54 #ifndef LINUX_TARGET
55 SemaphoreHandle_t nvs::Lock::mSemaphore = nullptr;
56 #endif // ! LINUX_TARGET
57
58 using namespace std;
59 using namespace nvs;
60
61 static intrusive_list<NVSHandleEntry> s_nvs_handles;
62
lookup_storage_from_name(const char * name)63 static nvs::Storage* lookup_storage_from_name(const char *name)
64 {
65 return NVSPartitionManager::get_instance()->lookup_storage_from_name(name);
66 }
67
nvs_dump(const char * partName)68 extern "C" void nvs_dump(const char *partName)
69 {
70 Lock lock;
71 nvs::Storage* pStorage;
72
73 pStorage = lookup_storage_from_name(partName);
74 if (pStorage == nullptr) {
75 return;
76 }
77
78 pStorage->debugDump();
79 }
80
close_handles_and_deinit(const char * part_name)81 static esp_err_t close_handles_and_deinit(const char* part_name)
82 {
83 auto belongs_to_part = [=](NVSHandleEntry& e) -> bool {
84 return strncmp(e.nvs_handle->get_partition_name(), part_name, NVS_PART_NAME_MAX_SIZE) == 0;
85 };
86
87 auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), belongs_to_part);
88
89 while (it != end(s_nvs_handles)) {
90 s_nvs_handles.erase(it);
91 it = find_if(begin(s_nvs_handles), end(s_nvs_handles), belongs_to_part);
92 }
93
94 // Deinit partition
95 return NVSPartitionManager::get_instance()->deinit_partition(part_name);
96 }
97
nvs_flash_init_partition_ptr(const esp_partition_t * partition)98 extern "C" esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partition)
99 {
100 esp_err_t lock_result = Lock::init();
101 if (lock_result != ESP_OK) {
102 return lock_result;
103 }
104 Lock lock;
105
106 if (partition == nullptr) {
107 return ESP_ERR_INVALID_ARG;
108 }
109
110 NVSPartition *part = new (std::nothrow) NVSPartition(partition);
111 if (part == nullptr) {
112 return ESP_ERR_NO_MEM;
113 }
114
115 esp_err_t init_res = NVSPartitionManager::get_instance()->init_custom(part,
116 partition->address / SPI_FLASH_SEC_SIZE,
117 partition->size / SPI_FLASH_SEC_SIZE);
118
119 if (init_res != ESP_OK) {
120 delete part;
121 }
122
123 return init_res;
124 }
125
126 #ifndef LINUX_TARGET
nvs_flash_init_partition(const char * part_name)127 extern "C" esp_err_t nvs_flash_init_partition(const char *part_name)
128 {
129 esp_err_t lock_result = Lock::init();
130 if (lock_result != ESP_OK) {
131 return lock_result;
132 }
133 Lock lock;
134
135 return NVSPartitionManager::get_instance()->init_partition(part_name);
136 }
137
nvs_flash_init(void)138 extern "C" esp_err_t nvs_flash_init(void)
139 {
140 #ifdef CONFIG_NVS_ENCRYPTION
141 esp_err_t ret = ESP_FAIL;
142 const esp_partition_t *key_part = esp_partition_find_first(
143 ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL);
144 if (key_part == NULL) {
145 ESP_LOGE(TAG, "CONFIG_NVS_ENCRYPTION is enabled, but no partition with subtype nvs_keys found in the partition table.");
146 return ret;
147 }
148
149 nvs_sec_cfg_t cfg = {};
150 ret = nvs_flash_read_security_cfg(key_part, &cfg);
151 if (ret == ESP_ERR_NVS_KEYS_NOT_INITIALIZED) {
152 ESP_LOGI(TAG, "NVS key partition empty, generating keys");
153 ret = nvs_flash_generate_keys(key_part, &cfg);
154 if (ret != ESP_OK) {
155 ESP_LOGE(TAG, "Failed to generate keys: [0x%02X] (%s)", ret, esp_err_to_name(ret));
156 return ret;
157 }
158 } else if (ret != ESP_OK) {
159 ESP_LOGE(TAG, "Failed to read NVS security cfg: [0x%02X] (%s)", ret, esp_err_to_name(ret));
160 return ret;
161 }
162
163 ret = nvs_flash_secure_init_partition(NVS_DEFAULT_PART_NAME, &cfg);
164 if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
165 ESP_LOGE(TAG, "Failed to initialize NVS partition: [0x%02X] (%s)", ret, esp_err_to_name(ret));
166 return ret;
167 }
168 ESP_LOGI(TAG, "NVS partition \"%s\" is encrypted.", NVS_DEFAULT_PART_NAME);
169 return ret;
170 #else // CONFIG_NVS_ENCRYPTION
171 return nvs_flash_init_partition(NVS_DEFAULT_PART_NAME);
172 #endif
173 }
174
175 #ifdef CONFIG_NVS_ENCRYPTION
nvs_flash_secure_init_partition(const char * part_name,nvs_sec_cfg_t * cfg)176 extern "C" esp_err_t nvs_flash_secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg)
177 {
178 esp_err_t lock_result = Lock::init();
179 if (lock_result != ESP_OK) {
180 return lock_result;
181 }
182 Lock lock;
183
184 return NVSPartitionManager::get_instance()->secure_init_partition(part_name, cfg);
185 }
186
nvs_flash_secure_init(nvs_sec_cfg_t * cfg)187 extern "C" esp_err_t nvs_flash_secure_init(nvs_sec_cfg_t* cfg)
188 {
189 return nvs_flash_secure_init_partition(NVS_DEFAULT_PART_NAME, cfg);
190 }
191 #endif
192
nvs_flash_erase_partition(const char * part_name)193 extern "C" esp_err_t nvs_flash_erase_partition(const char *part_name)
194 {
195 esp_err_t lock_result = Lock::init();
196 if (lock_result != ESP_OK) {
197 return lock_result;
198 }
199 Lock lock;
200
201 // if the partition is initialized, uninitialize it first
202 if (NVSPartitionManager::get_instance()->lookup_storage_from_name(part_name)) {
203 esp_err_t err = close_handles_and_deinit(part_name);
204
205 // only hypothetical/future case, deinit_partition() only fails if partition is uninitialized
206 if (err != ESP_OK) {
207 return err;
208 }
209 }
210
211 const esp_partition_t* partition = esp_partition_find_first(
212 ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name);
213 if (partition == nullptr) {
214 return ESP_ERR_NOT_FOUND;
215 }
216
217 return esp_partition_erase_range(partition, 0, partition->size);
218 }
219
nvs_flash_erase_partition_ptr(const esp_partition_t * partition)220 extern "C" esp_err_t nvs_flash_erase_partition_ptr(const esp_partition_t *partition)
221 {
222 esp_err_t lock_result = Lock::init();
223 if (lock_result != ESP_OK) {
224 return lock_result;
225 }
226 Lock lock;
227
228 if (partition == nullptr) {
229 return ESP_ERR_INVALID_ARG;
230 }
231
232 // if the partition is initialized, uninitialize it first
233 if (NVSPartitionManager::get_instance()->lookup_storage_from_name(partition->label)) {
234 const esp_err_t err = close_handles_and_deinit(partition->label);
235
236 // only hypothetical/future case, deinit_partition() only fails if partition is uninitialized
237 if (err != ESP_OK) {
238 return err;
239 }
240 }
241
242 return esp_partition_erase_range(partition, 0, partition->size);
243 }
244
nvs_flash_erase(void)245 extern "C" esp_err_t nvs_flash_erase(void)
246 {
247 return nvs_flash_erase_partition(NVS_DEFAULT_PART_NAME);
248 }
249 #endif // ! LINUX_TARGET
250
nvs_flash_deinit_partition(const char * partition_name)251 extern "C" esp_err_t nvs_flash_deinit_partition(const char* partition_name)
252 {
253 esp_err_t lock_result = Lock::init();
254 if (lock_result != ESP_OK) {
255 return lock_result;
256 }
257 Lock lock;
258
259 return close_handles_and_deinit(partition_name);
260 }
261
nvs_flash_deinit(void)262 extern "C" esp_err_t nvs_flash_deinit(void)
263 {
264 return nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME);
265 }
266
nvs_find_ns_handle(nvs_handle_t c_handle,NVSHandleSimple ** handle)267 static esp_err_t nvs_find_ns_handle(nvs_handle_t c_handle, NVSHandleSimple** handle)
268 {
269 auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](NVSHandleEntry& e) -> bool {
270 return e.mHandle == c_handle;
271 });
272 if (it == end(s_nvs_handles)) {
273 return ESP_ERR_NVS_INVALID_HANDLE;
274 }
275 *handle = it->nvs_handle;
276 return ESP_OK;
277 }
278
nvs_open_from_partition(const char * part_name,const char * name,nvs_open_mode_t open_mode,nvs_handle_t * out_handle)279 extern "C" esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle)
280 {
281 Lock lock;
282 ESP_LOGD(TAG, "%s %s %d", __func__, name, open_mode);
283
284 NVSHandleSimple *handle;
285 esp_err_t result = NVSPartitionManager::get_instance()->open_handle(part_name, name, open_mode, &handle);
286 if (result == ESP_OK) {
287 NVSHandleEntry *entry = new (std::nothrow) NVSHandleEntry(handle, part_name);
288 if (entry) {
289 s_nvs_handles.push_back(entry);
290 *out_handle = entry->mHandle;
291 } else {
292 delete handle;
293 return ESP_ERR_NO_MEM;
294 }
295 }
296
297 return result;
298 }
299
nvs_open(const char * name,nvs_open_mode_t open_mode,nvs_handle_t * out_handle)300 extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle)
301 {
302 return nvs_open_from_partition(NVS_DEFAULT_PART_NAME, name, open_mode, out_handle);
303 }
304
nvs_close(nvs_handle_t handle)305 extern "C" void nvs_close(nvs_handle_t handle)
306 {
307 Lock lock;
308 ESP_LOGD(TAG, "%s %d", __func__, static_cast<int>(handle));
309 auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](NVSHandleEntry& e) -> bool {
310 return e.mHandle == handle;
311 });
312 if (it == end(s_nvs_handles)) {
313 return;
314 }
315 s_nvs_handles.erase(it);
316 delete static_cast<NVSHandleEntry*>(it);
317 }
318
nvs_erase_key(nvs_handle_t c_handle,const char * key)319 extern "C" esp_err_t nvs_erase_key(nvs_handle_t c_handle, const char* key)
320 {
321 Lock lock;
322 ESP_LOGD(TAG, "%s %s\r\n", __func__, key);
323 NVSHandleSimple *handle;
324 auto err = nvs_find_ns_handle(c_handle, &handle);
325 if (err != ESP_OK) {
326 return err;
327 }
328
329 return handle->erase_item(key);
330 }
331
nvs_erase_all(nvs_handle_t c_handle)332 extern "C" esp_err_t nvs_erase_all(nvs_handle_t c_handle)
333 {
334 Lock lock;
335 ESP_LOGD(TAG, "%s\r\n", __func__);
336 NVSHandleSimple *handle;
337 auto err = nvs_find_ns_handle(c_handle, &handle);
338 if (err != ESP_OK) {
339 return err;
340 }
341
342 return handle->erase_all();
343 }
344
345 template<typename T>
nvs_set(nvs_handle_t c_handle,const char * key,T value)346 static esp_err_t nvs_set(nvs_handle_t c_handle, const char* key, T value)
347 {
348 Lock lock;
349 ESP_LOGD(TAG, "%s %s %d %ld", __func__, key, static_cast<int>(sizeof(T)), static_cast<long int>(value));
350 NVSHandleSimple *handle;
351 auto err = nvs_find_ns_handle(c_handle, &handle);
352 if (err != ESP_OK) {
353 return err;
354 }
355
356 return handle->set_item(key, value);
357 }
358
nvs_set_i8(nvs_handle_t handle,const char * key,int8_t value)359 extern "C" esp_err_t nvs_set_i8 (nvs_handle_t handle, const char* key, int8_t value)
360 {
361 return nvs_set(handle, key, value);
362 }
363
nvs_set_u8(nvs_handle_t handle,const char * key,uint8_t value)364 extern "C" esp_err_t nvs_set_u8 (nvs_handle_t handle, const char* key, uint8_t value)
365 {
366 return nvs_set(handle, key, value);
367 }
368
nvs_set_i16(nvs_handle_t handle,const char * key,int16_t value)369 extern "C" esp_err_t nvs_set_i16 (nvs_handle_t handle, const char* key, int16_t value)
370 {
371 return nvs_set(handle, key, value);
372 }
373
nvs_set_u16(nvs_handle_t handle,const char * key,uint16_t value)374 extern "C" esp_err_t nvs_set_u16 (nvs_handle_t handle, const char* key, uint16_t value)
375 {
376 return nvs_set(handle, key, value);
377 }
378
nvs_set_i32(nvs_handle_t handle,const char * key,int32_t value)379 extern "C" esp_err_t nvs_set_i32 (nvs_handle_t handle, const char* key, int32_t value)
380 {
381 return nvs_set(handle, key, value);
382 }
383
nvs_set_u32(nvs_handle_t handle,const char * key,uint32_t value)384 extern "C" esp_err_t nvs_set_u32 (nvs_handle_t handle, const char* key, uint32_t value)
385 {
386 return nvs_set(handle, key, value);
387 }
388
nvs_set_i64(nvs_handle_t handle,const char * key,int64_t value)389 extern "C" esp_err_t nvs_set_i64 (nvs_handle_t handle, const char* key, int64_t value)
390 {
391 return nvs_set(handle, key, value);
392 }
393
nvs_set_u64(nvs_handle_t handle,const char * key,uint64_t value)394 extern "C" esp_err_t nvs_set_u64 (nvs_handle_t handle, const char* key, uint64_t value)
395 {
396 return nvs_set(handle, key, value);
397 }
398
nvs_commit(nvs_handle_t c_handle)399 extern "C" esp_err_t nvs_commit(nvs_handle_t c_handle)
400 {
401 Lock lock;
402 // no-op for now, to be used when intermediate cache is added
403 NVSHandleSimple *handle;
404 auto err = nvs_find_ns_handle(c_handle, &handle);
405 if (err != ESP_OK) {
406 return err;
407 }
408 return handle->commit();
409 }
410
nvs_set_str(nvs_handle_t c_handle,const char * key,const char * value)411 extern "C" esp_err_t nvs_set_str(nvs_handle_t c_handle, const char* key, const char* value)
412 {
413 Lock lock;
414 ESP_LOGD(TAG, "%s %s %s", __func__, key, value);
415 NVSHandleSimple *handle;
416 auto err = nvs_find_ns_handle(c_handle, &handle);
417 if (err != ESP_OK) {
418 return err;
419 }
420 return handle->set_string(key, value);
421 }
422
nvs_set_blob(nvs_handle_t c_handle,const char * key,const void * value,size_t length)423 extern "C" esp_err_t nvs_set_blob(nvs_handle_t c_handle, const char* key, const void* value, size_t length)
424 {
425 Lock lock;
426 ESP_LOGD(TAG, "%s %s %d", __func__, key, static_cast<int>(length));
427 NVSHandleSimple *handle;
428 auto err = nvs_find_ns_handle(c_handle, &handle);
429 if (err != ESP_OK) {
430 return err;
431 }
432 return handle->set_blob(key, value, length);
433 }
434
435
436 template<typename T>
nvs_get(nvs_handle_t c_handle,const char * key,T * out_value)437 static esp_err_t nvs_get(nvs_handle_t c_handle, const char* key, T* out_value)
438 {
439 Lock lock;
440 ESP_LOGD(TAG, "%s %s %ld", __func__, key, static_cast<long int>(sizeof(T)));
441 NVSHandleSimple *handle;
442 auto err = nvs_find_ns_handle(c_handle, &handle);
443 if (err != ESP_OK) {
444 return err;
445 }
446 return handle->get_item(key, *out_value);
447 }
448
nvs_get_i8(nvs_handle_t c_handle,const char * key,int8_t * out_value)449 extern "C" esp_err_t nvs_get_i8 (nvs_handle_t c_handle, const char* key, int8_t* out_value)
450 {
451 return nvs_get(c_handle, key, out_value);
452 }
453
nvs_get_u8(nvs_handle_t c_handle,const char * key,uint8_t * out_value)454 extern "C" esp_err_t nvs_get_u8 (nvs_handle_t c_handle, const char* key, uint8_t* out_value)
455 {
456 return nvs_get(c_handle, key, out_value);
457 }
458
nvs_get_i16(nvs_handle_t c_handle,const char * key,int16_t * out_value)459 extern "C" esp_err_t nvs_get_i16 (nvs_handle_t c_handle, const char* key, int16_t* out_value)
460 {
461 return nvs_get(c_handle, key, out_value);
462 }
463
nvs_get_u16(nvs_handle_t c_handle,const char * key,uint16_t * out_value)464 extern "C" esp_err_t nvs_get_u16 (nvs_handle_t c_handle, const char* key, uint16_t* out_value)
465 {
466 return nvs_get(c_handle, key, out_value);
467 }
468
nvs_get_i32(nvs_handle_t c_handle,const char * key,int32_t * out_value)469 extern "C" esp_err_t nvs_get_i32 (nvs_handle_t c_handle, const char* key, int32_t* out_value)
470 {
471 return nvs_get(c_handle, key, out_value);
472 }
473
nvs_get_u32(nvs_handle_t c_handle,const char * key,uint32_t * out_value)474 extern "C" esp_err_t nvs_get_u32 (nvs_handle_t c_handle, const char* key, uint32_t* out_value)
475 {
476 return nvs_get(c_handle, key, out_value);
477 }
478
nvs_get_i64(nvs_handle_t c_handle,const char * key,int64_t * out_value)479 extern "C" esp_err_t nvs_get_i64 (nvs_handle_t c_handle, const char* key, int64_t* out_value)
480 {
481 return nvs_get(c_handle, key, out_value);
482 }
483
nvs_get_u64(nvs_handle_t c_handle,const char * key,uint64_t * out_value)484 extern "C" esp_err_t nvs_get_u64 (nvs_handle_t c_handle, const char* key, uint64_t* out_value)
485 {
486 return nvs_get(c_handle, key, out_value);
487 }
488
nvs_get_str_or_blob(nvs_handle_t c_handle,nvs::ItemType type,const char * key,void * out_value,size_t * length)489 static esp_err_t nvs_get_str_or_blob(nvs_handle_t c_handle, nvs::ItemType type, const char* key, void* out_value, size_t* length)
490 {
491 Lock lock;
492 ESP_LOGD(TAG, "%s %s", __func__, key);
493 NVSHandleSimple *handle;
494 auto err = nvs_find_ns_handle(c_handle, &handle);
495 if (err != ESP_OK) {
496 return err;
497 }
498
499 size_t dataSize;
500 err = handle->get_item_size(type, key, dataSize);
501 if (err != ESP_OK) {
502 return err;
503 }
504
505 if (length == nullptr) {
506 return ESP_ERR_NVS_INVALID_LENGTH;
507 } else if (out_value == nullptr) {
508 *length = dataSize;
509 return ESP_OK;
510 } else if (*length < dataSize) {
511 *length = dataSize;
512 return ESP_ERR_NVS_INVALID_LENGTH;
513 }
514
515 *length = dataSize;
516 return handle->get_typed_item(type, key, out_value, dataSize);
517 }
518
nvs_get_str(nvs_handle_t c_handle,const char * key,char * out_value,size_t * length)519 extern "C" esp_err_t nvs_get_str(nvs_handle_t c_handle, const char* key, char* out_value, size_t* length)
520 {
521 return nvs_get_str_or_blob(c_handle, nvs::ItemType::SZ, key, out_value, length);
522 }
523
nvs_get_blob(nvs_handle_t c_handle,const char * key,void * out_value,size_t * length)524 extern "C" esp_err_t nvs_get_blob(nvs_handle_t c_handle, const char* key, void* out_value, size_t* length)
525 {
526 return nvs_get_str_or_blob(c_handle, nvs::ItemType::BLOB, key, out_value, length);
527 }
528
nvs_get_stats(const char * part_name,nvs_stats_t * nvs_stats)529 extern "C" esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats)
530 {
531 Lock lock;
532 nvs::Storage* pStorage;
533
534 if (nvs_stats == nullptr) {
535 return ESP_ERR_INVALID_ARG;
536 }
537 nvs_stats->used_entries = 0;
538 nvs_stats->free_entries = 0;
539 nvs_stats->total_entries = 0;
540 nvs_stats->namespace_count = 0;
541
542 pStorage = lookup_storage_from_name((part_name == nullptr) ? NVS_DEFAULT_PART_NAME : part_name);
543 if (pStorage == nullptr) {
544 return ESP_ERR_NVS_NOT_INITIALIZED;
545 }
546
547 if(!pStorage->isValid()){
548 return ESP_ERR_NVS_INVALID_STATE;
549 }
550
551 return pStorage->fillStats(*nvs_stats);
552 }
553
nvs_get_used_entry_count(nvs_handle_t c_handle,size_t * used_entries)554 extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle_t c_handle, size_t* used_entries)
555 {
556 Lock lock;
557 if(used_entries == nullptr){
558 return ESP_ERR_INVALID_ARG;
559 }
560 *used_entries = 0;
561
562 NVSHandleSimple *handle;
563 auto err = nvs_find_ns_handle(c_handle, &handle);
564 if (err != ESP_OK) {
565 return err;
566 }
567
568 size_t used_entry_count;
569 err = handle->get_used_entry_count(used_entry_count);
570 if(err == ESP_OK){
571 *used_entries = used_entry_count;
572 }
573 return err;
574 }
575
576 #if (defined CONFIG_NVS_ENCRYPTION) && (!defined LINUX_TARGET)
577
nvs_flash_generate_keys(const esp_partition_t * partition,nvs_sec_cfg_t * cfg)578 extern "C" esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_t* cfg)
579 {
580 if (cfg == nullptr || partition == nullptr) {
581 return ESP_ERR_INVALID_ARG;
582 }
583
584 auto err = esp_partition_erase_range(partition, 0, partition->size);
585 if(err != ESP_OK) {
586 return err;
587 }
588
589 for(uint8_t cnt = 0; cnt < NVS_KEY_SIZE; cnt++) {
590 /* Adjacent 16-byte blocks should be different */
591 if (((cnt / 16) & 1) == 0) {
592 cfg->eky[cnt] = 0xff;
593 cfg->tky[cnt] = 0xee;
594 } else {
595 cfg->eky[cnt] = 0x99;
596 cfg->tky[cnt] = 0x88;
597 }
598 }
599
600 /**
601 * Write key configuration without encryption engine (using raw partition write APIs).
602 * But the read is decrypted through flash encryption engine. This allows unique NVS encryption configuration,
603 * as flash encryption key is randomly generated per device.
604 */
605 err = esp_partition_write_raw(partition, 0, cfg->eky, NVS_KEY_SIZE);
606 if(err != ESP_OK) {
607 return err;
608 }
609
610 /* Write without encryption, see note above */
611 err = esp_partition_write_raw(partition, NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE);
612 if(err != ESP_OK) {
613 return err;
614 }
615
616 err = esp_partition_read(partition, 0, cfg->eky, NVS_KEY_SIZE);
617 if(err != ESP_OK) {
618 return err;
619 }
620
621 err = esp_partition_read(partition, NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE);
622 if(err != ESP_OK) {
623 return err;
624 }
625
626 uint32_t crc_calc = esp_rom_crc32_le(0xffffffff, cfg->eky, NVS_KEY_SIZE);
627 crc_calc = esp_rom_crc32_le(crc_calc, cfg->tky, NVS_KEY_SIZE);
628
629 uint8_t crc_wr[16];
630 memset(crc_wr, 0xff, sizeof(crc_wr));
631 memcpy(crc_wr, &crc_calc, 4);
632
633 err = esp_partition_write(partition, 2 * NVS_KEY_SIZE, crc_wr, sizeof(crc_wr));
634 if(err != ESP_OK) {
635 return err;
636 }
637
638 return ESP_OK;
639
640 }
641
nvs_flash_read_security_cfg(const esp_partition_t * partition,nvs_sec_cfg_t * cfg)642 extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partition, nvs_sec_cfg_t* cfg)
643 {
644 if (cfg == nullptr || partition == nullptr) {
645 return ESP_ERR_INVALID_ARG;
646 }
647
648 uint8_t eky_raw[NVS_KEY_SIZE], tky_raw[NVS_KEY_SIZE];
649 uint32_t crc_raw, crc_read, crc_calc;
650
651 auto check_if_initialized = [](uint8_t* eky, uint8_t* tky, uint32_t crc) {
652 uint8_t cnt = 0;
653 while(cnt < NVS_KEY_SIZE && eky[cnt] == 0xff && tky[cnt] == 0xff) cnt++;
654
655 if(cnt == NVS_KEY_SIZE && crc == 0xffffffff) {
656 return false;
657 }
658 return true;
659 };
660
661 auto err = esp_partition_read_raw(partition, 0, eky_raw, NVS_KEY_SIZE);
662 if(err != ESP_OK) {
663 return err;
664 }
665
666 err = esp_partition_read_raw(partition, NVS_KEY_SIZE, tky_raw, NVS_KEY_SIZE);
667 if(err != ESP_OK) {
668 return err;
669 }
670
671 err = esp_partition_read_raw(partition, 2 * NVS_KEY_SIZE, &crc_raw, 4);
672 if(err != ESP_OK) {
673 return err;
674 }
675
676 if(!check_if_initialized(eky_raw, tky_raw, crc_raw)) {
677 /* This is an uninitialized key partition*/
678 return ESP_ERR_NVS_KEYS_NOT_INITIALIZED;
679 }
680
681 err = esp_partition_read(partition, 0, cfg->eky, NVS_KEY_SIZE);
682
683 if(err != ESP_OK) {
684 return err;
685 }
686
687 err = esp_partition_read(partition, NVS_KEY_SIZE, cfg->tky, NVS_KEY_SIZE);
688
689 if(err != ESP_OK) {
690 return err;
691 }
692
693 err = esp_partition_read(partition, 2 * NVS_KEY_SIZE, &crc_read, 4);
694
695 if(err != ESP_OK) {
696 return err;
697 }
698
699 crc_calc = esp_rom_crc32_le(0xffffffff, cfg->eky, NVS_KEY_SIZE);
700 crc_calc = esp_rom_crc32_le(crc_calc, cfg->tky, NVS_KEY_SIZE);
701
702 if(crc_calc != crc_read) {
703 if(!check_if_initialized(cfg->eky, cfg->tky, crc_read)) {
704 /* This is an uninitialized key partition*/
705 return ESP_ERR_NVS_KEYS_NOT_INITIALIZED;
706 }
707 return ESP_ERR_NVS_CORRUPT_KEY_PART;
708 }
709
710 return ESP_OK;
711 }
712
713 #endif
714
create_iterator(nvs::Storage * storage,nvs_type_t type)715 static nvs_iterator_t create_iterator(nvs::Storage *storage, nvs_type_t type)
716 {
717 nvs_iterator_t it = (nvs_iterator_t)calloc(1, sizeof(nvs_opaque_iterator_t));
718 if (it == nullptr) {
719 return nullptr;
720 }
721
722 it->storage = storage;
723 it->type = type;
724
725 return it;
726 }
727
nvs_entry_find(const char * part_name,const char * namespace_name,nvs_type_t type)728 extern "C" nvs_iterator_t nvs_entry_find(const char *part_name, const char *namespace_name, nvs_type_t type)
729 {
730 Lock lock;
731 nvs::Storage *pStorage;
732
733 pStorage = lookup_storage_from_name(part_name);
734 if (pStorage == nullptr) {
735 return nullptr;
736 }
737
738 nvs_iterator_t it = create_iterator(pStorage, type);
739 if (it == nullptr) {
740 return nullptr;
741 }
742
743 bool entryFound = pStorage->findEntry(it, namespace_name);
744 if (!entryFound) {
745 free(it);
746 return nullptr;
747 }
748
749 return it;
750 }
751
nvs_entry_next(nvs_iterator_t it)752 extern "C" nvs_iterator_t nvs_entry_next(nvs_iterator_t it)
753 {
754 Lock lock;
755 assert(it);
756
757 bool entryFound = it->storage->nextEntry(it);
758 if (!entryFound) {
759 free(it);
760 return nullptr;
761 }
762
763 return it;
764 }
765
nvs_entry_info(nvs_iterator_t it,nvs_entry_info_t * out_info)766 extern "C" void nvs_entry_info(nvs_iterator_t it, nvs_entry_info_t *out_info)
767 {
768 *out_info = it->entry_info;
769 }
770
nvs_release_iterator(nvs_iterator_t it)771 extern "C" void nvs_release_iterator(nvs_iterator_t it)
772 {
773 free(it);
774 }
775