mcu_hi3321_watch/middleware/utils/update/common/upg_common.c
2025-05-26 20:15:20 +08:00

1016 lines
33 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) @CompanyNameMagicTag 2021-2021. All rights reserved.
* Description: UPG common functions source file
*/
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "common_def.h"
#include "upg_config.h"
#if (UPG_CFG_SUPPORT_FILE_SYSTEM == YES)
#include "fcntl.h"
#include "unistd.h"
#include "sys/stat.h"
#include "sys/vfs.h"
#include "dfx_file_operation.h"
#endif /* (UPG_CFG_SUPPORT_FILE_SYSTEM == YES) */
#include "upg_common_porting.h"
#include "errcode.h"
#include "securec.h"
#include "partition.h"
#include "upg_alloc.h"
#include "upg_otp_reg.h"
#include "upg.h"
#include "upg_porting.h"
#include "upg_config.h"
#include "upg_debug.h"
#include "upg_common.h"
#define NOT_START_FLAG 0xFF
#define STARTED_FLAG 0x0F
#define FINISHED_FLAG 0x00
#define UPG_FINISH_HALF_FLAG 0xFFFF
#define UPG_FINISH_ALL_FLAG 0
#define UPG_ABNORMAL_FLAG 0x5a5a5a5a
#define PER_FILE_STORAGE_MAX_SIZE 4294967295
STATIC upg_storage_ctx_t g_upg_ctx = {0};
upg_storage_ctx_t *upg_get_ctx(void)
{
return &g_upg_ctx;
}
/* 获取升级标记结构到RAM中 */
errcode_t upg_alloc_and_get_upgrade_flag(fota_upgrade_flag_area_t **upg_flag)
{
uint32_t start_addr = 0;
errcode_t ret_val;
ret_val = upg_get_upgrade_flag_flash_start_addr(&start_addr);
if (ret_val != ERRCODE_SUCC) {
upg_msg0("upg_get_upgrade_flag_flash_start_addr fail\r\n");
return ret_val;
}
*upg_flag = (fota_upgrade_flag_area_t*)upg_malloc(sizeof(fota_upgrade_flag_area_t));
if (*upg_flag == NULL) {
upg_msg0("upg_alloc_and_get_upgrade_flag upg_malloc fail\r\n");
return ERRCODE_MALLOC;
}
ret_val = upg_flash_read(start_addr, sizeof(fota_upgrade_flag_area_t), (uint8_t *)(*upg_flag));
if (ret_val != ERRCODE_SUCC) {
upg_msg0("upg_alloc_and_get_upgrade_flag read flash fail\r\n");
upg_free(*upg_flag);
*upg_flag = NULL;
return ret_val;
}
return ERRCODE_SUCC;
}
/*
* 获取在当前Flash上指定固件镜像的地址信息。该地址为flash上的相对地址是相对flash基地址的偏移
* image_id 固件的镜像ID
* start_address 返回该镜像的起始地址
* size 返回该镜像区域的大小
*/
errcode_t upg_get_partition_info(uint32_t image_id, uint32_t *start_address, uint32_t *size)
{
errcode_t ret_val = ERRCODE_SUCC;
partition_information_t image_info = {0};
if (image_id == PARAMS_PARTITION_IMAGE_ID) {
/* 参数区地址信息 */
image_info.type = PARTITION_BY_ADDRESS;
image_info.part_info.addr_info.addr = PARAMS_PARTITION_START_ADDR;
image_info.part_info.addr_info.size = PARAMS_PARTITION_LENGTH;
#if UPG_CFG_SUPPORT_RESOURCES_FILE == YES
} else if (image_id == UPG_IMAGE_ID_RES_INDEX) {
image_info.type = PARTITION_BY_PATH;
#endif
} else {
ret_val = upg_get_image_info(image_id, &image_info);
if (ret_val != ERRCODE_SUCC) {
return ret_val;
}
}
if (image_info.type == PARTITION_BY_ADDRESS) {
*start_address = image_info.part_info.addr_info.addr;
*size = image_info.part_info.addr_info.size;
} else { /* PARTITION_BY_PATH */
*start_address = 0;
*size = uapi_upg_get_storage_size();
}
return ret_val;
}
STATIC errcode_t upg_img_id_convert_to_partition_id(uint32_t image_id, partition_ids_t *item_id)
{
upg_image_partition_ids_map_t *map = NULL;
uint32_t cnt = upg_get_ids_map(&map);
if (cnt == 0 || map == NULL || item_id == NULL) {
return ERRCODE_FAIL;
}
for (uint32_t i = 0; i < cnt; i++) {
if (map[i].image_id == image_id) {
*item_id = map[i].item_id;
return ERRCODE_SUCC;
}
}
return ERRCODE_FAIL;
}
errcode_t upg_get_image_info(uint32_t image_id, partition_information_t *image_info)
{
partition_ids_t item_id;
if (image_info == NULL || upg_img_id_convert_to_partition_id(image_id, &item_id) != ERRCODE_SUCC) {
return ERRCODE_PARTITION_INVALID_PARAMS;
}
return uapi_partition_get_info(item_id, image_info);
}
#if (UPG_CFG_SUPPORT_FILE_SYSTEM == NO)
/*
* 读取升级包中的数据到buffer中
* read_offset 相对升级包开头的偏移
* buffer 读取数据buffer指针
* read_len 输入buffer的长度输出实际读到的数据长度
*/
errcode_t upg_read_fota_pkg_data(uint32_t read_offset, uint8_t *buffer, uint32_t *read_len)
{
errcode_t ret_val;
uint32_t start_addr = 0;
uint32_t size = 0;
uint32_t actual_len;
ret_val = upg_get_fota_partiton_area_addr(&start_addr, &size);
if (ret_val != ERRCODE_SUCC) {
return ret_val;
}
if (read_offset >= size || *read_len == 0) {
return ERRCODE_UPG_INVALID_PARAMETER;
}
actual_len = ((read_offset + *read_len) > size) ? (size - read_offset) : *read_len;
start_addr += read_offset;
ret_val = upg_flash_read(start_addr, actual_len, (uint8_t *)buffer);
if (ret_val != ERRCODE_SUCC) {
return ret_val;
}
*read_len = actual_len;
return ERRCODE_SUCC;
}
STATIC errcode_t upg_package_get_storage_max_size(uint32_t *size)
{
uint32_t start_addr = 0;
uint32_t fota_size = 0;
errcode_t ret = upg_get_fota_partiton_area_addr(&start_addr, &fota_size);
if (ret != ERRCODE_SUCC) {
return ret;
}
fota_size -= UPG_META_DATA_LENGTH + UPG_UPGRADE_FLAG_LENGTH;
*size = fota_size;
return ERRCODE_SUCC;
}
#else
errcode_t upg_read_fota_pkg_data(uint32_t read_offset, uint8_t *buffer, uint32_t *read_len)
{
uint32_t len = 0;
struct stat stat_buff = {0};
errcode_t ret_code = ERRCODE_SUCC;
uint32_t ret = (uint32_t)stat(upg_get_pkg_file_path(), &stat_buff);
if (ret != 0 || stat_buff.st_size == 0) {
return ERRCODE_UPG_EMPTY_FILE;
}
/* create ota image file */
int32_t rd_fd = open(upg_get_pkg_file_path(), O_RDONLY);
if (rd_fd < 0) {
return ERRCODE_UPG_FILE_OPEN_FAIL;
}
if ((long int)read_offset >= (long int)stat_buff.st_size) {
upg_msg0("The read_offset is more than file size!\n");
ret_code = ERRCODE_UPG_FILE_READ_FAIL;
goto end;
}
long int left_len = ((long int)(read_offset + *read_len) > stat_buff.st_size) ?
stat_buff.st_size - (long int)read_offset : (long int)(*read_len);
ret = (uint32_t)lseek(rd_fd, read_offset, SEEK_SET);
if (ret != read_offset) {
ret_code = ERRCODE_UPG_FILE_SEEK_FAIL;
goto end;
}
while (left_len > 0) {
int32_t tmp = read(rd_fd, buffer + len, (size_t)left_len);
if (tmp <= 0) {
upg_msg0("read_fota_pkg_data failed");
ret_code = ERRCODE_UPG_FILE_READ_FAIL;
goto end;
}
left_len -= tmp;
len += (uint32_t)tmp;
}
end:
*read_len = len;
(void)close(rd_fd);
return ret_code;
}
STATIC errcode_t upg_package_get_storage_max_size(uint32_t *size)
{
struct statfs sfs;
int result;
uint64_t free_size;
(void)memset_s(&sfs, sizeof(sfs), 0, sizeof(sfs));
result = statfs(upg_get_pkg_file_dir(), &sfs);
if (result != 0 || sfs.f_type == 0) {
upg_msg0("statfs failed! Invalid argument!\n");
return ERRCODE_FAIL;
}
free_size = (uint64_t)sfs.f_bsize * sfs.f_bfree;
if (free_size <= PER_FILE_STORAGE_MAX_SIZE) {
*size = (uint32_t)free_size;
} else {
*size = PER_FILE_STORAGE_MAX_SIZE;
}
return ERRCODE_SUCC;
}
#endif
/*
* 获取本地存储空间可存储升级包的最大空间
* 返回最大空间
*/
uint32_t uapi_upg_get_storage_size(void)
{
if (upg_is_inited() == false) {
return 0;
}
uint32_t size;
if (upg_package_get_storage_max_size(&size) != ERRCODE_SUCC) {
return 0;
}
return size;
}
/*
* 获取升级包包头结构指针
* pkg_header 返回升级包头结构指针指针指向的空间在函数内分配需要使用者使用完后调用upg_free释放。
* (如果采用直接访问flash的方式返回升级包头所在的flash地址)
*/
errcode_t upg_get_package_header(upg_package_header_t **pkg_header)
{
#if (UPG_CFG_DIRECT_FLASH_ACCESS == NO)
errcode_t ret;
uint32_t actual_len = (uint32_t)sizeof(upg_package_header_t);
*pkg_header = upg_malloc(sizeof(upg_package_header_t));
if (*pkg_header == NULL) {
return ERRCODE_MALLOC;
}
ret = upg_read_fota_pkg_data(0, (uint8_t *)(*pkg_header), &actual_len);
if (ret != ERRCODE_SUCC || actual_len != sizeof(upg_package_header_t)) {
upg_free(*pkg_header);
*pkg_header = NULL;
return ret;
}
#else
uint32_t start_addr = 0;
uint32_t size = 0;
errcode_t ret;
ret = upg_get_fota_partiton_area_addr(&start_addr, &size);
if (ret != ERRCODE_SUCC) {
return ret;
}
*pkg_header = (upg_package_header_t*)(uintptr_t)(start_addr + upg_get_flash_base_addr());
#endif /* #if UPG_CFG_DIRECT_FLASH_ACCESS */
return ERRCODE_SUCC;
}
/*
* 获取镜像哈希表结构指针
* pkg_header 升级包头结构指针
* img_hash_table 返回对应的升级镜像HASH表头指针指针指向的空间在函数内分配需要使用者使用完后调用upg_free释放。
* (如果采用直接访问flash的方式返回升级镜像哈希表所在的flash地址)
*/
errcode_t upg_get_pkg_image_hash_table(const upg_package_header_t *pkg_header,
upg_image_hash_node_t **img_hash_table)
{
uint32_t offset;
errcode_t ret_val;
if (pkg_header->info_area.image_hash_table_addr == 0) {
offset = (uint32_t)sizeof(upg_package_header_t);
} else {
offset = pkg_header->info_area.image_hash_table_addr;
}
#if (UPG_CFG_DIRECT_FLASH_ACCESS == NO)
/* 由于ImageHashTable为了16字节对齐有填充字段此处的长度不能使用image_num * sizeof(upg_image_hash_node_t)) */
uint32_t actual_len = pkg_header->info_area.image_hash_table_length;
*img_hash_table = upg_malloc(actual_len);
if (*img_hash_table == NULL) {
return ERRCODE_MALLOC;
}
ret_val = upg_read_fota_pkg_data(offset, (uint8_t *)(*img_hash_table), &actual_len);
if (ret_val != ERRCODE_SUCC || actual_len != pkg_header->info_area.image_hash_table_length) {
upg_free(*img_hash_table);
*img_hash_table = NULL;
return ret_val;
}
#else
uint32_t start_addr = 0;
uint32_t size = 0;
ret_val = upg_get_fota_partiton_area_addr(&start_addr, &size);
if (ret_val != ERRCODE_SUCC) {
return ret_val;
}
start_addr += offset;
*img_hash_table = (upg_image_hash_node_t*)(uintptr_t)(start_addr + upg_get_flash_base_addr());
#endif /* #if UPG_CFG_DIRECT_FLASH_ACCESS */
return ERRCODE_SUCC;
}
/*
* 获取升级镜像的头结构指针
* img_hash_table 升级镜像HASH表节点指针
* img_header 返回对应的升级镜像头指针指针指向的空间在函数内分配需要使用者使用完后调用upg_free释放。
* (如果采用直接访问flash的方式返回镜像头所在的flash地址)
*/
errcode_t upg_get_pkg_image_header(const upg_image_hash_node_t *img_hash_table, upg_image_header_t **img_header)
{
#if (UPG_CFG_DIRECT_FLASH_ACCESS == NO)
errcode_t ret_val;
uint32_t actual_len = (uint32_t)sizeof(upg_image_header_t);
*img_header = upg_malloc(sizeof(upg_image_header_t));
if (*img_header == NULL) {
return ERRCODE_MALLOC;
}
ret_val = upg_read_fota_pkg_data(img_hash_table->image_addr, (uint8_t *)(*img_header), &actual_len);
if (ret_val != ERRCODE_SUCC || actual_len != sizeof(upg_image_header_t)) {
upg_free(*img_header);
*img_header = NULL;
return ret_val;
}
#else
uint32_t start_addr = 0;
uint32_t size = 0;
errcode_t ret_val;
ret_val = upg_get_fota_partiton_area_addr(&start_addr, &size);
if (ret_val != ERRCODE_SUCC) {
return ret_val;
}
start_addr += img_hash_table->image_addr;
*img_header = (upg_image_header_t*)(uintptr_t)(start_addr + upg_get_flash_base_addr());
#endif /* #if UPG_CFG_DIRECT_FLASH_ACCESS */
return ERRCODE_SUCC;
}
/*
* 获取升级镜像的数据指针
* img_header 升级镜像头结构指针
* data_offset 相对升级镜像数据开头的偏移
* data_len 输入要获取数据的长度,输出实际获取到的数据长度
* img_data 返回升级镜像数据的指针
如果未采用直接访问flash方式即UPG_CFG_DIRECT_FLASH_ACCESS==NO返回的指针指向的空间在函数内分配使用者使用完后
必须调用upg_free释放。
* 如果采用直接访问flash的方式即UPG_CFG_DIRECT_FLASH_ACCESS==YES返回指针为数据所在的flash地址使用者无需释放。
*/
errcode_t upg_get_pkg_image_data(const upg_image_header_t *img_header,
uint32_t data_offset, uint32_t *data_len, uint8_t **img_data)
{
#if (UPG_CFG_DIRECT_FLASH_ACCESS == NO)
errcode_t ret_val;
*img_data = upg_malloc(*data_len);
if (*img_data == NULL) {
return ERRCODE_MALLOC;
}
ret_val = upg_copy_pkg_image_data(img_header, data_offset, data_len, *img_data);
if (ret_val != ERRCODE_SUCC) {
upg_free(*img_data);
*img_data = NULL;
return ret_val;
}
#else
uint32_t start_addr = 0;
uint32_t size = 0;
uint32_t actual_len;
errcode_t ret_val;
uint32_t aligned_image_len = upg_aligned(img_header->image_len, 16); /* 16-byte alignment */
ret_val = upg_get_fota_partiton_area_addr(&start_addr, &size);
if (ret_val != ERRCODE_SUCC) {
return ret_val;
}
if (data_offset >= aligned_image_len || img_data == NULL ||
data_len == NULL || *data_len == 0) {
return ERRCODE_UPG_INVALID_PARAMETER;
}
actual_len = (data_offset + *data_len > aligned_image_len) ? (aligned_image_len - data_offset) : *data_len;
start_addr += img_header->image_offset;
*img_data = (uint8_t*)(uintptr_t)(start_addr + data_offset + upg_get_flash_base_addr());
*data_len = actual_len;
#endif /* #if UPG_CFG_DIRECT_FLASH_ACCESS */
return ERRCODE_SUCC;
}
/*
* 拷贝升级镜像指定范围的数据至buffer中
* img_header 升级镜像头结构指针
* data_offset 相对升级镜像数据开头的偏移
* data_len 输出要拷贝的数据的长度,输出实际拷贝的数据长度
* img_data 保存数据的buffer指针buffer的空间需要使用者分配
*/
errcode_t upg_copy_pkg_image_data(const upg_image_header_t *img_header,
uint32_t data_offset, uint32_t *data_len, uint8_t *img_data)
{
errcode_t ret_val;
uint32_t aligned_image_len = upg_aligned(img_header->image_len, 16); /* 16-byte alignment */
uint32_t actual_len;
if (data_offset >= aligned_image_len || img_data == NULL ||
data_len == NULL || *data_len == 0) {
return ERRCODE_UPG_INVALID_PARAMETER;
}
actual_len = (data_offset + *data_len > aligned_image_len) ? (aligned_image_len - data_offset) : *data_len;
ret_val = upg_read_fota_pkg_data(img_header->image_offset + data_offset, img_data, &actual_len);
if (ret_val != ERRCODE_SUCC) {
return ret_val;
}
*data_len = actual_len;
return ERRCODE_SUCC;
}
#if UPG_CFG_SUPPORT_IMAGE_ON_FILE_SYSTEM == YES
STATIC errcode_t upg_read_old_image_data_from_fs(const char *file_path, uint32_t read_offset,
uint8_t *buffer, uint32_t *read_len)
{
uint16_t len = 0;
struct stat stat_buff = {0};
uint32_t ret = stat(file_path, &stat_buff);
if (ret != 0 || stat_buff.st_size == 0) {
return ERRCODE_UPG_EMPTY_FILE;
}
/* create ota image file */
FILE *rd_fd = fopen(file_path, "rb");
if (rd_fd == NULL) {
upg_msg0("open file fail!");
upg_msg0((const char *)file_path);
upg_msg0("\r\n");
return ERRCODE_UPG_FILE_OPEN_FAIL;
}
if ((long int)read_offset > stat_buff.st_size) {
upg_msg0("The read_offset is more than file size!\n");
ret = ERRCODE_UPG_FILE_READ_FAIL;
goto end;
}
long int left_len = ((long int)(read_offset + *read_len) > stat_buff.st_size) ?
stat_buff.st_size - (long int)read_offset : (long int)(*read_len);
ret = fseek(rd_fd, read_offset, SEEK_SET);
if (ret != 0) {
upg_msg0("seek file fail!");
ret = ERRCODE_UPG_FILE_SEEK_FAIL;
goto end;
}
while (left_len > 0) {
uint16_t tmp_read = fread(buffer + len, 1, left_len, rd_fd);
if (tmp_read == 0) {
if (ferror(rd_fd)) {
upg_msg0("read file fail!");
ret = ERRCODE_UPG_FILE_READ_FAIL;
goto end;
}
}
left_len -= tmp_read;
len += tmp_read;
}
end:
*read_len = len;
(void)fclose(rd_fd);
return ret;
}
#endif
/*
* 从指定image_id的镜像所在的地址上读取数据到buffer中
* write_offset 相对镜像起始地址的偏移
* buffer 存储数据的buffer指针
* write_len buffer的长度
* image_id 镜像的ID
*/
errcode_t upg_read_old_image_data(uint32_t read_offset, uint8_t *buffer, uint32_t *read_len, uint32_t image_id)
{
errcode_t ret_val;
partition_information_t image_info = {0};
if (image_id == PARAMS_PARTITION_IMAGE_ID) {
/* 参数区地址信息 */
image_info.type = PARTITION_BY_ADDRESS;
image_info.part_info.addr_info.size = PARAMS_PARTITION_LENGTH;
image_info.part_info.addr_info.addr = PARAMS_PARTITION_START_ADDR;
} else {
ret_val = upg_get_image_info(image_id, &image_info);
if (ret_val != ERRCODE_SUCC) {
return ret_val;
}
}
if (image_info.type == PARTITION_BY_ADDRESS) {
uint32_t app_address = image_info.part_info.addr_info.addr;
ret_val = upg_flash_read(app_address + read_offset, *read_len, (uint8_t *)buffer);
} else { /* 分区类型PARTITION_BY_PATH */
#if UPG_CFG_SUPPORT_IMAGE_ON_FILE_SYSTEM == YES
ret_val = upg_read_old_image_data_from_fs(
(const char *)image_info.part_info.file_path, read_offset, buffer, read_len);
#else
ret_val = ERRCODE_UPG_INVALID_IMAGE_ID;
#endif
}
return ret_val;
}
STATIC errcode_t upg_get_firmware_flag_address(uint32_t firmware_index, uint32_t current_loop, uint32_t *flag_addr)
{
uint32_t fota_flag_addr = 0;
uint32_t addr;
errcode_t ret = upg_get_upgrade_flag_flash_start_addr(&fota_flag_addr);
if (ret != ERRCODE_SUCC) {
return ret;
}
if (firmware_index == UPG_IMAGE_ID_NV) {
addr = fota_flag_addr + offsetof(fota_upgrade_flag_area_t, nv_flag);
addr += current_loop * (uint32_t)sizeof(uint8_t);
} else {
addr = fota_flag_addr + offsetof(fota_upgrade_flag_area_t, firmware_flag);
addr += (firmware_index * UPG_FLAG_RETYR_TIMES) + (current_loop * (uint32_t)sizeof(uint8_t));
}
*flag_addr = addr;
return ERRCODE_SUCC;
}
/*
* 设置指定固件的升级标记
* firmware_index为升级包中的固件除NV之外的镜像的序号
* 如升级包中包含 固件0、固件1、固件2、NV、固件3其中固件3的序号为3而不是4
*/
errcode_t upg_set_firmware_update_status(fota_upgrade_flag_area_t *upg_flag,
uint32_t firmware_index, upg_image_status_switch_t switch_status)
{
uint32_t write_len = 0;
uint32_t flag_addr = 0;
uint8_t *firmware_flag;
uint32_t i;
if (firmware_index == UPG_IMAGE_ID_NV) {
firmware_flag = upg_flag->nv_flag;
} else {
firmware_flag = upg_flag->firmware_flag[firmware_index];
}
/* 获取第一个非0的flag, 即第i次重试的flag */
for (i = 0; i < UPG_FLAG_RETYR_TIMES; i++) {
if (firmware_flag[i] != 0) {
break;
}
}
if (i >= UPG_FLAG_RETYR_TIMES) {
return ERRCODE_SUCC;
}
errcode_t ret = upg_get_firmware_flag_address(firmware_index, i, &flag_addr);
if (ret != ERRCODE_SUCC) {
return ret;
}
if ((switch_status == UPG_IMAGE_STATUS_SWITCH_TO_STARTED) && (firmware_flag[i] == NOT_START_FLAG)) {
/* 当前flag为NOT_START, 要切换成STARTED */
write_len = 1;
firmware_flag[i] = STARTED_FLAG;
} else if ((switch_status == UPG_IMAGE_STATUS_SWITCH_TO_RETRY) && (firmware_flag[i] == STARTED_FLAG)) {
/* 当前flag为STARTED, 要切换成RETRY, 即当前flag置为0 */
write_len = 1;
firmware_flag[i] = FINISHED_FLAG;
} else if (switch_status == UPG_IMAGE_STATUS_SWITCH_TO_FINISHED) {
/* 要切换成FINISH即全部flag置为0 */
write_len = UPG_FLAG_RETYR_TIMES - i;
(void)memset_s(&firmware_flag[i], write_len, FINISHED_FLAG, write_len);
} else {
/* 其他情况不做处理 */
return ERRCODE_SUCC;
}
ret = upg_flash_write(flag_addr, write_len, (uint8_t *)&(firmware_flag[i]), false);
if (ret != ERRCODE_SUCC) {
upg_msg1("upg_flash_write upgrader flag fail. ret = ", ret);
return ret;
}
if (i >= UPG_FLAG_RETYR_TIMES - 1 && firmware_flag[i] == FINISHED_FLAG) {
upg_msg0("retry times all failed\n");
upg_set_temporary_result(UPG_RESULT_RETRY_ALL_FAILED);
return ERRCODE_UPG_RETRY_ALL_FAIL;
}
return ERRCODE_SUCC;
}
/*
* 获取升级包中的升级镜像的升级标记状态(NOT_STARTED/STARTED/RETRY/FINISHED)
* firmware_index为升级包中的固件除NV之外的镜像的序号
* 如升级包中包含 固件0、固件1、固件2、NV、固件3其中固件3的序号为3而不是4
* 如为NV镜像firmware_index参数可忽略
*/
upg_image_status_t upg_get_image_update_status(fota_upgrade_flag_area_t *upg_flag,
uint32_t firmware_index, uint32_t image_id)
{
uint8_t *firmware_flag;
uint8_t finished_flag[UPG_FLAG_RETYR_TIMES] = { FINISHED_FLAG, FINISHED_FLAG, FINISHED_FLAG };
uint8_t init_flag[UPG_FLAG_RETYR_TIMES] = { NOT_START_FLAG, NOT_START_FLAG, NOT_START_FLAG };
uint32_t i;
if (image_id == UPG_IMAGE_ID_NV) {
firmware_flag = upg_flag->nv_flag;
} else {
firmware_flag = upg_flag->firmware_flag[firmware_index];
}
if (memcmp(firmware_flag, finished_flag, UPG_FLAG_RETYR_TIMES) == 0) {
/* 3个flag都是0x00, 处理完成状态 */
return UPG_IMAGE_STATUS_FINISHED;
} else if (memcmp(firmware_flag, init_flag, UPG_FLAG_RETYR_TIMES) == 0) {
/* 3个flag都是0xFF, 未开始处理状态 */
return UPG_IMAGE_STATUS_NOT_STARTED;
} else {
/* 获取第一个非0的flag即当前正在处理的第i次重试的flag */
for (i = 0; i < UPG_FLAG_RETYR_TIMES; i++) {
if (firmware_flag[i] != 0) {
break;
}
}
if (firmware_flag[i] == STARTED_FLAG) {
return UPG_IMAGE_STATUS_STARTED;
} else if (firmware_flag[i] == NOT_START_FLAG) {
return UPG_IMAGE_STATUS_RETRY;
} else {
return UPG_IMAGE_STATUS_INVALID;
}
}
}
/* 擦除metadata数据区 */
errcode_t upg_flash_erase_metadata_pages(void)
{
return ERRCODE_SUCC;
}
/* 设置升级结果(临时保存) */
void upg_set_temporary_result(upg_result_t result)
{
upg_get_ctx()->temporary_result = result;
}
/* 获取临时保存的升级结果 */
upg_result_t upg_get_temporary_result(void)
{
return upg_get_ctx()->temporary_result;
}
/* 将升级结果保存至Flash升级标记区 */
void upg_set_update_result(upg_result_t result)
{
uint32_t fota_flag_addr = 0;
uint32_t result_tmp = (uint32_t)result;
errcode_t ret = upg_get_upgrade_flag_flash_start_addr(&fota_flag_addr);
if (ret != ERRCODE_SUCC) {
return;
}
uint32_t result_addr = fota_flag_addr + offsetof(fota_upgrade_flag_area_t, update_result);
ret = upg_flash_write(result_addr, sizeof(uint32_t), (uint8_t *)&(result_tmp), false);
if (ret != ERRCODE_SUCC) {
return;
}
return;
}
/* 检查是否所有镜像都已完成升级(包括升级失败但是已尝试最大次数) */
bool upg_check_image_update_complete(const fota_upgrade_flag_area_t *upg_flag, uint32_t image_num)
{
uint32_t firmware_index;
const uint8_t *firmware_flag;
uint8_t finish_flag[UPG_FLAG_RETYR_TIMES] = {FINISHED_FLAG, FINISHED_FLAG, FINISHED_FLAG};
for (firmware_index = 0; firmware_index < upg_flag->firmware_num; firmware_index++) {
firmware_flag = upg_flag->firmware_flag[firmware_index];
/* 存在升级包未完成升级 */
if (memcmp(firmware_flag, finish_flag, UPG_FLAG_RETYR_TIMES) != 0) {
return false;
}
}
/* 存在nv升级包并且nv升级准备工作未完成 */
if (upg_flag->firmware_num != image_num && upg_flag->nv_flag[0] != STARTED_FLAG) { /* index 0:start flag */
return false;
}
return true;
}
STATIC void upg_write_complete_flag(uint32_t fota_flag_addr, uint32_t complete_flag)
{
if (complete_flag != UPG_ABNORMAL_FLAG) {
uint32_t flag_addr = fota_flag_addr + offsetof(fota_upgrade_flag_area_t, complete_flag);
upg_msg1("write complete: ", complete_flag);
if (upg_flash_write(flag_addr, sizeof(uint32_t), (uint8_t *)&(complete_flag), false) != ERRCODE_SUCC) {
return;
}
}
#if (UPG_CFG_SUPPORT_RESOURCES_FILE == YES)
if (complete_flag == 0) {
if (access(upg_get_res_file_index_path(), R_OK) == 0) {
dfx_file_delete(upg_get_res_file_index_path());
}
}
#endif
}
/* 设置升级完成标记 */
void upg_set_complete_flag(uint32_t image_num, errcode_t result, bool direct_finish)
{
uint32_t fota_flag_addr = 0;
uint32_t complete_flag = UPG_ABNORMAL_FLAG;
bool image_complete = false;
errcode_t ret = upg_get_upgrade_flag_flash_start_addr(&fota_flag_addr);
if (ret != ERRCODE_SUCC) {
return;
}
fota_upgrade_flag_area_t upg_flag;
ret = upg_flash_read(fota_flag_addr, sizeof(fota_upgrade_flag_area_t), (uint8_t *)(&upg_flag));
if (ret != ERRCODE_SUCC) {
upg_msg0("upg_flash_read flag fail\r\n");
return;
}
do {
/*
* 1. 当前程序中升级流程返回失败,直接结束升级流程(如整包校验失败),
* 则升级流程失败结束升级将flag置成 UPG_FINISH_ALL_FLAG
*/
if (direct_finish && (upg_flag.complete_flag != UPG_FINISH_ALL_FLAG)) {
complete_flag = UPG_FINISH_ALL_FLAG;
/* 保存升级结果至升级标记区内 */
upg_set_update_result(upg_get_temporary_result());
break;
}
/*
* 2. 当前程序中升级流程返回成功,
* 即当前程序中支持升级的所有镜像成功升级但存在还需要升级的镜像则将flag置成 UPG_FINISH_HALF_FLAG
*/
image_complete = upg_check_image_update_complete(&upg_flag, image_num);
if (result == ERRCODE_SUCC && !image_complete) {
if (upg_flag.complete_flag != UPG_FINISH_HALF_FLAG) {
complete_flag = UPG_FINISH_HALF_FLAG;
}
} else if (image_complete && (upg_flag.complete_flag != UPG_FINISH_ALL_FLAG)) {
/*
* 3. 若升级包中所有镜像成功升级将flag置成 UPG_FINISH_ALL_FLAG
*/
complete_flag = UPG_FINISH_ALL_FLAG;
if (result == ERRCODE_SUCC) {
upg_set_temporary_result(UPG_RESULT_UPDATE_SUCCESS);
}
/* 保存升级结果至升级标记区内 */
upg_set_update_result(upg_get_temporary_result());
} else if (upg_get_temporary_result() == UPG_RESULT_RETRY_ALL_FAILED &&
(upg_flag.complete_flag != UPG_FINISH_ALL_FLAG)) {
/*
* 4. 当前程序中升级流程返回失败但最后一个已处理的镜像的3个flag全0即已经重试最大次数仍然失败
* 则升级流程失败结束升级将flag置成 UPG_FINISH_ALL_FLAG
*/
complete_flag = UPG_FINISH_ALL_FLAG;
upg_set_update_result(upg_get_temporary_result());
}
} while (0);
/* 升级标记需要修改 */
upg_write_complete_flag(fota_flag_addr, complete_flag);
}
/* 获取升级结果 */
errcode_t uapi_upg_get_result(upg_result_t *result, uint32_t *last_image_index)
{
if (result == NULL || last_image_index == NULL) {
return ERRCODE_UPG_NULL_POINTER;
}
fota_upgrade_flag_area_t *upg_flag_info;
errcode_t ret = upg_alloc_and_get_upgrade_flag(&upg_flag_info);
if (ret != ERRCODE_SUCC || upg_flag_info == NULL) {
return ret;
}
*result = upg_flag_info->update_result;
*last_image_index = UINT32_MAX;
upg_free(upg_flag_info);
return ERRCODE_SUCC;
}
/* 获取注册函数列表 */
upg_func_t *upg_get_func_list(void)
{
return &(g_upg_ctx.func_list);
}
bool upg_is_inited(void)
{
return g_upg_ctx.inited;
}
STATIC upg_status_t upg_get_status(void)
{
uint8_t temp = 0;
upg_status_t status = UPG_STATUS_NONE;
uint32_t flag_addr = 0;
fota_upgrade_flag_area_t *upg_flag_info = NULL;
if (upg_alloc_and_get_upgrade_flag(&upg_flag_info) != ERRCODE_SUCC) {
return status;
}
do {
if (upg_flag_info->head_magic != UPG_HEAD_MAGIC || upg_flag_info->head_end_magic != UPG_END_MAGIC) {
status = UPG_STATUS_NONE;
break;
}
if (upg_flag_info->complete_flag != 0) {
status = UPG_STATUS_UPDATING;
break;
}
if (upg_flag_info->ver_change_flag == 0) {
status = UPG_STATUS_NONE;
break;
}
if (upg_flag_info->update_result == UPG_RESULT_UPDATE_SUCCESS) {
status = UPG_STATUS_SUCC;
} else {
status = UPG_STATUS_FAIL;
}
if (upg_get_upgrade_flag_flash_start_addr(&flag_addr) != ERRCODE_SUCC) {
status = UPG_STATUS_NONE;
break;
}
flag_addr += offsetof(fota_upgrade_flag_area_t, ver_change_flag);
if (upg_flash_write(flag_addr, sizeof(uint8_t), &temp, false) != ERRCODE_SUCC) {
status = UPG_STATUS_NONE;
}
} while (0);
upg_free(upg_flag_info);
return status;
}
errcode_t uapi_upg_init(const upg_func_t *func_list)
{
if (upg_is_inited()) {
return ERRCODE_UPG_ALREADY_INIT;
}
if (func_list != NULL) {
g_upg_ctx.func_list.malloc = func_list->malloc;
g_upg_ctx.func_list.free = func_list->free;
g_upg_ctx.func_list.serial_putc = func_list->serial_putc;
}
g_upg_ctx.temporary_result = UPG_RESULT_MAX;
g_upg_ctx.packge_len = 0;
g_upg_ctx.inited = true;
g_upg_ctx.upg_status = upg_get_status();
return ERRCODE_SUCC;
}
#if (UPG_CFG_ANTI_ROLLBACK_SUPPORT == YES)
errcode_t upg_anti_rollback_version_verify(
const upg_package_header_t *pkg_header, const upg_image_header_t *img_header)
{
// NV及资源文件不做防回滚
if (img_header->image_id == UPG_IMAGE_ID_NV || img_header->image_id == UPG_IMAGE_ID_RES_INDEX ||
img_header->image_id == UPG_IMAGE_ID_RES_DATA) {
return ERRCODE_SUCC;
}
uint32_t image_id = img_header->image_id;
uint32_t key_ver = pkg_header->key_area.fota_key_version_ext;
uint32_t code_ver = img_header->version_ext;
uint32_t otp_ver;
errcode_t ret = upg_get_board_rollback_version(image_id, &otp_ver);
if (ret != ERRCODE_SUCC) {
return ret;
}
uint32_t board_key_mask;
uint32_t board_code_mask;
ret = upg_get_board_version_mask(image_id, &board_key_mask, &board_code_mask);
if (ret != ERRCODE_SUCC) {
return ret;
}
if (((key_ver & board_key_mask) < (otp_ver & board_key_mask)) ||
((code_ver & board_code_mask) < (otp_ver & board_code_mask))) {
return ERRCODE_FAIL;
}
upg_msg1("upg verify: anti rollback version_verify ok. image_id = ", img_header->image_id);
return ERRCODE_SUCC;
}
errcode_t upg_anti_rollback_version_update(const upg_image_header_t *img_header)
{
// NV及资源文件不做防回滚
if (img_header->image_id == UPG_IMAGE_ID_NV || img_header->image_id == UPG_IMAGE_ID_RES_INDEX ||
img_header->image_id == UPG_IMAGE_ID_RES_DATA) {
return ERRCODE_SUCC;
}
uint32_t image_id = img_header->image_id;
uint32_t key_ver = 0;
uint32_t board_key_mask = 0;
uint32_t code_ver = 0;
uint32_t board_code_mask = 0;
uint32_t new_ver;
uint32_t old_ver;
errcode_t ret = upg_get_board_rollback_version(image_id, &old_ver);
if (ret != ERRCODE_SUCC) {
return ret;
}
// 获取更新后的板端的掩码
ret = upg_get_board_version_mask(image_id, &board_key_mask, &board_code_mask);
if (ret != ERRCODE_SUCC) {
return ret;
}
// 获取更新后的板端镜像版本
ret = upg_get_board_version(image_id, &key_ver, &code_ver);
if (ret != ERRCODE_SUCC) {
return ret;
}
if ((code_ver & board_code_mask) < (old_ver & board_code_mask) ||
(key_ver & board_key_mask) < (old_ver & board_key_mask)) {
return ERRCODE_FAIL;
}
new_ver = (code_ver & board_code_mask) | (key_ver & board_key_mask);
return upg_set_board_rollback_version(image_id, &new_ver);
}
#endif