1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 * Description: NV Storage Library Restore factory settings interface
15 */
16 #include "nv.h"
17 #include "nv_store.h"
18 #include "nv_page.h"
19 #include "nv_storage.h"
20 #include "nv_nvregion.h"
21 #include "nv_porting.h"
22 #include "nv_notify.h"
23 #include "nv_task_adapt.h"
24 #include "nv_update.h"
25 #include "common_def.h"
26 #include "nv_storage_handle.h"
27 #include "nv_reset.h"
28
29 #if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
30
31 bool g_reset_region_flag[KEY_ID_REGION_MAX_NUM] = {0};
32
33 #define RESET_MAX_BINARY_VAL 1
34 #define assert_r(x) ((void)0)
35 #define NV_RESTORE_MAX_KEY 4060
36
kv_region_is_enable(uint16_t key_id)37 STATIC errcode_t kv_region_is_enable(uint16_t key_id)
38 {
39 uint16_t region_id = key_id / REGION_KEY_NUMS;
40 if (region_id < KEY_ID_REGION_MAX_NUM && g_reset_region_flag[region_id]) {
41 return ERRCODE_SUCC;
42 }
43 return ERRCODE_FAIL;
44 }
45
kv_backup_set_invalid_key(const kv_key_handle_t * key)46 errcode_t kv_backup_set_invalid_key(const kv_key_handle_t *key)
47 {
48 /* 如果key还是初始化时的状态,说明NV区域没有这个key,不需要将原来的key设置为无效, 返回成功不影响后续流程 */
49 if (key->key_location == 0) {
50 return ERRCODE_SUCC;
51 }
52
53 /* 计算valid相对于key起始的位置,即要写入数据在flash中相对于key_location的偏移量 */
54 uint32_t offset = ((uint32_t)(uintptr_t)&key->header.valid) - ((uint32_t)(uintptr_t)key);
55 uint32_t write_position = (uint32_t)(uintptr_t)key->key_location + offset - FLASH_PHYSICAL_ADDR_START;
56 uint32_t write_length = (uint32_t)sizeof(key->header.valid);
57 uint8_t *write_data = (uint8_t *)kv_zalloc(write_length);
58 if (write_data == NULL) {
59 return ERRCODE_MALLOC;
60 }
61 errcode_t ret = kv_flash_write(write_position, write_length, write_data, false);
62 kv_free(write_data);
63 return ret;
64 }
65
kv_backup_delete_one_page_repeat_key(kv_page_handle_t * page)66 STATIC errcode_t kv_backup_delete_one_page_repeat_key(kv_page_handle_t *page)
67 {
68 errcode_t ret;
69 kv_key_handle_t key;
70 errcode_t key_found = kv_page_find_first_key(page, NULL, &key);
71 while (key_found == ERRCODE_SUCC) {
72 if ((kv_key_is_valid(&key)) && (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC)) {
73 ret = kv_backup_set_invalid_key(&key);
74 if (ret != ERRCODE_SUCC) {
75 return ret;
76 }
77 }
78 key_found = kv_page_find_next_key(page, NULL, &key);
79 }
80 return ERRCODE_SUCC;
81 }
82
kv_backup_delete_repeat_key(void)83 errcode_t kv_backup_delete_repeat_key(void)
84 {
85 errcode_t ret;
86 kv_page_handle_t page;
87 kv_nvregion_area_t* nvregion_area = nv_get_region_area();
88 if (nvregion_area == NULL) {
89 return ERRCODE_FAIL;
90 }
91 uint32_t page_start = nvregion_area->nv_backup_addr;
92 /* 遍历备份区,将每个要被重复备份的key标志位置为无效 */
93 for (uint32_t page_index = 0; page_index < KV_BACKUP_PAGE_NUM; page_index++) {
94 page.page_location = (kv_page_location)(uintptr_t)(page_start + page_index * KV_PAGE_SIZE);
95 ret = kv_backup_delete_one_page_repeat_key(&page);
96 if (ret != ERRCODE_SUCC) {
97 return ret;
98 }
99 }
100
101 return ERRCODE_SUCC;
102 }
103
kv_backup_dragpage_switch_unused_page(kv_page_handle_t dragpage,kv_page_handle_t unused_page)104 STATIC errcode_t kv_backup_dragpage_switch_unused_page(kv_page_handle_t dragpage, kv_page_handle_t unused_page)
105 {
106 /* 将换页页内容转移到unused page */
107 errcode_t ret;
108 uint32_t page_head_size = (uint32_t)sizeof(kv_page_header_t);
109
110 /* 将换页页的页头转移到unused page */
111 kv_page_header_t head_buffer;
112 ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&head_buffer,
113 (uint32_t)(uintptr_t)dragpage.page_location, (uint16_t)page_head_size);
114 if (ret != ERRCODE_SUCC) {
115 return ret;
116 }
117 ret = kv_key_write_flash((uint32_t)(uintptr_t)unused_page.page_location, page_head_size, (uint8_t *)&head_buffer);
118 if (ret != ERRCODE_SUCC) {
119 return ret;
120 }
121
122 kv_key_handle_t key;
123 uint16_t key_size;
124 uint32_t write_position = (uint32_t)((uintptr_t)unused_page.page_location + page_head_size);
125 /* 将换页页的有效的key转移到unused page */
126 errcode_t key_found = kv_page_find_first_key(&dragpage, NULL, &key);
127 while (key_found == ERRCODE_SUCC) {
128 if (kv_key_is_valid(&key)) {
129 key_size = kv_key_flash_size(&key);
130 uint8_t *kv_buffer = (uint8_t *)kv_zalloc(key_size);
131 if (kv_buffer == NULL) {
132 return ERRCODE_MALLOC;
133 }
134 ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)kv_buffer, (uint32_t)(uintptr_t)key.key_location,
135 key_size);
136 if (ret != ERRCODE_SUCC) {
137 kv_free(kv_buffer);
138 return ret;
139 }
140 ret = kv_key_write_flash(write_position, key_size, kv_buffer);
141 if (ret != ERRCODE_SUCC) {
142 kv_free(kv_buffer);
143 return ret;
144 }
145 kv_free(kv_buffer);
146 write_position += key_size;
147 }
148 key_found = kv_page_find_next_key(&dragpage, NULL, &key);
149 }
150
151 return ERRCODE_SUCC;
152 }
153
kv_backup_copy_unused_page_to_dragpage(uint32_t dragpage_location,uint32_t unused_page_location)154 errcode_t kv_backup_copy_unused_page_to_dragpage(uint32_t dragpage_location, uint32_t unused_page_location)
155 {
156 errcode_t ret;
157
158 /* 首先将工作区用来换页的页的key内容全部转移到备份区原来的页上 */
159 uint8_t *page_buffer = (uint8_t *)kv_malloc(KV_PAGE_SIZE - sizeof(kv_page_header_t));
160 if (page_buffer == NULL) {
161 return ERRCODE_MALLOC;
162 }
163 ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)page_buffer,
164 unused_page_location + sizeof(kv_page_header_t), KV_PAGE_SIZE - sizeof(kv_page_header_t));
165 if (ret != ERRCODE_SUCC) {
166 kv_free(page_buffer);
167 return ret;
168 }
169 ret = kv_key_write_flash(dragpage_location + sizeof(kv_page_header_t),
170 KV_PAGE_SIZE - sizeof(kv_page_header_t), page_buffer);
171 if (ret != ERRCODE_SUCC) {
172 kv_free(page_buffer);
173 return ret;
174 }
175 kv_free(page_buffer);
176
177 /* 其次拷贝工作区换页页的页头内容:先拷贝页内容,后拷贝页头是为了更好的处理换页时掉电异常场景 */
178 kv_page_header_t head_buffer;
179 ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&head_buffer,
180 unused_page_location, sizeof(kv_page_header_t));
181 if (ret != ERRCODE_SUCC) {
182 return ret;
183 }
184 ret = kv_key_write_flash(dragpage_location, sizeof(kv_page_header_t), (uint8_t *)&head_buffer);
185 if (ret != ERRCODE_SUCC) {
186 return ret;
187 }
188
189 return ERRCODE_SUCC;
190 }
191
192 /* 备份区换页处理机制 */
kv_backup_dragpage_process(kv_page_handle_t dragpage)193 STATIC errcode_t kv_backup_dragpage_process(kv_page_handle_t dragpage)
194 {
195 errcode_t ret;
196 kv_page_handle_t unused_page;
197 kv_page_location unused_page_location = NULL;
198 /* 1、去找工作区可以换页的页,然后将可以换页的页地址给传出 */
199 ret = kv_nvregion_find_unused_page(&unused_page_location);
200 if (ret != ERRCODE_SUCC) {
201 return ret;
202 }
203 /* 2、将工作区内可以换页的页的内容擦除 */
204 ret = kv_nvregion_erase_page(unused_page_location);
205 if (ret != ERRCODE_SUCC) {
206 return ret;
207 }
208 unused_page.page_location = unused_page_location;
209 /* 3、将备份区要换页的内容拷贝到工作区可以换页的页上 */
210 ret = kv_backup_dragpage_switch_unused_page(dragpage, unused_page);
211 if (ret != ERRCODE_SUCC) {
212 return ret;
213 }
214 /* 4、将备份区要换页的页擦除内容 */
215 ret = kv_key_erase_flash((uint32_t)(uintptr_t)dragpage.page_location, KV_PAGE_SIZE);
216 if (ret != ERRCODE_SUCC) {
217 return ret;
218 }
219 /* 5、将换页页的内容拷贝到备份区被擦除的页上 */
220 ret = kv_backup_copy_unused_page_to_dragpage((uint32_t)(uintptr_t)dragpage.page_location,
221 (uint32_t)(uintptr_t)unused_page.page_location);
222 if (ret != ERRCODE_SUCC) {
223 return ret;
224 }
225 /* 6、擦除工作区换页页 */
226 ret = kv_nvregion_erase_page(unused_page_location);
227 if (ret != ERRCODE_SUCC) {
228 return ret;
229 }
230
231 return ERRCODE_SUCC;
232 }
233
kv_backup_find_write_position(uint16_t required_space,uint32_t * write_position)234 errcode_t kv_backup_find_write_position(uint16_t required_space, uint32_t *write_position)
235 {
236 errcode_t ret;
237 kv_page_handle_t page;
238 kv_page_status_t page_status;
239 kv_page_handle_t dragpage;
240 kv_nvregion_area_t* nvregion_area = nv_get_region_area();
241 uint32_t page_start = nvregion_area->nv_backup_addr;
242 for (uint32_t page_index = 0; page_index < KV_BACKUP_PAGE_NUM; page_index++) {
243 page.page_location = (kv_page_location)(uintptr_t)(page_start + page_index * KV_PAGE_SIZE);
244 kv_page_get_status(&page, &page_status);
245 if ((page_status.total_space - page_status.used_space) >= required_space) {
246 *write_position = page_status.first_writable_location;
247 return ERRCODE_SUCC;
248 }
249
250 /* 找可换页页 */
251 if (page_status.max_key_space >= required_space) {
252 dragpage = page;
253 }
254 }
255
256 /* 进行备份区换页 */
257 ret = kv_backup_dragpage_process(dragpage);
258 if (ret != ERRCODE_SUCC) {
259 return ret;
260 }
261
262 /* 将备份区整理好的页可以写的位置传出 */
263 kv_page_get_status(&dragpage, &page_status);
264 if ((page_status.total_space - page_status.used_space) >= required_space) {
265 *write_position = page_status.first_writable_location;
266 return ERRCODE_SUCC;
267 }
268 return ERRCODE_NV_NO_ENOUGH_SPACE;
269 }
270
kv_backup_write_one_page_key(kv_page_handle_t * page)271 STATIC errcode_t kv_backup_write_one_page_key(kv_page_handle_t *page)
272 {
273 errcode_t ret;
274 kv_key_handle_t key;
275 uint16_t key_size;
276 uint32_t write_position = 0;
277 errcode_t key_found = kv_page_find_first_key(page, NULL, &key);
278 while (key_found == ERRCODE_SUCC) {
279 if ((kv_key_is_valid(&key)) &&
280 (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC)) {
281 key_size = kv_key_flash_size(&key);
282 uint8_t *kv_buffer = (uint8_t *)kv_malloc(key_size);
283 if (kv_buffer == NULL) {
284 return ERRCODE_MALLOC;
285 }
286 ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)kv_buffer, (uint32_t)(uintptr_t)key.key_location,
287 key_size);
288 if (ret != ERRCODE_SUCC) {
289 kv_free(kv_buffer);
290 return ret;
291 }
292 ret = kv_backup_find_write_position(key_size, &write_position);
293 if (ret != ERRCODE_SUCC) {
294 kv_free(kv_buffer);
295 return ret;
296 }
297 ret = kv_key_write_flash(write_position, key_size, kv_buffer);
298 if (ret != ERRCODE_SUCC) {
299 kv_free(kv_buffer);
300 return ret;
301 }
302 kv_free(kv_buffer);
303 }
304 key_found = kv_page_find_next_key(page, NULL, &key);
305 }
306 return ERRCODE_SUCC;
307 }
308
kv_backup_write_key(void)309 errcode_t kv_backup_write_key(void)
310 {
311 errcode_t ret;
312 kv_page_handle_t page;
313
314 for (uint32_t page_index = 0; page_index < KV_STORE_PAGES_ACPU; page_index++) {
315 ret = kv_store_get_page_handle(KV_STORE_APPLICATION, page_index, &page);
316 if (ret != ERRCODE_SUCC) {
317 return ret;
318 }
319 ret = kv_backup_write_one_page_key(&page);
320 if (ret != ERRCODE_SUCC) {
321 return ret;
322 }
323 }
324
325 return ERRCODE_SUCC;
326 }
327
kv_read_backup_key(uint16_t key_id,uint16_t * kvalue_length,uint8_t * kvalue,nv_key_attr_t * attr,kv_page_location page_location)328 STATIC errcode_t kv_read_backup_key(uint16_t key_id, uint16_t *kvalue_length, uint8_t *kvalue, nv_key_attr_t *attr,
329 kv_page_location page_location)
330 {
331 kv_attributes_t backup_attribute = 0;
332 if (kvalue_length == NULL || kvalue == NULL || attr == NULL) {
333 return ERRCODE_NV_INVALID_PARAMS;
334 }
335
336 kv_store_key_data_t key_data = {*kvalue_length, 0, kvalue};
337 errcode_t ret_val = kv_store_get_backup_key(key_id, &key_data, &backup_attribute, page_location);
338 if (ret_val == ERRCODE_SUCC) {
339 memset_s(attr, sizeof(nv_key_attr_t), 0, sizeof(nv_key_attr_t));
340 if (((uint32_t)backup_attribute & NV_ATTRIBUTE_PERMANENT) != 0) {
341 attr->permanent = true;
342 attr->non_upgrade = true;
343 }
344 #if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
345 if (((uint32_t)backup_attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {
346 attr->encrypted = true;
347 attr->non_upgrade = true;
348 }
349 #endif
350 if (((uint32_t)backup_attribute & NV_ATTRIBUTE_NON_UPGRADE) != 0) {
351 attr->non_upgrade = true;
352 }
353 }
354 *kvalue_length = key_data.kvalue_actual_length;
355 return ret_val;
356 }
357
kv_start_restore_all_keys(void)358 STATIC errcode_t kv_start_restore_all_keys(void)
359 {
360 errcode_t ret = ERRCODE_SUCC;
361 uint16_t klength = 0;
362 uint8_t *kvalue;
363 nv_key_attr_t attr;
364 kv_key_handle_t key;
365 kv_page_handle_t page;
366 errcode_t key_found;
367 kv_nvregion_area_t* nvregion_area = nv_get_region_area();
368 if (nvregion_area == NULL) {
369 return ERRCODE_FAIL;
370 }
371 for (uint32_t page_num = 0; page_num < KV_BACKUP_PAGE_NUM; page_num++) {
372 page.page_location = (kv_page_location)(uintptr_t)(nvregion_area->nv_backup_addr + page_num * KV_PAGE_SIZE);
373 key_found = kv_page_find_first_key(&page, NULL, &key);
374 while (key_found == ERRCODE_SUCC) {
375 if (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC && kv_key_is_valid(&key)) {
376 kvalue = (uint8_t *)kv_malloc(key.header.length);
377 klength = key.header.length;
378 (void)kv_read_backup_key(key.header.key_id, &klength, kvalue, &attr, page.page_location);
379 ret = nv_direct_write_with_attr(key.header.key_id, kvalue, klength, &attr, NULL);
380 kv_free(kvalue);
381 }
382 key_found = kv_page_find_next_key(&page, NULL, &key);
383 }
384 }
385 return ret;
386 }
387
kv_enable_restore_flag(const nv_reset_mode_t * nv_reset_mode)388 errcode_t kv_enable_restore_flag(const nv_reset_mode_t *nv_reset_mode)
389 {
390 nv_key_attr_t attr = {0};
391 attr.non_upgrade = true;
392 errcode_t ret = nv_direct_write_with_attr(NV_ID_RESTORE_ENABLE,
393 (uint8_t *)(uintptr_t)nv_reset_mode, sizeof(nv_reset_mode_t), &attr, NULL);
394 return ret;
395 }
396
kv_disable_restore_flag(void)397 static errcode_t kv_disable_restore_flag(void)
398 {
399 nv_reset_mode_t nv_reset_mode = {0};
400 nv_key_attr_t attr = {0};
401 attr.non_upgrade = true;
402 errcode_t ret = nv_direct_write_with_attr(NV_ID_RESTORE_ENABLE,
403 (uint8_t *)(uintptr_t)&nv_reset_mode, sizeof(nv_reset_mode_t), &attr, NULL);
404 return ret;
405 }
406
kv_restore_set_region_flag(const bool * flag)407 errcode_t kv_restore_set_region_flag(const bool *flag)
408 {
409 if (flag == NULL) {
410 if (memset_s(g_reset_region_flag, sizeof(g_reset_region_flag), true, sizeof(g_reset_region_flag)) != EOK) {
411 return ERRCODE_MEMSET;
412 }
413 } else {
414 if (memcpy_s(g_reset_region_flag, sizeof(g_reset_region_flag), flag, sizeof(g_reset_region_flag)) != EOK) {
415 return ERRCODE_MEMCPY;
416 }
417 }
418 return ERRCODE_SUCC;
419 }
420
kv_restore_invalid_one_page_region_keys(kv_page_handle_t * page)421 STATIC errcode_t kv_restore_invalid_one_page_region_keys(kv_page_handle_t *page)
422 {
423 errcode_t ret;
424 kv_key_handle_t key;
425 errcode_t key_found = kv_page_find_first_key(page, NULL, &key);
426 while (key_found == ERRCODE_SUCC) {
427 if ((kv_key_is_valid(&key)) &&
428 (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC)) {
429 ret = kv_backup_set_invalid_key(&key);
430 if (ret != ERRCODE_SUCC) {
431 return ret;
432 }
433 }
434 key_found = kv_page_find_next_key(page, NULL, &key);
435 }
436 return ERRCODE_SUCC;
437 }
438
kv_restore_invalid_region_keys(void)439 STATIC errcode_t kv_restore_invalid_region_keys(void)
440 {
441 errcode_t ret;
442 kv_page_handle_t page;
443
444 for (uint32_t page_index = 0; page_index < KV_STORE_PAGES_ACPU; page_index++) {
445 ret = kv_store_get_page_handle(KV_STORE_APPLICATION, page_index, &page);
446 if (ret != ERRCODE_SUCC) {
447 return ret;
448 }
449 ret = kv_restore_invalid_one_page_region_keys(&page);
450 if (ret != ERRCODE_SUCC) {
451 return ret;
452 }
453 }
454
455 return ERRCODE_SUCC;
456 }
457
kv_restore_mode_a(void)458 STATIC errcode_t kv_restore_mode_a(void)
459 {
460 errcode_t ret;
461
462 /* 设定要恢复出厂的标记 */
463 ret = kv_restore_set_region_flag(NULL);
464 if (ret != ERRCODE_SUCC) {
465 return ret;
466 }
467
468 /* 将工作区全部的数据置为无效 */
469 ret = kv_restore_invalid_region_keys();
470 if (ret != ERRCODE_SUCC) {
471 return ret;
472 }
473
474 return kv_start_restore_all_keys();
475 }
476
kv_restore_mode_b(const bool * flag)477 STATIC errcode_t kv_restore_mode_b(const bool *flag)
478 {
479 if (flag == NULL) {
480 return ERRCODE_NV_ILLEGAL_OPERATION;
481 }
482
483 errcode_t ret;
484 ret = kv_restore_set_region_flag(flag);
485 if (ret != ERRCODE_SUCC) {
486 return ret;
487 }
488
489 /* 将工作区部分恢复的region区数据置为无效 */
490 ret = kv_restore_invalid_region_keys();
491 if (ret != ERRCODE_SUCC) {
492 return ret;
493 }
494
495 return kv_start_restore_all_keys();
496 }
497
kv_backup_keys(const nv_backup_mode_t * backup_flag)498 errcode_t kv_backup_keys(const nv_backup_mode_t *backup_flag)
499 {
500 errcode_t ret;
501 ret = kv_restore_set_region_flag(backup_flag->region_mode);
502 if (ret != ERRCODE_SUCC) {
503 return ret;
504 }
505 ret = kv_backup_delete_repeat_key();
506 if (ret != ERRCODE_SUCC) {
507 return ret;
508 }
509 return kv_backup_write_key();
510 }
511
kv_restore_all_keys(void)512 errcode_t kv_restore_all_keys(void)
513 {
514 errcode_t ret;
515 nv_reset_mode_t nv_reset_mode;
516 uint16_t flag_length;
517 nv_key_attr_t attr;
518 ret = nv_direct_get_key_data(NV_ID_RESTORE_ENABLE, sizeof(nv_reset_mode_t), &flag_length,
519 (uint8_t *)(uintptr_t)&nv_reset_mode, &attr);
520 if (ret != ERRCODE_SUCC) {
521 return ret;
522 }
523
524 if (nv_reset_mode.mode == RESET_MODE_A) {
525 ret = kv_restore_mode_a();
526 if (ret == ERRCODE_SUCC) {
527 (void)kv_disable_restore_flag();
528 }
529 return ret;
530 } else if (nv_reset_mode.mode == RESET_MODE_B) {
531 ret = kv_restore_mode_b(nv_reset_mode.region_flag);
532 if (ret == ERRCODE_SUCC) {
533 (void)kv_disable_restore_flag();
534 }
535 return ret;
536 } else {
537 return ERRCODE_NV_ILLEGAL_OPERATION;
538 }
539 }
540
541 #endif /* #if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES) */