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