• 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 #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