#include <common.h>
#include <command.h>
#include "md5.h"
#include "tapo_nand_upgrade.h"
#define ERR_NONE 0
#define ERR_GENERIC -1
#define ERR_RSA_CHECK_FAIL -2
#define ERR_HWID_NOT_FOUND -3
#define ERR_FWID_NOT_FOUND -4
#define ERR_HWID_NOT_SUPPORTED -5
#define ERR_FWID_NOT_SUPPORTED -6
#define ERR_PARTITION_TYPE_NOT_SUPPORTED -7
#define ERR_INCORRECT_FILE_SIZE -8
#define ERR_READ_FLASH -9
#define ERR_WRITE_FLASH -10
#define ERR_ERASE_FLASH -11
#define ERR_BAD_ADDRESS -12
#define ERR_MEMORY_ALLOC -13
#define ERR_INVALID_TP_HEADER -14
#define ERR_PARTITION_VALIDATION_FAILED -15
#define CFG_FLASH_BASE (0x0)
#define DEFAULT_8MB_FLASH_SIZE (8*1024*1024)
#ifndef FLASH_SIZE_IN_MB
#define CFG_FLASH_SIZE (DEFAULT_8MB_FLASH_SIZE)
#else
#define CFG_FLASH_SIZE (FLASH_SIZE_IN_MB*1024*1024)
#endif
#define CFG_FLASH_SECTOR_SIZE (64*1024)
#if defined(U_BOOT_COMPILE) || defined(DBG_U_BOOT_COMPILE) /* 地址和factory_boot中使用的WEBFAILSAFE_UPLOAD_RAM_ADDRESS一样 */
#ifdef CONFIG_LOADADDR
#undef CONFIG_LOADADDR
#endif
#define CONFIG_LOADADDR 0x24000000
#endif
#define MD5SUM_LEN 16
#define FW_ID_LEN 16
/* content type flags. */
#define CONTENT_TYPE_BOOTLOADER 0x0001
#define CONTENT_TYPE_KERNEL 0x0002
#define CONTENT_TYPE_ROMFS 0x0004
#define CONTENT_TYPE_JFFS2FS 0x0008
/* partition type flags. */
#define PARTITION_TYPE_BOOTLOADER CONTENT_TYPE_BOOTLOADER
#define PARTITION_TYPE_KERNEL CONTENT_TYPE_KERNEL
#define PARTITION_TYPE_ROOTFS_DATA CONTENT_TYPE_JFFS2FS
/* define tp header */
#define MAGIC_LEN 20
#define CRC_LEN 16
#define FW_DESC_LEN 12
#define ERR(fmt, ...) { \
printf("error: " fmt "\n", \
## __VA_ARGS__ ); \
}
#define DBG(fmt, ...) { \
printf( fmt "\n", ## __VA_ARGS__ ); \
}
typedef struct _TP_HEADER
{
unsigned int headerVersion;
unsigned char magicNumber[MAGIC_LEN];
unsigned int kernelLoadAddress;
unsigned int kernelEntryPoint;
unsigned short vendorId;
unsigned short zoneCode;
unsigned int partitionNum;
unsigned int factoryBootOffset;
unsigned int factoryBootLen;
unsigned int factoryInfoOffset;
unsigned int factoryInfoLen;
unsigned int radioOffset;
unsigned int radioLen;
unsigned int ucOffset;
unsigned int ucLen;
unsigned int bootloaderOffset;
unsigned int bootloaderLen;
unsigned int tpHeaderOffset;
unsigned int tpHeaderLen;
unsigned int kernelOffset;
unsigned int kernelLen;
unsigned int romFsOffset;
unsigned int romFsLen;
unsigned int jffs2FsOffset;
unsigned int jffs2FsLen;
unsigned char factoryInfoCRC[CRC_LEN];
unsigned char radioCRC[CRC_LEN];
unsigned char ubootCRC[CRC_LEN];
unsigned char kernelAndRomfsCRC[CRC_LEN];
unsigned char fwId[FW_ID_LEN];
unsigned char fwDescription[FW_DESC_LEN];
unsigned int fwIdBLNum;
unsigned char fwIdBL[0][FW_ID_LEN];
unsigned char serviceCRC[CRC_LEN];
unsigned int isVerified;
unsigned int jffs2RealFsLen;
} TP_HEADER;
/* content type flags. */
#define CONTENT_TYPE_BOOTLOADER 0x0001
#define CONTENT_TYPE_KERNEL 0x0002
#define CONTENT_TYPE_ROMFS 0x0004
#define CONTENT_TYPE_JFFS2FS 0x0008
#define CONTENT_TYPE_EXT_FW 0x0010
typedef enum
{
FW_TO_BEUPGRADE = 0,
FW_UBOOT_UPGRADED,
FW_WHOLE_UPGRADED
};
#define UP_BOOT_MAGIC "nand_upboot.bin"
#define NAND_BLOCK_SIZE ( 0x20000 )
#define UPBOOT_INFO_RSV_LEN 202
typedef struct _UPBOOT_INFO
{
char magic[16];
char md5[16];
int fwLen;
int fwStatus;
int up_contents;
int reserved_block; /* UPBOOT_INFO和UPBOOT_CONTENT之间的块数 */
char mac[6]; /* 用于uboot中isp升级判断 */
char reserve[UPBOOT_INFO_RSV_LEN];
} UPBOOT_INFO;
#define MAX_BLOCK_NUM 64
#define BLOCK_MAGIC_NUMBER_LEN 4
#define BLOCK_HEADER_RSV_LEN 504
#define BLOCK_MAX_SIZE 0x10000
typedef struct _BLOCK_INFO
{
unsigned int type;
unsigned int length;
} BLOCK_INFO;
typedef struct _BLOCK_HEADER
{
unsigned char magicNumber[BLOCK_MAGIC_NUMBER_LEN];
unsigned int num;
BLOCK_INFO info[MAX_BLOCK_NUM];
unsigned char reserve[BLOCK_HEADER_RSV_LEN];
} BLOCK_HEADER;
#define EXT_FW_HEADER_VERSION 0x00000001
#define SW_VER_LEN 64
#define RSV_LEN 96
#define EXT_FW_DEVNAME_LEN 64
typedef struct _EXT_FW_HEADER
{
unsigned int headerVersion;
unsigned char devName[EXT_FW_DEVNAME_LEN];
unsigned int compressType;
unsigned int version;
unsigned int length;
unsigned char md5[CRC_LEN];
unsigned char swVer[SW_VER_LEN];
unsigned char reserve[RSV_LEN];
} EXT_FW_HEADER;
#define EXT_FW_NOT_CHANGED 0
#define EXT_FW_CHANGED 1
typedef struct _EXT_FW_BLOCK_HANDLER
{
unsigned int type; /* type of block_handler, corresponding to block type */
unsigned int bNeedUpgrade; /* 1 means this kind of block need to be upgraded */
EXT_FW_HEADER* block; /* pointer to target block used for upgrading */
int (*checkExtFw)(BLOCK_HEADER* blockHdr, void* thisHandler);
int (*upgradeExtFw)(EXT_FW_HEADER* block);
} EXT_FW_BLOCK_HANDLER;
typedef enum
{
LOCAL_FW = 0,
UPGRADE_FW,
} FW_TYPE_E;
struct _STRUCT_SIZE_CHECK
{
char buf1[sizeof(EXT_FW_HEADER) == 256 ? 1 : -1];
char buf2[sizeof(BLOCK_HEADER) == 1024 ? 1 : -1];
};
static unsigned char blockHdrMagicNumber[] = {0x12, 0x34, 0x56, 0x78};
#ifdef ISP_IN_FLASH
static int checkFirmwareIsp(BLOCK_HEADER* blockHdr, void* thisHandler);
static int upgradeFirmwareIsp(EXT_FW_HEADER* block);
#endif
static EXT_FW_BLOCK_HANDLER blockHdrTbl[] =
{
#ifdef ISP_IN_FLASH
{
CONTENT_TYPE_EXT_FW,
EXT_FW_NOT_CHANGED,
NULL,
checkFirmwareIsp,
upgradeFirmwareIsp
},
#endif
{
0,
0,
NULL,
NULL,
NULL
}
};
static unsigned char gTpHeaderMagicNumber[MAGIC_LEN] = {0x55, 0xAA, 0x9D, 0xD1, 0xA8, 0xC8, 0x83, 0x31, 0xC9, 0x69, 0xFB, 0xBF, 0xBC, 0xF0, 0xD4, 0x32, 0x70, 0xC7, 0xAA, 0x55};
static int addr_flash(void* addr)
{
if((unsigned long)addr < 0
|| (unsigned long)addr >= CFG_FLASH_SIZE)
{
printf("%p: Not a valid flash address!", addr);
return ERR_BAD_ADDRESS;
}
return 0;
}
static int readFlash(uint32_t addrOffset, uint8_t* buf, uint32_t buflen)
{
int ret = 0;
char cmdbuf[70];
//TODO:need to detect address type.
ret = addr_flash((void*)addrOffset);
if(ret < 0)
{
return ret;
}
// ret = addr_mem(buf);
// if(ret < 0)
// {
// return ret;
// }
#ifdef USE_NAND_FLASH
sprintf(cmdbuf, "nand read.e 0x%x 0x%x 0x%x", (uint32_t)buf, addrOffset, buflen);
#else
sprintf(cmdbuf, "sf probe 0;sf read 0x%x 0x%x 0x%x", (uint32_t)buf, addrOffset, buflen);
#endif
if(run_command(cmdbuf, 0) < 0)
{
return ERR_READ_FLASH;
}
return 0;
}
static int writeFlash(uint32_t addrOffset, uint8_t* buf, uint32_t buflen)
{
int ret = 0;
char cmdbuf[70];
//TODO:need to detect address type.
ret = addr_flash((void*)addrOffset);
if(ret < 0)
{
return ret;
}
// ret = addr_mem(buf);
// if(ret < 0)
// {
// return ret;
// }
#ifdef USE_NAND_FLASH
sprintf(cmdbuf, "nand write.e 0x%x 0x%x 0x%x", (uint32_t)buf, addrOffset, buflen);
#else
sprintf(cmdbuf, "sf probe 0;sf erase 0x%x 0x%x;sf write 0x%x 0x%x 0x%x", addrOffset, buflen, (uint32_t)buf, addrOffset, buflen);
#endif
if(run_command(cmdbuf, 0) < 0)
{
return ERR_READ_FLASH;
}
return 0;
}
/*
* Function Name: eraseFlash
* Author: CaiBin
* Date: 2014-11-07
* Description: Erase flash content of a given flash address.
* Parameter:
* addrOffset: Flash address to erase.
* eraselen: Erase length in bytes.
* buflen: Length of the data buf in bytes.
* return:
* 0: Succeeded;
* ERR_ERASE_FLASH: Erase command execution error.
* ERR_BAD_ADDRESS: Invalid address values passed.
*/
static int eraseFlash(uint32_t addrOffset, uint32_t eraselen)
{
int ret;
char cmdbuf[70];
ret = addr_flash((void*)addrOffset);
if (ret < 0)
{
return ret;
}
//if addr offset or eraselen is not on sector boundary, return err.
if (0 != (addrOffset % CFG_FLASH_SECTOR_SIZE))
{
ERR("%s: addrOffset is 0x%08x\n, not on sector boundary!", __func__, addrOffset);
return ERR_BAD_ADDRESS;
}
if (0 != (eraselen % CFG_FLASH_SECTOR_SIZE))
{
ERR("%s: eraselen is 0x%08x\n, not on sector boundary!", __func__, eraselen);
return ERR_BAD_ADDRESS;
}
//TODO:need to detect address type.
#ifdef USE_NAND_FLASH
sprintf(cmdbuf, "nand erase 0x%x 0x%x", addrOffset, eraselen);
#else
sprintf(cmdbuf, "sf probe 0;sf erase 0x%x 0x%x", addrOffset, eraselen);
#endif
if (run_command(cmdbuf, 0) < 0)
{
return ERR_ERASE_FLASH;
}
return 0;
}
/* --------------------------------MD5 计算相关函数---------------------------*/
static void debug_print_md5(unsigned char *digest)
{
int i = 0;
for (i = 0; i < 16; i++)
printf("%02x", digest[i]);
printf("\n");
}
static void calcMd5(char *data, int size, char *md5)
{
MD5_CTX ctx;
MD5_Init(&ctx);
MD5_Update(&ctx, data, size);
MD5_Final(md5, &ctx);
}
/* 向UPBOOT_OFFSET的前一个分区写入升级状态 */
static inline void writeUpgradeStatsToFlash(UPBOOT_INFO *upboot_info, const int state)
{
upboot_info->fwStatus = ntohl(state);
eraseFlash(UPBOOT_OFFSET, NAND_BLOCK_SIZE * ntohl(upboot_info->reserved_block));
writeFlash(UPBOOT_OFFSET, (uint8_t *)upboot_info, sizeof(UPBOOT_INFO));
}
#ifdef FACTORY_BOOT_COMPILE
int processUboot(void)
{
int ret = 0;
UPBOOT_INFO *upboot_info = NULL;
TP_HEADER *header_up = NULL;
char *base = NULL;
unsigned char md5Tmp[MD5SUM_LEN] = {0};
ret = readFlash(UPBOOT_OFFSET, (uint8_t*)WEBFAILSAFE_UPLOAD_RAM_ADDRESS, sizeof(UPBOOT_INFO));
if (ret < 0)
{
ERR("reading flash to RAM failed.");
return ret;
}
upboot_info = (UPBOOT_INFO *)WEBFAILSAFE_UPLOAD_RAM_ADDRESS;
if (strncmp(upboot_info->magic, UP_BOOT_MAGIC, sizeof(UP_BOOT_MAGIC)))
{
DBG("UPBOOT_INFO is not written, skip...");
return 0;
}
if (ntohl(upboot_info->reserved_block) < 2)
{
printf("reserved_block between upboot_info and upboot is too short\n");
return 0;
}
if (upboot_info->fwStatus) /* 升级时将up_boot.bin中的主要内容写入后, 该字段才会为零 */
{
printf("No need to update uboot\n");
return 0;
}
printf("fwLen:0x%08x, fwStatus:0x%08x\n", ntohl(upboot_info->fwLen), ntohl(upboot_info->fwStatus));
printf("up_contents:0x%08x\n", ntohl(upboot_info->up_contents));
/* 固件升级时uboot不一定需要更新, nsd模块的upgrade会在将upboot写入flash之前进行检查是否改变 */
if (ntohl(upboot_info->up_contents) & CONTENT_TYPE_BOOTLOADER)
{
DBG("uboot need to upgrade");
base = WEBFAILSAFE_UPLOAD_RAM_ADDRESS + NAND_BLOCK_SIZE;
header_up = (TP_HEADER *)(base + BOOTLOADER_LEN); /* 待升级固件的tp_header */
/* read length ubootlen + tp_header or ntohl(upboot_info->fwLen) ? */
uint32_t upboot_content_offset = UPBOOT_OFFSET + NAND_BLOCK_SIZE * ntohl(upboot_info->reserved_block);
uint32_t upboot_content_length = BOOTLOADER_LEN + TP_HEADER_LEN;
ret = readFlash(upboot_content_offset, (uint8_t *)base, upboot_content_length);
if (ret < 0)
{
ERR("reading flash to RAM failed.");
return ret;
}
memset(md5Tmp, 0, MD5SUM_LEN);
calcMd5((char *)(base), (int)BOOTLOADER_LEN, (char *)md5Tmp);
// debug_print_md5(md5Tmp);
// debug_print_md5(header_up->ubootCRC);
if (memcmp(md5Tmp, header_up->ubootCRC, MD5SUM_LEN) == 0)
{
printf("uboot in up_boot check ok\n");
eraseFlash(BOOTLOADER_OFFSET, TP_HEADER_OFFSET - BOOTLOADER_OFFSET);
writeFlash(BOOTLOADER_OFFSET, (uint8_t *)base, BOOTLOADER_LEN);
}
}
/* set fwStatus flag to record upgrade status */
writeUpgradeStatsToFlash(upboot_info, FW_UBOOT_UPGRADED);
return 0;
}
#endif
#if defined(U_BOOT_COMPILE) || defined(DBG_U_BOOT_COMPILE)
#ifdef ISP_IN_FLASH
static bool IspPartitionIsDefault(EXT_FW_HEADER *localIspHdr)
{
EXT_FW_HEADER defultValue;
memset((char *)&defultValue, 0xFF, sizeof(EXT_FW_HEADER)); //default value for ISP is FF when mkslpfw
if(0 == memcmp((char *)localIspHdr, (char *)&defultValue, sizeof(EXT_FW_HEADER)))
{
return true;
}
else
{
return false;
}
}
/******************************************************************************
* FUNCTION : checkFirmwareIsp()
* AUTHOR : He Shufan (heshufan@tp-link.com.cn)
* DESCRIPTION : check isp content and if they are newer or not.
* INPUT : BLOCK_HEADER, pointer to block_handler of this function
*
* OUTPUT : N/A
* RETURN : ret code
* OTHERS :
******************************************************************************/
static int checkFirmwareIsp(BLOCK_HEADER* hdr, void* thisHandler)
{
int ret = 0;
int i = 0;
int blockNum = 0;
char md5Tmp[MD5SUM_LEN] = {0};
char* base = (char*)hdr;
EXT_FW_HEADER localIspHdr;
EXT_FW_HEADER* iHdr = NULL;
EXT_FW_BLOCK_HANDLER* pointer = thisHandler;
if (NULL == hdr || NULL == thisHandler)
{
ERR("NULL pointer!");
ret = ERR_GENERIC;
goto out;
}
blockNum = ntohl(hdr->num);
DBG("blockNum is %d",blockNum);
base += sizeof(BLOCK_HEADER);
memset((char *)&localIspHdr, 0, sizeof(EXT_FW_HEADER));
ret = readFlash(ISP_OFFSET, &localIspHdr, sizeof(EXT_FW_HEADER));
if (ret)
{
ERR("read flash failed");
goto out;
}
if(IspPartitionIsDefault(&localIspHdr))
{
DBG("Isp partition is default");
/* Tapo的ext_fw.config没有Default-devName_Default-hwVer, 固件中一定会有机型名对应的isp */
return ERR_GENERIC;
#if 0
if(MacIsDefault())
{
//use default device name in factory info, to match isp
DBG("Mac is default");
//getDeviceName(localIspHdr.devName);
memcpy(localIspHdr.devName, localInfo.devName, EXT_FW_DEVNAME_LEN);
}
else
{
ERR("Isp partition is default but mac is not default");
return ERR_GENERIC;
}
#endif
}
for (i = 0; i < blockNum; i++)
{
if (CONTENT_TYPE_EXT_FW == ntohl(hdr->info[i].type))
{
iHdr = (EXT_FW_HEADER*)base;
if (0 == memcmp(iHdr->devName, localIspHdr.devName, strlen(localIspHdr.devName)))
{
pointer->block = iHdr;
DBG("checkFirmwareIsp: device name %s supported", localIspHdr.devName);
break;
}
}
base += ntohl(hdr->info[i].length);
}
if (i == blockNum)
{
ERR("isp: device name not supported");
return ERR_GENERIC;
}
calcMd5((char*)iHdr + sizeof(EXT_FW_HEADER), ntohl(iHdr->length), md5Tmp);
ret = memcmp(iHdr->md5, md5Tmp, MD5SUM_LEN);
if (ret)
{
ERR("Invalid isp data in firmware");
return ERR_GENERIC;
}
ret = memcmp(&(iHdr->version), &(localIspHdr.version), sizeof(unsigned int));
if (ret)
{
DBG("isp is changed");
pointer->bNeedUpgrade = EXT_FW_CHANGED;
return ERR_NONE;
}
ret = memcmp(iHdr->md5, localIspHdr.md5, CRC_LEN);
if (ret)
{
DBG("isp is changed");
pointer->bNeedUpgrade = EXT_FW_CHANGED;
return ERR_NONE;
}
ret = memcmp(iHdr->swVer, localIspHdr.swVer, SW_VER_LEN);
if (ret)
{
DBG("isp is not changed but software version is changed");
pointer->bNeedUpgrade = EXT_FW_CHANGED;
return ERR_NONE;
}
DBG("isp is not changed");
pointer->bNeedUpgrade = EXT_FW_NOT_CHANGED;
out:
return ret;
}
/******************************************************************************
* FUNCTION : upgradeFirmwareIsp()
* AUTHOR : He Shufan (heshufan@tp-link.com.cn)
* DESCRIPTION : upgrade isp in flash
* INPUT : EXT_FW_HEADER
*
* OUTPUT : N/A
* RETURN : ret code
* OTHERS :
******************************************************************************/
static int upgradeFirmwareIsp(EXT_FW_HEADER* block)
{
int ret = 0;
char ispBuf[ISP_LEN] = {0};
uint32_t addrOffset = 0;
uint32_t size = 0;
if (NULL == block)
{
ERR("NULL pointer");
ret = ERR_GENERIC;
return ret;
}
size = ntohl(block->length) + sizeof(EXT_FW_HEADER);
memset(ispBuf, 0xff, ISP_LEN);
memcpy(ispBuf, (void *)block, size);
#ifdef USE_NAND_FLASH
ret = eraseFlash(ISP_OFFSET, UC_OFFSET - ISP_OFFSET);
#else
ret = eraseFlash(ISP_OFFSET, ISP_LEN);
#endif
if (ret)
{
return ret;
}
//ret = writePartitionData(ISP, ispBuf);
ret = writeFlash(ISP_OFFSET, ispBuf, ISP_LEN);
if (ret)
{
return ret;
}
DBG("upgrade isp done");
return ERR_NONE;
}
#endif /* #ifdef ISP_IN_FLASH */
#ifdef CONFIG_EXT_FW_UPGRADE
static int checkEXTFirmware(/*UPGRADE_HEADER* uHeader*/ unsigned char *buf)
{
int i = 0;
// unsigned short upContents = 0;
BLOCK_HEADER* blockHdr = NULL;
TP_HEADER* header;
// unsigned char* buf = (unsigned char*)uHeader;
int ret = 0;
// upContents = ntohs(uHeader->contentTypes);
header = (TP_HEADER*)(buf + /*ntohs(uHeader->tagLength) + */BOOTLOADER_LEN);
blockHdr = (BLOCK_HEADER*)((char*)header + ntohl(header->tpHeaderLen) + ntohl(header->kernelLen) + ntohl(header->romFsLen));
if (0 != memcmp(blockHdrMagicNumber, blockHdr->magicNumber, BLOCK_MAGIC_NUMBER_LEN))
{
ERR("invalid ext_fw block header");
return ERR_GENERIC;
}
for (i = 0; i < sizeof(blockHdrTbl) / sizeof(EXT_FW_BLOCK_HANDLER); i++)
{
if (0 != (blockHdrTbl[i].type /* & upContents*/ ))
{
ret = blockHdrTbl[i].checkExtFw(blockHdr, &blockHdrTbl[i]);
if (ret < 0)
{
ERR("check ext_fw failed, type:0x%x", blockHdrTbl[i].type);
return ERR_PARTITION_TYPE_NOT_SUPPORTED;
}
}
}
// printf("checkEXTFirmware done\n");
return ERR_NONE;
}
static int upgradeEXTFirmware(void)
{
int i = 0;
int ret = ERR_NONE;
// printf("blockHdrTbl[i].bNeedUpgrade is %d, %d\n", i, blockHdrTbl[i].bNeedUpgrade);
for (i = 0; i < sizeof(blockHdrTbl) / sizeof(EXT_FW_BLOCK_HANDLER); i++)
{
// printf("blockHdrTbl[i].bNeedUpgrade is %d, %d\n", i, blockHdrTbl[i].bNeedUpgrade);
if (blockHdrTbl[i].bNeedUpgrade)
{
ret = blockHdrTbl[i].upgradeExtFw(blockHdrTbl[i].block);
if (ret)
{
ERR("upgrade ext_fw failed, type:0x%x", blockHdrTbl[i].type);
return ret;
}
}
}
return ret;
}
#endif
static int executeUpgrade_nand(TP_HEADER* header)
{
int ret = 0;
int i =0;
uint32_t offset[] = {
TP_HEADER_OFFSET,
KERNEL_OFFSET,
ntohl(header->romFsOffset)
};
uint32_t eraseLen[] = {
KERNEL_OFFSET - TP_HEADER_OFFSET,
ntohl(header->romFsOffset) - KERNEL_OFFSET,
ntohl(header->jffs2FsOffset) - ntohl(header->romFsOffset)
};
uint32_t writeLen[] = {
TP_HEADER_LEN,
ntohl(header->kernelLen),
ntohl(header->romFsLen)
};
uint8_t* baseArr[] = {
(uint8_t*)header,
(uint8_t*)((uint8_t*)header + TP_HEADER_LEN),
(uint8_t*)((uint8_t*)header + TP_HEADER_LEN + ntohl(header->kernelLen))
};
printf("execute nand flash upgrade...\n");
for (i = 0; i < sizeof(offset) / sizeof(uint32_t); i++)
{
ret = eraseFlash(offset[i], eraseLen[i]);
if (ret < 0)
{
goto error_exit;
}
//start to write firmware.
printf("write offset: 0x%x, from: %p, size: 0x%x\n", offset[i], baseArr[i], writeLen[i]);
ret = writeFlash(offset[i], baseArr[i], writeLen[i]);
if (ret < 0)
{
goto error_exit;
}
}
return 0;
error_exit:
ERR("erase or write nand flash failed!");
return ret;
}
int validateFirmwareWithUpgrade(void)
{
int ret = 0;
UPBOOT_INFO *upboot_info = NULL;
ret = readFlash(UPBOOT_OFFSET, (uint8_t*)CONFIG_LOADADDR, sizeof(UPBOOT_INFO));
if (ret < 0)
{
ERR("reading flash to RAM failed.");
return ret;
}
upboot_info = (UPBOOT_INFO *)CONFIG_LOADADDR;
if (strncmp(upboot_info->magic, UP_BOOT_MAGIC, sizeof(UP_BOOT_MAGIC)))
{
DBG("UPBOOT_INFO is not written, skip...");
return 0;
}
if (ntohl(upboot_info->fwStatus) != FW_UBOOT_UPGRADED) /* factory_boot中已经处理完uboot升级逻辑 */
{
printf("No need to upgrade firmware\n");
return 0;
}
printf("fwLen:0x%08x, fwStatus:%d\n", ntohl(upboot_info->fwLen), ntohl(upboot_info->fwStatus));
TP_HEADER* header_up = NULL;
char *base = CONFIG_LOADADDR + NAND_BLOCK_SIZE;
header_up = (TP_HEADER *)(base + BOOTLOADER_LEN);
unsigned char md5Tmp[MD5SUM_LEN] = {0};
/* 根据upboot_info中的fwLen读取待升级固件 */
uint32_t upboot_content_offset = UPBOOT_OFFSET + NAND_BLOCK_SIZE * ntohl(upboot_info->reserved_block);
ret = readFlash(upboot_content_offset, (uint8_t *)base, ntohl(upboot_info->fwLen));
if (ret < 0)
{
ERR("reading flash to RAM failed.");
return ret;
}
/* check fwLen */
if (ntohl(upboot_info->fwLen) < \
ntohl(header_up->bootloaderLen) + ntohl(header_up->tpHeaderLen) + ntohl(header_up->kernelLen) + ntohl(header_up->romFsLen))
{
return 0;
}
memset(md5Tmp, 0, MD5SUM_LEN);
calcMd5((char *)(base + ntohl(header_up->bootloaderLen) + ntohl(header_up->tpHeaderLen)), \
(int)(ntohl(header_up->kernelLen) + ntohl(header_up->romFsLen)), (char *)md5Tmp);
// debug_print_md5(md5Tmp);
// debug_print_md5(header_up->kernelAndRomfsCRC);
/* 由于升级时固件版本会变, 导致kernelAndromfs一定会变, 在此不再判断up_contents */
if (memcmp(md5Tmp, header_up->kernelAndRomfsCRC, MD5SUM_LEN) == 0)
{
printf("uboot check kernelAndromfs in up_boot.bin ok\n");
executeUpgrade_nand(header_up);
}
/* isp也会改变, 不再判断up_contents, 升级ISP */
#ifdef CONFIG_EXT_FW_UPGRADE
checkEXTFirmware(base);
upgradeEXTFirmware();
#endif
/* set fwStatus flag to record upgrade status */
writeUpgradeStatsToFlash(upboot_info, FW_WHOLE_UPGRADED);
return 0;
}
#endif /* #ifdef U_BOOT_COMPILE */