| /****************************************************************************** |
| * |
| * (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; |
| } |