blob: 755a187aed95bffc9801904337782e1d332332dd [file] [log] [blame]
/******************************************************************************
*
* (C)Copyright 2005 - 2011 Marvell. All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
* The copyright notice above does not evidence any actual or intended
* publication of such source code.
* This Module contains Proprietary Information of Marvell and should be
* treated as Confidential.
* The information in this file is provided for the exclusive use of the
* licensees of Marvell.
* Such users have the right to use, modify, and incorporate this code into
* products for purposes authorized by the license agreement provided they
* include this notice and the associated copyright notice with any such
* product.
* The information in this file is provided "AS IS" without warranty.
******************************************************************************/
#include "tim.h"
#include "Typedef.h"
#include "Flash.h"
#include "Errors.h"
#include "usb_descriptors.h"
#include "PlatformConfig.h"
#include "ProtocolManager.h"
#include "loadoffsets.h" //For platform dependent FLASH_STREAM_SIZE definition
#include "obm2osl.h"
#include "fota.h"
#include "FM.h"
// Single copy must reside
extern OBM2OSL *pOBM2OSL_h;
#if !BOOTROM
/* Single copy of the Tim
* Currently only used by the Bootloader. Future versions of Bootrom
* can use this pointer.
*/
static TIM sTim;
pTIM GetTimPointer()
{
return &sTim;
}
#endif
INT_T SetTIMPointers( UINT8_T *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);
}
UINT_T LoadTim(UINT8_T *pTIMArea, TIM *pTIM_h, UINT_T SRAMLoad )
{
UINT_T Retval = NoError;
UINT_T TimSize = 0, i = 0;
P_FlashProperties_T pFlashProp;
UINT_T imageInfoSize,TimFlashAddress;
pIMAGE_INFO_3_4_0 pImage;
UINT8_T *pTempTIMArea = NULL;
if( SRAMLoad == TRUE)
{
// if no Flash properties were passed in then this was from a download and the TIM is in ISRAM
// just set the pointers correctly
SetTIMPointers(pTIMArea, pTIM_h);
if( pTIM_h->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER )
Retval = TIMNotFound;
return Retval;
}
pTempTIMArea = malloc(512);
if(pTempTIMArea == NULL)
return HeapExhaustedError;
//clear out the first 512 bytes of TIM area, to delete any stale data
memset(pTempTIMArea, 0, 512);
// Determine default TIM address
pFlashProp = GetFlashProperties(BOOT_FLASH);
//read up to (including) the first Image_Info field of the TIM
//then read the rest of the TIM based on the info read
// - for XIP, this will let us know whether we can just leave the TIM in flash
// - for NAND, this will keep us from reading unwritten pages
TimSize = sizeof(VERSION_I) + sizeof(FLASH_I) + 12 + sizeof(IMAGE_INFO_3_4_0);
//Note: For NAND and ONENAND, we need to read up to the first 10 blocks, incase
// block 0 got erased. The backup boot block must be in the first good block
for(i = 0; i < 10; i++)
{
TimFlashAddress = pFlashProp->TimFlashAddress + i*GetBlockSize(BOOT_FLASH);
//catch error, but we don't need to 'break' on the error. this will be caught after loop
Retval = ReadFlash(TimFlashAddress, (UINT_T)pTempTIMArea, TimSize, BOOT_FLASH);
//don't need to catch error return, since SetTIMPointers doesn't have error code
SetTIMPointers(pTempTIMArea, pTIM_h);
//if we found a TIM, break out of loop
if( pTIM_h->pConsTIM->VersionBind.Identifier == TIMIDENTIFIER )
{ //remember where we found the TIM, so we know which block is the backup boot block
pFlashProp->TimFlashAddress = TimFlashAddress;
break;
}
//if we are reading any device BUT NAND or ONENAND, break after first iteration
if( (pFlashProp->FlashType != ONENAND_FLASH) && (pFlashProp->FlashType != NAND_FLASH) && (pFlashProp->FlashType != SDMMC_FLASH) )
break;
}
//now return if we had an error or did not find a TIM or if TIM version is earlier than 3_2_00
if ( (Retval != NoError) ||
(pTIM_h->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER) ||
(pTIM_h->pConsTIM->VersionBind.Version < TIM_3_2_00) ){
free(pTempTIMArea);
return TIMNotFound;
}
//at this point, we have read part of a TIM... read the rest
pImage = FindImageInTIM(pTIM_h, TIMIDENTIFIER);
if (pImage != NULL)
TimSize = pImage->ImageSize; //less than 4K/8K
else{
free(pTempTIMArea);
return TIMNotFound;
}
free(pTempTIMArea);
// Read in the rest of the TIM
Retval = ReadFlash(pFlashProp->TimFlashAddress, (UINT_T) pTIMArea, TimSize, BOOT_FLASH);
if (Retval != NoError)
return Retval;
Retval = SetTIMPointers(pTIMArea, pTIM_h);
if( pTIM_h->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER )
return TIMNotFound;
return Retval;
}
static UINT_T TIM_ReservedAddr = 0;
VOID TIM_ReservedMemInit(UINT32 Buffer)
{
if(Buffer == 0)
return HeapExhaustedError;
TIM_ReservedAddr = Buffer;
return;
}
UINT_T getDTIMLoadAddress(UINT_T DTIMID)
{
UINT_T tempLoadAddress = 0xFFFFFFFF;
switch (DTIMID & 0x000000ff)
{
case 0x31:
pOBM2OSL_h->primary.tim_version = 0;
pOBM2OSL_h->primary.tim_ddr_address = tempLoadAddress;
tempLoadAddress = TIM_ReservedAddr;
break;
case 0x32:
pOBM2OSL_h->recovery.tim_version = 0;
pOBM2OSL_h->recovery.tim_ddr_address = tempLoadAddress;
tempLoadAddress = TIM_ReservedAddr + 0x2000;
break;
case 0x33:
pOBM2OSL_h->cp.tim_version = 0;
pOBM2OSL_h->cp.tim_ddr_address = tempLoadAddress;
tempLoadAddress = TIM_ReservedAddr + 0x4000;
break;
case 0x34:
tempLoadAddress = TIM_ReservedAddr + 0x6000;
break;
case 0x35:
tempLoadAddress = TIM_ReservedAddr + 0x8000;
break;
default:
tempLoadAddress = TIM_ReservedAddr + 0xA000;
break;
}
return tempLoadAddress;
}
UINT_T LoadDTimOTA(TIM *pTIM_h, pIMG_MAP_INFO pImgMapInfo, UINT_T TIMID)
{
UINT_T Retval = NoError;
UINT_T TimSize = 0, i = 0;
pIMAGE_INFO_3_4_0 pImage;
UINT8_T *pTempTIMArea = 0; //512 bytes is required to support MMC reads in SDMA mode
UINT_T DTIMLoadAddress = 0;
UINT_T offset = 0;
pTempTIMArea = malloc(512);
if(pTempTIMArea == NULL)
return HeapExhaustedError;
memset(pTempTIMArea, 0, 512);
// Set partition
#if MMC_CODE
SetPartition(pImgMapInfo->PartitionNumber, BOOT_FLASH);
#endif
// read up to (including) the first Image_Info field of the TIM
// then read the rest of the TIM based on the info read
TimSize = sizeof(VERSION_I) + sizeof(FLASH_I) + 12 + sizeof(IMAGE_INFO_3_4_0);
// Read the initial TimSize amount from flash
#if MMC_CODE
Retval = ReadFlash(pImgMapInfo->FlashEntryAddr[0]/512, (UINT_T)pTempTIMArea, TimSize, BOOT_FLASH);
#else
Retval = ReadFlash(pImgMapInfo->FlashEntryAddr[0], (UINT_T)pTempTIMArea, TimSize, BOOT_FLASH);
#endif
// If there is an error with the Read, return with the error code.
if ( Retval != NoError )
{
return Retval;
}
// Set TIM pointers
SetTIMPointers(pTempTIMArea, pTIM_h);
// Check if we found the correct TIM ID and if we are using the correct TIM version.
if( (pTIM_h->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER) || (pTIM_h->pConsTIM->VersionBind.Version < TIM_3_2_00) )
{
free(pTempTIMArea);
return IMAP_DTIMNotFound;
}
// If we are here, this means that we have read part of a TIM successfully. Read the rest!
pImage = FindImageInTIM(pTIM_h, TIMID);
if( pImage == NULL )
{
free(pTempTIMArea);
return IMAP_DTIMNotFound;
}
TimSize = pImage->ImageSize; // less than 4K/8K
DTIMLoadAddress = getDTIMLoadAddress(TIMID);
// Read in the rest of the TIM
offset = pImage->FlashEntryAddr;
#ifdef CONFIG_AB_SYSTEM
if (DTIM_GetABSystemType(pImgMapInfo, NULL)) {
offset = pImgMapInfo->FlashEntryAddr[0];
#if MMC_CODE
offset /= 512;
#endif
}
#endif
if ((pImage->LoadAddr != 0xFFFFFFFF) && (pImage->LoadAddr != 0x00000000))
Retval = ReadFlash(offset, pImage->LoadAddr, TimSize, BOOT_FLASH);
else
Retval = ReadFlash(offset, DTIMLoadAddress, TimSize, BOOT_FLASH);
free(pTempTIMArea);
if (Retval != NoError)
{
return Retval;
}
SetTIMPointers((UINT8_T*) DTIMLoadAddress, pTIM_h);
return NoError;
}
// 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.
pIMAGE_INFO_3_4_0 ReturnPImgPtr(pTIM pTIM_h, UINT_T ImageNumber)
{
pIMAGE_INFO_3_4_0 pIMG;
if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_4_00)
pIMG = (pIMAGE_INFO_3_4_0) &pTIM_h->pImg[ImageNumber];
else
#ifdef LINUX_BUILD
pIMG = &( ((pIMAGE_INFO_3_2_0) pTIM_h->pImg)[ImageNumber]);
#else
(pIMAGE_INFO_3_2_0)pIMG = &( ((pIMAGE_INFO_3_2_0) pTIM_h->pImg)[ImageNumber]);
#endif
return pIMG;
}
// This function will return the correct partition
// taking offset for different versions into account
UINT_T ReturnImgPartitionNumber(pTIM pTIM_h, pIMAGE_INFO_3_4_0 pImg)
{
return (pImg->PartitionNumber.bits.PartitionNumber);
}
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
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))
{
#ifdef LINUX_BUILD
pWRAH = (UINT_T)pWRAH + (pWRAH->Size + 3) & ~3; // Skip to the next one
#else
((UINT_T) pWRAH) += (pWRAH->Size + 3) & ~3; // Skip to the next one
#endif
Count++;
}
if (pWRAH->Identifier != Identifier)
{
*Retval = NotFoundError;
pWRAH = NULL;
}
return pWRAH;
}
// Finds an Image Map Information block with the given Image ID and OTA Image type
// in the IMAP reserved area package.
pIMG_MAP_INFO FindImageMapInfoInIMAP (pIMAGE_MAP pImgMap, UINT_T ImageID, OTA_IMAGE_TYPE OTAImageType)
{
pIMG_MAP_INFO pImgMapInfo;
UINT_T i = 0;
if (pImgMap)
{
pImgMapInfo = pImgMap->pImgMapInfo;
// Search for the DTIM image information in the IMAP reserved package.
for ( i = 0; i < pImgMap->NumberOfMappedImages; i++ )
{
if ( (pImgMapInfo->ImageID == ImageID) && (pImgMapInfo->ImageType == OTAImageType) )
{
return pImgMapInfo;
}
pImgMapInfo++;
}
}
return NULL;
}
//--------------------------------------------------------------------------------------------------------
// These 2 functions allow for more than one instance of each package "TYPE" to be retrieved
// from the reserved area.
// The TIM is expected to be a static data area.
//--------------------------------------------------------------------------------------------------------
//------------------------------------------------------
// This data is shared between typical Getfirst/GetNext
// functions below.
//------------------------------------------------------
static pTIM pGetNextTim_h = NULL;
static pWTP_RESERVED_AREA_HEADER pLastIdFound = NULL;
static UINT_T lastIdType = INVALIDID; // = "!!!!"
static UINT_T reservedPackageCount = 0;
//---------------------------------------------------------------------------------------------------
// FindFirstPackageInReserved()
//
// Starting from the begining of the reserved area, search for the first instance of
// a reserved package of the type specified by "Identifier"
//
// update the static data for FindNextPackageInReserved()
//
//---------------------------------------------------------------------------------------------------
pWTP_RESERVED_AREA_HEADER FindFirstPackageTypeInReserved (UINT_T * Retval, pTIM pTIM_h, UINT_T Identifier)
{
UINT_T Count = 0;
pWTP_RESERVED_AREA_HEADER pWRAH;
pWTP_RESERVED_AREA pWRA = (pWTP_RESERVED_AREA) pTIM_h->pReserved;
*Retval = CheckReserved(pTIM_h);
if (*Retval != NoError)
return NULL;
// Start from the begining of the reserved area
//---------------------------------------------
pWRAH = (pWTP_RESERVED_AREA_HEADER) (pWRA + 1);
while( (pWRAH->Identifier != Identifier) &&
(pWRAH->Identifier != TERMINATORID) &&
(Count < pWRA->NumReservedPackages) )
{
#ifdef LINUX_BUILD
pWRAH = (UINT_T)pWRAH + (pWRAH->Size + 3) & ~3; // Skip to the next one
#else
((UINT_T) pWRAH) += (pWRAH->Size + 3) & ~3; // Skip to the next one
#endif
Count++;
}
if (pWRAH->Identifier != Identifier)
{
*Retval = NotFoundError;
pLastIdFound = NULL;
pGetNextTim_h = NULL;
lastIdType = INVALIDID;
reservedPackageCount = 0;
return NULL;
}
else
{
pLastIdFound = pWRAH;
lastIdType = Identifier;
reservedPackageCount = Count;
pGetNextTim_h = pTIM_h;
return pWRAH;
}
}
//---------------------------------------------------------------------------------------------------
// FindNextPackageInReserved()
//
//
//
//---------------------------------------------------------------------------------------------------
pWTP_RESERVED_AREA_HEADER FindNextPackageTypeInReserved(UINT_T *Retval )
{
pWTP_RESERVED_AREA_HEADER pWRAH;
pWTP_RESERVED_AREA pWRA = (pWTP_RESERVED_AREA) pGetNextTim_h->pReserved;
*Retval = NoError;
if( (lastIdType == INVALIDID) ||
(pLastIdFound == NULL) ||
(pGetNextTim_h == NULL) )
{
*Retval = NotFoundError;
return NULL;
}
// Start from the last item of Identifier type found
//--------------------------------------------------
pWRAH = pLastIdFound;
#ifdef LINUX_BUILD
pWRAH = (UINT_T)pWRAH + pWRAH->Size; // Skip to the next one
#else
(UINT_T) pWRAH += pWRAH->Size; // Skip to the next one
#endif
reservedPackageCount++;
while( (pWRAH->Identifier != lastIdType) &&
(pWRAH->Identifier != TERMINATORID) &&
(reservedPackageCount < pWRA->NumReservedPackages) )
{
#ifdef LINUX_BUILD
pWRAH = (UINT_T)pWRAH + (pWRAH->Size + 3) & ~3; // Skip to the next one
#else
((UINT_T) pWRAH) += (pWRAH->Size + 3) & ~3; // Skip to the next one
#endif
reservedPackageCount++;
}
// Reset the get First / Next interaction
//---------------------------------------
if( pWRAH->Identifier != lastIdType )
{
*Retval = NotFoundError;
pLastIdFound = NULL;
lastIdType = INVALIDID;
reservedPackageCount = 0;
return NULL;
}
else
{
pLastIdFound = pWRAH;
return pWRAH;
}
}
pKEY_MOD_3_4_0 FindKeyInTIM(pTIM pTIM_h, UINT_T KeyID)
{
pKEY_MOD_3_4_0 pKeyInfo = NULL;
UINT8_T i;
if (pTIM_h)
{
for( i = 0, pKeyInfo = pTIM_h->pKey; i < pTIM_h->pConsTIM->NumKeys; i++)
{
if(pKeyInfo->KeyID == KeyID)
return pKeyInfo;
pKeyInfo++;
}
}
return NULL;
}
// This function is used to find an image information field in the TIM
// of the image with the ID passed in
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;
}
// This function is used to find an image information field in the TIM
// of the image with the ID passed in
pIMAGE_INFO_3_4_0 FindImageTypeInTIM(pTIM pTIM_h, UINT_T TypeID)
{
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 & TYPEMASK)>> 8) == TypeID)
return pImageInfo;
}
}
return NULL;
}
//-----------------------------------------------------------------------------------------
// InitDefaultPort
//
// Used to initialize default ports when no TIM is found or no port is specified in the TIM
//-----------------------------------------------------------------------------------------
void InitDefaultPort(pFUSE_SET pFuses)
{
Platform_PortEnable(pFuses);
}
UINT_T CheckResumeBLPackage(void *pTIM){
UINT_T Retval = NoError;
pOPT_RESUME_SET pOPT_Resume;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
// Is this TIM set for auto-bind?
pWRAH = FindPackageInReserved (&Retval, pTIM, RESUMEBLID);
if (Retval == NoError)
{
pOPT_Resume = (pOPT_RESUME_SET) pWRAH;
if (!(pOPT_Resume->ResumeDDRInfo.ResumeAddr))
{
Retval = NotFoundError;
}
}
return Retval;
}
UINT_T CheckAntiRollbackPackage(void *pTIM, UINT_T *SVN){
UINT_T Retval = NoError;
pATRB_INFO pAnti_Rollback;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
// Is this TIM set for auto-bind?
pWRAH = FindPackageInReserved (&Retval, pTIM, ATRB);
if (Retval == NoError)
{
pAnti_Rollback = (pATRB_INFO) pWRAH;
if(pAnti_Rollback->CurrSVN < pAnti_Rollback->MaxSVN)
{
if(SVN)
*SVN = pAnti_Rollback->CurrSVN;
return pAnti_Rollback->Enabled;
}
obm_printf("Error: CurrSVN %d, MaxSVN %d\n\r");
}
return 0;
}
//
// Add function to locate Consumer ID package
// returns a pointer to the CIPD_Entry_S for the consumer ID requested
// retursn NULL if CIDP entry not found
//
pCIDP_ENTRY FindMyConsumerArray(pTIM pTIM_h, UINT_T CID){
pCIDP_ENTRY ConsumerArray;
pWTP_RESERVED_AREA_HEADER pHeader;
pCIDP_PACKAGE pCIDP_Pack;
unsigned int Retval = NotFoundError;
unsigned int i;
unsigned int *pLocation;
if(pTIM_h){
//First find the main CIDP package
pHeader = FindPackageInReserved (&Retval, pTIM_h, CIDPID);
if ( (pHeader == NULL) || (Retval != NoError) )
Retval = NotFoundError;
else{
Retval = NotFoundError;
// now get my consumer id array entry
pCIDP_Pack = (pCIDP_PACKAGE)pHeader;
ConsumerArray = (pCIDP_ENTRY)(&pCIDP_Pack->Consumers);
for( i = 0; i < pCIDP_Pack->NumConsumers; i++){
if (ConsumerArray->ConsumerID == CID){
Retval = NoError;
break;
}
pLocation = (unsigned int *)ConsumerArray;
// Size of CIDP_ENTRY is converted from (# of bytes) to (# of 32-bit words)
pLocation += (sizeof(CIDP_ENTRY)/sizeof(int)) + ConsumerArray->NumPackagesToConsume - 1;
ConsumerArray = (pCIDP_ENTRY)pLocation;
}
}
}
if (Retval != NoError)
ConsumerArray = NULL;
return ConsumerArray;
}
#if TRUSTED
UINT_T ValiateDTIM(pTIM pDTIM_h, pTIM pTIM_h)
{
UINT_T Retval = NoError;
UINT_T PlainTextKeyPacked[MAXKEYSIZEWORDS * 2];
UINT_T PlainTextKeyLength;
pKEY_MOD_3_4_0 pEncryptedKey = NULL;
pKEY_MOD_3_4_0 pDecryptionKey = NULL;
pKEY_MOD_3_4_0 pPlainTextKey = NULL;
if( pDTIM_h->pConsTIM->VersionBind.Trusted )
{
// Prepare the ENCRYPTED KEY
// pEncryptedKey has the encrypted key now
pEncryptedKey = FindKeyInTIM(pDTIM_h, ENCK);
// If key not found, return with this error
if (pEncryptedKey == NULL)
{
obm_printf("ENCK Key Not Found\n\r");
return KeyNotFoundError;
}
pDecryptionKey = (KEY_MOD_3_4_0 *)malloc(DDR_DECRYPTIONKEY_LEN);
pPlainTextKey = (KEY_MOD_3_4_0 *)malloc(DDR_PLAINTEXTKEY_LEN);
if(pDecryptionKey == NULL || pPlainTextKey == NULL) {
return HeapExhaustedError;
}
memset(pDecryptionKey, 0, sizeof(KEY_MOD_3_4_0));
memset(pPlainTextKey, 0, sizeof(KEY_MOD_3_4_0));
// Prepare the DECRYPTION KEY
// Setup the key structure that will be used to decrypt the public
// key hash associated with DTIM. In this case, this key is the
// public key that is used in the initial TIM. The algorithm and
// key size information is imported from the encrypted key.
pDecryptionKey->HashAlgorithmID = pEncryptedKey->HashAlgorithmID;
pDecryptionKey->KeySize = pEncryptedKey->KeySize;
pDecryptionKey->EncryptAlgorithmID = (ENCRYPTALGORITHMID_T)((pEncryptedKey->EncryptAlgorithmID) & 0x7FFFFFFF);
// Since the keys are represented as a union, the following will
// work for ECC as well.
memcpy(pDecryptionKey->Rsa.RSAPublicExponent, pTIM_h->pTBTIM_DS->Rsa.RSAPublicExponent, MAXRSAKEYSIZEWORDS*4);
memcpy(pDecryptionKey->Rsa.RSAModulus, pTIM_h->pTBTIM_DS->Rsa.RSAModulus, MAXRSAKEYSIZEWORDS*4);
// Prepare the PLAINTEXT KEY
pPlainTextKey->KeySize = pDTIM_h->pTBTIM_DS->KeySize;
// Plain text key that is signed is essentially the public key of the DTIM.
// Read the public key components into the PlainTextKey structure.
// Note that since the keys are represented as a union, the following will
// work for ECC as well.
memcpy(pPlainTextKey->Rsa.RSAPublicExponent, pDTIM_h->pTBTIM_DS->Rsa.RSAPublicExponent, MAXRSAKEYSIZEWORDS*4);
memcpy(pPlainTextKey->Rsa.RSAModulus, pDTIM_h->pTBTIM_DS->Rsa.RSAModulus, MAXRSAKEYSIZEWORDS*4);
// Before we validate the TIM, make sure its public key is correct
// by comparing it against its encrypted hash.
Retval = VerifyEncryptedKey(pPlainTextKey, pEncryptedKey, pDecryptionKey);
free(pDecryptionKey);
free(pPlainTextKey);
if (Retval != NoError)
{
obm_printf("Verify Encrypted Key Failed: 0x%x\n\r", Retval);
return Retval;
}
}
// Validate the DTIM.
Retval = ValidateTIMSignature(pDTIM_h);
if (Retval != NoError)
{
obm_printf("Verify DTIM Signature Failed: 0x%x\n\r", Retval);
return IMAP_DTIMValidationFailed;
}
return NoError;
}
#endif
INT GetAutoDownloadConfig(pTIM pTIM_h)
{
UINT_T Retval = NoError, i = 0, j;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
pTransfer_Info_PACKAGE pInfo = NULL;
pWRAH = FindPackageInReserved(&Retval, pTIM_h, CUSTOMIEZED_INFO_TRANSFER2_AP);
if ((pWRAH == NULL) || (Retval != NoError))
{
return 0;
}else{
pInfo = (Transfer_Info_PACKAGE *) pWRAH;
while (i++ < pInfo->NumbersTransferInfo) {
if(pInfo->info[i].config_id == ATDL) {
return pInfo->info[i].config_value;
}
}
}
return 0;
}
/*TODO: May move this function to other place */
UINT_T TransCITA_2_OBM2OSLO(pTIM pTIM_h, OBM2OSL *pOBM2OSL_h)
{
UINT_T Retval = NoError, i, j;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
pTransfer_Info_PACKAGE pInfo = NULL;
CHAR CfgName[5];
#if defined(CONFIG_TEE_OS)
TEEC_INFO teec_info;
int sec_cfg, nsec_cfg;
#endif
pWRAH = FindPackageInReserved(&Retval, pTIM_h, CUSTOMIEZED_INFO_TRANSFER2_AP);
if ((pWRAH == NULL) || (Retval != NoError))
{
obm_printf("No customized info found\n\r");
}
else
{
pInfo = (Transfer_Info_PACKAGE *) pWRAH;
i = 0;
if (pInfo->NumbersTransferInfo < 32)
obm_printf("Unexpected CITA numbers\n\r");
while (i < pInfo->NumbersTransferInfo)
{
if(pInfo->info[i].config_value != 0)
{
j = 0;
while(j < pOBM2OSL_h->info.cfg_numbers)
{
/* ignore configuration which is already configured by asr flag */
if(pOBM2OSL_h->info.cfg_info[j].cfg_id == pInfo->info[i].config_id)
break;
j++;
}
if(j == pOBM2OSL_h->info.cfg_numbers)
{
pOBM2OSL_h->info.cfg_info[j].cfg_id = pInfo->info[i].config_id;
pOBM2OSL_h->info.cfg_info[j].cfg_value = pInfo->info[i].config_value;
pOBM2OSL_h->info.cfg_numbers++;
}
}
i++;
}
}
#if defined(CONFIG_TEE_OS)
memset(&teec_info, 0, sizeof(TEEC_INFO));
#endif
for (i = 0; i < pOBM2OSL_h->info.cfg_numbers; i++)
{
switch (pOBM2OSL_h->info.cfg_info[i].cfg_id)
{
case FASTID:
switch(pOBM2OSL_h->info.cfg_info[i].cfg_value)
{
case LWG_3MODE:
obm_printf("[3Mode]LWG image\n\r");
break;
case LTG_3MODE:
obm_printf("[3Mode]LTG image\n\r");
break;
case LWG_5MODE:
obm_printf("[5Mode]LWG image\n\r");
break;
case LTG_5MODE:
obm_printf("[5Mode]LTG image\n\r");
break;
default:
obm_printf("Unknown CP type!!\n\r");
break;
}
break;
#if defined(CONFIG_TEE_OS)
case TSDS:
teec_info.SecDramSize = pOBM2OSL_h->info.cfg_info[i].cfg_value;
teec_info.WRAH.Size = 4;
break;
case TNMZ:
teec_info.NsecSharedMemSize = pOBM2OSL_h->info.cfg_info[i].cfg_value;
teec_info.WRAH.Size = 8;
break;
case TLVL:
teec_info.LogLevel = pOBM2OSL_h->info.cfg_info[i].cfg_value;
teec_info.WRAH.Size = 12;
break;
#endif
case 0:
break;
default:
CfgName[4] = '\0';
memcpy(CfgName, &(pOBM2OSL_h->info.cfg_info[i].cfg_id), 4);
obm_printf("OBM2OSL_CFG%d %s: 0x%08x\n\r", i, CfgName,
pOBM2OSL_h->info.cfg_info[i].cfg_value);
break;
}
}
#if defined(CONFIG_TEE_OS)
if (teec_info.WRAH.Size && pAsrTeec->WRAH.Size == 0) {
teec_info.WRAH.Identifier = TEEC;
teec_info.WRAH.Size += 8; //size of WRAH
sec_cfg = !!teec_info.SecDramSize;
nsec_cfg = !!teec_info.NsecSharedMemSize;
if (sec_cfg ^ nsec_cfg) {
obm_printf("Invalid TEEC config in CITA\n\r");
return NoError;
} else {
pOBM2OSL_h->tee_dram_size = teec_info.SecDramSize + teec_info.NsecSharedMemSize;
}
memcpy(pAsrTeec, &teec_info, sizeof(TEEC_INFO));
}
#endif
return NoError;
}
INT ImageIsSDTIMIncluded(pIMAGE_INFO_3_4_0 pImageInfo)
{
if(pImageInfo->LoadAddr == SDTIM)
return 1;
return 0;
}
UINT_T GetSDTimSpaceSize(pIMAGE_INFO_3_4_0 pSdtimImageInfo)
{
return pSdtimImageInfo->LoadAddr;
}
UINT_T GetSDTimSecureConfig(pIMAGE_INFO_3_4_0 pSdtimImageInfo)
{
return pSdtimImageInfo->FlashEntryAddr;
}
pIMAGE_INFO_3_4_0 SDTimImageInfoUpdate(pIMAGE_INFO_3_4_0 pImgInfoSrc,
pIMAGE_INFO_3_4_0 pImgInfoDst, OTA_IMAGE_TYPE DTIMType)
{
INT_T Retval;
UINT_T offset;
TIM *pSDTIM_h = NULL;
CHAR *SDTimBuf = NULL;
pIMAGE_INFO_3_4_0 pImgInfo;
if (DTIMType == PrimaryImage)
offset = pImgInfoSrc->FlashEntryAddr;
else {
offset = pImgInfoSrc->PartitionNumber.bits.Reserved << 17;
#if MMC_CODE
offset /= 512;
#endif
}
SDTimBuf = malloc(SDTIM_MAX_SIZE);
pSDTIM_h = malloc(sizeof(TIM));
if(SDTimBuf == NULL || pSDTIM_h == NULL)
return NULL;
Retval = ReadFlash(offset, SDTimBuf, SDTIM_MAX_SIZE, BOOT_FLASH);
if(Retval != NoError)
goto exit;
Retval = SetTIMPointers( SDTimBuf, pSDTIM_h);
if(Retval)
goto exit;
pImgInfo = FindImageInTIM(pSDTIM_h, pImgInfoSrc->ImageID);
if(pImgInfo == NULL)
goto exit;
memcpy(pImgInfoDst, pImgInfo, sizeof(*pImgInfo));
free(SDTimBuf); free(pSDTIM_h);
return pImgInfoDst;
exit:
free(SDTimBuf); free(pSDTIM_h);
return NULL;
}
INT_T IsTim4OBMI(pTIM pTIM_h)
{
pIMAGE_INFO_3_4_0 pTimInfo = NULL;
pTimInfo = FindImageInTIM(pTIM_h, TIMIDENTIFIER);
if(pTimInfo == NULL)
FatalError(TIMNotFound, "IT4O", NULL);
if(pTimInfo->NextImageID == OBMIDENTIFIER)
return 1;
return 0;
}
INT_T IsTim4DKBI(pTIM pTIM_h)
{
pIMAGE_INFO_3_4_0 pTimInfo = NULL;
pTimInfo = FindImageInTIM(pTIM_h, TIMIDENTIFIER);
if(pTimInfo == NULL)
FatalError(TIMNotFound, "IT4D", NULL);
if(pTimInfo->NextImageID == DKBIDENTIFIER)
return 1;
return 0;
}
INT_T IsTim4FBF(pTIM pTIM_h)
{
pIMAGE_INFO_3_4_0 pTimInfo = NULL;
pTimInfo = FindImageInTIM(pTIM_h, TIMIDENTIFIER);
if(pTimInfo == NULL)
FatalError(TIMNotFound, "IT4F", NULL);
if(((pTimInfo->NextImageID) & 0xFFFFFF00) == FBFIDENTIFIER0)
return 1;
return 0;
}
static AsrDualTimInfo DualTimInfo;
INT_T GetCurTimBlock(VOID)
{
if(DualTimInfo.CurrentTim == 0)
return DualTimInfo.MainTimBlock;
else
return DualTimInfo.BackupTimBlock;
}
VOID DualTimEnable(VOID) {
DualTimInfo.DualTimEnable = 1;
}
#if DUAL_TIM
INT_T DualTimEnabled(VOID) {
return DualTimInfo.DualTimEnable;
}
#else
INT_T DualTimEnabled(VOID) {
return 0;
}
#endif
INT_T DualTimIsEqual(VOID)
{
return DualTimInfo.DualTimIsEqual;
}
pAsrDualTimInfo GetDualTimInfo(VOID)
{
return &DualTimInfo;
}
/* When This function is called, BBM is not initialized yet, should avoid to access flash */
VOID InitializeDualTimEarly(pTIM pTIM_h)
{
memset(&DualTimInfo, 0, sizeof(AsrDualTimInfo));
#if DUAL_TIM
UINT_T Retval = NoError;
UINT_T ImageInfoNum = 0;
pDTIP pDualTimImageInfo = NULL;
pIMAGE_INFO_3_4_0 pTimInfo = NULL;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
INT_T i;
P_FlashProperties_T pFlashP = GetFlashProperties(BOOT_FLASH);
UINT_T BlockSize = pFlashP->BlockSize;
if(IsTim4DKBI(pTIM_h)) {
/* Temp value, should called by a TIMH for DKBI */
DualTimInfo.DualTimEnable = 0;
DualTimInfo.CurrentTim = 0;
return;
}
// Is this TIM set for auto-bind?
pWRAH = FindPackageInReserved (&Retval, pTIM_h, DTIPID);
if (Retval == NoError)
{
DualTimInfo.DualTimEnable = 1;
#if LAPW
if(PlatformIsLapwA0() || PlatformIsLapwB0())
DualTimInfo.DualTimIsEqual = 1;
#endif
if(IsTim4FBF(pTIM_h)) {
DualTimInfo.CurrentTim = 0;
obm_printf("Dual TIM enabled for Download\n\r");
}
ImageInfoNum = (pWRAH->Size - 8) / sizeof(DTIP_Img_Info);
pDualTimImageInfo = (pDTIP) pWRAH;
for(i = 0; i < ImageInfoNum; i ++) {
if(pDualTimImageInfo->ImageInfo[i].ImageID == TIMIDENTIFIER &&
pDualTimImageInfo->ImageInfo[i].TIM_INC == TIMH_INC)
{
DualTimInfo.MainTimBlock = pDualTimImageInfo->ImageInfo[i].FlashAddr / BlockSize;
DualTimInfo.MainPartition = pDualTimImageInfo->ImageInfo[i].PartitionNumber;
}
if(pDualTimImageInfo->ImageInfo[i].ImageID == OBMIDENTIFIER &&
pDualTimImageInfo->ImageInfo[i].TIM_INC == TIMH_INC)
{
DualTimInfo.MainObmBlock = pDualTimImageInfo->ImageInfo[i].FlashAddr / BlockSize;
}
if(pDualTimImageInfo->ImageInfo[i].ImageID == TIMIDENTIFIER &&
pDualTimImageInfo->ImageInfo[i].TIM_INC == TIMH_RECOVERY_INC)
{
DualTimInfo.BackupTimBlock = pDualTimImageInfo->ImageInfo[i].FlashAddr / BlockSize;
DualTimInfo.BackupPartition = pDualTimImageInfo->ImageInfo[i].PartitionNumber;
}
if(pDualTimImageInfo->ImageInfo[i].ImageID == OBMIDENTIFIER &&
pDualTimImageInfo->ImageInfo[i].TIM_INC == TIMH_RECOVERY_INC)
{
DualTimInfo.BackupObmBlock = pDualTimImageInfo->ImageInfo[i].FlashAddr / BlockSize;
}
}
if(IsTim4OBMI(pTIM_h)) {
pTimInfo = FindImageInTIM(pTIM_h, TIMIDENTIFIER);
if(pTimInfo == NULL) {
return;
}
#if MMC_CODE
if(pTimInfo->PartitionNumber.bits.PartitionNumber == MMC_SD_BOOT_PARTITION2){
DualTimInfo.CurrentTim = 1;
SetPartition(MMC_SD_BOOT_PARTITION2, BOOT_FLASH);
obm_printf("Boot up from Backup TIM\n\r");
}
else {
DualTimInfo.CurrentTim = 0;
SetPartition(MMC_SD_BOOT_PARTITION, BOOT_FLASH);
obm_printf("Boot up from Main TIM\n\r");
}
#else
if(DualTimIsEqual()) {
UINT8_T *Tmpbuf = malloc(BlockSize);
if(Tmpbuf == NULL)
return HeapExhaustedError;
Retval = pFlashP->ReadFromFlash(0, Tmpbuf, pTimInfo->ImageSize, BOOT_FLASH);
if((Retval == NoError) && /* loaded TIM is same with block0 */
memcmp(pTIM_h->pConsTIM, Tmpbuf, pTimInfo->ImageSize) == 0) {
DualTimInfo.CurrentTim = 0;
} else {
DualTimInfo.CurrentTim = 1;
}
} else {
if(pTimInfo->FlashEntryAddr > 0){
DualTimInfo.CurrentTim = 1;
}
else {
DualTimInfo.CurrentTim = 0;
}
}
if(DualTimInfo.CurrentTim == 0)
obm_printf("Boot up from Main TIM\n\r");
else
obm_printf("Boot up from Backup TIM\n\r");
#endif
}
}
#endif
return;
}
UINT_T InitializeDualTimLate(pTIM pTIM_h)
{
UINT_T Retval = NoError;
UINT_T BlockSize;
pIMAGE_INFO_3_4_0 pTimInfo = NULL;
pIMAGE_INFO_3_4_0 pObmInfo = NULL;
pTIM pTIM_Main = NULL;
pTIM pTIM_Bkup = NULL;
UINT8_T *TimObmTotalBuf = NULL;
UINT8_T *MainTimBuf = NULL;
UINT8_T *BkupTimBuf = NULL;
UINT8_T *MainObmBuf = NULL;
UINT8_T *BkupObmBuf = NULL;
UINT_T TimSize, ObmSize;
UINT_T MaxTimSize, MaxObmSize;
UINT_T TimObmTotalSize;
UINT_T BkupTimOffset, BkupObmOffset;
UINT_T MainTimOffset, MainObmOffset;
UINT_T FlashOffFac;
P_FlashProperties_T pFlashP = GetFlashProperties(BOOT_FLASH);
if(!DualTimEnabled() || IsTim4FBF(pTIM_h) || IsTim4DKBI(pTIM_h))
return NoError;
#if MMC_CODE
FlashOffFac = 1;
MaxTimSize = MAX_TIM_SIZE;
MaxObmSize = MAX_OBM_SIZE;
#else
FlashOffFac = BlockSize = pFlashP->BlockSize;
MaxTimSize = MaxObmSize = BlockSize;
#endif
TimObmTotalSize = (MaxTimSize + MaxObmSize) << 1;
TimObmTotalBuf = malloc(TimObmTotalSize); /* two TIMs + two OBMs */
if (TimObmTotalBuf == NULL)
return HeapExhaustedError;
pTIM_Main = malloc(sizeof(*pTIM_Main));
pTIM_Bkup = malloc(sizeof(*pTIM_Bkup));
if(pTIM_Main == NULL || pTIM_Bkup == NULL) {
Retval = HeapExhaustedError;
goto exit;
}
MainTimBuf = TimObmTotalBuf;
BkupTimBuf = MainTimBuf + MaxTimSize;
MainObmBuf = BkupTimBuf + MaxTimSize;
BkupObmBuf = MainObmBuf + MaxObmSize;
/* Get TIM and OBM image info from the boot TIM */
pTimInfo = FindImageInTIM(pTIM_h, TIMIDENTIFIER);
if(pTimInfo == NULL)
FatalError(ImageNotFound, "IDTL", 1);
TimSize = pTimInfo->ImageSize;
pObmInfo = FindImageInTIM(pTIM_h, OBMIDENTIFIER);
if(pObmInfo == NULL)
FatalError(ImageNotFound, "IDTL", 2);
ObmSize = pObmInfo->ImageSize;
MainTimOffset = DualTimInfo.MainTimBlock * FlashOffFac;
BkupTimOffset = DualTimInfo.BackupTimBlock * FlashOffFac;
MainObmOffset = DualTimInfo.MainObmBlock * FlashOffFac;
BkupObmOffset = DualTimInfo.BackupObmBlock * FlashOffFac;
#if MMC_CODE
SetPartition(MMC_SD_BOOT_PARTITION, BOOT_FLASH);
#endif
Retval = ReadFlash(MainTimOffset, MainTimBuf, MaxTimSize, BOOT_FLASH);
if (Retval && Retval != FlashReadEccError) goto exit;
Retval = ReadFlash(MainObmOffset, MainObmBuf, MaxObmSize, BOOT_FLASH);
if (Retval && Retval != FlashReadEccError) goto exit;
#if MMC_CODE
SetPartition(MMC_SD_BOOT_PARTITION2, BOOT_FLASH);
#endif
Retval = ReadFlash(BkupTimOffset, BkupTimBuf, MaxTimSize, BOOT_FLASH);
if (Retval && Retval != FlashReadEccError) goto exit;
Retval = ReadFlash(BkupObmOffset, BkupObmBuf, MaxObmSize, BOOT_FLASH);
if (Retval && Retval != FlashReadEccError) goto exit;
if ((DualTimInfo.CurrentTim == 1) || DualTimIsEqual()) { /* boot up from bkup TIM */
#ifdef ENABLE_BBM
if (IsBlockRelocated(DualTimInfo.MainTimBlock))
{
obm_printf("Main TIM relocated\n\r");
Retval = NoError;
goto exit;
}
#endif
Retval = SetTIMPointers(MainTimBuf, pTIM_Main);
if (Retval == NoError) {
Retval = ValidateImage(MainTimBuf, TIMIDENTIFIER, pTIM_Main);
}
if (Retval) {
obm_printf("Main TIM corrupt, restore it\n\r");
#if MMC_CODE
SetPartition(MMC_SD_BOOT_PARTITION, BOOT_FLASH);
memcpy(MainTimBuf, BkupObmBuf+ObmSize, TimSize);
#else
memcpy(MainTimBuf, BkupTimBuf, MaxTimSize); //to get BBT, only needed for nand
if(!DualTimIsEqual())
memcpy(MainTimBuf, BkupObmBuf+ObmSize, TimSize);
Retval = EraseFlash(MainTimOffset, MaxTimSize, BOOT_FLASH);
if(Retval) goto exit;
#endif
Retval = WriteFlash(MainTimOffset, MainTimBuf, MaxTimSize, BOOT_FLASH);
if(Retval) goto exit;
Retval = SetTIMPointers(MainTimBuf, pTIM_Main); //g
if(Retval) goto exit;
}
Retval = ValidateImage(MainObmBuf, OBMIDENTIFIER, pTIM_Main);
if (Retval) {
obm_printf("Main OBM corrupt, restore it\n\r");
memcpy(MainObmBuf, BkupObmBuf, ObmSize);
if(!DualTimIsEqual())
memcpy(MainObmBuf+ObmSize, BkupTimBuf, TimSize);
#if MMC_CODE
SetPartition(MMC_SD_BOOT_PARTITION, BOOT_FLASH);
#else
Retval = EraseFlash(MainObmOffset, MaxObmSize, BOOT_FLASH);
if(Retval) goto exit;
#endif
Retval = WriteFlash(MainObmOffset, MainObmBuf, MaxObmSize, BOOT_FLASH);
if(Retval) goto exit;
}
}
if((DualTimInfo.CurrentTim == 0) || DualTimIsEqual())
{
#ifdef ENABLE_BBM
if (IsBlockRelocated(DualTimInfo.BackupTimBlock))
{
obm_printf("Bkup TIM relocated\n\r");
Retval = NoError;
goto exit;
}
#endif
Retval = SetTIMPointers(BkupTimBuf, pTIM_Bkup);
if (Retval == NoError) {
Retval = ValidateImage(BkupTimBuf, TIMIDENTIFIER, pTIM_Bkup);
}
if (Retval) {
obm_printf("Bkup TIM corrupt, restore it\n\r");
#if MMC_CODE
SetPartition(MMC_SD_BOOT_PARTITION2, BOOT_FLASH);
memcpy(BkupTimBuf, MainObmBuf+ObmSize, TimSize);
#else
memcpy(BkupTimBuf, MainTimBuf, MaxTimSize); //to get BBT, only needed for nand
if(!DualTimIsEqual())
memcpy(BkupTimBuf, MainObmBuf+ObmSize, TimSize);
Retval = EraseFlash(BkupTimOffset, MaxTimSize, BOOT_FLASH);
if(Retval) goto exit;
#endif
Retval = WriteFlash(BkupTimOffset, BkupTimBuf, MaxTimSize, BOOT_FLASH);
if(Retval) goto exit;
Retval = SetTIMPointers(BkupTimBuf, pTIM_Bkup); //golden backup TIM
if(Retval) goto exit;
}
Retval = ValidateImage(BkupObmBuf, OBMIDENTIFIER, pTIM_Bkup);
if (Retval) {
obm_printf("Bkup OBM corrupt, restore it\n\r");
memcpy(BkupObmBuf, MainObmBuf, ObmSize);
if(!DualTimIsEqual())
memcpy(BkupObmBuf+ObmSize, MainTimBuf, TimSize);
#if MMC_CODE
SetPartition(MMC_SD_BOOT_PARTITION2, BOOT_FLASH);
#else
Retval = EraseFlash(BkupObmOffset, MaxObmSize, BOOT_FLASH);
if(Retval) goto exit;
#endif
Retval = WriteFlash(BkupObmOffset, BkupObmBuf, MaxObmSize, BOOT_FLASH);
if(Retval) goto exit;
}
}
exit:
if(pTIM_Main) free(pTIM_Main);
if(pTIM_Bkup) free(pTIM_Bkup);
if(TimObmTotalBuf) free(TimObmTotalBuf);
return Retval;
}