• 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  * Description: UPG process management functions source file
15  */
16 
17 #include <stddef.h>
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include "securec.h"
22 #include "common_def.h"
23 #include "partition.h"
24 #include "upg_definitions.h"
25 #include "errcode.h"
26 #include "upg_common.h"
27 #include "upg_common_porting.h"
28 #include "upg_alloc.h"
29 #include "upg_porting.h"
30 #include "upg_config.h"
31 #include "upg_debug.h"
32 
33 #if ((UPG_CFG_SUPPORT_IMAGE_ON_FILE_SYSTEM == YES) || (UPG_CFG_SUPPORT_RESOURCES_FILE == YES))
34 #include "fcntl.h"
35 #include "sys/stat.h"
36 #include "sys/vfs.h"
37 #endif
38 
39 #define NOT_START_FLAG 0xFF
40 
upg_get_package_info(fota_upgrade_flag_area_t * upg_flag,const upg_package_header_t * pkg_header,upg_package_info_t * pkg_info)41 STATIC errcode_t upg_get_package_info(fota_upgrade_flag_area_t *upg_flag,
42                                       const upg_package_header_t *pkg_header, upg_package_info_t *pkg_info)
43 {
44     errcode_t ret;
45     upg_image_hash_node_t *img_hash_table = NULL;
46     int32_t image_index;
47     int32_t firmware_index;
48     uint32_t image_num;
49 
50     pkg_info->total_new_fw_size = 0;
51     pkg_info->finished_fw_size = 0;
52 
53     ret = upg_get_pkg_image_hash_table(pkg_header, &img_hash_table);
54     if (ret != ERRCODE_SUCC || img_hash_table == NULL) {
55         upg_log_err("[UPG] upg_get_pkg_image_hash_table fail\r\n");
56         return ret;
57     }
58 
59     image_num = pkg_header->info_area.image_num;
60 
61     for (image_index = 0, firmware_index = 0; image_index < (int32_t)image_num; image_index++, firmware_index++) {
62         if (img_hash_table[image_index].image_id == UPG_IMAGE_ID_NV) {
63             firmware_index--;
64             continue;
65         }
66 
67         upg_image_header_t *img_header = NULL;
68         ret = upg_get_pkg_image_header((const upg_image_hash_node_t *)&(img_hash_table[image_index]), &img_header);
69         if (ret != ERRCODE_SUCC || img_header == NULL) {
70             upg_log_err("[UPG] upg_get_pkg_image_header fail\r\n");
71             upg_free(img_hash_table);
72             return ret;
73         }
74 
75         pkg_info->total_new_fw_size += img_header->new_image_len;
76 
77         upg_image_status_t status;
78         status = upg_get_image_update_status(upg_flag, (uint32_t)firmware_index, img_hash_table[image_index].image_id);
79         if (status == UPG_IMAGE_STATUS_FINISHED) {
80             pkg_info->finished_fw_size += img_header->new_image_len;
81         }
82         upg_free(img_header);
83     }
84     upg_free(img_hash_table);
85     upg_log_info("[UPG] package info total= 0x%x, finished = 0x%x\r\n",
86         pkg_info->total_new_fw_size, pkg_info->finished_fw_size);
87 
88     return ret;
89 }
90 
91 #if defined(UPG_CFG_SUPPORT_ERASE_WHOLE_IMAGE) && defined(YES) && (UPG_CFG_SUPPORT_ERASE_WHOLE_IMAGE == YES)
upg_erase_whole_image(const upg_image_header_t * img_header)92 __attribute__((weak)) errcode_t upg_erase_whole_image(const upg_image_header_t *img_header)
93 {
94     unused(img_header);
95     return ERRCODE_SUCC;
96 }
97 #endif
98 /* 执行指定固件的更新任务 */
upg_perform_image_task(const upg_image_header_t * img_header)99 STATIC errcode_t upg_perform_image_task(const upg_image_header_t *img_header)
100 {
101     errcode_t ret;
102     if (img_header->image_id != UPG_IMAGE_ID_RES_INDEX && img_header->image_id != UPG_IMAGE_ID_RES_DATA) {
103         upg_log_info("[UPG] image decompress_flag: 0x%x\r\n", img_header->decompress_flag);
104         if (img_header->decompress_flag == DECOMPRESS_FLAG_ZIP) {
105             /* 压缩升级 */
106             upg_log_info("[UPG] decompress upg\r\n");
107 #if defined(UPG_CFG_SUPPORT_ERASE_WHOLE_IMAGE) && defined(YES) && (UPG_CFG_SUPPORT_ERASE_WHOLE_IMAGE == YES)
108             ret = upg_erase_whole_image(img_header);
109             if (ret != ERRCODE_SUCC) {
110                 return ret;
111             }
112 #endif
113             ret = uapi_upg_compress_image_update(img_header);
114         } else if (img_header->decompress_flag == DECOMPRESS_FLAG_DIFF) {
115             /* 差分升级 */
116             upg_log_info("[UPG] diff upg\r\n");
117             ret = uapi_upg_diff_image_update(img_header);
118         } else {
119             /* 全镜像升级 */
120             upg_log_info("[UPG] full upg\r\n");
121 #if defined(UPG_CFG_SUPPORT_ERASE_WHOLE_IMAGE) && defined(YES) && (UPG_CFG_SUPPORT_ERASE_WHOLE_IMAGE == YES)
122             ret = upg_erase_whole_image(img_header);
123             if (ret != ERRCODE_SUCC) {
124                 return ret;
125             }
126 #endif
127             ret = uapi_upg_full_image_update(img_header);
128         }
129 #if (UPG_CFG_SUPPORT_RESOURCES_FILE == YES)
130     } else if (img_header->image_id == UPG_IMAGE_ID_RES_INDEX) {
131         ret = uapi_upg_resource_index_process(img_header);
132     } else {
133         ret = uapi_upg_resource_data_process(img_header);
134 #else
135     } else {
136         ret = ERRCODE_UPG_NOT_SUPPORTED;
137 #endif
138     }
139 
140     return ret;
141 }
142 
upg_perform_upgrade_task(const upg_image_header_t * img_header,const upg_image_hash_node_t * img_hash_table,uint32_t firmware_index,upg_image_status_t status,fota_upgrade_flag_area_t * upg_flag)143 STATIC errcode_t upg_perform_upgrade_task(const upg_image_header_t *img_header,
144                                           const upg_image_hash_node_t *img_hash_table, uint32_t firmware_index,
145                                           upg_image_status_t status, fota_upgrade_flag_area_t *upg_flag)
146 {
147     errcode_t ret;
148     upg_image_status_switch_t switch_status;
149 
150     if (status == UPG_IMAGE_STATUS_NOT_STARTED) {
151         ret = upg_flash_erase_metadata_pages();
152         if (ret != ERRCODE_SUCC) {
153             upg_log_err("[UPG] upg_flash_erase_metadata_pages fail.\r\n");
154             goto end;
155         }
156     }
157 
158 #if (UPG_CFG_VERIFICATION_SUPPORT == YES)
159     /* 校验Image, 如果校验失败,再次尝试 */
160     ret = uapi_upg_verify_file_image(img_header, img_hash_table->image_hash, SHA_256_LENGTH,
161                                      status == UPG_IMAGE_STATUS_NOT_STARTED);
162     if (ret != ERRCODE_SUCC) {
163         goto end;
164     }
165 #else
166     unused(img_hash_table);
167 #endif
168 
169     ret = upg_perform_image_task(img_header);
170 end:
171     if (ret == ERRCODE_SUCC) {
172         /* 校验并升级成功,设置升级标记为FINISH */
173         switch_status = UPG_IMAGE_STATUS_SWITCH_TO_FINISHED;
174 #if (UPG_CFG_ANTI_ROLLBACK_SUPPORT == YES)
175         (void)upg_anti_rollback_version_update(img_header);
176 #endif
177     } else {
178         /* 校验或升级不成功,设置升级标记为RETRY */
179         switch_status = UPG_IMAGE_STATUS_SWITCH_TO_RETRY;
180     }
181 
182     upg_log_info("[UPG] switch status = 0x%x\r\n", (uint32_t)switch_status);
183     errcode_t status_ret = upg_set_firmware_update_status(upg_flag, firmware_index, switch_status);
184     if (ret != ERRCODE_SUCC) {
185         return ret;
186     }
187     return status_ret;
188 }
189 
190 /* 执行NV镜像的处理任务 */
upg_perform_nv_task(const upg_image_header_t * img_header,uint32_t image_header_offset,fota_upgrade_flag_area_t * upg_flag)191 STATIC errcode_t upg_perform_nv_task(const upg_image_header_t *img_header,
192                                      uint32_t image_header_offset, fota_upgrade_flag_area_t *upg_flag)
193 {
194     errcode_t ret;
195 
196     if (img_header->image_id != UPG_IMAGE_ID_NV) {
197         return ERRCODE_UPG_INVALID_IMAGE_ID;
198     }
199 
200     upg_flag->nv_data_offset = img_header->image_offset;
201     upg_flag->nv_data_len = upg_aligned(img_header->image_len, 16); /* 16-byte alignment */
202     upg_flag->nv_hash_offset = image_header_offset + offsetof(upg_image_header_t, image_hash);
203     upg_flag->nv_hash_len = SHA_256_LENGTH;
204 
205     uint32_t fota_flag_addr = 0;
206     ret = upg_get_upgrade_flag_flash_start_addr(&fota_flag_addr);
207     if (ret != ERRCODE_SUCC) {
208         return ret;
209     }
210 
211     uint32_t nv_addr = fota_flag_addr + offsetof(fota_upgrade_flag_area_t, nv_data_offset);
212     uint32_t nv_info_len = 4 * (uint32_t)sizeof(uint32_t); /* write 4 fields of u32 */
213     ret = upg_flash_write(nv_addr, nv_info_len, (uint8_t *)&(upg_flag->nv_data_offset), false);
214     if (ret != ERRCODE_SUCC) {
215         return ret;
216     }
217 
218     return upg_set_firmware_update_status(upg_flag, UPG_IMAGE_ID_NV, UPG_IMAGE_STATUS_SWITCH_TO_STARTED);
219 }
220 
upg_process_update_image_tasks(fota_upgrade_flag_area_t * upg_flag,uint32_t image_num,const upg_image_hash_node_t * hash_table)221 STATIC errcode_t upg_process_update_image_tasks(fota_upgrade_flag_area_t *upg_flag,
222                                                 uint32_t image_num, const upg_image_hash_node_t *hash_table)
223 {
224     upg_image_header_t *img_header = NULL;
225     int32_t img_idx;
226     int32_t fw_idx;
227     errcode_t ret = ERRCODE_SUCC;
228 
229     for (img_idx = 0, fw_idx = 0; img_idx < (int32_t)image_num; img_idx++, fw_idx++) {
230         if (hash_table[img_idx].image_id == UPG_IMAGE_ID_NV) {
231             fw_idx--;
232         }
233 
234         if (!upg_img_in_set(hash_table[img_idx].image_id)) {
235             continue;
236         }
237 
238         upg_image_status_t status =
239             upg_get_image_update_status(upg_flag, (uint32_t)fw_idx, hash_table[img_idx].image_id);
240         /* 如果该Image已经完成,处理下一个image */
241         if (status == UPG_IMAGE_STATUS_FINISHED) {
242             upg_log_info("[UPG] The image has finished. image_id = 0x%x\r\n", hash_table[img_idx].image_id);
243             continue;
244         }
245 
246         /* 获取Image Header */
247         ret = upg_get_pkg_image_header(&(hash_table[img_idx]), &img_header);
248         if (ret != ERRCODE_SUCC || img_header == NULL) {
249             upg_log_err("[UPG] upg_get_pkg_image_header fail.\r\n");
250             goto ret_free;
251         }
252 
253         /* 执行Image的更新 */
254         if (img_header->image_id != UPG_IMAGE_ID_NV) {
255             /* 设置升级标记为STARTED */
256             ret = upg_set_firmware_update_status(upg_flag, (uint32_t)fw_idx, UPG_IMAGE_STATUS_SWITCH_TO_STARTED);
257             if (ret != ERRCODE_SUCC) {
258                 upg_log_err("[UPG] upg_set_firmware_update_status fail\r\n");
259                 goto ret_free;
260             }
261             upg_log_info("[UPG] start perform update image : 0x%x\r\n", img_header->image_id);
262             ret = upg_perform_upgrade_task(img_header, &(hash_table[img_idx]), (uint32_t)fw_idx, status, upg_flag);
263             upg_log_info("[UPG] perform update image over. ret = 0x%x\r\n", ret);
264 
265             if (ret != ERRCODE_SUCC) {
266                 goto ret_free;
267             }
268         } else {
269             upg_log_info("[UPG] start perform NV image : 0x%x\r\n", img_header->image_id);
270             ret = upg_perform_nv_task(img_header, hash_table[img_idx].image_addr, upg_flag);
271             upg_log_info("[UPG] perform NV image over. ret = 0x%x\r\n", ret);
272         }
273 
274         upg_free(img_header);
275         img_header = NULL;
276         upg_watchdog_kick();
277     }
278 ret_free:
279     if (img_header) {
280         upg_free(img_header);
281     }
282     return ret;
283 }
284 
upg_process_update(fota_upgrade_flag_area_t * upg_flag,const upg_package_header_t * pkg_header)285 STATIC errcode_t upg_process_update(fota_upgrade_flag_area_t *upg_flag, const upg_package_header_t *pkg_header)
286 {
287     errcode_t ret_val = ERRCODE_SUCC;
288     upg_image_hash_node_t *img_hash_table = NULL;
289 
290     uint32_t image_num = pkg_header->info_area.image_num;
291     upg_log_info("[UPG] update image number = 0x%x\r\n", image_num);
292     upg_log_info("[UPG] update firmware number = 0x%x\r\n", upg_flag->firmware_num);
293 
294     /* 升级标记中的firmware数量与升级包中的image数量不一致 */
295     if ((upg_flag->firmware_num != image_num && upg_flag->firmware_num != image_num - 1) ||
296         (upg_flag->firmware_num > UPG_FIRMWARE_MAX_NUM)) {
297         return ERRCODE_UPG_WRONG_IMAGE_NUM;
298     }
299 
300     ret_val = upg_get_pkg_image_hash_table((const upg_package_header_t *)pkg_header, &img_hash_table);
301     if (ret_val != ERRCODE_SUCC || img_hash_table == NULL) {
302         upg_log_err("[UPG] upg_get_pkg_image_hash_table fail\r\n");
303         return ret_val;
304     }
305 
306     ret_val = upg_process_update_image_tasks(upg_flag, image_num, (const upg_image_hash_node_t *)img_hash_table);
307     if (ret_val != ERRCODE_SUCC) {
308         upg_log_err("[UPG] upg_process_update_image_tasks fail, ret = 0x%x\r\n", ret_val);
309     }
310     upg_free(img_hash_table);
311     return ret_val;
312 }
313 
314 #if (UPG_CFG_VERIFICATION_SUPPORT == YES) && (UPG_CFG_INTEGRITY_VERIFICATION_ONLY == NO)
upg_check_first_entry(const fota_upgrade_flag_area_t * upg_flag_info)315 bool upg_check_first_entry(const fota_upgrade_flag_area_t *upg_flag_info)
316 {
317     uint8_t check_flag[UPG_FLAG_RETYR_TIMES] = {NOT_START_FLAG, NOT_START_FLAG, NOT_START_FLAG};
318     for (uint32_t i = 0; i < upg_flag_info->firmware_num; i++) {
319         if (memcmp(upg_flag_info->firmware_flag[i], check_flag, UPG_FLAG_RETYR_TIMES) != 0) {
320             return false;
321         }
322     }
323     return true;
324 }
325 #endif
326 
327 /* 开始升级 */
uapi_upg_start(void)328 errcode_t uapi_upg_start(void)
329 {
330     fota_upgrade_flag_area_t *upg_flag_info = NULL;
331     upg_package_header_t     *pkg_header = NULL;
332     errcode_t                 ret;
333     uint32_t                  img_num = 0;
334     upg_package_info_t       *pkg_info = NULL;
335     bool                      direct_finish = true;
336 
337     if (upg_is_inited() == false) {
338         ret = ERRCODE_UPG_NOT_INIT;
339         goto end;
340     }
341 
342     ret = upg_alloc_and_get_upgrade_flag(&upg_flag_info);
343     if (ret != ERRCODE_SUCC || upg_flag_info == NULL) {
344         goto end;
345     }
346 
347     /* 判断升级区有没有升级包 */
348     if (!(upg_flag_info->head_magic == UPG_HEAD_MAGIC &&
349         upg_flag_info->head_end_magic == UPG_END_MAGIC && upg_flag_info->complete_flag != 0)) {
350         /* 不需要升级直接返回 */
351         upg_log_err("[UPG] Not need to upgrade...\r\n");
352         ret = ERRCODE_UPG_NOT_NEED_TO_UPDATE;
353         goto end;
354     }
355 
356     ret = upg_get_package_header(&pkg_header);
357     if (ret != ERRCODE_SUCC || pkg_header == NULL) {
358         upg_log_err("[UPG] upg_get_package_header fail\r\n");
359         goto end;
360     }
361 
362 #if (UPG_CFG_VERIFICATION_SUPPORT == YES) && (UPG_CFG_INTEGRITY_VERIFICATION_ONLY == NO)
363     /* 升级包的整包校验 */
364     if (upg_check_first_entry((const fota_upgrade_flag_area_t *)upg_flag_info)) {
365         ret = uapi_upg_verify_file((const upg_package_header_t *)pkg_header);
366         if (ret != ERRCODE_SUCC) {
367             goto end;
368         }
369     }
370 #endif
371 
372     pkg_info = &upg_get_ctx()->package_info;
373     ret = upg_get_package_info(upg_flag_info, (const upg_package_header_t *)pkg_header, pkg_info);
374     if (ret != ERRCODE_SUCC) {
375         upg_set_temporary_result(UPG_RESULT_VERIFY_HEAD_FAILED);
376         goto end;
377     }
378 
379     ret = upg_process_update(upg_flag_info, (const upg_package_header_t *)pkg_header);
380     direct_finish = false;
381     img_num = pkg_header->info_area.image_num;
382 end:
383     /* 更新complete_flag */
384     upg_set_complete_flag(img_num, ret, direct_finish);
385     upg_free(upg_flag_info);
386     upg_free(pkg_header);
387     return ret;
388 }
389 
390 /* 注册升级进度通知回调函数 */
uapi_upg_register_progress_callback(uapi_upg_progress_cb func)391 errcode_t uapi_upg_register_progress_callback(uapi_upg_progress_cb func)
392 {
393 #if (UPG_CFG_PROCESS_NOTIFY_SUPPORT == YES)
394     upg_get_ctx()->progress_cb = func;
395     return ERRCODE_SUCC;
396 #else
397     unused(func);
398     return ERRCODE_UPG_NOT_SUPPORTED;
399 #endif
400 }
401 
402 /* 计算升级进度并通知上层 */
upg_calculate_and_notify_process(uint32_t current_size)403 void upg_calculate_and_notify_process(uint32_t current_size)
404 {
405 #if (UPG_CFG_PROCESS_NOTIFY_SUPPORT == YES)
406     static uint32_t last_percent = 0;
407     uint32_t percent = 0;
408     upg_package_info_t *pkg_info = &upg_get_ctx()->package_info;
409 
410     if (upg_get_ctx()->progress_cb != NULL) {
411         pkg_info->finished_fw_size += current_size;
412         if (pkg_info->total_new_fw_size != 0) {
413             percent = pkg_info->finished_fw_size * 100 / pkg_info->total_new_fw_size; /* 100: percent */
414         }
415         if (percent != last_percent) {
416             upg_get_ctx()->progress_cb(percent);
417             last_percent = percent;
418         }
419     }
420 #else
421     unused(current_size);
422 #endif
423 }
424 
425 #if ((UPG_CFG_SUPPORT_IMAGE_ON_FILE_SYSTEM == YES) || (UPG_CFG_SUPPORT_RESOURCES_FILE == YES))
upg_write_new_image_data_on_fs(const char * file_path,uint32_t write_offset,uint8_t * buffer,uint32_t * write_len)426 STATIC errcode_t upg_write_new_image_data_on_fs(const char *file_path, uint32_t write_offset,
427                                                 uint8_t *buffer, uint32_t *write_len)
428 {
429     uint16_t real_len = 0;
430     FILE *wr_fd = NULL;
431 
432     if (write_offset == 0) {
433         wr_fd = fopen(file_path, "wb");
434     } else {
435         wr_fd = fopen(file_path, "rb+");
436     }
437     if (wr_fd == NULL) {
438         upg_log_err("[UPG] open %s fail!\r\n", file_path);
439         return ERRCODE_UPG_FILE_OPEN_FAIL;
440     }
441 
442     errcode_t ret = fseek(wr_fd, write_offset, SEEK_SET);
443     if (ret != 0) {
444         ret = ERRCODE_UPG_FILE_SEEK_FAIL;
445         upg_log_err("[UPG] seek file fail!\r\n");
446         goto end;
447     }
448 
449     uint16_t left_len = *write_len;
450     while (left_len > 0) {
451         /* 一次未写完,可多次读取 */
452         uint16_t tmp = fwrite(buffer + real_len, 1, left_len, wr_fd);
453         if (tmp == 0) {
454             /* 写入失败,中断写入操作 */
455             if (ferror(wr_fd)) {
456                 ret = ERRCODE_UPG_FILE_WRITE_FAIL;
457                 upg_log_err("[UPG] write file fail!\r\n");
458                 goto end;
459             }
460         }
461         left_len -= tmp;
462         real_len += tmp;
463     }
464 
465 end:
466     *write_len = real_len;
467     (void)fclose(wr_fd);
468     return ret;
469 }
470 #endif
471 
472 /*
473  * 将buffer中的数据写入指定image_id的镜像所在的地址上
474  * write_offset 相对镜像起始地址的偏移
475  * buffer       写入数据的buffer指针
476  * write_len    输入buffer的长度,输出实际写入的数据长度
477  * image_id     镜像的ID
478  */
upg_write_new_image_data(uint32_t write_offset,uint8_t * buffer,uint32_t * write_len,uint32_t image_id,bool do_erase)479 errcode_t upg_write_new_image_data(uint32_t write_offset, uint8_t *buffer, uint32_t *write_len, uint32_t image_id,
480     bool do_erase)
481 {
482     errcode_t ret = ERRCODE_SUCC;
483     partition_information_t image_info = {0};
484 
485     if (image_id == PARAMS_PARTITION_IMAGE_ID) {
486         /* 参数区地址信息 */
487         image_info.type = PARTITION_BY_ADDRESS;
488         image_info.part_info.addr_info.addr = PARAMS_PARTITION_START_ADDR;
489         image_info.part_info.addr_info.size = PARAMS_PARTITION_LENGTH;
490 #if (UPG_CFG_SUPPORT_RESOURCES_FILE == YES)
491     } else if (image_id == UPG_IMAGE_ID_RES_INDEX) {
492         image_info.type = PARTITION_BY_PATH;
493         image_info.part_info.file_path = upg_get_res_file_index_path();
494 #endif
495     } else {
496         ret = upg_get_image_info(image_id, &image_info);
497         if (ret != ERRCODE_SUCC) {
498             return ret;
499         }
500     }
501 
502     if (image_info.type == PARTITION_BY_ADDRESS) {
503         ret = upg_flash_write(
504             image_info.part_info.addr_info.addr + write_offset, *write_len, (uint8_t *)buffer, do_erase); /* 写前擦除 */
505     } else { /* 分区类型:PARTITION_BY_PATH */
506 #if ((UPG_CFG_SUPPORT_IMAGE_ON_FILE_SYSTEM == YES) || (UPG_CFG_SUPPORT_RESOURCES_FILE == YES))
507         ret = upg_write_new_image_data_on_fs(
508             (const char *)image_info.part_info.file_path, write_offset, buffer, write_len);
509 #else
510         ret = ERRCODE_IMAGE_CONFIG_NOT_FOUND;
511 #endif
512     }
513     return ret;
514 }
515