• 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 Async Store Used Hash
15  */
16 
17 #include "nv_porting.h"
18 #include "nv_config.h"
19 #include "nv_storage_handle.h"
20 #include "common_def.h"
21 
22 #if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)
23 #include "osal_task.h"
24 #include "osal_msgqueue.h"
25 #include "osal_semaphore.h"
26 #include "cstl_hash.h"
27 #include "nv_async_store.h"
28 
29 #define MAX_BINARY_VAL 1
30 #define NV_QUEUE_ID 0XFFFFFF
31 #define NV_MSG_MAX_SIZE sizeof(nv_queue_msg_handle_t)
32 
33 static unsigned long g_nv_msg_queue_id = NV_QUEUE_ID;
34 static uint32_t g_nv_async_flash_space = KV_STORE_DATA_SIZE;
35 osal_semaphore nv_async_sem;
36 CstlHash *g_hash_table = NULL;
37 
nv_async_hash_init(void)38 static void nv_async_hash_init(void)
39 {
40     /* 使用了自定义的数据类型 注册nv_psram_free函数 */
41     CstlDupFreeFuncPair value_func = {NULL, nv_psram_free};
42     g_hash_table = CstlHashCreate(NV_BACKET_SIZE, NULL, NULL, NULL, &value_func);
43 }
44 
nv_async_hash_add(nv_key_map_t * cur_key)45 static void nv_async_hash_add(nv_key_map_t* cur_key)
46 {
47     CstlHashIterator it = CstlHashFind(g_hash_table,  cur_key->key_id);
48     if (it != CstlHashIterEnd(g_hash_table)) {
49         (void)CstlHashErase(g_hash_table,  cur_key->key_id);
50     }
51     uint32_t cur_key_size = sizeof(nv_key_map_t) + (cur_key->key_id * sizeof(uint8_t));
52     int ret = CstlHashInsert(g_hash_table, cur_key->key_id, sizeof(uint16_t), (uintptr_t)cur_key, (size_t)cur_key_size);
53 }
54 
nv_asynv_send_msg_to_write_flash(nv_key_map_t * cur_key)55 static errcode_t nv_asynv_send_msg_to_write_flash(nv_key_map_t* cur_key)
56 {
57     nv_queue_msg_handle_t nv_msg;
58     nv_msg.key_id = cur_key->key_id;
59     nv_msg.key_ram_location = (uintptr_t)cur_key;
60     int ret = osal_msg_queue_write_copy(g_nv_msg_queue_id, (void *)&nv_msg, sizeof(nv_queue_msg_handle_t), 0);
61     if (ret != OSAL_SUCCESS) {
62         return ERRCODE_FAIL;
63     }
64     return ERRCODE_SUCC;
65 }
66 
nv_async_check_writeable(uint16_t key,nv_key_attr_t * attr,uint16_t kvalue_length)67 static bool nv_async_check_writeable(uint16_t key, nv_key_attr_t *attr, uint16_t kvalue_length)
68 {
69     uintptr_t value;
70     if (CstlHashAt(g_hash_table, key, &value) != CSTL_OK) {
71         return true;
72     }
73 
74     nv_key_map_t *cur_key = (nv_key_map_t *)value;
75     if (cur_key->permanent == 1 || (cur_key->encrypted == 1 &&
76     (attr == NULL || (attr != NULL && attr->encrypted == false)))
77         || (attr == NULL && cur_key->upgrade == 1)) {
78         return false;
79     }
80 
81     return true;
82 }
83 
nv_async_calculate_flash_size(uint16_t kvlaue_length,nv_key_attr_t * attr)84 static uint16_t nv_async_calculate_flash_size(uint16_t kvlaue_length, nv_key_attr_t *attr)
85 {
86     uint16_t size;
87     kv_attributes_t attributes = {0};
88     uint16_t hash_crc_size = KV_CRYPTO_CRC_SIZE;
89 
90 #if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
91     if (attr->encrypted) {
92         hash_crc_size = KV_CRYPTO_HASH_SIZE;
93         attributes = KV_ATTRIBUTE_ENCRYPTED;
94     }
95 #endif
96 
97     size = (uint16_t)sizeof(kv_key_header_t) + hash_crc_size;
98     size += kv_key_padded_data_length(attributes, kvlaue_length);
99 
100     return size;
101 }
102 
nv_async_update_attr(nv_key_map_t * cur_key,nv_key_attr_t * attr)103 static errcode_t nv_async_update_attr(nv_key_map_t* cur_key, nv_key_attr_t *attr)
104 {
105     if (attr == NULL) {
106         return ERRCODE_SUCC;
107     }
108 
109     /* 保持hash表中数据和传入的属性保持一致 */
110     cur_key->permanent = attr->permanent;
111     cur_key->encrypted = attr->encrypted;
112     cur_key->upgrade = attr->non_upgrade;
113 
114     return ERRCODE_SUCC;
115 }
116 
nv_async_update_value(nv_key_map_t * cur_key,uint16_t key,const uint8_t * kvalue,uint16_t kvalue_length,nv_key_attr_t * attr)117 static errcode_t nv_async_update_value(nv_key_map_t* cur_key, uint16_t key, const uint8_t *kvalue,
118     uint16_t kvalue_length, nv_key_attr_t *attr)
119 {
120     errcode_t res = ERRCODE_SUCC;
121     cur_key->key_id = key;
122     cur_key->key_len = kvalue_length;
123     if (memcpy_s(cur_key->kvalue, cur_key->key_len, kvalue, cur_key->key_len) != EOK) {
124         nv_log_err("[NV] nv async update value: memcpy_s fail!\r\n");
125         return ERRCODE_FAIL;
126     }
127     (void)nv_async_update_attr(cur_key, attr);
128     res = nv_asynv_send_msg_to_write_flash(cur_key);
129     return res;
130 }
131 
nv_async_add_key(uint16_t key,const uint8_t * kvalue,uint16_t kvalue_length,nv_key_attr_t * attr)132 static errcode_t nv_async_add_key(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length, nv_key_attr_t *attr)
133 {
134     errcode_t ret;
135     nv_key_map_t *cur_key = NULL;
136     uint32_t cur_key_size = sizeof(nv_key_map_t) + kvalue_length * (sizeof(uint8_t));
137     cur_key = (nv_key_map_t *)nv_psram_malloc(cur_key_size);
138     if (cur_key == NULL) {
139         nv_log_err("[NV] nv async add key: malloc fail!\r\n");
140         return ERRCODE_MALLOC;
141     }
142     if (memset_s(cur_key, cur_key_size, 0, cur_key_size) != EOK) {
143         nv_log_err("[NV] nv async add key: memeset_s fail!\r\n");
144         nv_psram_free(cur_key);
145         return ERRCODE_FAIL;
146     }
147     ret = nv_async_update_value(cur_key, key, kvalue, kvalue_length, attr);
148     if (ret != ERRCODE_SUCC) {
149         nv_log_err("[NV] nv_async_update_value fail!\r\n");
150         nv_psram_free(cur_key);
151         return ERRCODE_FAIL;
152     }
153     (void)nv_async_hash_add(cur_key);
154     return ERRCODE_SUCC;
155 }
156 
nv_async_store_init_keys_one_page(kv_page_handle_t * page)157 static errcode_t nv_async_store_init_keys_one_page(kv_page_handle_t *page)
158 {
159     errcode_t res;
160     kv_key_handle_t key;
161     nv_key_map_t *cur_key = NULL;
162 
163     errcode_t key_found = kv_page_find_first_key(page, NULL, &key);
164     while (key_found == ERRCODE_SUCC) {
165         if (kv_key_is_valid(&key)) {
166             /* 给后续的柔性数组分配内存指定大小的内存 */
167             uint32_t cur_key_size = sizeof(nv_key_map_t) + (key.header.length * sizeof(uint8_t));
168 
169             cur_key = (nv_key_map_t *)nv_psram_malloc(cur_key_size);
170             if (cur_key == NULL) {
171                 nv_log_err("[NV] nv async store init keys one page: malloc fail!\r\n");
172                 nv_psram_free(cur_key);
173                 return ERRCODE_MALLOC;
174             }
175             if (memset_s(cur_key, cur_key_size, 0, cur_key_size) != EOK) {
176                 nv_log_err("[NV] nv async store init keys one page: memset_s fail!\r\n");
177                 nv_psram_free(cur_key);
178                 return ERRCODE_FAIL;
179             }
180             cur_key->key_id = key.header.key_id;
181             cur_key->key_len = key.header.length;
182             /* 对三个属性进行判断 */
183             if (key.header.type != KV_KEY_TYPE_NORMAL) {
184                 cur_key->permanent = 1;
185                 cur_key->upgrade = 1;
186             }
187             if (key.header.enc_key != 0) {
188                 cur_key->encrypted = 1;
189                 cur_key->upgrade = 1;
190             }
191             if (key.header.upgrade != KV_KEY_TYPE_NORMAL) {
192                 cur_key->upgrade = 1;
193             }
194             /* 传入柔性数组的数组名既首地址,获取flash数据 */
195             res = kv_key_read_data(&key, cur_key->kvalue);
196             if (res != ERRCODE_SUCC) {
197                 nv_log_err("[NV] nv async store init keys one page: kv key read data fail key= 0x%d\r\n",
198                     key.header.key_id);
199                 nv_psram_free(cur_key);
200                 return ERRCODE_FAIL;
201             }
202             (void)nv_async_hash_add(cur_key);
203         }
204         key_found = kv_page_find_next_key(page, NULL, &key);
205     }
206     return ERRCODE_SUCC;
207 }
208 
nv_async_read_with_attr(uint16_t key,uint16_t kvalue_max_length,uint16_t * kvalue_length,uint8_t * kvalue,nv_key_attr_t * attr)209 errcode_t nv_async_read_with_attr(uint16_t key, uint16_t kvalue_max_length,
210     uint16_t *kvalue_length, uint8_t *kvalue, nv_key_attr_t *attr)
211 {
212     if (g_hash_table == NULL) {
213         nv_log_err("[NV] nv async read with attr: g_hash_table not init!\r\n");
214         return ERRCODE_NV_INIT_FAILED;
215     }
216 
217     if (osal_sem_down_timeout(&nv_async_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
218         nv_log_err("[NV] nv async read with attr: semaphore error!\r\n");
219         return ERRCODE_NV_SEM_WAIT_ERR;
220     }
221 
222     uintptr_t value;
223     if (CstlHashAt(g_hash_table, key, &value) != CSTL_OK) {
224         osal_sem_up(&nv_async_sem);
225         nv_log_err("[NV] nv async read with attr: not found key 0x%x!\r\n", key);
226         return ERRCODE_NV_KEY_NOT_FOUND;
227     }
228 
229     nv_key_map_t *cur_key = (nv_key_map_t *)value;
230 
231     *kvalue_length = cur_key->key_len;
232     if (kvalue_max_length < cur_key->key_len) {
233         osal_sem_up(&nv_async_sem);
234         return ERRCODE_NV_GET_BUFFER_TOO_SMALL;
235     }
236 
237     if (memcpy_s(kvalue, cur_key->key_len, cur_key->kvalue, cur_key->key_len) != EOK) {
238         osal_sem_up(&nv_async_sem);
239         nv_log_err("[NV] nv async read with attr: memcpy_s fail!\r\n");
240         return ERRCODE_FAIL;
241     }
242     if (cur_key->permanent == 1) {
243         attr->permanent = true;
244         attr->non_upgrade = true;
245     }
246     if (cur_key->encrypted == 1) {
247         attr->encrypted = true;
248         attr->non_upgrade = true;
249     }
250     if (cur_key->upgrade == 1) {
251         attr->non_upgrade = true;
252     }
253     osal_sem_up(&nv_async_sem);
254     return ERRCODE_SUCC;
255 }
256 
nv_async_write_with_attr(uint16_t key,const uint8_t * kvalue,uint16_t kvalue_length,nv_key_attr_t * attr,nv_storage_completed_callback func)257 errcode_t nv_async_write_with_attr(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length, nv_key_attr_t *attr,
258     nv_storage_completed_callback func)
259 {
260     unused(func);
261     errcode_t ret;
262     if (g_hash_table == NULL) {
263         nv_log_err("[NV] nv async write with attr: g_hash_table not init!\r\n");
264         return ERRCODE_NV_INIT_FAILED;
265     }
266 
267     if (osal_sem_down_timeout(&nv_async_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
268         nv_log_err("[NV] nv async write with attr: semaphore error!\r\n");
269         return ERRCODE_NV_SEM_WAIT_ERR;
270     }
271     if (nv_async_check_writeable(key, attr, kvalue_length) == false) {
272         osal_sem_up(&nv_async_sem);
273         nv_log_info("[NV] nv async write with attr: not support write!\r\n");
274         return ERRCODE_NV_ILLEGAL_OPERATION;
275     }
276 
277     uint32_t flash_size = nv_async_calculate_flash_size(kvalue_length, attr);
278     if (g_nv_async_flash_space < flash_size) {
279         osal_sem_up(&nv_async_sem);
280         nv_log_info("[NV] nv async write with attr: not enough space!\r\n");
281         return ERRCODE_NV_NO_ENOUGH_SPACE;
282     }
283     /* 如果hash表里没旧key,直接新增一个节点 */
284     CstlHashIterator it = CstlHashFind(g_hash_table, key);
285     if (it == CstlHashIterEnd(g_hash_table)) {
286         ret = nv_async_add_key(key, kvalue, kvalue_length, attr);
287         osal_sem_up(&nv_async_sem);
288         return ret;
289     }
290 
291     nv_key_map_t *old_key = (nv_key_map_t *)CstlHashIterValue(g_hash_table, it);
292     /* 哈希表里存在旧key,且长度大于新写入key的长度,更新节点值 */
293     if (old_key->key_len >= kvalue_length) {
294         ret = nv_async_update_value(old_key, key, kvalue, kvalue_length, attr);
295     } else {
296         /* 否则,新建节点 */
297         ret = nv_async_add_key(key, kvalue, kvalue_length, attr);
298     }
299 
300     osal_sem_up(&nv_async_sem);
301     return ret;
302 }
303 
nv_async_msg_process(nv_queue_msg_handle_t * msg_data_t)304 static errcode_t nv_async_msg_process(nv_queue_msg_handle_t *msg_data_t)
305 {
306     errcode_t res;
307     CstlHashIterator it;
308 
309     if (osal_sem_down_timeout(&nv_async_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
310         nv_log_err("[NV] nv async msg process: semaphore error!\r\n");
311         return ERRCODE_NV_SEM_WAIT_ERR;
312     }
313 
314     it = CstlHashFind(g_hash_table,  msg_data_t->key_id);
315     if (it == CstlHashIterEnd(g_hash_table)) {
316         nv_log_info("[NV] nv async msg process not found key in hashtable!\r\n");
317         osal_sem_up(&nv_async_sem);
318         return ERRCODE_FAIL;
319     }
320 
321     if (msg_data_t->key_ram_location != (uint32_t)CstlHashIterValue(g_hash_table, it)) {
322         nv_log_info("[NV] nv async msg process location not same!\r\n");
323         osal_sem_up(&nv_async_sem);
324         return ERRCODE_FAIL;
325     }
326     nv_key_map_t *msg_data =  (nv_key_map_t *)msg_data_t->key_ram_location;
327     nv_key_attr_t attr;
328     attr.permanent = (msg_data->permanent == 1) ? true : false;
329     attr.encrypted = (msg_data->encrypted == 1) ? true : false;
330     attr.non_upgrade = (msg_data->upgrade == 1) ? true : false;
331     nv_log_debug("[NV] nv async msg process key=0x%x,len=%d,attr %d %d %d\r\n",
332         msg_data->key_id, msg_data->key_len, attr.permanent, attr.encrypted, attr.non_upgrade);
333     res = nv_direct_write_with_attr(msg_data->key_id, msg_data->kvalue, msg_data->key_len, &attr, NULL);
334     nv_store_status_t status;
335 
336     res = nv_direct_get_store_status(&status);
337     if (res != ERRCODE_SUCC) {
338         nv_log_err("[NV] nv async msg process flash_space get fail!\r\n");
339         osal_sem_up(&nv_async_sem);
340         return res;
341     }
342 
343     g_nv_async_flash_space = status.max_key_space;
344     osal_sem_up(&nv_async_sem);
345     return res;
346 }
347 
nv_async_msg_process_thread(void)348 static errcode_t nv_async_msg_process_thread(void)
349 {
350     nv_queue_msg_handle_t msg_data_t;
351     uint32_t msg_data_size = sizeof(nv_queue_msg_handle_t);
352 
353     while (true) {
354         (void)memset_s(&msg_data_t, msg_data_size, 0, msg_data_size);
355         osal_msg_queue_read_copy(g_nv_msg_queue_id, &msg_data_t, &msg_data_size, OSAL_MSGQ_WAIT_FOREVER);
356         nv_async_msg_process(&msg_data_t);
357     }
358 
359     return ERRCODE_SUCC;
360 }
361 
nv_async_thread_msg_event_init(void)362 static errcode_t nv_async_thread_msg_event_init(void)
363 {
364     int ret;
365     ret = osal_msg_queue_create("nv_write_task", NV_QUEUE_MAX_SIZE, &g_nv_msg_queue_id,
366                                 0, NV_MSG_MAX_SIZE);
367     if (ret != 0) {
368         nv_log_err("[NV] nv async thread msg event init: osal msg queue create!\r\n");
369         return ERRCODE_FAIL;
370     }
371     osal_kthread_lock();
372     osal_task *task = osal_kthread_create(nv_async_msg_process_thread, NULL, "nv_write_task", 0x1000);
373     if (task == NULL) {
374         osal_kthread_unlock();
375         nv_log_err("[NV] nv async thread msg event init:: osal kthread create!\r\n");
376         return ERRCODE_FAIL;
377     }
378     osal_kthread_set_priority(task, NV_THREAD_PRIORITY_NUM);
379     osal_kthread_unlock();
380     return ERRCODE_SUCC;
381 }
382 
nv_async_flush(void)383 errcode_t nv_async_flush(void)
384 {
385     nv_queue_msg_handle_t msg_data_t;
386     uint32_t msg_data_size = sizeof(nv_queue_msg_handle_t);
387     uint8_t cur_queue_num = (uint8_t)osal_msg_queue_get_msg_num(g_nv_msg_queue_id);
388 
389     while (cur_queue_num > 0) {
390         (void)memset_s(&msg_data_t, msg_data_size, 0, msg_data_size);
391         osal_msg_queue_read_copy(g_nv_msg_queue_id, &msg_data_t, &msg_data_size, OSAL_MSGQ_NO_WAIT);
392         nv_async_msg_process(&msg_data_t);
393         cur_queue_num--;
394     }
395 
396     return ERRCODE_SUCC;
397 }
398 
nv_key_map_init(kv_store_t store,uint8_t num_pages)399 errcode_t nv_key_map_init(kv_store_t store, uint8_t num_pages)
400 {
401     errcode_t ret;
402     kv_page_handle_t kv_page;
403     nv_store_status_t status;
404     (void)nv_direct_get_store_status(&status);
405     g_nv_async_flash_space = status.max_key_space;
406     for (uint8_t page_index = 0; page_index < num_pages; page_index++) {
407         ret = kv_store_get_page_handle(store, page_index, &kv_page);
408         if (ret != ERRCODE_SUCC) {
409             nv_log_err("[NV] nv_key_map_init: get page handle error!\r\n");
410             return ret;
411         }
412         ret = nv_async_store_init_keys_one_page(&kv_page);
413         if (ret != ERRCODE_SUCC) {
414             nv_log_err("[NV] nv_key_map_init: init keys one page error!\r\n");
415             return ret;
416         }
417     }
418     return ERRCODE_SUCC;
419 }
420 
nv_async_init(kv_store_t store,uint8_t num_pages)421 errcode_t nv_async_init(kv_store_t store, uint8_t num_pages)
422 {
423     errcode_t ret;
424     if (osal_sem_binary_sem_init(&nv_async_sem, MAX_BINARY_VAL) != ERRCODE_SUCC) {
425         nv_log_err("[NV] nv_key_map_init: osal sem binary sem init!\r\n");
426         return ERRCODE_FAIL;
427     }
428 
429     /* 创建哈希表 */
430     (void)nv_async_hash_init();
431     if (g_hash_table == NULL) {
432         nv_log_err("[NV] nv_key_map_init: nv async hash init fail!\r\n");
433         return ERRCODE_FAIL;
434     }
435 
436     /* 创建nv写线程 */
437     ret = nv_async_thread_msg_event_init();
438     if (ret != ERRCODE_SUCC) {
439         nv_log_err("[NV] nv_key_map_init: nv async thread msg event init!\r\n");
440         return ret;
441     }
442 
443     /* hash表数据初始化 */
444     ret = nv_key_map_init(store, num_pages);
445     return ret;
446 }
447 
448 #endif /* #if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES) */
449 
450