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