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
18 #include <hi_boot_err.h>
19 #include <hi_loaderboot_flash.h>
20
21 typedef hi_u32(*hi_nvm_changed_notify_f) (hi_u8 id);
22
23 typedef struct {
24 hi_u8 min_id;
25 hi_u8 max_id;
26 hi_u16 count;
27 } nvm_changed_proc_stru;
28 typedef struct {
29 hi_u32 base_addr;
30 hi_u32 total_size;
31 hi_u32 block_size;
32 } nvm_basic_info;
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 }
nv_init_start(hi_u32 block_size,hi_u8 ** data,hi_u8 ** back,hi_nv_ctrl ** nv_ctrl,hi_nv_type nv_type)123 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)
124 {
125 if (nv_type >= HI_TYPE_NV_MAX) {
126 return HI_ERR_NV_INVALID_PARAMETER;
127 }
128 *nv_ctrl = &g_s_nv_ctrl[nv_type];
129 *data = (hi_u8 *)rom_boot_malloc(block_size);
130 if (*data == HI_NULL) {
131 return HI_ERR_MALLOC_FAILUE;
132 }
133 *back = (hi_u8 *)rom_boot_malloc(block_size);
134 if (*back == HI_NULL) {
135 rom_boot_free(*data);
136 return HI_ERR_MALLOC_FAILUE;
137 }
138 return HI_ERR_SUCCESS;
139 }
140
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)141 hi_u32 nv_init_index(hi_nv_ctrl* nv_ctrl, const nvm_basic_info* nv_info, hi_u8* p_index, const hi_u8** data,
142 const hi_u8** back)
143 {
144 hi_u32 ret, cs;
145 hi_u32 index_size = sizeof(hi_nv_item_index) * nv_ctrl->total_num;
146 hi_u16 block_count = (hi_u16)nv_info->total_size / (hi_u16)nv_info->block_size;
147 nv_ctrl->index = (hi_nv_item_index*)rom_boot_malloc(index_size);
148 if (nv_ctrl->index == HI_NULL) {
149 ret = HI_ERR_MALLOC_FAILUE;
150 rom_boot_free((hi_void *)*back);
151 rom_boot_free((hi_void *)*data);
152 return ret;
153 }
154 cs = (uintptr_t)(nv_ctrl->index) ^ index_size ^ (uintptr_t)p_index ^ index_size;
155 ret = (hi_u32)memcpy_s(nv_ctrl->index, index_size, p_index, index_size, cs);
156 if (ret != HI_ERR_SUCCESS) {
157 ret = HI_ERR_NV_FILE_ERR;
158 rom_boot_free(p_index);
159 rom_boot_free((hi_void *)*back);
160 rom_boot_free((hi_void *)*data);
161 return ret;
162 }
163 nv_ctrl->base_addr = nv_info->base_addr;
164 nv_ctrl->block_size = nv_info->block_size;
165 nv_ctrl->total_block_size = nv_info->block_size * block_count;
166 nv_ctrl->init_flag = HI_TRUE;
167
168 rom_boot_free((hi_void *)*back);
169 rom_boot_free((hi_void *)*data);
170 return HI_ERR_SUCCESS;
171 }
172
nv_init_common(hi_u32 base_addr,hi_u32 total_size,hi_u32 block_size,hi_nv_type nv_type)173 hi_u32 nv_init_common(hi_u32 base_addr, hi_u32 total_size, hi_u32 block_size, hi_nv_type nv_type)
174 {
175 hi_nv_ctrl* nv_ctrl = HI_NULL;
176 nvm_basic_info nv_info;
177 hi_u8* data = HI_NULL;
178 hi_u8* back = HI_NULL;
179 hi_u32 seq_max = 0;
180 hi_u8* p_index = HI_NULL;
181 if (block_size == (hi_u32)0) {
182 return HI_ERR_FAILURE;
183 }
184 hi_bool flag_read_success = HI_FALSE;
185
186 hi_u32 ret = nv_init_start(block_size, &data, &back, &nv_ctrl, nv_type);
187 if (ret != HI_ERR_SUCCESS) {
188 return ret;
189 }
190 for (hi_u16 i = 0; i < (hi_u16)total_size / (hi_u16)block_size; i++) {
191 hi_u32 flash_addr = base_addr + i * block_size;
192 if (nv_read_flash(flash_addr, block_size, data) != HI_ERR_SUCCESS) {
193 /* Continue to process read errors. */
194 continue;
195 }
196 if (nv_check_file(data, block_size, nv_type) != HI_ERR_SUCCESS) { /* Check the validity of the NV file. */
197 continue;
198 }
199 hi_nv_manage* nv_head = (hi_nv_manage*)data;
200 if (nv_head->seq >= seq_max) {
201 seq_max = nv_head->seq;
202 nv_ctrl->seq = nv_head->seq;
203 nv_ctrl->current_addr = flash_addr;
204 nv_ctrl->total_num = nv_head->total_num;
205 nv_ctrl->ver_magic = nv_head->ver_magic;
206 hi_u32 cs = (uintptr_t)back ^ block_size ^ (uintptr_t)data ^ block_size;
207 if (memcpy_s(back, block_size, data, block_size, cs) != EOK) {
208 continue;
209 }
210 p_index = &(((hi_nv_manage*)back)->nv_item_data[0]);
211 flag_read_success = HI_TRUE;
212 }
213 }
214 if (flag_read_success != HI_TRUE) {
215 rom_boot_free(data);
216 rom_boot_free(back);
217 return HI_ERR_NV_INITILIZATION;
218 }
219 nv_info.base_addr = base_addr;
220 nv_info.block_size = block_size;
221 nv_info.total_size = total_size;
222 /* Applying for Index Space CNcomment:索引空间申请 */
223 ret = nv_init_index(nv_ctrl, (const nvm_basic_info*)&nv_info, p_index, (const hi_u8**)&data, (const hi_u8**)&back);
224 return ret;
225 }
226
nv_get_item_len(hi_u32 id,hi_nv_type nv_type)227 hi_u8 nv_get_item_len(hi_u32 id, hi_nv_type nv_type)
228 {
229 hi_nv_item_index* nv_index;
230
231 nv_index = nv_find_item(HI_NULL, (hi_u8)id, nv_type);
232 if (nv_index == HI_NULL) {
233 return 0;
234 }
235 return nv_index->nv_len;
236 }
nv_read_common(hi_u8 id,hi_pvoid pdata,hi_u8 len,hi_nv_type nv_type)237 hi_u32 nv_read_common(hi_u8 id, hi_pvoid pdata, hi_u8 len, hi_nv_type nv_type)
238 {
239 hi_u32 ret;
240 hi_nv_ctrl* nv_ctrl = HI_NULL;
241 hi_nv_item_index* nv_index = HI_NULL;
242 hi_u32 crc = 0;
243 hi_u32 flash_addr;
244 hi_u8 item_len;
245 hi_bool to_check_crc;
246 hi_u32 crc_val = 0;
247
248 if (nv_type >= HI_TYPE_NV_MAX) {
249 return HI_ERR_NV_INVALID_PARAMETER;
250 }
251 nv_ctrl = &g_s_nv_ctrl[nv_type];
252 nv_index = nv_find_item(HI_NULL, id, nv_type);
253 if (nv_index == HI_NULL) {
254 return HI_ERR_NV_ERROR_READ;
255 }
256 if (nv_index->nv_len == len) {
257 item_len = len;
258 to_check_crc = HI_TRUE;
259 } else {
260 item_len = hi_min(nv_index->nv_len, len);
261 to_check_crc = HI_FALSE;
262 }
263
264 flash_addr = nv_ctrl->current_addr + nv_index->nv_offset;
265 ret = nv_read_flash(flash_addr, item_len, pdata);
266 if (ret != HI_ERR_SUCCESS) {
267 return ret;
268 }
269
270 if (to_check_crc == HI_TRUE) {
271 ret = nv_read_flash(flash_addr + item_len, sizeof(crc), (hi_u8*)&crc);
272 if (ret != HI_ERR_SUCCESS) {
273 return ret;
274 }
275 hi_crc32_nv(0, pdata, item_len, &crc_val);
276 if (crc != crc_val) {
277 return HI_ERR_NV_BAD_DATA;
278 }
279 } else {
280 ret = HI_ERR_NV_LEN_ERR;
281 }
282
283 return ret;
284 }
285
286
nv_next_addr(HI_CONST hi_nv_ctrl * nv_ctrl)287 hi_u32 nv_next_addr(HI_CONST hi_nv_ctrl *nv_ctrl)
288 {
289 hi_u32 new_addr = ((nv_ctrl->current_addr + nv_ctrl->block_size) < (nv_ctrl->base_addr + nv_ctrl->total_block_size))
290 ? (nv_ctrl->current_addr + nv_ctrl->block_size) : (nv_ctrl->base_addr);
291
292 return new_addr;
293 }
294
nv_block_write(hi_u8 * p_nv_file,hi_nv_type nv_type)295 hi_u32 nv_block_write(hi_u8* p_nv_file, hi_nv_type nv_type)
296 {
297 hi_u32 ret;
298 hi_nv_ctrl* nv_ctrl = &g_s_nv_ctrl[nv_type];
299 hi_nv_manage* nv_head = (hi_nv_manage*)p_nv_file;
300 hi_u32 flash_addr = nv_next_addr((HI_CONST hi_nv_ctrl *)nv_ctrl);
301
302 nv_head->ver_magic = g_ver_magic;
303 nv_head->seq = nv_ctrl->seq + 1;
304
305 hi_crc32_nv(0, p_nv_file + 8, nv_ctrl->block_size - 8, &(nv_head->crc)); // 8
306 ret = nv_write_flash(flash_addr, nv_ctrl->block_size, p_nv_file);
307 if (ret != HI_ERR_SUCCESS) {
308 return ret;
309 }
310 nv_ctrl->seq = nv_head->seq;
311 nv_ctrl->current_addr = flash_addr;
312
313 return ret;
314 }
nv_common_write(hi_u8 id,hi_nv_type nv_type,hi_u8 len,const hi_pvoid data)315 hi_u32 nv_common_write(hi_u8 id, hi_nv_type nv_type, hi_u8 len, const hi_pvoid data)
316 {
317 hi_u8 backup_num = 1;
318 hi_u8 item_len = len;
319 hi_u32 ret, crc, cs;
320 hi_nv_ctrl* nv_ctrl = &g_s_nv_ctrl[nv_type];
321
322 /* Normal write process */
323 hi_nv_item_index* nv_index = nv_find_item(HI_NULL, id, nv_type);
324 if (nv_index == HI_NULL) {
325 return HI_ERR_NV_ERROR_READ;
326 }
327 /* Length processing */
328 if (nv_index->nv_len != len) {
329 item_len = hi_min(nv_index->nv_len, len);
330 }
331
332 hi_u8* nv_file = (hi_u8 *)rom_boot_malloc(nv_ctrl->block_size);
333 if (nv_file == HI_NULL) {
334 return HI_ERR_MALLOC_FAILUE;
335 }
336 if (nv_type == HI_TYPE_FACTORY_NV) {
337 backup_num = 2; /* 2:Two copies of operations in the factory area are backed up. */
338 }
339 for (; backup_num > 0; backup_num--) {
340 ret = nv_read_flash(nv_ctrl->current_addr, nv_ctrl->block_size, nv_file);
341 if (ret != HI_ERR_SUCCESS) {
342 continue;
343 }
344
345 hi_crc32_nv(0, data, item_len, &crc);
346 cs = (uintptr_t)(nv_file + nv_index->nv_offset) ^ item_len ^ (uintptr_t)data ^ item_len;
347 if (memcpy_s(nv_file + nv_index->nv_offset, item_len, data, item_len, cs) != EOK) {
348 continue;
349 }
350 cs = (uintptr_t)(nv_file + nv_index->nv_offset + item_len) ^ sizeof(crc) ^ ((uintptr_t)&crc) ^ sizeof(crc);
351 if (memcpy_s(nv_file + nv_index->nv_offset + item_len, sizeof(crc), &crc, sizeof(crc), cs) != EOK) {
352 continue;
353 }
354 ret = nv_block_write(nv_file, nv_type);
355 if (ret != HI_ERR_SUCCESS) {
356 continue;
357 }
358 }
359 rom_boot_free(nv_file);
360 return ret;
361 }
362
nv_write_common(hi_u8 id,const hi_pvoid data,hi_u8 len,hi_nv_type nv_type)363 hi_u32 nv_write_common(hi_u8 id, const hi_pvoid data, hi_u8 len, hi_nv_type nv_type)
364 {
365 if (nv_type >= HI_TYPE_NV_MAX) {
366 return HI_ERR_NV_INVALID_PARAMETER;
367 }
368
369 hi_u8* item_readback = (hi_u8 *)rom_boot_malloc(HNV_ITEM_MAXLEN);
370 if (item_readback == HI_NULL) {
371 return HI_ERR_MALLOC_FAILUE;
372 }
373
374 hi_u32 ret = nv_read_common(id, item_readback, len, nv_type);
375 if (ret != HI_ERR_SUCCESS) {
376 rom_boot_free(item_readback);
377 return ret;
378 }
379 if (memcmp(data, item_readback, len) == HI_ERR_SUCCESS) {
380 rom_boot_free(item_readback);
381 return HI_ERR_SUCCESS;
382 }
383 rom_boot_free(item_readback);
384
385 /* Normal write process */
386 ret = nv_common_write(id, nv_type, len, data);
387 if (ret != HI_ERR_SUCCESS) {
388 return ret;
389 }
390 return HI_ERR_SUCCESS;
391 }
392
hi_factory_nv_init(hi_u32 addr,hi_u32 total_size,hi_u32 block_size)393 hi_u32 hi_factory_nv_init(hi_u32 addr, hi_u32 total_size, hi_u32 block_size)
394 {
395 return nv_init_common(addr, total_size, block_size, HI_TYPE_FACTORY_NV);
396 }
397
hi_factory_nv_write(hi_u8 id,hi_pvoid pdata,hi_u8 len,hi_u32 flag)398 hi_u32 hi_factory_nv_write(hi_u8 id, hi_pvoid pdata, hi_u8 len, hi_u32 flag)
399 {
400 hi_unref_param(flag);
401 hi_u32 ret;
402 hi_nv_ctrl* nv_ctrl = HI_NULL;
403
404 if (id >= HI_NV_FACTORY_USR_ID_END) {
405 return HI_ERR_NV_NOT_SUPPORT;
406 }
407 if ((pdata == HI_NULL) || (len == 0) || (len > HNV_ITEM_MAXLEN)) {
408 return HI_ERR_NV_INVALID_PARAMETER;
409 }
410 nv_ctrl = &g_s_nv_ctrl[HI_TYPE_FACTORY_NV];
411 if (nv_ctrl->init_flag != HI_TRUE) {
412 return HI_ERR_NV_INITILIZATION;
413 }
414 ret = nv_write_common(id, (HI_CONST hi_pvoid)pdata, len, HI_TYPE_FACTORY_NV);
415
416 return ret;
417 }
418
hi_factory_nv_read(hi_u8 id,hi_pvoid data,hi_u8 len,hi_u32 flag)419 hi_u32 hi_factory_nv_read(hi_u8 id, hi_pvoid data, hi_u8 len, hi_u32 flag)
420 {
421 hi_unref_param(flag);
422 hi_u32 ret;
423 hi_nv_ctrl* nv_ctrl = HI_NULL;
424
425 if (id >= HI_NV_FACTORY_USR_ID_END) {
426 return HI_ERR_NV_NOT_SUPPORT;
427 }
428 if ((data == HI_NULL) || (len == 0) || (len > HNV_ITEM_MAXLEN)) {
429 return HI_ERR_NV_INVALID_PARAMETER;
430 }
431 nv_ctrl = &g_s_nv_ctrl[HI_TYPE_FACTORY_NV];
432 if (nv_ctrl->init_flag != HI_TRUE) {
433 return HI_ERR_NV_INITILIZATION;
434 }
435 ret = nv_read_common(id, data, len, HI_TYPE_FACTORY_NV);
436
437 return ret;
438 }
439