mirror of
https://github.com/gnuton/asuswrt-merlin.ng.git
synced 2025-05-19 16:02:36 +02:00
859 lines
25 KiB
C
Executable file
859 lines
25 KiB
C
Executable file
/***********************************************************************
|
|
* <:copyright-BRCM:2016:DUAL/GPL:standard
|
|
*
|
|
* Copyright (c) 2016 Broadcom
|
|
* All Rights Reserved
|
|
*
|
|
* Unless you and Broadcom execute a separate written software license
|
|
* agreement governing use of this software, this software is licensed
|
|
* to you under the terms of the GNU General Public License version 2
|
|
* (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
|
|
* with the following added to such license:
|
|
*
|
|
* As a special exception, the copyright holders of this software give
|
|
* you permission to link this software with independent modules, and
|
|
* to copy and distribute the resulting executable under terms of your
|
|
* choice, provided that you also meet, for each linked independent
|
|
* module, the terms and conditions of the license of that module.
|
|
* An independent module is a module which is not derived from this
|
|
* software. The special exception does not apply to any modifications
|
|
* of the software.
|
|
*
|
|
* Not withstanding the above, under no circumstances may you combine
|
|
* this software in any way with any other Broadcom software provided
|
|
* under a license other than the GPL, without Broadcom's express prior
|
|
* written consent.
|
|
*
|
|
* :>
|
|
************************************************************************/
|
|
|
|
/*!\file bcm_imgutil.c
|
|
* \brief Broadcom firmware image utils. Most of this file is copied from
|
|
* cms_util/image.c This file is the correct place for most
|
|
* Broadcom image utils, since the image functions applies to
|
|
* non-CMS builds as well. Going forward, make fixes and enhancements
|
|
* in this file and redirect calls from image.c to this file.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <net/if.h>
|
|
#ifdef DESKTOP_LINUX
|
|
#include <arpa/inet.h>
|
|
#endif /* DESKTOP_LINUX */
|
|
|
|
#include "bcmTag.h"
|
|
#include "board.h"
|
|
#include "bcm_boarddriverctl.h"
|
|
|
|
#include "genutil_crc.h"
|
|
#include "bcm_flashutil.h"
|
|
#include "bcm_flashutil_nand.h"
|
|
#include "bcm_flashutil_emmc.h"
|
|
#include "bcm_flashutil_nor.h"
|
|
#include "bcm_imgutil.h"
|
|
#include "libfdt.h"
|
|
|
|
/* #define CC_IMGUTIL_DEBUG 1 */
|
|
#define cmsLog_error(fmt, arg...) \
|
|
printf("ERROR[%s.%u]: " fmt "\n", __FUNCTION__, __LINE__, ##arg)
|
|
#if defined(CC_IMGUTIL_DEBUG)
|
|
#define cmsLog_debug(fmt, arg...) \
|
|
printf("%s.%u: " fmt "\n", __FUNCTION__, __LINE__, ##arg)
|
|
#else
|
|
#define cmsLog_debug(fmt, arg...)
|
|
#endif /* CC_IMGUTIL_DEBUG */
|
|
#if defined(CC_IMGUTIL_NOTICE)
|
|
#define cmsLog_notice(fmt, arg...) \
|
|
printf("%s.%u: " fmt "\n", __FUNCTION__, __LINE__, ##arg)
|
|
#else
|
|
#define cmsLog_notice(fmt, arg...)
|
|
#endif /* CC_IMGUTIL_NOTICE */
|
|
|
|
|
|
static UBOOL8 matchChipId(const char *strTagChipId, const char *signature2);
|
|
CmsRet bcmImg_verifyBroadcomFileTag(FILE_TAG *pTag, UBOOL8 fullImageB, int imageLen);
|
|
void dumpBcmFileTag(FILE_TAG *tagP);
|
|
|
|
|
|
UBOOL8 bcmImg_MatchChipId( const char *strTagChipId )
|
|
{
|
|
return(matchChipId(strTagChipId, NULL));
|
|
}
|
|
|
|
/**
|
|
* @return TRUE if the modem's chip id matches that of the image.
|
|
*/
|
|
static UBOOL8 matchChipId(const char *strTagChipId, const char *signature2 __attribute__((unused)))
|
|
{
|
|
UINT32 tagChipId = 0;
|
|
UINT32 chipId;
|
|
UBOOL8 match;
|
|
|
|
/* this is the image's chip id */
|
|
tagChipId = (UINT32) strtol(strTagChipId, NULL, 16);
|
|
|
|
/* get the system's chip id */
|
|
devCtl_getChipId(&chipId);
|
|
if (tagChipId == chipId)
|
|
{
|
|
match = TRUE;
|
|
}
|
|
else if (tagChipId == CHIP_FAMILY_ID_HEX)
|
|
{
|
|
match = TRUE;
|
|
}
|
|
else
|
|
{
|
|
cmsLog_error("Chip Id error. Image Chip Id = %04x, Board Chip Id = %04x.", tagChipId, chipId);
|
|
match = FALSE;
|
|
#ifdef DESKTOP_LINUX
|
|
match = TRUE; /* For debugging. */
|
|
#endif
|
|
}
|
|
|
|
return match;
|
|
}
|
|
|
|
// verify the tag of the image
|
|
CmsRet bcmImg_verifyBroadcomFileTag(FILE_TAG *pTag, UBOOL8 fullImageB, int imageLen)
|
|
{
|
|
UINT32 crc;
|
|
int totalImageSize;
|
|
int tagVer, curVer;
|
|
UINT32 tokenCrc, imageCrc, *pTokenCrc, *pImageCrc;
|
|
|
|
|
|
cmsLog_debug("start of pTag=%p tagversion %02x %02x %02x %02x", pTag,
|
|
pTag->tagVersion[0],
|
|
pTag->tagVersion[1],
|
|
pTag->tagVersion[2],
|
|
pTag->tagVersion[3]);
|
|
|
|
pTokenCrc = (UINT32 *)pTag->tagValidationToken;
|
|
tokenCrc = *pTokenCrc;
|
|
pImageCrc = (UINT32 *)pTag->imageValidationToken;
|
|
imageCrc = *pImageCrc;
|
|
#ifdef DESKTOP_LINUX
|
|
/* assume desktop is running on little endien intel, but the CRC has been
|
|
* written for big endien mips, so swap before compare.
|
|
* FIXME! this part of code might not work with Little-endian target system.
|
|
*/
|
|
tokenCrc = htonl(tokenCrc);
|
|
imageCrc = htonl(imageCrc);
|
|
#endif
|
|
|
|
// check tag validate token first
|
|
crc = CRC_INITIAL_VALUE;
|
|
crc = genUtl_getCrc32((UINT8 *) pTag, (UINT32)TAG_LEN-TOKEN_LEN, crc);
|
|
if (crc != tokenCrc)
|
|
{
|
|
/* this function is called even when we are not sure the image is
|
|
* a broadcom image. So if crc fails, it is not a big deal. It just
|
|
* means this is not a broadcom image.
|
|
*/
|
|
cmsLog_debug("token crc failed, this is not a valid broadcom image");
|
|
cmsLog_debug("calculated crc=0x%x tokenCrc=0x%x", crc, tokenCrc);
|
|
return CMSRET_INVALID_IMAGE;
|
|
}
|
|
cmsLog_debug("header CRC is OK.");
|
|
|
|
tagVer = atoi((char *) pTag->tagVersion);
|
|
curVer = atoi(BCM_TAG_VER);
|
|
|
|
if (tagVer != curVer)
|
|
{
|
|
cmsLog_error("Firmware tag version [%d] is not compatible with the current Tag version [%d]", tagVer, curVer);
|
|
return CMSRET_INVALID_IMAGE;
|
|
}
|
|
|
|
cmsLog_debug("tarVer=%d, curVar=%d", tagVer, curVer);
|
|
|
|
if (!matchChipId((char *) pTag->chipId, (char *) pTag->signiture_2))
|
|
{
|
|
cmsLog_error("chipid check failed");
|
|
return CMSRET_INVALID_IMAGE;
|
|
}
|
|
|
|
cmsLog_debug("chipid is OK");
|
|
|
|
if (fullImageB == FALSE)
|
|
{
|
|
cmsLog_debug("Good broadcom image header");
|
|
return CMSRET_SUCCESS;
|
|
}
|
|
|
|
// check imageCrc
|
|
totalImageSize = atoi((char *) pTag->totalImageLen);
|
|
cmsLog_debug("totalImageLen=%d, imageLen=%d, TAG_LEN=%d\n", totalImageSize, imageLen, TAG_LEN);
|
|
|
|
if (totalImageSize > (imageLen -TAG_LEN))
|
|
{
|
|
cmsLog_error("invalid size\n");
|
|
return CMSRET_INVALID_IMAGE;
|
|
}
|
|
crc = CRC_INITIAL_VALUE;
|
|
crc = genUtl_getCrc32(((UINT8 *)pTag + TAG_LEN), (UINT32) totalImageSize, crc);
|
|
if (crc != imageCrc)
|
|
{
|
|
/*
|
|
* This should not happen. We already passed the crc check on the header,
|
|
* so we should pass the crc check on the image. If this fails, something
|
|
* is wrong.
|
|
*/
|
|
cmsLog_error("image crc failed after broadcom header crc succeeded");
|
|
cmsLog_error("calculated crc=0x%x imageCrc=0x%x totalImageSize=%d", crc, imageCrc, totalImageSize);
|
|
return CMSRET_INVALID_IMAGE;
|
|
}
|
|
cmsLog_debug("image crc is OK");
|
|
|
|
cmsLog_debug("Good broadcom image");
|
|
|
|
return CMSRET_SUCCESS;
|
|
}
|
|
|
|
|
|
// depending on the image type, do the brcm image or whole flash image
|
|
CmsRet bcmImg_flashImage(char *imagePtr, UINT32 imageLen, CmsImageFormat format, UINT32 opts, int * noReboot)
|
|
{
|
|
FILE_TAG *pTag = (FILE_TAG *) imagePtr;
|
|
int cfeSize, rootfsSize, kernelSize;
|
|
unsigned long cfeAddr, rootfsAddr, kernelAddr;
|
|
UINT32 flags=0;
|
|
CmsRet ret;
|
|
|
|
if( opts & CMS_IMAGE_WR_OPT_PART1 )
|
|
{
|
|
*noReboot = (opts & CMS_IMAGE_WR_OPT_NO_REBOOT) ? FLASH_PART1_NO_REBOOT : FLASH_PART1_REBOOT;
|
|
}
|
|
else if( opts & CMS_IMAGE_WR_OPT_PART2 )
|
|
{
|
|
*noReboot = (opts & CMS_IMAGE_WR_OPT_NO_REBOOT) ? FLASH_PART2_NO_REBOOT : FLASH_PART2_REBOOT;
|
|
}
|
|
else
|
|
{
|
|
*noReboot = (opts & CMS_IMAGE_WR_OPT_NO_REBOOT) ? FLASH_PARTDEFAULT_NO_REBOOT : FLASH_PARTDEFAULT_REBOOT;
|
|
}
|
|
|
|
cmsLog_debug("format=%d noReboot=0x%x", format, *noReboot);
|
|
|
|
if (format != CMS_IMAGE_FORMAT_FLASH && format != CMS_IMAGE_FORMAT_BROADCOM)
|
|
{
|
|
cmsLog_error("invalid image format %d", format);
|
|
return CMSRET_INVALID_IMAGE;
|
|
}
|
|
|
|
if (format == CMS_IMAGE_FORMAT_FLASH)
|
|
{
|
|
cmsLog_notice("Flash whole image...");
|
|
// Pass zero for the base address of whole image flash. It will be filled by kernel code
|
|
// was sysFlashImageSet
|
|
if ((ret = getFlashInfo(&flags)) == CMSRET_SUCCESS)
|
|
{
|
|
if(flags & FLASH_INFO_FLAG_NOR)
|
|
{ // NOR flash device
|
|
ret = devCtl_boardIoctl(BOARD_IOCTL_FLASH_WRITE,
|
|
BCM_IMAGE_WHOLE,
|
|
imagePtr,
|
|
imageLen-TOKEN_LEN,
|
|
*noReboot, 0);
|
|
}
|
|
else
|
|
{ // NAND flash device
|
|
ret = writeImageToNand( (unsigned char *)imagePtr, imageLen - TOKEN_LEN );
|
|
}
|
|
}
|
|
|
|
if (ret != CMSRET_SUCCESS)
|
|
{
|
|
cmsLog_error("Failed to flash whole image");
|
|
return CMSRET_IMAGE_FLASH_FAILED;
|
|
}
|
|
else
|
|
{
|
|
return CMSRET_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* this must be a broadcom format image */
|
|
// check imageCrc
|
|
cfeSize = rootfsSize = kernelSize = 0;
|
|
|
|
// check cfe's existence
|
|
cfeAddr = (unsigned long) strtoul((char *) pTag->cfeAddress, NULL, 10);
|
|
cfeSize = atoi((char *) pTag->cfeLen);
|
|
// check kernel existence
|
|
kernelAddr = (unsigned long) strtoul((char *) pTag->kernelAddress, NULL, 10);
|
|
kernelSize = atoi((char *) pTag->kernelLen);
|
|
// check root filesystem existence
|
|
rootfsAddr = (unsigned long) strtoul((char *) pTag->rootfsAddress, NULL, 10);
|
|
rootfsSize = atoi((char *) pTag->rootfsLen);
|
|
cmsLog_debug("cfeSize=%d kernelSize=%d rootfsSize=%d", cfeSize, kernelSize, rootfsSize);
|
|
|
|
if (cfeAddr)
|
|
{
|
|
printf("Flashing CFE...\n");
|
|
|
|
ret = devCtl_boardIoctl(BOARD_IOCTL_FLASH_WRITE,
|
|
BCM_IMAGE_CFE,
|
|
imagePtr+TAG_LEN,
|
|
cfeSize,
|
|
(int) cfeAddr, 0);
|
|
if (ret != CMSRET_SUCCESS)
|
|
{
|
|
cmsLog_error("Failed to flash CFE");
|
|
return CMSRET_IMAGE_FLASH_FAILED;
|
|
}
|
|
}
|
|
|
|
if (rootfsAddr && kernelAddr)
|
|
{
|
|
char *tagFs = imagePtr;
|
|
|
|
// tag is alway at the sector start of fs
|
|
if (cfeAddr)
|
|
{
|
|
tagFs = imagePtr + cfeSize; // will trash cfe memory, but cfe is already flashed
|
|
memcpy(tagFs, imagePtr, TAG_LEN);
|
|
}
|
|
|
|
printf("Flashing root file system and kernel...\n");
|
|
/* only the buf pointer and length is needed, the offset parameter
|
|
* was present in the legacy code, but is not used. */
|
|
ret = devCtl_boardIoctl(BOARD_IOCTL_FLASH_WRITE,
|
|
BCM_IMAGE_FS,
|
|
tagFs,
|
|
TAG_LEN+rootfsSize+kernelSize,
|
|
*noReboot, 0);
|
|
if (ret != CMSRET_SUCCESS)
|
|
{
|
|
cmsLog_error("Failed to flash root file system and kernel");
|
|
return CMSRET_IMAGE_FLASH_FAILED;
|
|
}
|
|
}
|
|
|
|
cmsLog_notice("Image flash done.");
|
|
|
|
return CMSRET_SUCCESS;
|
|
}
|
|
|
|
|
|
CmsRet get_mtd_device_size(const char * partition, unsigned int * size)
|
|
{
|
|
FILE *fp;
|
|
char sze[MAX_MTD_NAME_SIZE] = {0};
|
|
char line[MAX_MTD_NAME_SIZE*2] = {0};
|
|
char name[MAX_MTD_NAME_SIZE] = {0};
|
|
char compare[MAX_MTD_NAME_SIZE] = {0};
|
|
|
|
if ( (fp = fopen("/proc/mtd","r")) == 0)
|
|
{
|
|
printf("ERROR in %s!!! Could not open /proc/mtd\n", __FUNCTION__);
|
|
|
|
return(CMSRET_OPEN_FILE_ERROR);
|
|
}
|
|
|
|
snprintf(compare, sizeof(compare), "%s%s%s", "\"", partition, "\"");
|
|
|
|
while(fgets(line, sizeof(line), fp))
|
|
{
|
|
sscanf(line, "%*s %s %*s %s", sze, name);
|
|
|
|
if(!strcmp(name, compare))
|
|
{
|
|
fclose(fp);
|
|
|
|
*size = (unsigned int)strtol(sze, NULL, 16);
|
|
|
|
return(CMSRET_SUCCESS);
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
printf("%s: MTD partition/device %s not found/opened\n", __FUNCTION__, partition);
|
|
return(CMSRET_OBJECT_NOT_FOUND);
|
|
}
|
|
|
|
|
|
unsigned int bcmImg_getImageFlashSize(void)
|
|
{
|
|
UINT32 flashSize=0;
|
|
CmsRet ret = CMSRET_OBJECT_NOT_FOUND;
|
|
|
|
if(isLegacyFlashLayout())
|
|
{
|
|
ret = devCtl_boardIoctl(BOARD_IOCTL_FLASH_READ,
|
|
FLASH_SIZE,
|
|
0, 0, 0, &flashSize);
|
|
}
|
|
else
|
|
{
|
|
unsigned int gFlashInfo = 0;
|
|
|
|
getFlashInfo(&gFlashInfo);
|
|
|
|
if (gFlashInfo == FLASH_INFO_FLAG_NAND)
|
|
{
|
|
ret = get_mtd_device_size("image", &flashSize);
|
|
}
|
|
else if (gFlashInfo == FLASH_INFO_FLAG_EMMC)
|
|
{
|
|
#ifndef DESKTOP_LINUX
|
|
flashSize = emmcGetAvailLoaderSpace() + 2 * emmcGetAvailImgSpace(1);
|
|
#else
|
|
flashSize = 0x1000000;
|
|
#endif
|
|
ret = CMSRET_SUCCESS;
|
|
}
|
|
else if (gFlashInfo == FLASH_INFO_FLAG_NOR)
|
|
ret = get_mtd_device_size(SPI_NOR_FLASH_NAME, &flashSize);
|
|
}
|
|
|
|
if (ret != CMSRET_SUCCESS)
|
|
{
|
|
cmsLog_error("Could not get flash size, return 0");
|
|
flashSize = 0;
|
|
}
|
|
|
|
return flashSize;
|
|
}
|
|
|
|
|
|
unsigned int bcmImg_getBroadcomImageTagSize(void)
|
|
{
|
|
return TOKEN_LEN;
|
|
}
|
|
|
|
|
|
unsigned int bcmImg_getConfigFlashSize(void)
|
|
{
|
|
UINT32 realSize;
|
|
|
|
realSize = bcmImg_getRealConfigFlashSize();
|
|
|
|
#ifdef COMPRESSED_CONFIG_FILE
|
|
/*
|
|
* A multiplier of 2 is now too small for some of the big voice and WLAN configs,
|
|
* so allow for the possibility of 4x compression ratio. In a recent test on the
|
|
* 6368 with wireless enabled, I got a compression ratio of 3.5.
|
|
* The real test comes in management.c: after we do the
|
|
* compression, writeValidatedConfigBuf will verify that the compressed buffer can
|
|
* fit into the flash.
|
|
* A 4x multiplier should be OK for small memory systems such as the 6338.
|
|
* The kernel does not allocate physical pages until they are touched.
|
|
* However, allocating an overly large buffer could be rejected immediately by the
|
|
* kernel because it does not know we don't actually plan to use the entire buffer.
|
|
* So if this is a problem on the 6338, we could improve this algorithm to
|
|
* use a smaller factor on low memory systems.
|
|
*/
|
|
realSize = realSize * 4;
|
|
#endif
|
|
|
|
return realSize;
|
|
}
|
|
|
|
|
|
unsigned int bcmImg_getRealConfigFlashSize(void)
|
|
{
|
|
CmsRet ret;
|
|
UINT32 size=0;
|
|
UINT32 flags=0;
|
|
|
|
if ((ret = getFlashInfo(&flags)) == CMSRET_SUCCESS)
|
|
{
|
|
if(flags & FLASH_INFO_FLAG_NOR)
|
|
{
|
|
#ifndef DESKTOP_LINUX
|
|
if( norIsNewFlashLayout())
|
|
size=128*1024;
|
|
else
|
|
#endif
|
|
{
|
|
ret = devCtl_boardIoctl(BOARD_IOCTL_GET_PSI_SIZE, 0, NULL, 0, 0, (void *)&size);
|
|
if (ret != CMSRET_SUCCESS)
|
|
{
|
|
cmsLog_error("boardIoctl to get config flash size failed.");
|
|
size = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If we are using NAND, config file is stored in the /data partition,
|
|
* so config file size is only limited by the size of the /data
|
|
* partition. For now, implement a quick solution and hardcode the
|
|
* NAND config file size to 128KB (so far, nothing has hit this limit).
|
|
* In the future, could improve this solution by:
|
|
* - checking against size of /data partition
|
|
* - if we have 1 copy or 2 (for backup config file).
|
|
* whether we are doing a distributed MDM config (done by BDK)
|
|
* - reserve the space on the FS so there is no chance FS is too
|
|
* full to accept the config file.
|
|
*/
|
|
size=128*1024; // 128KB
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cmsLog_error("could not determine NAND or NOR");
|
|
}
|
|
|
|
cmsLog_debug("returning size=%d", size);
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
unsigned char bcmImg_willFitInFlash(unsigned int imageSize)
|
|
{
|
|
UINT32 flashSize;
|
|
|
|
#ifdef DESKTOP_LINUX
|
|
flashSize = 2 * (imageSize + CMS_IMAGE_OVERHEAD);
|
|
#else
|
|
flashSize = bcmImg_getImageFlashSize();
|
|
|
|
cmsLog_debug("flash size is %u bytes, imageSize=%u bytes", flashSize, imageSize);
|
|
#endif /* DESKTOP_LINUX */
|
|
|
|
return (flashSize > (imageSize + CMS_IMAGE_OVERHEAD));
|
|
}
|
|
|
|
|
|
unsigned char bcmImg_isBackupConfigFlashAvailable(void)
|
|
{
|
|
static UBOOL8 firstTime=TRUE;
|
|
static UBOOL8 avail=FALSE;
|
|
CmsRet ret;
|
|
|
|
if (firstTime)
|
|
{
|
|
UINT32 size=0;
|
|
UINT32 flags=0;
|
|
|
|
if ((ret = getFlashInfo(&flags)) == CMSRET_SUCCESS)
|
|
{
|
|
if(flags & FLASH_INFO_FLAG_NOR)
|
|
{
|
|
#ifndef DESKTOP_LINUX
|
|
if( norIsNewFlashLayout() )
|
|
avail = TRUE;
|
|
else
|
|
#endif
|
|
{
|
|
ret = devCtl_boardIoctl(BOARD_IOCTL_GET_BACKUP_PSI_SIZE, 0, NULL,
|
|
0, 0, (void *)&size);
|
|
if (ret == CMSRET_SUCCESS)
|
|
{
|
|
avail = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Backup PSI file is always available in NAND
|
|
avail = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cmsLog_error("could not determine NAND or NOR");
|
|
}
|
|
|
|
firstTime = FALSE;
|
|
}
|
|
|
|
return avail;
|
|
}
|
|
|
|
|
|
unsigned char bcmImg_isConfigFileLikely(const char *buf)
|
|
{
|
|
const char *header = "<?xml version";
|
|
const char *dslCpeConfig = "<DslCpeConfig";
|
|
UINT32 len, i;
|
|
UBOOL8 likely=FALSE;
|
|
|
|
if (strncmp(buf, "<?xml version", strlen(header)) == 0)
|
|
{
|
|
len = strlen(dslCpeConfig);
|
|
for (i=20; i<50 && !likely; i++)
|
|
{
|
|
if (strncmp(&(buf[i]), dslCpeConfig, len) == 0)
|
|
{
|
|
likely = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
cmsLog_debug("returning likely=%d", likely);
|
|
|
|
return likely;
|
|
}
|
|
|
|
|
|
void bcmImg_reboot(void)
|
|
{
|
|
devCtl_boardIoctl(BOARD_IOCTL_MIPS_SOFT_RESET, 0, NULL, 0, 0, 0);
|
|
}
|
|
|
|
|
|
imgutil_ret_e bcmImg_getImageVersion(char *imagePtr, int imageLen, char *imageName, int imageNameLen)
|
|
{
|
|
int ret;
|
|
|
|
ret = getImageVersion((uint8_t*)imagePtr, imageLen, imageName, imageNameLen);
|
|
if (ret != 0)
|
|
{
|
|
return IMGUTIL_PROC_INVALID_IMG;
|
|
}
|
|
|
|
return IMGUTIL_PROC_OK;
|
|
}
|
|
|
|
|
|
CmsImageFormat bcmImg_validateImage(const char *imageBuf, UINT32 imageLen)
|
|
{
|
|
CmsImageFormat result = CMS_IMAGE_FORMAT_INVALID;
|
|
|
|
if (imageBuf == NULL)
|
|
{
|
|
cmsLog_error("FORMAT_INVALID");
|
|
return CMS_IMAGE_FORMAT_INVALID;
|
|
}
|
|
|
|
if ((imageLen > sizeof(struct fdt_header)) && (fdt_check_header(imageBuf) == 0))
|
|
{
|
|
/* Found a valid Broadcom defined TAG record at the beginning of the image */
|
|
cmsLog_debug("Broadcom pktb format verified.");
|
|
|
|
//FIXME: Cannot detemine total size of image at this point since we may not
|
|
//have the entire dtb in memory. Will do that later
|
|
result = CMS_IMAGE_FORMAT_BROADCOM;
|
|
}
|
|
else if ((imageLen > sizeof(FILE_TAG)) && (bcmImg_verifyBroadcomFileTag((FILE_TAG *) imageBuf, 1, imageLen) == CMSRET_SUCCESS))
|
|
{
|
|
UINT32 maxLen;
|
|
|
|
/* Found a valid Broadcom defined TAG record at the beginning of the image */
|
|
cmsLog_debug("Broadcom format verified.");
|
|
maxLen = bcmImg_getImageFlashSize() + bcmImg_getBroadcomImageTagSize();
|
|
if (imageLen > maxLen)
|
|
{
|
|
cmsLog_error("broadcom image is too large for flash, got %u, max %u", imageLen, maxLen);
|
|
}
|
|
else
|
|
{
|
|
result = CMS_IMAGE_FORMAT_BROADCOM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* if It is not a Broadcom flash format file. Now check if it is a
|
|
* flash image format file. A flash image format file must have a
|
|
* CRC at the end of the image.
|
|
*/
|
|
UINT32 crc = CRC_INITIAL_VALUE;
|
|
UINT32 imageCrc;
|
|
UINT8 *crcPtr;
|
|
|
|
if (imageLen > TOKEN_LEN)
|
|
{
|
|
crcPtr = (UINT8 *) (imageBuf + (imageLen - TOKEN_LEN));
|
|
/*
|
|
* CRC may not be word aligned, so extract the bytes out one-by-one.
|
|
* Whole image CRC is calculated, then htonl, then written out using
|
|
* fwrite (see addvtoken.c in hostTools). Because of the way we are
|
|
* extracting the CRC here, we don't have to swap for endieness when
|
|
* doing compares on desktop Linux and modem (?).
|
|
*/
|
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
imageCrc = crcPtr[0] | (crcPtr[1] << 8) | (crcPtr[2] << 16) | (crcPtr[3] << 24);
|
|
#else
|
|
imageCrc = (crcPtr[0] << 24) | (crcPtr[1] << 16) | (crcPtr[2] << 8) | crcPtr[3];
|
|
#endif
|
|
|
|
crc = genUtl_getCrc32((unsigned char *) imageBuf, imageLen - TOKEN_LEN, crc);
|
|
#ifndef DESKTOP_LINUX
|
|
if (crc == imageCrc)
|
|
#else
|
|
if ((crc == imageCrc) || crc == htonl(imageCrc))
|
|
#endif
|
|
{
|
|
UINT32 maxLen;
|
|
|
|
cmsLog_debug("Whole flash image format [%d bytes] verified.", imageLen);
|
|
maxLen = bcmImg_getImageFlashSize();
|
|
if (imageLen > maxLen)
|
|
{
|
|
cmsLog_error("whole image is too large for flash, got %u, max %u", imageLen, maxLen);
|
|
}
|
|
else
|
|
{
|
|
result = CMS_IMAGE_FORMAT_FLASH;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if defined(EPON_SDK_BUILD)
|
|
cmsLog_debug("Could not determine image format [%d bytes]", imageLen);
|
|
#else
|
|
cmsLog_error("Could not determine image format [%d bytes]", imageLen);
|
|
#endif
|
|
cmsLog_debug("calculated crc=0x%x image crc=0x%x", crc, imageCrc);
|
|
}
|
|
}
|
|
}
|
|
|
|
cmsLog_debug("returning image format %d", result);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
UBOOL8 bcmImg_isBcmTaggedImage(const char *imageBuf, UINT32 *imageSize)
|
|
{
|
|
FILE_TAG *pTag = (FILE_TAG *)imageBuf;
|
|
UINT32 crc;
|
|
UINT32 tokenCrc, *pTokenCrc;
|
|
UBOOL8 isBcmImg = FALSE;
|
|
|
|
pTokenCrc = (UINT32 *)pTag->tagValidationToken;
|
|
tokenCrc = *pTokenCrc;
|
|
#ifdef DESKTOP_LINUX
|
|
/* assume desktop is running on little endien intel, but the CRC has been
|
|
* written for big endien mips, so swap before compare.
|
|
* FIXME! this part of code might not work with Little-endian target system.
|
|
*/
|
|
tokenCrc = htonl(tokenCrc);
|
|
#endif
|
|
|
|
/* check tag validate token to see if it is a valid bcmTag */
|
|
crc = CRC_INITIAL_VALUE;
|
|
crc = genUtl_getCrc32((UINT8 *) pTag, (UINT32)TAG_LEN-TOKEN_LEN, crc);
|
|
if (crc == tokenCrc)
|
|
{
|
|
isBcmImg = TRUE;
|
|
*imageSize = (UINT32) atoi((char *)pTag->totalImageLen) + TAG_LEN;
|
|
cmsLog_debug("It's a broadcom tagged image with length %d", *imageSize );
|
|
}
|
|
else
|
|
{
|
|
cmsLog_debug("token crc failed, this is not a valid broadcom image");
|
|
}
|
|
|
|
return isBcmImg;
|
|
|
|
}
|
|
|
|
CmsImageFormat bcmImg_parseImgHdr(UINT8 *bufP, UINT32 bufLen)
|
|
{
|
|
CmsImageFormat result = CMS_IMAGE_FORMAT_INVALID;
|
|
|
|
if (bufP == NULL)
|
|
{
|
|
cmsLog_debug("NULL bufP pointer.");
|
|
result = CMS_IMAGE_FORMAT_INVALID;
|
|
}
|
|
else if ((bufLen > CMS_CONFIG_FILE_DETECTION_LENGTH) &&
|
|
bcmImg_isConfigFileLikely((char*)bufP))
|
|
{
|
|
cmsLog_debug("Detected possible CMS XML config file format");
|
|
result = CMS_IMAGE_FORMAT_XML_CFG;
|
|
}
|
|
#ifdef SUPPORT_MODSW_LINUXPFP
|
|
else if (cmsImg_isModSwLinuxPfp((UINT8*)bufP, bufLen))
|
|
{
|
|
cmsLog_debug("Detected Modular Software Linux PFP format.");
|
|
result = CMS_IMAGE_FORMAT_MODSW_LINUXPFP;
|
|
}
|
|
#endif
|
|
else if ((bufLen > sizeof(FILE_TAG)) &&
|
|
(bcmImg_verifyBroadcomFileTag((FILE_TAG*)bufP, 0, bufLen) == CMSRET_SUCCESS))
|
|
{
|
|
cmsLog_debug("Detected Broadcom image format.");
|
|
result = CMS_IMAGE_FORMAT_BROADCOM;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void dumpBcmFileTag(FILE_TAG *tagP)
|
|
{
|
|
printf("--------------------------------------------------------------\n");
|
|
printf("Broadcom image tag:\n");
|
|
printf("\ttagVersion: %02x %02x %02x %02x\n",
|
|
tagP->tagVersion[0], tagP->tagVersion[1],
|
|
tagP->tagVersion[2], tagP->tagVersion[3]);
|
|
printf("\tendian: %s\n", tagP->bigEndian);
|
|
printf("\ttotalImageLen: %s\n", tagP->totalImageLen);
|
|
printf("\tcfeAddress: %s\n", tagP->cfeAddress);
|
|
printf("\tcfeLen: %s\n", tagP->cfeLen);
|
|
printf("\trootfsAddress: %s\n", tagP->rootfsAddress);
|
|
printf("\trootfsLen: %s\n", tagP->rootfsLen);
|
|
printf("\tkernelAddress: %s\n", tagP->kernelAddress);
|
|
printf("\tkernelLen: %s\n", tagP->kernelLen);
|
|
printf("\timageSequence: %s\n", tagP->imageSequence);
|
|
printf("\timageVersion: %s\n", tagP->imageVersion);
|
|
printf("--------------------------------------------------------------\n");
|
|
}
|
|
|
|
/*
|
|
* IMGUTIL_TODO: the following logic is replicated in a few places.
|
|
* To consolidate.
|
|
* ./private/apps/tr69c/main/informer.c: allocSize -= 64 * 1024;
|
|
* ./gpl/apps/ftpd/ftpd/commands.c: totalAllocatedSize -= 64 * 1024;
|
|
*/
|
|
|
|
/*
|
|
* If maxBufSize is initialized, try that (with allocSize = maxBufSize)
|
|
* and if still failing, try reducing 64K from allocSize and try again as
|
|
* long as allocSize > CMS_IMAGE_REQUIRED_LEN.
|
|
*/
|
|
UINT8* bcmImg_allocImgBuf(UINT32 maxBufSize, UINT32 *allocBufSizeP)
|
|
{
|
|
UINT32 allocSize;
|
|
UINT8 *bufP = NULL;
|
|
|
|
if (maxBufSize > 0)
|
|
{
|
|
allocSize = maxBufSize;
|
|
}
|
|
else
|
|
{
|
|
allocSize = bcmImg_getImageFlashSize() +
|
|
bcmImg_getBroadcomImageTagSize();
|
|
}
|
|
|
|
cmsLog_debug("bcmImg_allocImgBuf() begin, %d", allocSize);
|
|
|
|
if ((bufP = (UINT8*)malloc(allocSize)) == NULL)
|
|
{
|
|
/* TODO: this logic in commands.c does not seem to be correct. */
|
|
/* if (maxBufSize > 0) */
|
|
{
|
|
while (((bufP = (UINT8*)malloc(allocSize)) == NULL) &&
|
|
(allocSize > CMS_IMAGE_REQUIRED_LEN))
|
|
{
|
|
allocSize -= 64 * 1024;
|
|
cmsLog_debug("Try allocating %d kb", allocSize/1024);
|
|
}
|
|
}
|
|
|
|
if (bufP == NULL)
|
|
{
|
|
cmsLog_error("Not enough memory to alloc %u bytes.", allocSize);
|
|
*allocBufSizeP = 0;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
cmsLog_debug("bcmImg_allocImgBuf() end, %d", allocSize);
|
|
|
|
*allocBufSizeP = allocSize;
|
|
return bufP;
|
|
}
|