303 lines
9.5 KiB
C
303 lines
9.5 KiB
C
/*
|
|
* Copyright (c) CompanyNameMagicTag 2018-2019. All rights reserved.
|
|
* Description: Upgrade base funciton - file check.
|
|
*/
|
|
|
|
#include "upg_base_file_check.h"
|
|
#include <soc_mdm_types.h>
|
|
#include <soc_21_upg.h>
|
|
#include <soc_ft_nv.h>
|
|
#include <soc_mdm_flash.h>
|
|
#include <soc_mdm_mem.h>
|
|
#include <soc_stdlib.h>
|
|
#include <upg_base_tool.h>
|
|
#include <soc_partition_table.h>
|
|
#include <soc_mdm_init.h>
|
|
#include <soc_upg_api.h>
|
|
#include "upg_base_secure_check.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
EXT_PRV td_u32 upg_check_product_list(const ext_21_upg_head_product *product_info, td_u32 list_count);
|
|
EXT_PRV td_u32 upg_conver_tail_addr_2_head_addr(td_u32 upg_tail_addr, td_u32 *upg_head_addr);
|
|
EXT_PRV td_u32 upg_get_head_from_flash(td_bool end_addr, td_u32 flash_addr, ext_21_upg_head *upg_head,
|
|
td_u32 *upg_head_addr);
|
|
EXT_PRV td_u32 upg_check_head_common_info(const ext_21_upg_head *upg_head, td_u32 head_size, td_u8 *file_type);
|
|
EXT_PRV td_u32 uapi_upg_partion_update(td_u32 head_addr, EXT_CONST ext_21_upg_head *upg_head);
|
|
|
|
td_u32 upg_check_chip_magic(td_u32 chip_magic)
|
|
{
|
|
if (chip_magic != PRODUCT_CFG_CHIP_MAGIC) {
|
|
return EXT_ERR_UPG_HEAD_CHECK_MAGIC_WRONG;
|
|
}
|
|
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
|
|
td_u32 upg_check_manufactuer(td_u16 manufactuer_code)
|
|
{
|
|
if (manufactuer_code != PRODUCT_CFG_MANUCODE) {
|
|
return EXT_ERR_UPG_HEAD_CHECK_MANUCODE_WRONG;
|
|
}
|
|
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
|
|
EXT_PRV td_u32 upg_check_product_list(const ext_21_upg_head_product *product_info, td_u32 list_count)
|
|
{
|
|
td_u32 i;
|
|
td_u16 product_type = (td_u16)uapi_get_product_type();
|
|
|
|
for (i = 0; i < list_count; i++) {
|
|
const ext_21_upg_head_product *item = &product_info[i];
|
|
|
|
if ((product_type >= item->min_id) && (product_type <= item->max_id)) {
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return EXT_ERR_UPG_HEAD_CHECK_PRODUCT_LIST_WRONG;
|
|
}
|
|
|
|
td_u32 upg_check_file_type(td_u8 file_type)
|
|
{
|
|
if (file_type == EXT_21_UPG_TYPE_KERNEL || file_type == EXT_21_UPG_TYPE_BOOT ||
|
|
file_type == EXT_21_UPG_TYPE_PARTITION) {
|
|
return EXT_ERR_SUCCESS;
|
|
} else {
|
|
return EXT_ERR_UPG_HEAD_CHECK_FILE_TYPE_WRONG;
|
|
}
|
|
}
|
|
|
|
EXT_PRV td_u32 upg_conver_tail_addr_2_head_addr(td_u32 upg_tail_addr, td_u32 *upg_head_addr)
|
|
{
|
|
td_u32 ret;
|
|
ext_21_upg_tail tail = { 0 };
|
|
|
|
/* read file tail */
|
|
ret =
|
|
uapi_flash_read((td_u32)(upg_tail_addr - sizeof(ext_21_upg_tail)), sizeof(ext_21_upg_tail), ((td_u8 *)(&tail)));
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
/* file ending magic byte verify */
|
|
if (tail.head_end_magic != PRODUCT_CFG_UPG_FILE_END_SIGNATURE) {
|
|
return EXT_ERR_UPG_CHECK_UPG_END_MAGIC_FAIL;
|
|
}
|
|
|
|
/* assure upgrade file head position */
|
|
if (upg_tail_addr > tail.head_before_offset) {
|
|
*upg_head_addr = upg_tail_addr - tail.head_before_offset;
|
|
} else {
|
|
return EXT_ERR_UPG_CHECK_UPG_END_OFFSET_FAIL;
|
|
}
|
|
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
|
|
EXT_PRV td_u32 upg_get_head_from_flash(td_bool end_addr, td_u32 flash_addr, ext_21_upg_head *upg_head,
|
|
td_u32 *upg_head_addr)
|
|
{
|
|
td_u32 ret;
|
|
|
|
/* get upg head position */
|
|
if (end_addr == TD_TRUE) {
|
|
ret = upg_conver_tail_addr_2_head_addr(flash_addr, upg_head_addr);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
} else {
|
|
*upg_head_addr = flash_addr;
|
|
}
|
|
|
|
/* read upg head */
|
|
ret = uapi_flash_read(*upg_head_addr, sizeof(ext_21_upg_head), (td_u8 *)upg_head);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
EXT_PRV td_u32 upg_check_head_common_info(const ext_21_upg_head *upg_head, td_u32 head_size, td_u8 *file_type)
|
|
{
|
|
td_u32 ret;
|
|
td_u32 not_check_ret = EXT_ERR_SUCCESS;
|
|
|
|
if (head_size < ext_struct_offset(ext_21_upg_head, chip_magic) + sizeof(upg_head->chip_magic)) {
|
|
return not_check_ret;
|
|
}
|
|
|
|
/* file head chip magic byte and manufacturer magic verify */
|
|
ret = upg_check_chip_magic(upg_head->chip_magic);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
if (head_size < ext_struct_offset(ext_21_upg_head, manufactuer_code) + sizeof(upg_head->manufactuer_code)) {
|
|
return not_check_ret;
|
|
}
|
|
|
|
ret = upg_check_manufactuer(upg_head->manufactuer_code);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
if (head_size < ext_struct_offset(ext_21_upg_head, file_type) + sizeof(upg_head->file_type)) {
|
|
return not_check_ret;
|
|
}
|
|
|
|
*file_type = upg_head->file_type;
|
|
ret = upg_check_file_type(upg_head->file_type);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
if (head_size < ext_struct_offset(ext_21_upg_head, product_list[0]) + sizeof(upg_head->product_list)) {
|
|
return not_check_ret;
|
|
}
|
|
|
|
/* upg file product type verify */
|
|
ret = upg_check_product_list(upg_head->product_list, PRODUCT_LIST_SIZE);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
|
|
td_u32 uapi_upg_check_head(const ext_21_upg_head *upg_head, td_u32 head_size)
|
|
{
|
|
td_u32 ret;
|
|
ext_partition_ver ver_ret;
|
|
td_u8 file_type = EXT_21_UPG_TYPE_NONE;
|
|
td_u32 not_check_ret = EXT_ERR_SUCCESS;
|
|
|
|
ret = upg_check_head_common_info(upg_head, head_size, &file_type);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
if (head_size < ext_struct_offset(ext_21_upg_head, partion_ver) + sizeof(upg_head->partion_ver)) {
|
|
return not_check_ret;
|
|
}
|
|
|
|
ver_ret = uapi_flash_partition_check_ver(&upg_head->partion_ver);
|
|
if (file_type == EXT_21_UPG_TYPE_KERNEL) {
|
|
if (ver_ret == EXT_PARTITION_VER_THE_SAME) {
|
|
return EXT_ERR_SUCCESS;
|
|
} else {
|
|
return EXT_ERR_UPG_HEAD_CHECK_PARTION_NOT_SAME;
|
|
}
|
|
} else if (file_type == EXT_21_UPG_TYPE_PARTITION) {
|
|
if (ver_ret == EXT_PARTITION_VER_THE_SAME || ver_ret == EXT_PARTITION_VER_NEW) {
|
|
return EXT_ERR_SUCCESS;
|
|
} else {
|
|
return EXT_ERR_UPG_HEAD_CHECK_PARTION_NOT_SUPPORT_UPG;
|
|
}
|
|
} else if (file_type == EXT_21_UPG_TYPE_BOOT) {
|
|
/* boot not discriminated by product type. All of product use the same boot */
|
|
return EXT_ERR_SUCCESS;
|
|
} else {
|
|
return EXT_ERR_UPG_HEAD_CHECK_PARTION_NOT_SUPPORT_UPG;
|
|
}
|
|
}
|
|
|
|
EXT_PRV td_u32 uapi_upg_partion_update(td_u32 head_addr, EXT_CONST ext_21_upg_head *upg_head)
|
|
{
|
|
td_u32 ret;
|
|
td_u8 *partion_info = TD_NULL;
|
|
|
|
if (upg_head->partition_info_offset == 0 || upg_head->partition_info_size == 0 ||
|
|
upg_head->file_type != EXT_21_UPG_TYPE_PARTITION) {
|
|
return EXT_ERR_SUCCESS;
|
|
}
|
|
|
|
partion_info = uapi_malloc(EXT_MOD_ID_DRV_UPG, upg_head->partition_info_size);
|
|
if (partion_info == TD_NULL) {
|
|
return EXT_ERR_FAILURE;
|
|
}
|
|
|
|
ret = uapi_flash_read(head_addr + upg_head->partition_info_offset, upg_head->partition_info_size, partion_info);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
uapi_free(EXT_MOD_ID_DRV_UPG, partion_info);
|
|
return ret;
|
|
}
|
|
|
|
ret = uapi_flash_partition_config((ext_flash_partition_chage_info *)partion_info,
|
|
(td_u16)upg_head->partition_info_size);
|
|
if (ret == EXT_ERR_PARTITION_UPDATA_TBL_SAME || ret == EXT_ERR_PARTITION_UPDATA_VER_SAME) {
|
|
/* flash partition list process with success */
|
|
ret = EXT_ERR_SUCCESS;
|
|
}
|
|
|
|
uapi_free(EXT_MOD_ID_DRV_UPG, partion_info);
|
|
return ret;
|
|
}
|
|
|
|
/* weak check function. This function has no meaning if power down with exception before checking */
|
|
td_u32 uapi_upg_check_upg_file(td_bool end_addr, td_u32 flash_addr, ext_upg_file_base_info *upg_info)
|
|
{
|
|
td_u32 ret;
|
|
td_u8 check_sum[EXT_SHA256_SIZE] = { 0 };
|
|
ext_21_upg_head *upg_head = TD_NULL;
|
|
td_u32 upg_head_addr = 0;
|
|
|
|
/* apply for upgrading file head space */
|
|
upg_head = (ext_21_upg_head *)uapi_malloc(EXT_MOD_ID_DRV_UPG, sizeof(ext_21_upg_head));
|
|
if (upg_head == TD_NULL) {
|
|
ret = EXT_ERR_UPG_ERR_MALLOC_FAIL;
|
|
goto END;
|
|
}
|
|
|
|
/* get upg head position */
|
|
ret = upg_get_head_from_flash(end_addr, flash_addr, upg_head, &upg_head_addr);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
goto END;
|
|
}
|
|
|
|
ret = uapi_upg_check_head(upg_head, sizeof(ext_21_upg_head));
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
goto END;
|
|
}
|
|
/* file section check with hash */
|
|
ret = uapi_hash_flash_content(upg_head_addr + EXT_UPG_HEAD_CHECK_SUM_START_OFFSET,
|
|
upg_head->file_len - EXT_UPG_HEAD_CHECK_SUM_START_OFFSET, check_sum, EXT_SHA256_SIZE);
|
|
if ((ret != EXT_ERR_SUCCESS) || memcmp(upg_head->check_sum, check_sum, sizeof(upg_head->check_sum))) {
|
|
ret = EXT_ERR_UPG_FILE_CHECK_SUM_WRONG;
|
|
goto END;
|
|
}
|
|
|
|
ret = upg_check_secure_head(upg_head_addr, upg_head);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
goto END;
|
|
}
|
|
|
|
ret = uapi_upg_partion_update(upg_head_addr, upg_head);
|
|
if (ret != EXT_ERR_SUCCESS) {
|
|
goto END;
|
|
}
|
|
|
|
/* return with file info */
|
|
upg_info->file_type = upg_head->file_type;
|
|
upg_info->flash_addr = upg_head_addr;
|
|
upg_info->flash_size = upg_head->file_len;
|
|
uapi_crc32_flash_content(0, upg_info->flash_addr, upg_info->flash_size, &(upg_info->crc));
|
|
ret = EXT_ERR_SUCCESS;
|
|
|
|
END:
|
|
if (upg_head != TD_NULL) {
|
|
uapi_free(EXT_MOD_ID_DRV_UPG, upg_head);
|
|
upg_head = TD_NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|