/***************************************************************************** * file lib/process/pd_upgrade.c * author WangBo * version 1.0.0 * date 07-Feb-2023 * brief This file provides all the softwave upgrade related operation functions. ****************************************************************************** * Attention * *

© COPYRIGHT(c) 2024 LandPower

* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of LandPower nor the names of its contributors may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef CFG_DEV_TYPE_LAND_PD /* 标准 C 库头文件 */ #include #include #include #include #include #include #include /* 第三方头文件 */ /* 私有头文件 */ #include "main.h" #include "pd_upgrade.h" #include "pd_dau.h" #include "pd_csg.h" #include "pd_dbg.h" /* Private define ------------------------------------------------------------*/ #define PD_UPG_READ_SIZE (1024*1024) #define PD_UPG_HARDWARE_VERSON "GIS6.0" /* Private macro -------------------------------------------------------------*/ /* Private typedef -----------------------------------------------------------*/ typedef void (*pd_upg_sighandler)(int); /* Private variables ---------------------------------------------------------*/ static pd_upg_ctrl_t pd_upg_ctrl; static const char *pd_upg_type_str[PD_UPG_SEL_MAX] = { "all", "cmu", "dau" }; /* Private function prototypes -----------------------------------------------*/ /* Internal functions --------------------------------------------------------*/ /* description: 调用 system 下发 shell 命令 param: cmd_line -- 需要执行的命令 return: */ int _pd_upg_system(const char *cmd_line) { int ret = 0; pd_upg_sighandler old_handler; old_handler = signal(SIGCHLD, SIG_DFL); ret = system(cmd_line); signal(SIGCHLD, old_handler); return ret; } /* description: 提取升级数据写成文件 param: addr -- 起始地址 len -- 大小 name -- 文件名字 return: E_NONE - 成功, E_XXXX - 失败 */ int32_t _pd_upg_write_file(int32_t addr, int32_t size, const char *name) { int fp_wr = -1; int fp_rd = -1; char *buf = NULL; int32_t len = 0; int32_t len_wr = 0; int32_t len_rd = 0; int32_t rv = E_NONE; /* 打开文件 */ fp_wr = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0777); if (fp_wr <= 0) { DBG(DBG_M_PD_UPGRADE, "Open %s failed!\n", name); return E_SYS_CALL; } fp_rd = open(PD_UPG_SOFTWARE, O_RDONLY); if (fp_rd <= 0) { close(fp_wr); DBG(DBG_M_PD_UPGRADE, "Open " PD_UPG_SOFTWARE " failed!\n"); return E_SYS_CALL; } /* 偏移到读取位置 */ if (lseek(fp_rd, addr, SEEK_SET) < 0) { close(fp_wr); close(fp_rd); rv = E_SYS_CALL; DBG(DBG_M_PD_UPGRADE, "Fseek %d failed!\n", addr); return E_SYS_CALL; } /* 申请 buf */ buf = (char*)XMALLOC_Q(MTYPE_UPGRADE, PD_UPG_READ_SIZE); if (!buf) { close(fp_wr); close(fp_rd); DBG(DBG_M_PD_UPGRADE, "Malloc failed!\n"); return E_MEM; } while (len < size) { len_rd = read(fp_rd, buf, PD_UPG_READ_SIZE); if (len_rd > 0) { len_wr = write(fp_wr, buf, len_rd); if(len_wr != len_rd) { DBG(DBG_M_PD_UPGRADE, "Write %s error!\n", name); rv = E_SYS_CALL; break; } } else if(0 == len_rd) { break; } else { DBG(DBG_M_PD_UPGRADE, "Read " PD_UPG_SOFTWARE " error!\n"); rv = E_SYS_CALL; break; } len += len_rd; } close(fp_rd); close(fp_wr); XFREE(MTYPE_UPGRADE, buf); _pd_upg_system("sync"); sleep(1); return rv; } /* description: 升级 CMU param: return: E_NONE - 成功, E_XXXX - 失败 */ int32_t _pd_upg_upgrade_dau(void) { uint8_t i = 0; int32_t offset = 0; int32_t lenth = 0; int32_t rv = E_ERROR; /* 查找升级文件 */ for (i = 0; i < PD_UPG_AREA_MAX; i++) { if (0 == pd_upg_ctrl.head.arr_info[i].len) { continue; } if (PD_UPG_TYPE_DAU == pd_upg_ctrl.head.arr_info[i].type) { offset = pd_upg_ctrl.head.arr_info[i].start; lenth = pd_upg_ctrl.head.arr_info[i].len; break; } } /* 没有找到 */ if (0 == lenth) { snprintf(pd_upg_ctrl.msg, 128, "DAU file is not found."); DBG(DBG_M_PD_UPGRADE, "DAU file is not found.\n"); return E_NOT_FOUND; } /* 读取并写升级文件 */ rv = _pd_upg_write_file(offset, lenth, DEBUG_DAU_FILE); if (rv != E_NONE) { snprintf(pd_upg_ctrl.msg, 128, "DAU write file error."); return E_NOT_FOUND; } return E_NONE; } /* description: 升级 CMU param: return: E_NONE - 成功, E_XXXX - 失败 */ int32_t _pd_upg_upgrade_cmu(void) { char cmd[128] = {0}; uint8_t i = 0; int32_t offset = 0; int32_t lenth = 0; int32_t rv = E_ERROR; /* 查找升级文件 */ for (i = 0; i < PD_UPG_AREA_MAX; i++) { if (0 == pd_upg_ctrl.head.arr_info[i].len) { continue; } if (PD_UPG_TYPE_CMU == pd_upg_ctrl.head.arr_info[i].type) { offset = pd_upg_ctrl.head.arr_info[i].start; lenth = pd_upg_ctrl.head.arr_info[i].len; break; } } /* 没有找到 */ if (0 == lenth) { snprintf(pd_upg_ctrl.msg, 128, "CMU file is not found."); DBG(DBG_M_PD_UPGRADE, "CMU file is not found.\n"); return E_NOT_FOUND; } /* 先备份原始文件 */ snprintf(cmd, 128, "cp -rf %s bak", PD_UPG_CMU_FILE); _pd_upg_system(cmd); _pd_upg_system("sync"); sleep(1); /* 读取并写升级文件 */ rv = _pd_upg_write_file(offset, lenth, PD_UPG_CMU_FILE_BAK); if (rv != E_NONE) { snprintf(pd_upg_ctrl.msg, 128, "CMU write file error."); return E_NOT_FOUND; } if (rename(PD_UPG_CMU_FILE_BAK, PD_UPG_CMU_FILE) != 0) { snprintf(pd_upg_ctrl.msg, 128, "CMU file rename error."); DBG(DBG_M_PD_UPGRADE, "Can't rename file %s!\n", PD_UPG_CMU_FILE_BAK); return E_SYS_CALL; } DBG(DBG_M_PD_UPGRADE, "Upgrade CMU Ok.\n"); return E_NONE; } /* description: 升级系统 param: return: E_NONE - 成功, E_XXXX - 失败 */ int32_t _pd_upg_upgrade(void) { if (PD_UPG_SEL_ALL == pd_upg_ctrl.upg_type || PD_UPG_SEL_CMU == pd_upg_ctrl.upg_type) { LD_E_RETURN(DBG_M_PD_UPGRADE, _pd_upg_upgrade_cmu()); } if (PD_UPG_SEL_ALL == pd_upg_ctrl.upg_type || PD_UPG_SEL_DAU == pd_upg_ctrl.upg_type) { LD_E_RETURN(DBG_M_PD_UPGRADE, _pd_upg_upgrade_dau()); } return E_NONE; } /* description: 检测硬件版本号是否匹配 param: return: E_NONE - 成功, E_XXXX - 失败 */ int32_t _pd_upg_hardware_check(void) { if (strncmp(pd_upg_ctrl.head.hard_ver, PD_UPG_HARDWARE_VERSON, strlen(PD_UPG_HARDWARE_VERSON))) { DBG(DBG_M_PD_UPGRADE, "Hardware version(%s) not match\n", pd_upg_ctrl.head.hard_ver); return E_ERROR; } return E_NONE; } /* description: 验证升级文件, CRC 校验升级文件并对比每段分区确定是否需要升级 param: return: E_NONE - 成功, E_XXXX - 失败 */ int32_t _pd_upg_verify_file(void) { int32_t rv = 0; int fd = 0; unsigned int crc = 0; char *buf = NULL; /*读取升级文件头信息*/ fd = open(PD_UPG_SOFTWARE, O_RDONLY); if (fd < 0) { DBG(DBG_M_PD_UPGRADE, "Open file "PD_UPG_SOFTWARE" failed!\n"); return E_SYS_CALL; } rv = read(fd, &pd_upg_ctrl.head, sizeof(pd_upg_head_t)); if (rv != sizeof(pd_upg_head_t) || pd_upg_ctrl.head.magic != PD_UPG_MAGICNUM) { close(fd); DBG(DBG_M_PD_UPGRADE, "Read len %d(%d), magic %x(%x)\n", rv, sizeof(pd_upg_head_t), pd_upg_ctrl.head.magic, PD_UPG_MAGICNUM); return E_NOT_IDENTIFY; } /*crc校验*/ buf = (char*)XMALLOC_Q(MTYPE_UPGRADE, PD_UPG_BLOCK_SIZE); if (!buf) { close(fd); DBG(DBG_M_PD_UPGRADE, "Malloc error!\n"); return E_MEM; } while (1) { rv = read(fd, buf, PD_UPG_BLOCK_SIZE); if (rv < 0) { DBG(DBG_M_PD_UPGRADE, "Read failed!\n"); rv = E_SYS_CALL; break; } else if(rv == 0) { rv = E_NONE; break; } crc = crc32(crc, buf, (unsigned long)rv); } if (E_NONE == rv) { if (crc != pd_upg_ctrl.head.crc) { DBG(DBG_M_PD_UPGRADE, "CRC error!\n"); rv = E_ERROR;; } } /* 释放资源 */ XFREE(MTYPE_UPGRADE, buf); close(fd); DBG(DBG_M_PD_UPGRADE, "Verfiy upgrade success.\n"); return rv; } /* description: 检测是否存在满足升级的条件 param: return: E_NONE - 成功, E_XXXX - 失败 */ int32_t _pd_upg_file_check(void) { int32_t rv = 0; /* 读取升级文件并校验 */ rv = _pd_upg_verify_file(); if (rv != E_NONE) { snprintf(pd_upg_ctrl.msg, 128, "App CRC verify error."); return rv; } /* 硬件版本号检查 */ rv = _pd_upg_hardware_check(); if (rv != E_NONE) { snprintf(pd_upg_ctrl.msg, 128, "Hardware is not match."); return rv; } return rv; } /* description: 软件升级处理线程 param: parm -- 控制结构体 return: */ void *_pd_upg_handle(void *parm) { char cmd[128] = {0}; int32_t rv = E_ERROR; while(1) { /* 文件检查 */ rv = _pd_upg_file_check(); if (rv != E_NONE) { break; } /* 升级系统 */ rv = _pd_upg_upgrade(); if (rv != E_NONE) { break; } break; } /* 保存升级原始文件 */ snprintf(cmd, 128, "mv " PD_UPG_SOFTWARE " bak"); _pd_upg_system(cmd); _pd_upg_system("sync"); sleep(1); /* 处理升级结果 */ if (E_NONE == rv) { DBG(DBG_M_PD_UPGRADE, "Upgrade ok.\n"); if (pd_upg_ctrl.upgrade_result) { pd_upg_ctrl.upgrade_result(1, "App and dua update successful."); } /* 升级成功, 主动重启 */ log_notice(LOG_UPGRADE, "Upgrade %s ok.", pd_upg_type_str[pd_upg_ctrl.upg_type]); reboot_system(LOG_UPGRADE, REBOOT_UPGRADE_ALL); } else { DBG(DBG_M_PD_UPGRADE, "Upgrade failed.\n"); if (pd_upg_ctrl.upgrade_result) { pd_upg_ctrl.upgrade_result(0, pd_upg_ctrl.msg); } } pd_upg_ctrl.is_start = FALSE; pthread_exit(NULL); return NULL; } /* description: 启动升级线程 param: return: E_NONE - 成功, E_XXXX - 失败 */ int32_t _pd_upg_start(void) { struct sched_param param; pthread_attr_t attr; pthread_t pid; int32_t rv = 0; /* 创建线程 配置线程 RR 调度, 优先级 50 */ pthread_attr_init(&attr); param.sched_priority = 50; pthread_attr_setschedpolicy(&attr, SCHED_RR); pthread_attr_setschedparam(&attr, ¶m); pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); rv = pthread_create(&pid, &attr, _pd_upg_handle, NULL); if (rv != 0) { log_err(LOG_UPGRADE, "PD can't create pthread %d!", rv); return E_SYS_CALL; } else { thread_m_add("UPGRADE", pid); } pthread_attr_destroy(&attr); return E_NONE; } /* Interface functions -------------------------------------------------------*/ /* description: 软件升级开始 param: from -- 来自谁的升级 PD_UPG_FROM_xxx type -- 升级类型 PD_UPG_SEL_xxx return: E_NONE - 成功, E_XXXX - 失败 */ int32_t pd_upg_start(uint8_t from, uint8_t type) { int32_t rv = E_NONE; if (pd_upg_ctrl.is_start == FALSE) { DBG(DBG_M_PD_UPGRADE, "Start upgrade system.\n"); pd_upg_ctrl.is_start = TRUE; pd_upg_ctrl.upg_from = from; pd_upg_ctrl.upg_type = type; if (PD_UPG_FROM_CSG == from) { pd_upg_ctrl.upgrade_result = csg_upgrade_result_send; } else if(PD_UPG_FROM_DBG == from) { //pd_upg_ctrl.upgrade_result = debug_upgrade_result_send; } else { pd_upg_ctrl.upgrade_result = NULL; } /* 初始化模块. */ LD_E_RETURN(DBG_M_PD_UPGRADE, _pd_upg_start()); } else { DBG(DBG_M_PD_UPGRADE, "Upgrade is busy!\n"); rv = E_TIMEOUT; } return rv; } #endif /************************ (C) COPYRIGHT LandPower ***** END OF FILE ****/