• 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  */
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