• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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