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