#ifdef SUPPORT_MS_EXTENSIONS #pragma bss_seg(".ex_flash_file_download.data.bss") #pragma data_seg(".ex_flash_file_download.data") #pragma const_seg(".ex_flash_file_download.text.const") #pragma code_seg(".ex_flash_file_download.text") #endif #include "app_config.h" #include "typedef.h" #include "fs.h" #include "norflash.h" /* #include "spi/nor_fs.h" */ #include "rec_nor/nor_interface.h" #include "update_loader_download.h" #if (TCFG_UPDATE_RESOURCE_EN) #define LOG_TAG "[UP_FILE_DNLD]" #define LOG_INFO_ENABLE #define LOG_ERROR_ENABLE #include "debug.h" #define EX_FLASH_FILE_NAME "res.bin" #define EX_FLASH_UPDATE_WRITE_TASK_NAME "ex_f_update" #define ONCE_REQ_SIZE (0x200) #define FLASH_SECTOR_SIZE (4096L) #define __SECTOR_4K_ALIGN(len) (((len) + FLASH_SECTOR_SIZE -1 )/FLASH_SECTOR_SIZE * FLASH_SECTOR_SIZE) #define FLASH_BLOCK_SIZE (64*1024L) #define __BLOCK_64K_ALIGN(len) (((len) + FLASH_BLOCK_SIZE -1 )/FLASH_BLOCK_SIZE * FLASH_BLOCK_SIZE) #define EX_FLASH_ERASE_IN_4K 1 #define EX_FLASH_UPDATE_DEBUG_ENABLE 0 #define EX_FLASH_MUTIL_FILE_UPDATE 0 // 外挂flash升级多个文件,要和库中对应的宏对应起来,默认关闭 #define EX_FLASH_CHECK_EXIT_WIRTE_TASK_TIME (100) // ms typedef struct _resource_update_info_t { user_chip_update_info_t info; void *dev_hdl; #if EX_FLASH_MUTIL_FILE_UPDATE void *dev_hdl_noenc; #endif update_op_api_t *file_ops; /* u32 buf[ONCE_REQ_SIZE / 4]; */ u8 *buf; u8 exit_write_task_flag; } res_update_info_t; extern const u32 g_res_nor_unencry_start_addr; static u32 g_once_req_size = ONCE_REQ_SIZE; static u16 g_exit_opt_timer_hdl = 0; #define EX_UPDATE_SEMAPHORE_WAIT_TIME (500) static volatile int g_ex_update_timeout = EX_UPDATE_SEMAPHORE_WAIT_TIME; static res_update_info_t *res_info = NULL; #define __this (res_info) static int norflash_f_open(u32 file_len) { int ret = 0; g_ex_update_timeout = EX_UPDATE_SEMAPHORE_WAIT_TIME; if (__this) { __this->dev_hdl = dev_open("res_nor", NULL); #if EX_FLASH_MUTIL_FILE_UPDATE __this->dev_hdl_noenc = dev_open("update_noenc", NULL); if (__this->dev_hdl && __this->dev_hdl_noenc) { log_info("open dev succ 0x%x, 0x%x\n", __this->dev_hdl, __this->dev_hdl_noenc); #else // EX_FLASH_MUTIL_FILE_UPDATE if (__this->dev_hdl) { log_info("open dev succ 0x%x\n", __this->dev_hdl); #endif // EX_FLASH_MUTIL_FILE_UPDATE } else { log_error("open dev fail"); ret = -1; } } else { ret = -2; } return ret; } static u32 norflash_f_read(void *buf, u32 addr, u32 len) { int rlen = 0; #if EX_FLASH_MUTIL_FILE_UPDATE if (__this && __this->dev_hdl && __this->dev_hdl_noenc) { wdt_clear(); //log_info("%s: addr = 0x%x, rlen = 0x%x", __func__, addr, len); if (g_res_nor_unencry_start_addr > addr) { #if TCFG_SFC_ENCRY_ENABLE struct sfc_no_enc_wr r_info = {(u8 *)buf, addr, len}; if (0 == dev_ioctl(__this->dev_hdl, IOCTL_SFC_NORFLASH_READ_NO_ENC, &r_info)) { rlen = len; } #else rlen = dev_bulk_read(__this->dev_hdl, buf, addr, len); #endif //put_buf(buff, 128); } else { rlen = dev_bulk_read(__this->dev_hdl_noenc, buf, addr - g_res_nor_unencry_start_addr, len); } } #else // EX_FLASH_MUTIL_FILE_UPDATE if (__this && __this->dev_hdl) { wdt_clear(); //log_info("%s: addr = 0x%x, rlen = 0x%x", __func__, addr, len); #if TCFG_SFC_ENCRY_ENABLE struct sfc_no_enc_wr r_info = {(u8 *)buf, addr, len}; if (0 == dev_ioctl(__this->dev_hdl, IOCTL_SFC_NORFLASH_READ_NO_ENC, &r_info)) { rlen = len; } #else rlen = dev_bulk_read(__this->dev_hdl, buf, addr, len); #endif //put_buf(buff, 128); } #endif // EX_FLASH_MUTIL_FILE_UPDATE return rlen; } typedef enum _FLASH_ERASER { CHIP_ERASER, BLOCK_ERASER, SECTOR_ERASER, PAGE_ERASER, } FLASH_ERASER; static int norflash_f_erase(int cmd, u32 addr) { u32 type = 0; switch (cmd) { case BLOCK_ERASER: type = IOCTL_ERASE_BLOCK; break; case SECTOR_ERASER: type = IOCTL_ERASE_SECTOR; break; case CHIP_ERASER: type = IOCTL_ERASE_CHIP; break; } #if EX_FLASH_MUTIL_FILE_UPDATE if (__this && type) { if (__this->dev_hdl && __this->dev_hdl_noenc) { wdt_clear(); if (g_res_nor_unencry_start_addr > addr) { dev_ioctl(__this->dev_hdl, type, addr); } else { dev_ioctl(__this->dev_hdl_noenc, type, addr - g_res_nor_unencry_start_addr); } } #else // EX_FLASH_MUTIL_FILE_UPDATE if (__this && __this->dev_hdl && type) { wdt_clear(); dev_ioctl(__this->dev_hdl, type, addr); #endif // EX_FLASH_MUTIL_FILE_UPDATE } else { log_error("f_erase parm err\n"); } return 0; } static u32 norflash_f_write(void *buf, u32 addr, u32 len) { int rlen = 0; #if EX_FLASH_MUTIL_FILE_UPDATE if (__this && __this->dev_hdl && __this->dev_hdl_noenc) { wdt_clear(); if (g_res_nor_unencry_start_addr > addr) { #if TCFG_SFC_ENCRY_ENABLE struct sfc_no_enc_wr w_info = {(u8 *)buf, addr, len}; if (0 == dev_ioctl(__this->dev_hdl, IOCTL_SFC_NORFLASH_WRITE_NO_ENC, (void *)&w_info)) { rlen = len; } #else //log_info("%s: addr = 0x%x, rlen = 0x%x", __func__, addr, len); rlen = dev_bulk_write(__this->dev_hdl, buf, addr, len); #endif //log_info_hexdump(buff, 128); } else { rlen = dev_bulk_write(__this->dev_hdl_noenc, buf, addr - g_res_nor_unencry_start_addr, len); } } #else // EX_FLASH_MUTIL_FILE_UPDATE if (__this && __this->dev_hdl) { wdt_clear(); #if TCFG_SFC_ENCRY_ENABLE struct sfc_no_enc_wr w_info = {(u8 *)buf, addr, len}; if (0 == dev_ioctl(__this->dev_hdl, IOCTL_SFC_NORFLASH_WRITE_NO_ENC, (void *)&w_info)) { rlen = len; } #else //log_log("%s: addr = 0x%x, rlen = 0x%x", __func__, addr, len); rlen = dev_bulk_write(__this->dev_hdl, buf, addr, len); #endif //log_info_hexdump(buff, 128); } #endif // EX_FLASH_MUTIL_FILE_UPDATE return rlen; } static int ex_flash_update_file_init(void *priv, const update_op_api_t *file_ops) { int ret = 0; user_chip_update_info_t *info = (user_chip_update_info_t *)priv; if (priv && file_ops) { __this = malloc(sizeof(res_update_info_t)); if (!__this) { ret = -1; goto _ERR_RET; } memset((u8 *)__this, 0x00, sizeof(res_update_info_t)); memcpy((u8 *)&__this->info, (u8 *)info, sizeof(user_chip_update_info_t)); __this->file_ops = (update_op_api_t *)file_ops; #if EX_FLASH_MUTIL_FILE_UPDATE if (info->priv) { __this->info.priv = (void *)zalloc(info->files_info_len); if (NULL == __this->info.priv) { ret = -1; goto _ERR_RET; } memcpy((u8 *)__this->info.priv, info->priv, info->files_info_len); log_info("update multiple files to exflash, total_len:%x files_info_len:%x\n", __this->info.len, __this->info.files_info_len); } else { log_info("ADDR:%x LEN:%x CRC:%x dev_addr:%x\n", __this->info.addr, __this->info.len, __this->info.crc, __this->info.dev_addr); } #else // EX_FLASH_MUTIL_FILE_UPDATE log_info("ADDR:%x LEN:%x CRC:%x dev_addr:%x\n", __this->info.addr, __this->info.len, __this->info.crc, __this->info.dev_addr); #endif // EX_FLASH_MUTIL_FILE_UPDATE if (norflash_f_open(__this->info.len)) { ret = -3; } } else { log_error("not find target file :%s\n", EX_FLASH_FILE_NAME); ret = -2; goto _ERR_RET; } #if RCSP_MODE extern void app_rcsp_prepare_update_ex_flash(void); app_rcsp_prepare_update_ex_flash(); #endif _ERR_RET: return ret; } static int ex_flash_update_file_get_len(void) { if (__this) { return __this->info.len; } else { return 0; } } typedef struct _program_info_t { u32 remote_file_begin; u32 remote_file_length; u32 local_program_addr; u32(*remote_file_read)(void *buf, u32 addr, u32 len); u32(*local_write_hdl)(void *buf, u32 addr, u32 len); int (*local_erase_hdl)(int cmd, u32 addr); u8 *buf; } program_info_t; static u32 remote_file_read(void *buf, u32 addr, u32 len) { u32 ret = 0; if (__this && __this->file_ops) { putchar('%'); __this->file_ops->f_seek(NULL, SEEK_SET, addr); if ((u16) - 1 == __this->file_ops->f_read(NULL, buf, len)) { ret = (u32) - 1; } } return ret; } typedef struct _ex_update_exit_write_opt_t { void *priv; bool (*condition)(void *priv); u32 check_period; // ms u16 timer_hdl; } ex_update_exit_write_opt; typedef struct _ex_update_write_info_t { OS_SEM write_sem; OS_SEM write_finish_sem; u16 write_len; u32 write_offset; u32 write_program_addr; int ret; u32(*write_hdl)(void *buf, u32 addr, u32 len); int (*erase_hdl)(int cmd, u32 addr); u8 *write_buf; ex_update_exit_write_opt exit_opt; u8 en; } ex_update_write_info; static bool exit_write_condition(ex_update_write_info *write_info) { if (write_info) { if (write_info->exit_opt.condition) { return write_info->exit_opt.condition(write_info->exit_opt.priv); } } return false; } static void exit_write_opt_prepare(ex_update_write_info *write_info); static void exit_write_opt_func(void *priv) { ex_update_write_info *write_info = (ex_update_write_info *)priv; if (g_exit_opt_timer_hdl && write_info) { if (exit_write_condition(write_info)) { // post消息到write结束任务等待 os_sem_post(&write_info->write_sem); } else { g_exit_opt_timer_hdl = 0; exit_write_opt_prepare(write_info); } } } static void exit_write_opt_prepare(ex_update_write_info *write_info) { if (write_info && (0 == g_exit_opt_timer_hdl)) { if (0 == write_info->exit_opt.check_period) { write_info->exit_opt.check_period = EX_FLASH_CHECK_EXIT_WIRTE_TASK_TIME; } g_exit_opt_timer_hdl = sys_timeout_add((void *)write_info, exit_write_opt_func, write_info->exit_opt.check_period); } } static void exit_write_finsh_opt(ex_update_write_info *write_info) { if (write_info) { if (g_exit_opt_timer_hdl) { sys_timeout_del(g_exit_opt_timer_hdl); g_exit_opt_timer_hdl = 0; } } } static void ex_update_write_task_exit(ex_update_write_info *write_info) { exit_write_finsh_opt(write_info); if (0 == write_info->ret) { os_sem_pend(&write_info->write_finish_sem, 0); } if (write_info->write_buf) { free(write_info->write_buf); } task_kill(EX_FLASH_UPDATE_WRITE_TASK_NAME); } #if EX_FLASH_UPDATE_DEBUG_ENABLE static void flash_info_debug_func(void *buf, u32 addr, u32 len) { // 记录远端传过来的crc u16 crc = CRC16((u8 *)buf, len); // 清除buffer memset((u8 *)buf, 0, len); // 从flash中读出刚写入的数据计算crc norflash_f_read(buf, addr, len); // 打印地址、长度、crc信息 log_info("%x,%x,%x", addr, len, crc); // 校验flash的数据 if (crc != CRC16((u8 *)buf, len)) { log_error("%s, %d >>>>>>>>>>>>>>>>>error : %x, %x, %x, %x\n", __func__, __LINE__, addr, len, crc, CRC16((u8 *)buf, len)); } } #endif extern void flash_erase_by_blcok_n_sector(u32 start_addr, u32 len, int (*erase_hdl)(int cmd, u32 addr)); static void ex_update_write_task(void *p) { ex_update_write_info *write_info = (ex_update_write_info *)p; u8 begin_flag = 1; #if EX_FLASH_ERASE_IN_4K u32 erase_addr = __SECTOR_4K_ALIGN(write_info->write_program_addr); #else u32 erase_addr = __BLOCK_64K_ALIGN(write_info->write_program_addr); #endif write_info->en = 1; // 检测是否退出写线程timeout定时器 /* exit_write_opt_prepare(write_info); */ while (0 == write_info->ret) { if (os_sem_pend(&write_info->write_sem, g_ex_update_timeout)) { log_error("%s timeout\n", __func__); write_info->ret = -1; break; } // 如果退出条件满足,则结束写流程,并返回错误 if (exit_write_condition(write_info)) { log_error("%s, exit right now\n", __func__); write_info->ret = -1; break; } /* if (write_info->write_buf) { */ /* memcpy(write_info->write_buf, __this->buf, write_info->write_len); */ /* } */ if (write_info->erase_hdl) { #if EX_FLASH_ERASE_IN_4K u32 cur_erase_len = __SECTOR_4K_ALIGN(write_info->write_len); u32 tmp_addr = (write_info->write_offset) / FLASH_SECTOR_SIZE * FLASH_SECTOR_SIZE; #else u32 cur_erase_len = __BLOCK_64K_ALIGN(write_info->write_len); u32 tmp_addr = (write_info->write_offset) / FLASH_BLOCK_SIZE * FLASH_BLOCK_SIZE; #endif if (erase_addr != tmp_addr || begin_flag) { if (erase_addr > tmp_addr) { cur_erase_len = erase_addr - tmp_addr; } erase_addr = tmp_addr; log_info("erase_addr:%x len:%d\n", erase_addr, cur_erase_len); flash_erase_by_blcok_n_sector(erase_addr, cur_erase_len, write_info->erase_hdl); begin_flag = 0; } } if (write_info->write_hdl && write_info->write_buf) { log_info("write_addr:%x, len:%x\n", write_info->write_offset, write_info->write_len); if (write_info->write_len != write_info->write_hdl(write_info->write_buf, write_info->write_offset, write_info->write_len)) { log_error("write addr:%x len:%x err\n", write_info->write_offset, write_info->write_len); write_info->ret = -2; break; } } else { log_error("%s basic interface err\n"); write_info->ret = -1; break; } #if EX_FLASH_UPDATE_DEBUG_ENABLE flash_info_debug_func(write_info->write_buf, write_info->write_offset, write_info->write_len); #endif if (write_info->write_offset == write_info->write_program_addr) { break; } if (0 == write_info->ret) { os_sem_post(&write_info->write_finish_sem); } /* if (write_info->write_offset == write_info->write_program_addr) { */ /* break; */ /* } */ } os_sem_post(&write_info->write_finish_sem); while (1) { os_time_dly(10); } } static int ex_update_write_data(ex_update_write_info *write_info, u32 offset, u16 data_len) { if (0 == write_info->ret) { os_sem_pend(&write_info->write_finish_sem, 0); } write_info->write_offset = offset; write_info->write_len = data_len; if (write_info->write_buf) { memcpy(write_info->write_buf, __this->buf, write_info->write_len); } os_sem_post(&write_info->write_sem); return write_info->ret; } static bool ex_update_write_task_exit_condition(void *priv) { return __this->exit_write_task_flag; } static int ex_update_write_task_active(ex_update_write_info *write_info, program_info_t *info) { memset(write_info, 0, sizeof(ex_update_write_info)); write_info->write_buf = zalloc(g_once_req_size); if (NULL == write_info->write_buf) { log_error("%s alloc fail\n"); return -1; } if (info->local_write_hdl) { write_info->write_hdl = info->local_write_hdl; } if (info->local_erase_hdl) { write_info->erase_hdl = info->local_erase_hdl; } write_info->write_program_addr = info->local_program_addr; os_sem_create(&write_info->write_sem, 0); os_sem_create(&write_info->write_finish_sem, 1); // 指定写任务立即退出条件 write_info->exit_opt.condition = ex_update_write_task_exit_condition; // 检测是否退出写线程timeout定时器 exit_write_opt_prepare(write_info); task_create(ex_update_write_task, (void *)write_info, EX_FLASH_UPDATE_WRITE_TASK_NAME); // 保证先创建写线程再进行外挂flash升级 u32 create_timeout_cnt = EX_UPDATE_SEMAPHORE_WAIT_TIME / 10; while ((0 == write_info->en) && (--create_timeout_cnt)) { os_time_dly(10); } if (0 == create_timeout_cnt) { log_error("%s, create task timeout\n", __func__); write_info->ret = -1; return -1; } return 0; } static int ex_flash_program_loop(program_info_t *info) { int ret = 0; u32 remain_len; u32 remote_addr; u32 local_addr; u32 erase_addr = __SECTOR_4K_ALIGN(info->local_program_addr); u32 cur_erase_len = 0; /* if (info->local_erase_hdl) { */ /* remain_len = __SECTOR_4K_ALIGN(info->remote_file_length); */ /* local_addr = __SECTOR_4K_ALIGN(info->local_program_addr); */ /* flash_erase_by_blcok_n_sector(local_addr, remain_len, info->local_erase_hdl); */ /* } */ remain_len = info->remote_file_length; remote_addr = info->remote_file_begin; local_addr = info->local_program_addr; u32 tmp_addr = 0; u16 r_len = 0; ex_update_write_info write_info; ret = ex_update_write_task_active(&write_info, info); if (ret) { goto _ERR_RET; } do { r_len = (remain_len % g_once_req_size) ? (remain_len % g_once_req_size) : g_once_req_size; remain_len -= r_len; if (info->remote_file_read && info->buf) { ret = info->remote_file_read(info->buf, remote_addr + remain_len, r_len); if (ret != 0) { log_error("read addr:%x len:%x err\n", remote_addr - remain_len, r_len); ret = -1; break; } } if (0 == write_info.ret) { ret = ex_update_write_data(&write_info, local_addr + remain_len, r_len); } if (ret) { log_error("write err\n"); break; } } while (remain_len); _ERR_RET: if (write_info.ret) { ret = write_info.ret; } ex_update_write_task_exit(&write_info); return ret; } extern u16 calc_crc16_with_init_val(u16 init_crc, u8 *ptr, u16 len); static u16 ex_flash_local_file_verify(u8 *buf, u32 addr, u32 len, u32(*read_func)(u8 *buf, u32 addr, u32 len)) { u16 crc_temp = 0; u16 r_len; log_info("verify-addr:%x len:%x\n", addr, len); while (len) { r_len = (len > g_once_req_size) ? g_once_req_size : len; if (read_func) { read_func(buf, addr, r_len); } crc_temp = calc_crc16_with_init_val(crc_temp, buf, r_len); addr += r_len; len -= r_len; } return crc_temp; } #if EX_FLASH_MUTIL_FILE_UPDATE static int ex_flash_file_download_all_res_loop(void) { int ret = 0; u16 offset = 0; u16 files_info_len = 0; user_chip_update_info_t *update_info = NULL; program_info_t info = { .remote_file_read = remote_file_read, .local_write_hdl = norflash_f_write, .local_erase_hdl = norflash_f_erase, .buf = __this->buf, }; if (__this->info.priv) { update_info = (user_chip_update_info_t *)__this->info.priv; files_info_len = __this->info.files_info_len; } else { update_info = &__this->info; } do { info.remote_file_begin = update_info->addr; info.remote_file_length = update_info->len; info.local_program_addr = update_info->dev_addr; ret = ex_flash_program_loop(&info); if (ret) { ret = -1; break; } if (update_info->crc != \ ex_flash_local_file_verify(__this->buf, update_info->dev_addr, update_info->len, (void *)norflash_f_read)) { log_error("update crc verify err\n"); ret = -2; break; } else { log_info("update crc verify succ\n"); } if (files_info_len) { update_info++; offset += sizeof(user_chip_update_info_t); } } while (files_info_len > offset); return ret; } #endif static int ex_flash_file_download_loop(void *priv) { int ret = 0; if (0 == __this->info.len) { ret = -1; goto _ERR_RET; } __this->buf = malloc(g_once_req_size); if (NULL == __this->buf) { ret = -1; goto _ERR_RET; } // 遍历、升级所有的res资源 #if EX_FLASH_MUTIL_FILE_UPDATE ret = ex_flash_file_download_all_res_loop(); #else // EX_FLASH_MUTIL_FILE_UPDATE program_info_t info = { .remote_file_begin = __this->info.addr, .remote_file_length = __this->info.len, .local_program_addr = __this->info.dev_addr, .remote_file_read = remote_file_read, .local_write_hdl = norflash_f_write, .local_erase_hdl = norflash_f_erase, .buf = __this->buf, }; ret = ex_flash_program_loop(&info); if (ret) { ret = -1; goto _ERR_RET; } if (__this->info.crc != \ ex_flash_local_file_verify(__this->buf, __this->info.dev_addr, __this->info.len, (void *)norflash_f_read)) { log_error("update crc verify err\n"); ret = -2; } else { log_info("update crc verify succ\n"); } #endif // EX_FLASH_MUTIL_FILE_UPDATE _ERR_RET: __this->exit_write_task_flag = 0; if (__this->buf) { free(__this->buf); __this->buf = NULL; g_once_req_size = ONCE_REQ_SIZE; } return ret; } #if EX_FLASH_MUTIL_FILE_UPDATE static int ex_flash_file_release(void) { if (__this) { if (__this->info.priv) { free(__this->info.priv); __this->info.priv = NULL; } free(__this); __this = NULL; } return 0; } #endif const static user_chip_update_t ex_flash_update_ins = { .retry_cnt = 2, .file_name = EX_FLASH_FILE_NAME, .update_init = ex_flash_update_file_init, .update_get_len = ex_flash_update_file_get_len, .update_loop = ex_flash_file_download_loop, #if EX_FLASH_MUTIL_FILE_UPDATE .update_release = ex_flash_file_release, #endif }; void ex_flash_update_once_req_size_set(u32 pack_size) { g_once_req_size = pack_size; } void ex_flash_file_download_init(void) { register_user_chip_update_handle(&ex_flash_update_ins); } void ex_flash_update_len_clear(void) { if (__this && __this->info.len) { __this->info.len = 0; } } void ex_flash_read_timeout_set(int read_timeout) { g_ex_update_timeout = read_timeout; } void ex_flash_exit_write_task(void) { if (__this) { __this->exit_write_task_flag = 1; } } #else // TCFG_UPDATE_RESOURCE_EN void ex_flash_update_once_req_size_set(u32 pack_size) { } void ex_flash_file_download_init(void) { } void ex_flash_update_len_clear(void) { } void ex_flash_read_timeout_set(int read_timeout) { } void ex_flash_exit_write_task(void) { } #endif // TCFG_UPDATE_RESOURCE_EN