1016 lines
33 KiB
C
1016 lines
33 KiB
C
/*
|
||
* 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
|