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 */
15
16 #include "hi_nvm.h"
17 #include <hi_boot_err.h>
18 #include <hi_flashboot.h>
19
20 typedef hi_u32(*hi_nvm_changed_notify_f) (hi_u8 id);
21
22 typedef struct {
23 hi_u8 min_id;
24 hi_u8 max_id;
25 hi_u16 count;
26 } nvm_changed_proc_stru;
27 typedef struct {
28 hi_u32 base_addr;
29 hi_u32 total_size;
30 hi_u32 block_size;
31 } nvm_basic_info;
32
33
34 HI_CONST hi_u32 g_ver_magic = 0x12345678;
35
36 static hi_nv_ctrl g_s_nv_ctrl[HI_TYPE_NV_MAX];
37 hi_u16 g_s_nv_change_notify_list_cnt = 0;
38
hi_crc32_nv(hi_u32 crc_start,HI_CONST hi_u8 * buf,hi_u32 len,hi_u32 * crc_result)39 hi_u32 hi_crc32_nv(hi_u32 crc_start, HI_CONST hi_u8* buf, hi_u32 len, hi_u32 *crc_result)
40 {
41 if (!buf || !len || !crc_result) {
42 return HI_ERR_CRC_INVALID_PARAMETER;
43 }
44 *crc_result = hi_crc32(crc_start, buf, len);
45 return HI_ERR_SUCCESS;
46 }
47
nv_read_flash(hi_u32 addr,hi_u32 size,hi_u8 * data)48 hi_u32 nv_read_flash(hi_u32 addr, hi_u32 size, hi_u8* data)
49 {
50 hi_u32 ret;
51
52 for (hi_u32 i = 0; i < HNV_FAULT_TOLERANT_TIMES; i++) {
53 ret = hi_flash_read(addr, size, data);
54 if (ret == HI_ERR_SUCCESS) {
55 return HI_ERR_SUCCESS;
56 }
57 }
58
59 return HI_ERR_NV_FAIL_N_TIMES;
60 }
61
nv_write_flash(hi_u32 addr,hi_u32 size,const hi_u8 * data)62 hi_u32 nv_write_flash(hi_u32 addr, hi_u32 size, const hi_u8* data)
63 {
64 hi_u32 ret;
65
66 for (hi_u32 i = 0; i < HNV_FAULT_TOLERANT_TIMES; i++) {
67 ret = hi_flash_write(addr, size, data, HI_TRUE);
68 if (ret == HI_ERR_SUCCESS) {
69 return HI_ERR_SUCCESS;
70 }
71 }
72
73 return HI_ERR_NV_FAIL_N_TIMES;
74 }
75
76 /* Check the validity of the NV file. */
nv_check_file(hi_u8 * pdata,hi_u32 len,hi_nv_type nv_type)77 hi_u32 nv_check_file(hi_u8* pdata, hi_u32 len, hi_nv_type nv_type)
78 {
79 hi_nv_manage* nv_head;
80 hi_u32 magic = HNV_FILE_SIGNATURE;
81 hi_u32 crc_val = 0;
82
83 nv_head = (hi_nv_manage*)pdata;
84 if (nv_type == HI_TYPE_FACTORY_NV) {
85 magic = FNV_FILE_SIGNATURE;
86 }
87 if (magic != nv_head->magic) {
88 return HI_ERR_NV_INVALID_TYPE;
89 }
90 if (nv_head->total_num >= NV_TOTAL_MAX_NUM) {
91 return HI_ERR_NV_FULL;
92 }
93 hi_crc32_nv(0, pdata + HNV_NCRC_SIZE, len - HNV_NCRC_SIZE, &crc_val);
94
95 if (nv_head->crc != crc_val) {
96 return HI_ERR_NV_BAD_DATA;
97 }
98 return HI_ERR_SUCCESS;
99 }
100
101 /* Returns the corresponding NV index. */
nv_find_item(hi_u8 * data,hi_u8 id,hi_nv_type nv_type)102 hi_nv_item_index* nv_find_item(hi_u8* data, hi_u8 id, hi_nv_type nv_type)
103 {
104 hi_nv_item_index* index = HI_NULL;
105 hi_u16 total_num;
106
107 if (data == HI_NULL) {
108 total_num = g_s_nv_ctrl[nv_type].total_num;
109 index = g_s_nv_ctrl[nv_type].index;
110 } else {
111 hi_nv_manage* nv_head = (hi_nv_manage*)data;
112 total_num = nv_head->total_num;
113 index = (hi_nv_item_index*)&nv_head->nv_item_data[0];
114 }
115
116 for (hi_u32 i = 0; i < total_num; i++) {
117 if (id == index[i].nv_id) {
118 return &index[i];
119 }
120 }
121 return (hi_nv_item_index*)HI_NULL;
122 }
123
nv_init_start(hi_u32 block_size,hi_u8 ** data,hi_u8 ** back,hi_nv_ctrl ** nv_ctrl,hi_nv_type nv_type)124 hi_u32 nv_init_start(hi_u32 block_size, hi_u8** data, hi_u8** back, hi_nv_ctrl** nv_ctrl, hi_nv_type nv_type)
125 {
126 if (nv_type >= HI_TYPE_NV_MAX) {
127 return HI_ERR_NV_INVALID_PARAMETER;
128 }
129 *nv_ctrl = &g_s_nv_ctrl[nv_type];
130 *data = (hi_u8 *)rom_boot_malloc(block_size);
131 if (*data == HI_NULL) {
132 return HI_ERR_MALLOC_FAILUE;
133 }
134 *back = (hi_u8 *)rom_boot_malloc(block_size);
135 if (*back == HI_NULL) {
136 rom_boot_free(*data);
137 return HI_ERR_MALLOC_FAILUE;
138 }
139 return HI_ERR_SUCCESS;
140 }
141
nv_init_index(hi_nv_ctrl * nv_ctrl,const nvm_basic_info * nv_info,hi_u8 * p_index,const hi_u8 ** data,const hi_u8 ** back)142 hi_u32 nv_init_index(hi_nv_ctrl* nv_ctrl, const nvm_basic_info* nv_info, hi_u8* p_index, const hi_u8** data,
143 const hi_u8** back)
144 {
145 hi_u32 ret, cs;
146 hi_u32 index_size = sizeof(hi_nv_item_index) * nv_ctrl->total_num;
147 hi_u16 block_count = (hi_u16)nv_info->total_size / (hi_u16)nv_info->block_size;
148 nv_ctrl->index = (hi_nv_item_index*)rom_boot_malloc(index_size);
149 if (nv_ctrl->index == HI_NULL) {
150 ret = HI_ERR_MALLOC_FAILUE;
151 rom_boot_free((hi_void *)*back);
152 rom_boot_free((hi_void *)*data);
153 return ret;
154 }
155 cs = (uintptr_t)(nv_ctrl->index) ^ index_size ^ (uintptr_t)p_index ^ index_size;
156 ret = (hi_u32)memcpy_s(nv_ctrl->index, index_size, p_index, index_size, cs);
157 if (ret != HI_ERR_SUCCESS) {
158 ret = HI_ERR_NV_FILE_ERR;
159 rom_boot_free(p_index);
160 rom_boot_free((hi_void *)*back);
161 rom_boot_free((hi_void *)*data);
162 return ret;
163 }
164 nv_ctrl->base_addr = nv_info->base_addr;
165 nv_ctrl->block_size = nv_info->block_size;
166 nv_ctrl->total_block_size = nv_info->block_size * block_count;
167 nv_ctrl->init_flag = HI_TRUE;
168
169 rom_boot_free((hi_void *)*back);
170 rom_boot_free((hi_void *)*data);
171 return HI_ERR_SUCCESS;
172 }
173
nv_init_common(hi_u32 base_addr,hi_u32 total_size,hi_u32 block_size,hi_nv_type nv_type)174 hi_u32 nv_init_common(hi_u32 base_addr, hi_u32 total_size, hi_u32 block_size, hi_nv_type nv_type)
175 {
176 hi_nv_ctrl* nv_ctrl = HI_NULL;
177 nvm_basic_info nv_info;
178 hi_u8* data = HI_NULL;
179 hi_u8* back = HI_NULL;
180 hi_u32 seq_max = 0;
181 hi_u8* p_index = HI_NULL;
182 if (block_size == (hi_u32)0) {
183 return HI_ERR_FAILURE;
184 }
185 hi_bool flag_read_success = HI_FALSE;
186
187 hi_u32 ret = nv_init_start(block_size, &data, &back, &nv_ctrl, nv_type);
188 if (ret != HI_ERR_SUCCESS) {
189 return ret;
190 }
191 for (hi_u16 i = 0; i < (hi_u16)total_size / (hi_u16)block_size; i++) {
192 hi_u32 flash_addr = base_addr + i * block_size;
193 if (nv_read_flash(flash_addr, block_size, data) != HI_ERR_SUCCESS) { /* 读取 hi_nv_manage nv_head */
194 /* If the read value is incorrect, continue the processing. */
195 continue;
196 }
197 if (nv_check_file(data, block_size, nv_type) != HI_ERR_SUCCESS) { /* 检查nv文件合法性 */
198 continue;
199 }
200 hi_nv_manage* nv_head = (hi_nv_manage*)data;
201 if (nv_head->seq >= seq_max) {
202 seq_max = nv_head->seq;
203 nv_ctrl->seq = nv_head->seq;
204 nv_ctrl->current_addr = flash_addr;
205 nv_ctrl->total_num = nv_head->total_num;
206 nv_ctrl->ver_magic = nv_head->ver_magic;
207 hi_u32 cs = (uintptr_t)back ^ block_size ^ (uintptr_t)data ^ block_size;
208 if (memcpy_s(back, block_size, data, block_size, cs) != EOK) {
209 continue;
210 }
211 p_index = &(((hi_nv_manage*)back)->nv_item_data[0]);
212 flag_read_success = HI_TRUE;
213 }
214 }
215 if (flag_read_success != HI_TRUE) {
216 rom_boot_free(data);
217 rom_boot_free(back);
218 return HI_ERR_NV_INITILIZATION;
219 }
220 nv_info.base_addr = base_addr;
221 nv_info.block_size = block_size;
222 nv_info.total_size = total_size;
223 /* Index space application */
224 ret = nv_init_index(nv_ctrl, (const nvm_basic_info*)&nv_info, p_index, (const hi_u8**)&data, (const hi_u8**)&back);
225 return ret;
226 }
227
nv_get_item_len(hi_u32 id,hi_nv_type nv_type)228 hi_u8 nv_get_item_len(hi_u32 id, hi_nv_type nv_type)
229 {
230 hi_nv_item_index* nv_index;
231
232 nv_index = nv_find_item(HI_NULL, (hi_u8)id, nv_type);
233 if (nv_index == HI_NULL) {
234 return 0;
235 }
236 return nv_index->nv_len;
237 }
238
nv_read_common(hi_u8 id,hi_pvoid pdata,hi_u8 len,hi_nv_type nv_type)239 hi_u32 nv_read_common(hi_u8 id, hi_pvoid pdata, hi_u8 len, hi_nv_type nv_type)
240 {
241 hi_u32 ret;
242 hi_nv_ctrl* nv_ctrl = HI_NULL;
243 hi_nv_item_index* nv_index = HI_NULL;
244 hi_u32 crc = 0;
245 hi_u32 flash_addr;
246 hi_u8 item_len;
247 hi_bool to_check_crc;
248 hi_u32 crc_val = 0;
249
250 if (nv_type >= HI_TYPE_NV_MAX) {
251 return HI_ERR_NV_INVALID_PARAMETER;
252 }
253 nv_ctrl = &g_s_nv_ctrl[nv_type];
254 nv_index = nv_find_item(HI_NULL, id, nv_type);
255 if (nv_index == HI_NULL) {
256 return HI_ERR_NV_ERROR_READ;
257 }
258 if (nv_index->nv_len == len) {
259 item_len = len;
260 to_check_crc = HI_TRUE;
261 } else {
262 item_len = hi_min(nv_index->nv_len, len);
263 to_check_crc = HI_FALSE;
264 }
265
266 flash_addr = nv_ctrl->current_addr + nv_index->nv_offset;
267 ret = nv_read_flash(flash_addr, item_len, pdata);
268 if (ret != HI_ERR_SUCCESS) {
269 return ret;
270 }
271 /* CRC is verified only when the lengths are the same. */
272 if (to_check_crc == HI_TRUE) {
273 ret = nv_read_flash(flash_addr + item_len, sizeof(crc), (hi_u8*)&crc);
274 if (ret != HI_ERR_SUCCESS) {
275 return ret;
276 }
277 hi_crc32_nv(0, pdata, item_len, &crc_val);
278 if (crc != crc_val) {
279 return HI_ERR_NV_BAD_DATA;
280 }
281 } else {
282 ret = HI_ERR_NV_LEN_ERR;
283 }
284
285 return ret;
286 }
287
288
nv_next_addr(HI_CONST hi_nv_ctrl * nv_ctrl)289 hi_u32 nv_next_addr(HI_CONST hi_nv_ctrl *nv_ctrl)
290 {
291 hi_u32 new_addr = ((nv_ctrl->current_addr + nv_ctrl->block_size) < (nv_ctrl->base_addr + nv_ctrl->total_block_size))
292 ? (nv_ctrl->current_addr + nv_ctrl->block_size) : (nv_ctrl->base_addr);
293
294 return new_addr;
295 }
296
nv_block_write(hi_u8 * p_nv_file,hi_nv_type nv_type)297 hi_u32 nv_block_write(hi_u8* p_nv_file, hi_nv_type nv_type)
298 {
299 hi_u32 ret;
300 hi_nv_ctrl* nv_ctrl = &g_s_nv_ctrl[nv_type];
301 hi_nv_manage* nv_head = (hi_nv_manage*)p_nv_file;
302 hi_u32 flash_addr = nv_next_addr((HI_CONST hi_nv_ctrl *)nv_ctrl);
303
304 nv_head->ver_magic = g_ver_magic;
305 nv_head->seq = nv_ctrl->seq + 1;
306
307 hi_crc32_nv(0, p_nv_file + 8, nv_ctrl->block_size - 8, &(nv_head->crc)); // 8
308 ret = nv_write_flash(flash_addr, nv_ctrl->block_size, p_nv_file);
309 if (ret != HI_ERR_SUCCESS) {
310 return ret;
311 }
312 nv_ctrl->seq = nv_head->seq;
313 nv_ctrl->current_addr = flash_addr;
314
315 return ret;
316 }
317
nv_common_write(hi_u8 id,hi_nv_type nv_type,hi_u8 len,const hi_pvoid data)318 hi_u32 nv_common_write(hi_u8 id, hi_nv_type nv_type, hi_u8 len, const hi_pvoid data)
319 {
320 hi_u8 backup_num = 1;
321 hi_u8 item_len = len;
322 hi_u32 ret, crc, cs;
323 hi_nv_ctrl* nv_ctrl = &g_s_nv_ctrl[nv_type];
324
325 /* Normal write process */
326 hi_nv_item_index* nv_index = nv_find_item(HI_NULL, id, nv_type);
327 if (nv_index == HI_NULL) {
328 return HI_ERR_NV_ERROR_READ;
329 }
330
331 if (nv_index->nv_len != len) {
332 item_len = hi_min(nv_index->nv_len, len);
333 }
334
335 hi_u8* nv_file = (hi_u8 *)rom_boot_malloc(nv_ctrl->block_size);
336 if (nv_file == HI_NULL) {
337 return HI_ERR_MALLOC_FAILUE;
338 }
339 if (nv_type == HI_TYPE_FACTORY_NV) {
340 backup_num = 2; /* The operations in the factory area are mutually backed up. 2 copies are written. */
341 }
342 for (; backup_num > 0; backup_num--) {
343 ret = nv_read_flash(nv_ctrl->current_addr, nv_ctrl->block_size, nv_file);
344 if (ret != HI_ERR_SUCCESS) {
345 continue;
346 }
347
348 hi_crc32_nv(0, data, item_len, &crc);
349 cs = (uintptr_t)(nv_file + nv_index->nv_offset) ^ item_len ^ (uintptr_t)data ^ item_len;
350 if (memcpy_s(nv_file + nv_index->nv_offset, item_len, data, item_len, cs) != EOK) {
351 continue;
352 }
353 cs = (uintptr_t)(nv_file + nv_index->nv_offset + item_len) ^ sizeof(crc) ^ ((uintptr_t)&crc) ^ sizeof(crc);
354 if (memcpy_s(nv_file + nv_index->nv_offset + item_len, sizeof(crc), &crc, sizeof(crc), cs) != EOK) {
355 continue;
356 }
357 ret = nv_block_write(nv_file, nv_type);
358 if (ret != HI_ERR_SUCCESS) {
359 continue;
360 }
361 }
362 rom_boot_free(nv_file);
363 return ret;
364 }
365
nv_write_common(hi_u8 id,const hi_pvoid data,hi_u8 len,hi_nv_type nv_type)366 hi_u32 nv_write_common(hi_u8 id, const hi_pvoid data, hi_u8 len, hi_nv_type nv_type)
367 {
368 if (nv_type >= HI_TYPE_NV_MAX) {
369 return HI_ERR_NV_INVALID_PARAMETER;
370 }
371 /* If the readback is equal, no write operation is performed. */
372 hi_u8* item_readback = (hi_u8 *)rom_boot_malloc(HNV_ITEM_MAXLEN);
373 if (item_readback == HI_NULL) {
374 return HI_ERR_MALLOC_FAILUE;
375 }
376
377 hi_u32 ret = nv_read_common(id, item_readback, len, nv_type);
378 if (ret != HI_ERR_SUCCESS) {
379 rom_boot_free(item_readback);
380 return ret;
381 }
382 if (memcmp(data, item_readback, len) == HI_ERR_SUCCESS) {
383 rom_boot_free(item_readback);
384 return HI_ERR_SUCCESS;
385 }
386 rom_boot_free(item_readback);
387
388 /* Normal write process */
389 ret = nv_common_write(id, nv_type, len, data);
390 if (ret != HI_ERR_SUCCESS) {
391 return ret;
392 }
393 return HI_ERR_SUCCESS;
394 }
395
hi_factory_nv_init(hi_u32 addr,hi_u32 total_size,hi_u32 block_size)396 hi_u32 hi_factory_nv_init(hi_u32 addr, hi_u32 total_size, hi_u32 block_size)
397 {
398 return nv_init_common(addr, total_size, block_size, HI_TYPE_FACTORY_NV);
399 }
400
hi_factory_nv_write(hi_u8 id,hi_pvoid pdata,hi_u8 len,hi_u32 flag)401 hi_u32 hi_factory_nv_write(hi_u8 id, hi_pvoid pdata, hi_u8 len, hi_u32 flag)
402 {
403 hi_unref_param(flag);
404 hi_u32 ret;
405 hi_nv_ctrl* nv_ctrl = HI_NULL;
406
407 if (id >= HI_NV_FACTORY_USR_ID_END) {
408 return HI_ERR_NV_NOT_SUPPORT;
409 }
410 if ((pdata == HI_NULL) || (len == 0) || (len > HNV_ITEM_MAXLEN)) {
411 return HI_ERR_NV_INVALID_PARAMETER;
412 }
413 nv_ctrl = &g_s_nv_ctrl[HI_TYPE_FACTORY_NV];
414 if (nv_ctrl->init_flag != HI_TRUE) {
415 return HI_ERR_NV_INITILIZATION;
416 }
417 ret = nv_write_common(id, (HI_CONST hi_pvoid)pdata, len, HI_TYPE_FACTORY_NV);
418
419 return ret;
420 }
421
hi_factory_nv_read(hi_u8 id,hi_pvoid data,hi_u8 len,hi_u32 flag)422 hi_u32 hi_factory_nv_read(hi_u8 id, hi_pvoid data, hi_u8 len, hi_u32 flag)
423 {
424 hi_unref_param(flag);
425 hi_u32 ret;
426 hi_nv_ctrl* nv_ctrl = HI_NULL;
427
428 if (id >= HI_NV_FACTORY_USR_ID_END) {
429 return HI_ERR_NV_NOT_SUPPORT;
430 }
431 if ((data == HI_NULL) || (len == 0) || (len > HNV_ITEM_MAXLEN)) {
432 return HI_ERR_NV_INVALID_PARAMETER;
433 }
434 nv_ctrl = &g_s_nv_ctrl[HI_TYPE_FACTORY_NV];
435 if (nv_ctrl->init_flag != HI_TRUE) {
436 return HI_ERR_NV_INITILIZATION;
437 }
438 ret = nv_read_common(id, data, len, HI_TYPE_FACTORY_NV);
439
440 return ret;
441 }
442
443