Files
2025-12-03 11:12:34 +08:00

435 lines
13 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".reusable_update.data.bss")
#pragma data_seg(".reusable_update.data")
#pragma const_seg(".reusable_update.text.const")
#pragma code_seg(".reusable_update.text")
#endif
#include "update.h"
#include "update_loader_download.h"
#include "app_config.h"
#include "cpu.h"
#include "system/includes.h"
#include "app_main.h"
#include "fs/sdfile.h"
#include "norflash.h"
#include "rec_nor/nor_interface.h"
#include "user_cfg_id.h"
#if TCFG_UPDATE_ENABLE
#define LOG_TAG "[REUSABLE-UPDATE]"
#define LOG_INFO_ENABLE
#define LOG_ERROR_ENABLE
#include "debug.h"
/*
REUSABLE RESERVED AREA
#-----------------------------------------------------------------+ ->4KB aligned
# |
# EXIF (4KB) |
# |
#-----------------------------------------------------------------| ->4KB aligned
# |
# loader.bin |
# vm bak |
# update_param |
# |
#-----------------------------------------------------------------+ ->end
*/
#define SECTOR_SIZE 4096
#define ALIGN_SECTOR(x) (((x + SECTOR_SIZE - 1) / SECTOR_SIZE) * SECTOR_SIZE)
#define LOADER_RESERVE_SIZE (100) // 单位是K
#define REUSABLE_RESERVED "REUSABLE"
#define SDFILE_EXT_RESERVED_ROOT_PATH "mnt/sdfile/EXT_RESERVED/"
struct reuable_info_record {
union {
struct {
u32 reserve;
};
struct {
u8 app_update_flag;
};
};
u32 update_again_flag;
};
struct reusable_reserv {
u8 init_flag;
u32 base_addr;
u32 total_size;
u32 exif_addr;
u32 exif_size;
u32 loader_addr;
u32 loader_size;
};
struct reusable_reserv reusable_region = {0};
#define __this (&reusable_region)
static u8 new_sdk_update_again_flag = 0;
static void reusable_param_dump(void)
{
printf("init_flag = %d\n", __this->init_flag);
printf("base_addr = 0x%x\n", __this->base_addr);
printf("total_size = 0x%x\n", __this->total_size);
printf("exif_addr = 0x%x\n", __this->exif_addr);
printf("exif_size = 0x%x\n", __this->exif_size);
printf("loader_addr = 0x%x\n", __this->loader_addr);
printf("loader_size = 0x%x\n", __this->loader_size);
}
extern u32 sfc_read(u8 *buf, u32 addr, u32 len);
extern u32 sfc_write(const u8 *buf, u32 addr, u32 len);
extern bool sfc_erase(int cmd, u32 addr);
extern bool reserved_area_special_handle(u8 opt);
extern const int support_reusable_special_update;
extern u32 config_update_features;
extern char *watch_get_root_path();
static u32 reusable_region_write(const u8 *buf, u32 addr, u32 len)
{
if (__this->init_flag == 0) {
return 0;
}
return sfc_write(buf, addr, len);
}
static u32 reusable_region_read(u8 *buf, u32 addr, u32 len)
{
if (__this->init_flag == 0) {
return 0;
}
return sfc_read(buf, addr, len);
}
static bool reusable_region_erase(int cmd, u32 addr)
{
if (__this->init_flag == 0) {
return false;
}
return sfc_erase(cmd, addr);
}
int reusable_region_init(void)
{
int ret;
FILE *fp = NULL;
struct vfs_attr file_attr;
const char *fpth = SDFILE_EXT_RESERVED_ROOT_PATH;
u8 file_path_len = sizeof(SDFILE_EXT_RESERVED_ROOT_PATH) + strlen((const char *)REUSABLE_RESERVED);
u8 *file_path = zalloc(file_path_len);
if (NULL == file_path) {
log_error("%s, alloc fail\n", __func__);
ret = -1;
goto err1;
}
// 如果SDFILE_APP_ROOT_PATH + REUSABLE_RESERVED不行,则还需要尝试打开扩展预留区域(mnt/sdfile/EXT_RESERVED)
memcpy(file_path, SDFILE_APP_ROOT_PATH, strlen(SDFILE_APP_ROOT_PATH));
memcpy(file_path + strlen(SDFILE_APP_ROOT_PATH), REUSABLE_RESERVED, strlen((const char *)REUSABLE_RESERVED));
fp = fopen((const char *)file_path, "r");
if (!fp) {
memset((void *)file_path, 0, file_path_len);
memcpy((void *)file_path, SDFILE_EXT_RESERVED_ROOT_PATH, strlen(SDFILE_EXT_RESERVED_ROOT_PATH));
memcpy((void *)(file_path + strlen(SDFILE_EXT_RESERVED_ROOT_PATH)), REUSABLE_RESERVED, strlen((const char *)REUSABLE_RESERVED));
fp = fopen((const char *)file_path, "r");
}
if (!fp) {
log_error("open %s fail\n", fpth);
ret = -2;
goto err2;
}
fget_attrs(fp, &file_attr);
__this->base_addr = sdfile_cpu_addr2flash_addr(file_attr.sclust);
__this->total_size = file_attr.fsize;
__this->exif_addr = ALIGN_SECTOR(__this->base_addr);
__this->exif_size = SECTOR_SIZE;
__this->loader_addr = __this->exif_addr + __this->exif_size;
__this->loader_size = __this->base_addr + __this->total_size - __this->loader_addr;
__this->loader_size = __this->loader_size / SECTOR_SIZE * SECTOR_SIZE;
if (__this->loader_size < SECTOR_SIZE) {
log_error("loader region too small\n");
ret = -3;
goto err2;
}
__this->init_flag = 1;
reusable_param_dump();
free(file_path);
return 0;
err2:
free(file_path);
err1:
__this->init_flag = 0;
return ret;
}
static bool reusable_update_flag_handle(u32 *value, u8 type, u8 dir)
{
struct reuable_info_record reuable_info = {0};
// 先读
bool ret = (sizeof(reuable_info) == syscfg_read(VM_REUSABLE_SPECIAL_UPDATE_INFO, &reuable_info, sizeof(reuable_info)));
if (dir) {
// 写前判断当前值是否一致
switch (type) {
case 0: // 对app下发的标志位进行操作
u8 app_update_flag = ((u8 *)value)[0];
if (ret && reuable_info.app_update_flag == app_update_flag) {
break;
}
reuable_info.app_update_flag = app_update_flag;
syscfg_write(VM_REUSABLE_SPECIAL_UPDATE_INFO, &reuable_info, sizeof(reuable_info));
break;
case 1: // 对升级标志位进行操作
u32 update_again_flag = *value;
if (ret && reuable_info.update_again_flag == update_again_flag) {
break;
}
reuable_info.update_again_flag = update_again_flag;
syscfg_write(VM_REUSABLE_SPECIAL_UPDATE_INFO, &reuable_info, sizeof(reuable_info));
break;
}
} else {
switch (type) {
case 0:
if (ret) {
((u8 *)value)[0] = reuable_info.app_update_flag;
}
break;
case 1:
if (ret) {
*value = reuable_info.update_again_flag;
}
break;
}
}
return ret;
}
static bool reusable_update_is_push_loader_only(void)
{
bool ret = reusable_update_flag_handle(&config_update_features, 1, 0);
if (ret) {
ret = (~BIT(CONFIG_UPDATE_FEATRUES_CONTENT_COMPARE_EN) & config_update_features) == BIT(CONFIG_UPDATE_FEATRUES_PUSH_LOADER_ONLY_EN);
}
return ret;
}
static int reusable_update_specail_handle(int update_type)
{
if (0 == reserved_area_special_handle(0)) {
// 如果蓝牙升级,则必须带资源
if (BT_UPDATA == update_type || BLE_TEST_UPDATA == update_type) {
return -1;
}
return 0;
}
if (reusable_update_is_push_loader_only()) {
config_update_features |= BIT(CONFIG_UPDATE_FEATRUES_UPDATE_RES_ONLY_EN);
config_update_features &= ~BIT(CONFIG_UPDATE_FEATRUES_PUSH_LOADER_ONLY_EN);
} else if (0 == (~BIT(CONFIG_UPDATE_FEATRUES_CONTENT_COMPARE_EN) & config_update_features)) {
config_update_features |= BIT(CONFIG_UPDATE_FEATRUES_PUSH_LOADER_ONLY_EN);
config_update_features &= ~BIT(CONFIG_UPDATE_FEATRUES_UPDATE_RES_ONLY_EN);
reserved_area_special_handle(1);
new_sdk_update_again_flag = 3;
}
reusable_update_flag_handle(&config_update_features, 1, 1);
return 0;
}
bool reusable_update_result_deal(bool result)
{
if (result) {
if (reusable_update_flag_handle(&config_update_features, 1, 0) &&
config_update_features & BIT(CONFIG_UPDATE_FEATRUES_UPDATE_RES_ONLY_EN)) {
u8 state = 0;
reusable_update_flag_handle((u32 *)&state, 0, 1);
}
config_update_features = 0;
reusable_update_flag_handle(&config_update_features, 1, 1);
}
return result;
}
int reusable_loader_region(loader_area_t *loader_area)
{
int ret;
int update_type = 0;
if (loader_area == NULL) {
return -1;
}
update_type = loader_area->type;
if (__this->init_flag == 0) {
ret = reusable_region_init();
if (ret) {
ret = -2;
goto end;
}
}
loader_area->type = 0;
loader_area->start_addr = __this->loader_addr;
loader_area->usable_size = __this->loader_size;
loader_area->write_hdl = (void *)reusable_region_write;
loader_area->read_hdl = (void *)reusable_region_read;
loader_area->erase_hdl = (void *)reusable_region_erase;
if (support_reusable_special_update) {
loader_area->result = reusable_update_specail_handle(update_type);
}
return 0;
end:
return ret;
}
int reusable_exif_region(u32 *base, u32 *len)
{
int ret = 0;
if (__this->init_flag == 0) {
ret = reusable_region_init();
if (ret) {
ret = -1;
goto end;
}
}
if (base != NULL) {
*base = __this->exif_addr;
}
if (len != NULL) {
*len = __this->exif_size;
}
end:
return ret;
}
u8 new_sdk_update_again_flag_get(void)
{
return new_sdk_update_again_flag;
}
void reusable_update_flag_clear(void)
{
if (__this->loader_size && reusable_update_is_push_loader_only()) {
reusable_update_result_deal(true);
}
memset(__this, 0, sizeof(struct reusable_reserv));
new_sdk_update_again_flag = 0;
}
u8 reusable_update_app_flag_handle(u8 state, u8 opt)
{
u8 ret = 0;
if (opt) {
// 写入
if (2 == state || 0 == state) {
if (state) {
new_sdk_update_again_flag = 2;
}
reusable_update_flag_handle((u32 *)&state, 0, 1);
}
} else {
// 从vm中获取对标志位,结合升级标志位确定返回值
u32 update_flag = 0;
if (reusable_update_flag_handle(&update_flag, 1, 0) &&
((update_flag & BIT(CONFIG_UPDATE_FEATRUES_PUSH_LOADER_ONLY_EN)) || (update_flag & BIT(CONFIG_UPDATE_FEATRUES_UPDATE_RES_ONLY_EN)))) {
ret = 3;
} else if (reusable_update_flag_handle((u32 *)&state, 0, 0)) {
ret = state;
}
}
return ret;
}
u32 reusable_area_flash_space(u32 *start_addr, u32 *free_space)
{
u32 size = 0;
FILE *fp = NULL;
struct vfs_attr file_attr;
const char *fpth = SDFILE_EXT_RESERVED_ROOT_PATH;
u8 file_path_len = 0;
u8 *file_path = NULL;
if (!support_reusable_special_update) {
goto _ERR_RET;
}
file_path_len = sizeof(SDFILE_EXT_RESERVED_ROOT_PATH) + strlen((const char *)REUSABLE_RESERVED);
file_path = zalloc(file_path_len);
if (NULL == file_path) {
log_error("%s, alloc fail\n", __func__);
goto _ERR_RET;
}
// 如果SDFILE_APP_ROOT_PATH + REUSABLE_RESERVED不行,则还需要尝试打开扩展预留区域(mnt/sdfile/EXT_RESERVED)
memcpy(file_path, SDFILE_APP_ROOT_PATH, strlen(SDFILE_APP_ROOT_PATH));
memcpy(file_path + strlen(SDFILE_APP_ROOT_PATH), REUSABLE_RESERVED, strlen((const char *)REUSABLE_RESERVED));
u32 space = 0;
fget_free_space(watch_get_root_path(), &space);
fp = fopen((const char *)file_path, "r");
if (!fp) {
memset((void *)file_path, 0, file_path_len);
memcpy((void *)file_path, SDFILE_EXT_RESERVED_ROOT_PATH, strlen(SDFILE_EXT_RESERVED_ROOT_PATH));
memcpy((void *)(file_path + strlen(SDFILE_EXT_RESERVED_ROOT_PATH)), REUSABLE_RESERVED, strlen((const char *)REUSABLE_RESERVED));
fp = fopen((const char *)file_path, "r");
}
if (!fp) {
log_error("%s, open %s fail\n", __func__, fpth);
goto _ERR_RET;
}
fget_attrs(fp, &file_attr);
if (start_addr) {
*start_addr = sdfile_cpu_addr2flash_addr(file_attr.sclust);
}
if (free_space) {
*free_space = space > LOADER_RESERVE_SIZE ? (space - LOADER_RESERVE_SIZE) : 0;
}
size = file_attr.fsize / 1024;
_ERR_RET:
if (file_path) {
free(file_path);
}
if (fp) {
fclose(fp);
}
return size;
}
#endif // TCFG_UPDATE_ENABLE