blob: cb0c9761ff51bb13f3dca460e384da299128ee89 [file] [log] [blame]
#include "tim.h"
#define DTIM_MAX_SIZE (128 * 1024)
#if 0
static const char *id2str(unsigned int id)
{
switch (id) {
case IMAGE_ID_ARBEL:
return "ARBEL";
case IMAGE_ID_DTIM_A:
return "DTIM_A";
case IMAGE_ID_DTIM_B:
return "DTIM_B";
case IMAGE_ID_KERNEL:
return "KERNEL";
case IMAGE_ID_MSA:
return "MSA";
case IMAGE_ID_OEMD:
return "OEMD";
case IMAGE_ID_RF:
return "RF";
case IMAGE_ID_ROOTFS:
return "ROOTFS";
case IMAGE_ID_UBOOT:
return "UBOOT";
default:
OTA_ERR("Unkown id: 0x%x\n", id);
return "NULL";
}
}
#endif
static int SetTIMPointers( void *pStartAddr, TIM *pTIM_h)
{
pTIM_h->pConsTIM = (pCTIM) pStartAddr; // Overlap Contant Part of TIM with actual TIM...
if ((pTIM_h->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER) ||
(pTIM_h->pConsTIM->VersionBind.Version < TIM_3_2_00)) {
/* incorrect tim */
pTIM_h->pConsTIM = NULL;
return -1;
}
// Assign a pointer to start of Images Area
pTIM_h->pImg = (pIMAGE_INFO_3_4_0) (pStartAddr + sizeof (CTIM));
// Assign a pointer to start of Key Area
if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_4_00)
pTIM_h->pKey = (pKEY_MOD_3_4_0) ((UINT_T)pTIM_h->pImg + ((pTIM_h->pConsTIM->NumImages) * sizeof (IMAGE_INFO_3_4_0)));
else
pTIM_h->pKey = (pKEY_MOD_3_4_0) ((UINT_T)pTIM_h->pImg + ((pTIM_h->pConsTIM->NumImages) * sizeof (IMAGE_INFO_3_2_0)));
// Assign a pointer to start of reserved area
if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_4_00)
pTIM_h->pReserved = (PUINT) ((UINT_T)pTIM_h->pKey + ((pTIM_h->pConsTIM->NumKeys) * sizeof (KEY_MOD_3_4_0)));
else if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_3_00)
pTIM_h->pReserved = (PUINT) ((UINT_T)pTIM_h->pKey + ((pTIM_h->pConsTIM->NumKeys) * sizeof (KEY_MOD_3_3_0)));
else
pTIM_h->pReserved = (PUINT) ((UINT_T)pTIM_h->pKey + ((pTIM_h->pConsTIM->NumKeys) * sizeof (KEY_MOD_3_2_0)));
// Assign a pointer to start of DS
pTIM_h->pTBTIM_DS = (pPLAT_DS) ((UINT_T)pTIM_h->pReserved + pTIM_h->pConsTIM->SizeOfReserved);
return (NoError);
}
#if 0
static void dump_dtim(pTIM t)
{
int i;
pIMAGE_INFO_3_4_0 pImg;
OTA_DEBUG("### Image in dtim ###\n");
OTA_DEBUG("Images number: %d\n", t->pConsTIM->NumImages);
for (i = 0; i < t->pConsTIM->NumImages; i++) {
pImg = (pIMAGE_INFO_3_4_0)(t->pImg + i);
OTA_DEBUG("[%d] ID: %s, NextID: %s, Offset: 0x%x, "
"LoadAddr: 0x%x, Size: %d, SizeToHash: %d, HashAlgorithmID: 0x%x\n", i,
id2str(pImg->ImageID), id2str(pImg->NextImageID), pImg->FlashEntryAddr,
pImg->LoadAddr, pImg->ImageSize, pImg->ImageSizeToHash,
pImg->HashAlgorithmID);
OTA_DEBUG("[%d] Hash: 0x%x, 0x%x, 0x%x, 0x%x, "
"0x%x, 0x%x, 0x%x, 0x%x, "
"0x%x, 0x%x, 0x%x, 0x%x, "
"0x%x, 0x%x, 0x%x, 0x%x\n", i,
pImg->Hash[0], pImg->Hash[1], pImg->Hash[2], pImg->Hash[3],
pImg->Hash[4], pImg->Hash[5], pImg->Hash[6], pImg->Hash[7],
pImg->Hash[8], pImg->Hash[9], pImg->Hash[10], pImg->Hash[11],
pImg->Hash[12], pImg->Hash[13], pImg->Hash[14], pImg->Hash[15]);
}
}
static void *load_dtim(const char *dev)
{
int fd = -1;
char _dev[32] = {0};
char *buf = malloc(DTIM_MAX_SIZE);
if (!buf) {
OTA_ERR("failed to malloc 0x%x for dtim.\n", DTIM_MAX_SIZE);
goto out;
}
sprintf(_dev, "/dev/%s", dev);
fd = open(_dev, O_RDWR | O_SYNC);
if (fd < 0) {
OTA_ERR("failed to open %s.\n", _dev);
free(buf);
buf = NULL;
goto out;
}
if (complete_read(fd, buf, DTIM_MAX_SIZE) < 0) {
OTA_ERR("failed to load %s.\n", _dev);
free(buf);
buf = NULL;
goto out;
}
out:
if (fd >= 0)
close(fd);
return buf;
}
static int __save_dtim(int fd, pTIM pTIM_h)
{
int r = -1;
struct erase_info_user mtdEraseInfo;
struct mtd_info_user mtdInfo;
if (ioctl(fd, MEMGETINFO, &mtdInfo)) {
OTA_ERR("could not get MTD device info.\n");
goto out;
}
mtdEraseInfo.start = 0;
mtdEraseInfo.length = mtdInfo.erasesize;
ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
ioctl(fd, MEMERASE, &mtdEraseInfo);
if (complete_write(fd, (char *)pTIM_h->pConsTIM, DTIM_MAX_SIZE) < 0)
goto out;
r = 0;
out:
return r;
}
static int save_dtim(const char *dev, pTIM pTIM_h)
{
int fd = -1;
int r = -1;
char _dev[32] = {0};
sprintf(_dev, "/dev/%s", dev);
fd = open(_dev, O_RDWR | O_SYNC);
if (fd < 0) {
OTA_ERR("failed to open %s.\n", _dev);
goto out;
}
r = __save_dtim(fd, pTIM_h);
if (r)
OTA_ERR("failed to save dtim to %s.\n", _dev);
out:
if (fd >= 0)
close(fd);
return r;
}
/* sync the new to old */
static int __sync_dtim(pTIM pNew, pTIM pOld)
{
int r = -1, i, j, found = 0, images;
int flag = 0;
pIMAGE_INFO_3_4_0 pImgSrc, pImgDst;
OTA_DEBUG("%s: new dtim mode: %d, old dtim mode: %d.\n", __func__,
pNew->pConsTIM->VersionBind.Trusted, pOld->pConsTIM->VersionBind.Trusted);
if (pNew->pConsTIM->VersionBind.Trusted != pOld->pConsTIM->VersionBind.Trusted) {
OTA_ERR("%s: Fatal Error. Can't sync two different trust mode dtim.\n", __func__);
return -1;
}
for (i = 0; i < pNew->pConsTIM->NumImages; i++) {
pImgSrc = (pIMAGE_INFO_3_4_0)(pNew->pImg + i);
for (j = 0; j < pOld->pConsTIM->NumImages; j++) {
pImgDst = (pIMAGE_INFO_3_4_0)(pOld->pImg + j);
if (pImgSrc->ImageID == pImgDst->ImageID &&
pImgSrc->ImageID != IMAGE_ID_DTIM_A &&
pImgSrc->ImageID != IMAGE_ID_DTIM_B) {
found++;
if (pImgSrc->ImageSize != pImgDst->ImageSize ||
pImgSrc->ImageSizeToHash != pImgDst->ImageSizeToHash ||
pImgSrc->LoadAddr != pImgDst->LoadAddr ||
pImgSrc->HashAlgorithmID != pImgDst->HashAlgorithmID ||
memcmp(pImgSrc->Hash, pImgDst->Hash, sizeof(pImgSrc->Hash)) != 0)
{
OTA_DEBUG("Image: %s has been changed.\n", id2str(pImgSrc->ImageID));
pImgDst->ImageID = pImgSrc->ImageID;
pImgDst->ImageSize = pImgSrc->ImageSize;
pImgDst->ImageSizeToHash = pImgSrc->ImageSizeToHash;
pImgDst->LoadAddr = pImgSrc->LoadAddr;
pImgDst->HashAlgorithmID = pImgSrc->HashAlgorithmID;
memcpy(pImgDst->Hash, pImgSrc->Hash, sizeof(pImgSrc->Hash));
flag = 1;
break;
}
}
}
}
images = pNew->pConsTIM->NumImages - 1;
/* omit the first image(dtim it self) */
if (found != images) {
OTA_ERR("FATAL ERROR: NumImage: %d, found: %d, not exactly match.\n"
, pNew->pConsTIM->NumImages, found);
goto out;
}
r = flag;
out:
return r;
}
static int update_dtim(const char *dev, void *bufNew)
{
int r = -1;
TIM tNew, tOld;
char *buf = load_dtim(dev);
if (!buf) {
OTA_ERR("%s: failed to load dtim for %s.\n", __func__, dev);
goto out;
}
SetTIMPointers(buf, &tOld);
SetTIMPointers(bufNew, &tNew);
OTA_DEBUG("### Dump orignal dtim of %s. ###\n", dev);
dump_dtim(&tOld);
OTA_DEBUG("### Dump the new dtim. ###\n");
dump_dtim(&tNew);
r = __sync_dtim(&tNew, &tOld);
if (r < 0)
goto out;
if (r > 0) {
OTA_DEBUG("Images have been changed, update %s\n", dev);
r = save_dtim(dev, &tOld);
} else {
OTA_DEBUG("Images have NO change, DO NOT need to sync.\n");
r = 0;
}
OTA_DEBUG("%s: %s.\n", __func__, (r >= 0) ? "OK" : "FAILED");
out:
if (buf)
free(buf);
return r;
}
static int sync_dtim(const char *src, const char *dst)
{
int r = -1;//, i, j, found = 0;
// int flag = 0;
// pIMAGE_INFO_3_4_0 pImgSrc, pImgDst;
TIM tSrc;
TIM tDst;
char *bufSrc = load_dtim(src);
char *bufDst = load_dtim(dst);
OTA_DEBUG("Start to sync %s to %s.\n", src, dst);
if (!bufSrc || !bufDst) {
OTA_ERR("failed to sync %s to %s.\n", src, dst);
goto out;
}
SetTIMPointers(bufSrc, &tSrc);
SetTIMPointers(bufDst, &tDst);
OTA_DEBUG("Dump dtim info of %s.\n", src);
dump_dtim(&tSrc);
OTA_DEBUG("Dump dtim info of %s.\n", dst);
dump_dtim(&tDst);
if (tSrc.pConsTIM->NumImages != tDst.pConsTIM->NumImages) {
OTA_ERR("FATAL ERROR: NumImages(%s): %d, NumImages(%s): %d.\n",
src, tSrc.pConsTIM->NumImages, dst, tDst.pConsTIM->NumImages);
goto out;
}
r = __sync_dtim(&tSrc, &tDst);
if (r < 0)
goto out;
if (r > 0) {
OTA_DEBUG("Images have been changed, need to sync %s to %s.\n", src, dst);
r = save_dtim(dst, &tDst);
} else {
OTA_DEBUG("Images have NO change, DO NOT need to sync.\n");
r = 0;
}
out:
if (bufSrc)
free(bufSrc);
if (bufDst)
free(bufDst);
return r;
}
/* dev is the mtd device of dtim */
static int get_image_mode(const char *dev)
{
char *buf = load_dtim(dev);
TIM tim;
int mode;
if (!buf) {
OTA_ERR("%s: failed to load dtim for %s.\n", __func__, dev);
return -1;
}
SetTIMPointers(buf, &tim);
mode = tim.pConsTIM->VersionBind.Trusted;
OTA_DEBUG("%s: it is %s mode(%s).\n", __func__, (mode == 1) ? "Trusted" : "NON-Trusted", dev);
free(buf);
return mode;
}
#endif
static UINT_T CheckReserved (pTIM pTIM_h)
{
pWTP_RESERVED_AREA pWRA = (pWTP_RESERVED_AREA) pTIM_h->pReserved;
// Make sure that the TIM has a credible size
if(pTIM_h->pConsTIM->SizeOfReserved == 0)
return NotFoundError;
// Older TIM's had old reserved fields definition
if (pTIM_h->pConsTIM->VersionBind.Version == (0x00030101))
return NotFoundError;
// Was this area in reserved field created by a WTP compliant tool so we can parse?
if (pWRA->WTPTP_Reserved_Area_ID != WTPRESERVEDAREAID)
return NotFoundError;
return NoError;
}
// Finds a Package of WTP recognized information in the reserved area based on identifier
static pWTP_RESERVED_AREA_HEADER FindPackageInReserved (UINT_T * Retval, pTIM pTIM_h, UINT_T Identifier)
{
UINT_T Count = 0;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
pWTP_RESERVED_AREA pWRA = (pWTP_RESERVED_AREA) pTIM_h->pReserved;
*Retval = CheckReserved(pTIM_h);
if (*Retval != NoError)
return NULL;
// Start from the begining
pWRAH = (pWTP_RESERVED_AREA_HEADER) (pWRA + 1);
while ((pWRAH->Identifier != Identifier) && (pWRAH->Identifier != TERMINATORID) && (Count < pWRA->NumReservedPackages))
{
pWRAH = (pWTP_RESERVED_AREA_HEADER)((UINT_T)pWRAH + ((pWRAH->Size + 3) & ~3)); // Skip to the next one
Count++;
}
if (pWRAH->Identifier != Identifier)
{
*Retval = NotFoundError;
pWRAH = NULL;
}
return pWRAH;
}
// This function has been added to support to isolate backwards compatibility to tim.c
// It will return a point to pIMAGE_INFO based on TIM version.
static pIMAGE_INFO_3_4_0 ReturnPImgPtr(pTIM pTIM_h, UINT_T ImageNumber)
{
pIMAGE_INFO_3_4_0 pIMG;
pIMG = (pIMAGE_INFO_3_4_0) &pTIM_h->pImg[ImageNumber];
return pIMG;
}
// This function is used to find an image information field in the TIM
// of the image with the ID passed in
static pIMAGE_INFO_3_4_0 FindImageInTIM(pTIM pTIM_h, UINT_T ImageID)
{
pIMAGE_INFO_3_4_0 pImageInfo = NULL;
UINT8_T i;
if (pTIM_h)
{
for( i = 0; i < pTIM_h->pConsTIM->NumImages; i++)
{
pImageInfo = ReturnPImgPtr(pTIM_h, i);
if(pImageInfo->ImageID == ImageID)
return pImageInfo;
}
}
return NULL;
}
static int __retrive_timh_by_ddrid(pTIM pTIM_h, unsigned int *DDR_ID, int *imagesize)
{
int i, DDRTimIndex = -1;
UINT_T /*LoadAddr, TimSize, */TimLoadAddr, Retval;
pIMAGE_INFO_3_4_0 pTimInfo = NULL;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
pDDR_FLASH_MCP_PACKAGE pMCP = NULL;
#if 0
if (DDR_ID == 0xFFFFFFFF || DDR_ID == 0) {
OTA_ERR("Warning: no valid DDR ID in ASR Flag\n");
return NoError;
}
#endif
TimLoadAddr = (UINT_T)pTIM_h->pConsTIM;
pWRAH = FindPackageInReserved(&Retval, pTIM_h, DDR_FLASH_MCP_PACKAGE_ID);
if(pWRAH == NULL) {
OTA_ERR("No DFMP found, single DDR TIM\n\r");
return NoError;
} else {
pMCP = (DDR_FLASH_MCP_PACKAGE *) pWRAH;
for (i = 0; i < pMCP->NumberVendorDdrFlashSpec; i++) {
if(pMCP->ddrFlashSpec[i].VendorDdrPid == *DDR_ID) {
DDRTimIndex = i;
OTA_DEBUG("%s: [%d] got ddr id: 0x%x\n", __func__, i, *DDR_ID);
break;
}
}
pTimInfo = FindImageInTIM(pTIM_h, IMAGE_ID_TIMH);
if(pTimInfo == NULL) {
OTA_ERR("%s %d: No TIMH found, error\n", __func__, __LINE__);
return TIMNotFound;
}
if (DDRTimIndex < 0) {
OTA_ERR("NOT found ddr id: 0x%x, use the first TIM ddrid: 0x%x",
*DDR_ID, pMCP->ddrFlashSpec[0].VendorDdrPid);
*DDR_ID = pMCP->ddrFlashSpec[0].VendorDdrPid;
goto out;
}
/* go through all the TIMs to the right one */
for (i = 0; i < (DDRTimIndex + 1); i++) {
Retval = SetTIMPointers((void *)TimLoadAddr, pTIM_h);
if(Retval) {
OTA_ERR("%s %d: failed\n", __func__, __LINE__);
return TIMNotFound;
}
pTimInfo = FindImageInTIM(pTIM_h, IMAGE_ID_TIMH);
if(pTimInfo == NULL) {
OTA_ERR("%s %d: No TIMH found, error\n", __func__, __LINE__);
return TIMNotFound;
}
TimLoadAddr += pTimInfo->ImageSize;
}
}
out:
*imagesize = pTimInfo->ImageSize;
OTA_DEBUG("%s: index: %d, size: 0x%x\n", __func__, DDRTimIndex, pTimInfo->ImageSize);
return NoError;
}