blob: 288c5b4be773d1f558ac50321bfd7b2371293a11 [file] [log] [blame]
/******************************************************************************
*
* (C)Copyright 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.
*
*
* FILENAME: TIMDownload.c
*
* PURPOSE: Contains BootLoader's TIM based download code.
*
******************************************************************************/
//////////////////////////////////////////////////////////////////////
// Library Support for the TIMDownload.c
// Include any shared libraries in the TIMDownload.h file to keep this
// code clean.
//////////////////////////////////////////////////////////////////////
#include "TIMDownload.h"
#include "obm2osl.h"
#include "fota.h"
#include "tim.h"
#include "ProtocolManager.h"
UINT_T NandID = 0x0; // make sure the nand ID OBM detected is the equals to the nand ID OBM got from SWD
UINT_T Reset = 1;
UINT_T Flash_size = 0x01000000; // default 16MB
extern UINT8_T FlashInitDone;
extern FOTA_Info FOTAInfo;
extern UINT_T ddr_id_update_with_crc;
static INT_T DownloadReadBackCRC = IMAGE_READ_BACK_CRC_DISABLED;
static ImageCRCInfo AllImageCRCInfo __attribute__ ((aligned (4)));
SkipBlocksInfoStruct *pSkipAddress = NULL;
UINT_T All_FF_flag = 0;
INT_T AB_DL = 0; //Indicate if AB system download
pTIM pTIM_DTIM = NULL;
Platform_ID Lookup_ChipID(UINT_T chipID)
{
Platform_ID ID = PLAT_UNKNOWN;
switch (chipID)
{
//SWD treat below SoCs as 1826 for now
case 0x1829:
case 0x1901:
case 0x1803:
case 0x1802:
case 0x1806:
case 0x1906:
case 0x1903:
case 0x1826:
ID = PLAT_NEZHA3;
break;
case 0x1822:
ID = PLAT_NEZHA2;
break;
default:
break;
}
return ID;
}
UINT_T PlatformCheckChipID(Platform_ID chip_ID_num)
{
UINT_T ChipID_value;
Platform_ID ID_num, ID_numV2;
ChipID_value = PlatformGetChipID();
if (chip_ID_num == PLAT_UNKNOWN)
return 1;
ID_num = Lookup_ChipID(ChipID_value & 0xffff);
if (ID_num == chip_ID_num)
return 0;
else
return 1; // chip ID check fail
}
UINT32 PlatformGetPlatId(void)
{
UINT_T ChipID_value, PlatId;
ChipID_value = PlatformGetChipID();
PlatId = ChipID_value & 0xFFFF;
if(ChipID_value == 0x1829)
PlatId = 0x1828;
if(ChipID_value == 0x1802)
{
if(PlatformCoreIsCR5())
PlatId = 0x531802; //1802S
else
PlatId = 0x4C531802; //1802SL
}
return PlatId;
}
/* return value: 0 : CHIP and OS are both matched, 1: not matched*/
INT PlatformFBFDevCheckChipOS(PDeviceHeader_11 pDevHeader)
{
UINT32 FFOSTypeInFbf, ChipIDinFbf, FFOSType, ChipIDinDevPara;
FFOSTypeInFbf = pDevHeader->DeviceParameters[1];
ChipIDinFbf = pDevHeader->ChipID;
//FFOS_Type is not supported yet, old way, only check chip ID
if(FFOSTypeInFbf == 0)
{
return PlatformCheckChipID(ChipIDinFbf);
}
if(PlatformCoreIsCR5())
FFOSType = RTOS;
else
FFOSType = OWRT;
if(FFOSType != FFOSTypeInFbf){
return 1; //OS doesn't match
}
/* ChipID mismatch, return */
if(PlatformCheckChipID(ChipIDinFbf)){
return 1;
}
/* ChipID in FBF of 1826/1826S/1901/1803/1802SL are all PLAT_NEZHA3,
* need to check detail in DeviceParameters[0]
*/
if(ChipIDinFbf == PLAT_NEZHA3)
{
ChipIDinDevPara = pDevHeader->DeviceParameters[0];
if(ChipIDinDevPara == PlatformGetPlatId()){
return 0;
}
else{
return 1;
}
}
return 0;
}
/* return value: 0: CMOD matched, 1: not matched*/
UINT_T PlatformFBFCheckCMOD(pTIM pTIM_FBF, PDeviceHeader_11 pDevHeader_11)
{
UINT_T imagenum;
INT_T temp_p;
TIM FlashTim;
pTIM pTIM_H_DL;;
pTIM pTIM_H_Flash = &FlashTim;
PImageStruct_11 pImage_11 = NULL;
pCMOD_INFO pCmodDlTim, pCmodFlashTim;
UINT_T Retval = NoError;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
INT NoDLTimCMOD = 0;
INT NoDLTIM = 0;
INT i;
UCHAR *TempBuffer = 0;
TempBuffer = malloc(0x4000);
if(TempBuffer == NULL)
return HeapExhaustedError;
pTIM_H_DL = pTIM_FBF;
ReadFlash(0, TempBuffer, 0x4000, BOOT_FLASH); //Read TIM in flash, max tim is 16KB for all platforms
SetTIMPointers((UINT8_T *)TempBuffer, pTIM_H_Flash);
if(pTIM_H_DL->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER){
//obm_printf("Warning: No valid TIM in FBF\n\r");
NoDLTIM = 1;
}
if(NoDLTIM == 0) {
pWRAH = FindPackageInReserved(&Retval, pTIM_H_DL, CMODID);
if ((pWRAH == NULL) || (Retval != NoError))
{
//obm_printf("No CMODID in DL TIM\n\r");
NoDLTimCMOD = 1;
}
else
{
pCmodDlTim = (pCMOD_INFO) pWRAH;
}
} else {
NoDLTimCMOD == 1;
}
/* If CMOD is "ASRCMODFORCEERASE", only erase all only is allowed */
if( (NoDLTimCMOD == 0) &&
(pCmodDlTim->Length == 17) &&
(memcmp(pCmodDlTim->CMOD, "ASRCMODFORCEERASE", 17) == 0))
{
free(TempBuffer);
if(pDevHeader_11->FlashOpt.EraseAll == 2){
obm_printf("Magic CMOD to force erase\n\r");
return 0;
}else{
return 1;
}
}
if(pTIM_H_Flash->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER){
//obm_printf("No valid Flash TIM\n\r");
free(TempBuffer);
return 0; //Allow to burn any version to an empty board except CMOD is ASRCMODFORCEERASE
}
pWRAH = FindPackageInReserved(&Retval, pTIM_H_Flash, CMODID);
if ((pWRAH == NULL) || (Retval != NoError))
{
//obm_printf("No CMOD in In Flash TIM\n\r");
free(TempBuffer);
return 0;
}
else
{
if(NoDLTimCMOD == 1 || NoDLTIM == 1){
//obm_printf("Flash TIM has CMOD, No DL TIM or No CMOD in DL TIM\n\r");
free(TempBuffer);
return 1;
}
pCmodFlashTim = (pCMOD_INFO) pWRAH;
}
obm_printf("CMOD in DL TIM: ");
for(i =0; i < pCmodDlTim->Length; i++)
obm_printf("%c", pCmodDlTim->CMOD[i]);
obm_printf("\n\r");
obm_printf("CMOD in In Flash TIM:");
for(i =0; i < pCmodFlashTim->Length; i++)
obm_printf("%c", pCmodFlashTim->CMOD[i]);
obm_printf("\n\r");
free(TempBuffer);
if(pCmodDlTim->Length != pCmodFlashTim->Length)
return 1;
if(memcmp(pCmodDlTim->CMOD, pCmodFlashTim->CMOD, pCmodFlashTim->Length) == 0)
return 0;
else
return 1;
}
UINT32 PlatformFBFCheckDownload(pTIM pTIM_FBF, PDeviceHeader_11 pDevHeader_11)
{
UINT32 Retval = NoError;
if(PlatformFBFCheckCMOD(pTIM_FBF, pDevHeader_11))
Retval = CMODMISMATCH;
if(PlatformFBFDevCheckChipOS(pDevHeader_11))
Retval = CHIPIDMISMATCH;
if(Retval != NoError)
{
ASRFlag_DLStatus_Update(pTIM_FBF, 0, 0);
FatalError(Retval, "PFCD", NULL);
}
return Retval;
}
UINT32 PlatformFBFCheckSWDVersion(PDeviceHeader_11 pDevHeader_11)
{
UINT_T LegacySWDNotSupported = 0;
UINT32 SWDVerInFBF = pDevHeader_11->DeviceParameters[3];
#if defined(CONFIG_AB_SYSTEM) || (ENABLE_ATRB)
/* legacy SWD is the one older than 4.9.1.9
* which doesn't support SWD version in FBF
*/
LegacySWDNotSupported = 1;
#endif
if(LegacySWDNotSupported && (SWDVerInFBF == 0))
{
goto swd_out_of_date;
}
if (SWDVerInFBF != 0)
{
obm_printf("SWDownloader used: %s\n\r", HexToSwdObmVersion(SWDVerInFBF));
if(SWDVerInFBF < SWD_VERSION) {
goto swd_out_of_date;
}
}
return NoError;
swd_out_of_date:
obm_printf("SWDownloader is out of date\n\r");
obm_printf("Please upgrade to %s\n\r", HexToSwdObmVersion(SWD_VERSION));
return SWD_OUTOFDATE;
}
#if ENABLE_ATRB
/* For Downloading, only check major version anti-rollback */
UINT_T TIMDownloadAntiRollbackCheck(pTIM pTIM_h)
{
UINT_T Retval = NoError;
UINT_T MajorVersionInTIM = 0;
UINT_T AntiRollbackTimEnabled;
UINT_T AntiRollbackFuseEnabled;
INT_T AntiRollbackFuseVersion;
AntiRollbackTimEnabled = CheckAntiRollbackPackage(pTIM_h, &MajorVersionInTIM);
AntiRollbackTimEnabled &= MAJOR_ATRB_ENABLED;
AntiRollbackFuseEnabled = GEU_MajorAntiRollBackEnabled();
if(AntiRollbackFuseEnabled)
{
/* The chip is already burned to enable anti-rollback */
AntiRollbackFuseVersion = GEU_ReadMajorVersion();
if(AntiRollbackTimEnabled == 0 || MajorVersionInTIM < AntiRollbackFuseVersion)
{
obm_printf("Anti-rollback error: %d %d %d\n\r", AntiRollbackTimEnabled,
MajorVersionInTIM, AntiRollbackFuseVersion);
FatalError(ATRB_MajorRollbackError, "ATRB", 1);
return ATRB_MajorRollbackError;
}
if(MajorVersionInTIM > AntiRollbackFuseVersion)
{
Retval = GEU_ProgramMajorVersion(pTIM_h);
if(Retval != NoError)
FatalError(Retval, "ATRB", 2);
}
return Retval;
}
/* The chip is not already burned to enable anti-rollback, burn it here */
if(AntiRollbackTimEnabled)
{
Retval = GEU_ProgramMajorVersion(pTIM_h);
if(Retval != NoError)
FatalError(Retval, "ATRB", 3);
obm_printf("ATRB: burn major version as %d\n\r", MajorVersionInTIM);
}
return Retval;
}
#endif
INT_T IsDLImageDTIM(PImageStruct_11 pImage_11)
{
#if BURN_DTIM_LAST
if (((pImage_11->Image_ID & 0xFFFFFF00) == TIM_TYPE))
{
switch(pImage_11->Image_In_TIM) {
case 0: /* NTIM */
case 1: /* TIMH */
case 5: /* TIMH recovery */
return 0;
default: /* differnet DTIMs */
return 1;
}
}
#if defined(CONFIG_ASR_SDTIM) && OUM4DFOTA
/* If SDTIM is enabled and OUM is used,
* OUM locates in first 10 blocks and has a SDTIM ahead.
* Then OUM also needs to be burned after TIMH/OBMI
*/
if (pImage_11->Image_ID == OUMIDENTIFIER)
return 1;
#endif
#endif
return 0;
}
static pDtimDlInfo_t DtimDLInfo[MAX_DL_DTIM_NUM];
static INT_T DtimDLNums = 0;
VOID SaveDTIMs2Memory(PImageStruct_11 pImage_11, UINT_T FbfLoadAddr)
{
pDtimDlInfo_t pDtimDLInfo = NULL;
pDtimDLInfo = malloc(sizeof(DtimDlInfo_t) + pImage_11->length);
if(pDtimDLInfo == NULL)
FatalError(HeapExhaustedError, NULL, NULL);
pDtimDLInfo->Image_ID = pImage_11->Image_ID;
pDtimDLInfo->Length = pImage_11->length;
pDtimDLInfo->FlashOffsetA = pImage_11->Flash_Start_Address;
pDtimDLInfo->FlashOffsetB = pImage_11->Flash_Start_Address_B;
memcpy(pDtimDLInfo->Buffer, FbfLoadAddr+(pImage_11->First_Sector<<12), pImage_11->length);
DtimDLInfo[DtimDLNums] = pDtimDLInfo;
DtimDLNums ++;
if (DtimDLNums == MAX_DL_DTIM_NUM)
FatalError(TooMuchDlDTims, NULL, NULL);
}
VOID BurnDTIMs2Flash(VOID)
{
INT_T i;
UINT_T Retval = NoError;
pDtimDlInfo_t pDtimDLInfo = NULL;
if (DtimDLNums == 0)
return;
for (i = 0; i < DtimDLNums; i ++)
{
pDtimDLInfo = DtimDLInfo[i];
Retval = WriteFlash(pDtimDLInfo->FlashOffsetA, pDtimDLInfo->Buffer, pDtimDLInfo->Length, BOOT_FLASH);
if(Retval == NoError && pDtimDLInfo->FlashOffsetB != 0xFFFFFFFF) {
Retval = WriteFlash(pDtimDLInfo->FlashOffsetB, pDtimDLInfo->Buffer, pDtimDLInfo->Length, BOOT_FLASH);
}
if(Retval)
obm_printf("Write %s fails\n\r", ImageID2String(pDtimDLInfo->Image_ID));
free(pDtimDLInfo);
}
}
//////////////////////////////////////////////////////////////////////
// This is the entry point for the TIM based download functionality.
//
// Inputs: Pointer to the TIM we just downloaded.
// Outputs: Returns the next image (OBM) that we will transfer the control to.
//
// It mainly functions as following:
// 1) Sets the TIM pointers.
// 2) Validates the downloaded TIM.
// 3) Configures the Flashes.
// 4) Wipes the whole Flash device.
// 5) Checks if there is already a FBBT on the Flash. If there is
// NO FBBT on the Flash, creates it.
// 6) Checks if there is a PT being downloaded. If so, it first
// tries to validate it with the existing HW partitions on the
// Flash. If they don't match, re-creates the HW partitions.
// If HW partitions are not supported, these functions will do
// nothing and return. Next, the downloaded PT is loaded into
// Flash Management (FM).
// 7) Runtime-BBT is generated.
// 8) Writes the downloaded TIM, created FBBT, PT to Flash.
// 9) Download TIM Images LOOP implements the following:
// i. Download Image
// ii. Validate Image
// iii. Set Partition
// iv. Erase Image Area from Flash
// v. Write the image to Flash
// vi. Verify the Flash write
// 10) The RBBT is written to the Flash.
//////////////////////////////////////////////////////////////////////
pIMAGE_INFO_3_4_0 TIMDownloadMain(pFUSE_SET pFuses, pTIM pTIM_h)
{
pIMAGE_INFO_3_4_0 pImageInfo = NULL;
UINT_T Retval = NoError;
UINT8_T FlashNumber = 0;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
pImage_CRC_Check crcCheck;
// setup the TIM pointers in pTIM_h
Retval = LoadTim((UINT8_T*)pTIM_h->pConsTIM, pTIM_h, TRUE);
if (Retval != NoError)
{
FatalError(Retval, "TDM", 1);
}
#if ENABLE_ATRB
Retval = TIMDownloadAntiRollbackCheck(pTIM_h);
if (Retval != NoError)
{
FatalError(Retval, "TDM", 2);
}
#endif
Retval = PlatformInitFlash(pTIM_h);
if( Retval != NoError)
FatalError(Retval, "TDM", 3);
#if IMG_RBC
pWRAH = FindPackageInReserved(&Retval, pTIM_h, CRCS);
if ((pWRAH == NULL) || (Retval != NoError))
{
DownloadReadBackCRC = IMAGE_READ_BACK_CRC_DISABLED;
}
else
{
crcCheck = (pImage_CRC_Check) pWRAH;
if(crcCheck->Enabled)
DownloadReadBackCRC = IMAGE_READ_BACK_CRC_ENABLED;
else
DownloadReadBackCRC = IMAGE_READ_BACK_CRC_DISABLED;
}
if(IMAGE_READ_BACK_CRC_ENABLED == DownloadReadBackCRC)
obm_printf("Image RB/CRC Enabled\n\r");
else
obm_printf("Image RB/CRC disabled\n\r");
#endif
ASRFlag_DLStatus_Update(pTIM_h, DLFLG, 0);
obm_printf("Download...\n\r");
// At this point, we can start downloading images one by one.
// IMPORTANT: For now, we download all the images to their load address that is
// specified in the TIM. We assume that the images will not overwrite the existing
// DKB code that is already running.
//
// KDA TO DO:
// Potentially, we might want to download all the images to a specific
// DOWNLOAD_AREAD in the DDR.
pImageInfo = DownloadTIMImages(pFuses, pTIM_h);
return pImageInfo;
}
UINT_T ValidateTIMInFBF(UINT_T address, PImageStruct_11 pTIM_Image, TIMIncluded_Type type, UINT_T verify_aux)
{
pTIM pTIM_h = NULL;
#if TRUSTED && SECURE_DOWNLOAD
pTIM pTIM_h_boot = NULL;
#endif
UINT_T Retval = NoError;
if (type == TIMH_NOTINC)
return NoError;
else
pTIM_h = (pTIM_DTIM + type);
Retval = SetTIMPointers((UINT8_T *)(address + (pTIM_Image->First_Sector << 12)), pTIM_h);
if (Retval != NoError)
return 1;
#if TRUSTED && SECURE_DOWNLOAD
if (verify_aux) {
switch(type) {
case DTIM_PRIMARY_INC:
case DTIM_RECOVERY_INC:
pTIM_h_boot = GetBootTIMH();
if (pTIM_h_boot == NULL)
return 4;
Retval = ValiateDTIM(pTIM_h, pTIM_h_boot);
if (Retval!= NoError)
return 5;
return NoError;
break;
case TIMH_RECOVERY_INC:
case TIMH_INC:
Retval = VerifyPlatformKey(pTIM_h);
if (Retval != NoError)
return 3;
break;
default:
break;
}
}
#endif
if (pTIM_h->pConsTIM->VersionBind.Trusted)
{
Retval = ValidateTIMSignature(pTIM_h); // validate TIMH
if (Retval != NoError)
return 2;
}
return Retval;
}
UINT_T ValidateImageInTIM(UINT_T address, PImageStruct_11 pImage, pTIM pTIM_h)
{
UINT_T Retval = NoError;
UINT_T ImageAddr;
#ifdef CONFIG_ASR_SDTIM
pIMAGE_INFO_3_4_0 pSDtimImageInfo = NULL;
pTIM pSDTim_h = NULL;
#endif
pIMAGE_INFO_3_4_0 pImageInfo = NULL;
pTIM pTIM_V = NULL;
UINT8_T *ImageBuff = NULL;
UINT_T ImageType;
UINT_T DecompressLen = 0;
#if XZ_SUPPORT || XZDEC_SUPPORT
VOID *nextInBuf = NULL;
INT_T compressed = 0;
#endif
if ((pTIM_h != NULL) && (pImage->Image_In_TIM != TIMH_NOTINC))
{
if ((pImage->Image_ID & 0xFFFFFF00) != TIM_TYPE) // this is not TIMx in FBF file
{
if (pTIM_h->pConsTIM->VersionBind.Trusted)
{
ImageAddr = address + (pImage->First_Sector << 12);
#ifdef CONFIG_ASR_SDTIM
pImageInfo = FindImageInTIM(pTIM_h, pImage->Image_ID);
if(pImageInfo == NULL)
return Retval;
if(ImageIsSDTIMIncluded(pImageInfo)) {
pSDTim_h = malloc(sizeof(TIM));
if(pSDTim_h == NULL)
return HeapExhaustedError;
Retval = SetTIMPointers(ImageAddr, pSDTim_h);
if(Retval)
return TIMNotFound;
pSDtimImageInfo = FindImageInTIM(pSDTim_h, SDTIM);
if(pSDtimImageInfo == NULL) {
free(pSDTim_h);
return Retval;
}
if (0 == GetSDTimSecureConfig(pSDtimImageInfo))
goto exit;
ImageAddr += GetSDTimSpaceSize(pSDtimImageInfo);
pTIM_V = pSDTim_h;
} else
#endif
{
pTIM_V = pTIM_h;
}
#if LZMA_SUPPORT
ImageType = IMAGE_TYPE(pImage->commands);
if (DLCMD_IMG_LZMA_IMAGE_TYPE == ImageType) {
pImageInfo = FindImageInTIM(pTIM_V, pImage->Image_ID);
if (pImageInfo == NULL)
{
Retval = ImageNotFound;
goto exit;
}
DecompressLen = pImageInfo->ImageSizeToHash;
ImageBuff = malloc(DecompressLen);
if(ImageBuff == NULL) {
Retval = HeapExhaustedError;
goto exit;
}
Retval = LZMA_Decompress(ImageBuff,
&DecompressLen,
ImageAddr,
pImage->length,
0x0);
if(Retval != NoError) {
obm_printf("LZMA Decompress error\n\r");
goto exit;
}
ImageAddr = ImageBuff;
}
#endif
#if XZ_SUPPORT || XZDEC_SUPPORT
ImageType = IMAGE_TYPE(pImage->commands);
if (DLCMD_IMG_MXZ_IMAGE_TYPE == ImageType) {
pImageInfo = FindImageInTIM(pTIM_V, pImage->Image_ID);
if (pImageInfo == NULL)
{
Retval = ImageNotFound;
goto exit;
}
ImageBuff = malloc(pImageInfo->ImageSizeToHash);
if(ImageBuff == NULL) {
Retval = HeapExhaustedError;
goto exit;
}
DecompressLen = pImageInfo->ImageSizeToHash;
Retval = xz_decompress(ImageAddr, pImage->length, ImageBuff, &DecompressLen, &nextInBuf, &compressed);
if(Retval) {
Retval = XZDecodeError;
goto exit;
}
ImageAddr = ImageBuff;
}
#endif
Retval = ValidateImage(ImageAddr, pImage->Image_ID, pTIM_V);
if (Retval != NoError)
FatalError(Retval, "VIIT", NULL);
return Retval;
}
}
}
exit:
#ifdef CONFIG_ASR_SDTIM
if(pSDTim_h) free(pSDTim_h);
#endif
return Retval;
}
UINT_T DLEraseFlashToBurnImage(PImageStruct_11 pImage_11)
{
UINT_T Retval = NoError;
P_FOTA_Info pFOTAInfo = &FOTAInfo;
#if MMC_CODE
if (((pImage_11->commands & 0xF) == 2) || //erase only for eMMC, NAND needs to erase before writing
(pImage_11->Flash_erase_size > pImage_11->length) // erase eMMC if user set erase size in blf
)
#endif
{
Retval = EraseFlash(pImage_11->Flash_Start_Address, pImage_11->Flash_erase_size, BOOT_FLASH );
if(AB_DL && (pImage_11->Flash_Start_Address_B != 0xFFFFFFFF))
Retval |= EraseFlash(pImage_11->Flash_Start_Address_B, pImage_11->Flash_erase_size, BOOT_FLASH );
}
if(Retval != NoError )
FatalError(Retval, "DLEF", NULL);
if(pFOTAInfo->FOTA_Addr >= pImage_11->Flash_Start_Address &&
(pFOTAInfo->FOTA_Addr+sizeof(FOTA_Firmware)) <= (pImage_11->Flash_Start_Address+pImage_11->Flash_erase_size))
{
//Force ASR flag re-init later.
pFOTAInfo->InitFlag = 0;
}
if(AB_DL && (pFOTAInfo->FOTA_Addr >= pImage_11->Flash_Start_Address_B) &&
(pFOTAInfo->FOTA_Addr+sizeof(FOTA_Firmware)) <= (pImage_11->Flash_Start_Address_B+pImage_11->Flash_erase_size))
{
//Force ASR flag re-init later.
pFOTAInfo->InitFlag = 0;
}
return Retval;
}
UINT_T DLBurnImageToFlash(PImageStruct_11 pImage_11, UINT_T loadAddr)
{
UINT_T Retval = NoError;
UINT_T imageType = DLCMD_RAW_BINARY_IMAGE_TYPE;
#if NZAS
P_FlashProperties_T pFlashP = GetFlashProperties(BOOT_FLASH);
UINT_T Temp1 = 0, Temp2 = 0, Len1, Len2;
#endif
#if DUAL_TIM
UINT8_T *TmpBuf = NULL;
pIMAGE_INFO_3_4_0 pTimInfo = NULL;
pIMAGE_INFO_3_4_0 pObmInfo = NULL;
UINT_T TimOBMLen = 0;
pTIM pTIM_h;
#endif
imageType = IMAGE_TYPE(pImage_11->commands);
#if NAND_CODE
if ( imageType == DLCMD_YAFFS_IMAGE_TYPE)
{
SetUseSpareArea( TRUE, BOOT_FLASH );
All_FF_flag = 1;
}
else if(imageType == DLCMD_UBIFS_IMAGE_TYPE)
{
SetUseSpareArea( FALSE, BOOT_FLASH);
All_FF_flag = 1;
}
else
{
SetUseSpareArea( FALSE, BOOT_FLASH );
All_FF_flag = 0;
}
#endif
#if MMC_CODE
if (imageType == DLCMD_SPARSE_IMAGE_TYPE)
{
Retval = HandleSparseImage(loadAddr+(pImage_11->First_Sector<<12),
pImage_11->Flash_Start_Address,
pImage_11->length,
BOOT_FLASH);
}
else
#endif
{ /* not MMC_CODE */
#if NZAC
//To workaroud the issue that 1802SL BootROM miss a word when OBM size is bigger than 0x1df88 in SPI-NOR
if(PlatformIsNezhac() && (pImage_11->Image_ID == OBMIDENTIFIER) && (pFlashP->FlashType == SPI_FLASH)
&& (pImage_11->length > 0x1df88))
{
Temp1 = loadAddr+(pImage_11->First_Sector<<12);
Temp2 = malloc(256*1024);
if(Temp2 == NULL)
return HeapExhaustedError;
Len1 = Len2 = pImage_11->length;
while(Len1)
{
memcpy((void *)Temp2, (void *)Temp1, 0x1df88);
Temp1 += 0x1df88;
Temp2 += 0x1df88;
*(UINT_T *)Temp2 = 0xdeadbeef;//This word will not be read by BootROM
Temp2 += 4;
Len2 += 4;
Len1 -= 0x1df88;
if(Len1 <= 0x1df88){
memcpy((void *)Temp2, (void *)Temp1, Len1);
break;
}
}
Retval = WriteFlash( pImage_11->Flash_Start_Address,
Temp2,
Len2, BOOT_FLASH );
free(Temp2);
goto read_back_check;
}
#endif /* NZAS */
#if DUAL_TIM
if((pImage_11->Image_ID == OBMIDENTIFIER) && DualTimEnabled() && !DualTimIsEqual())
{
pTIM_h = pTIM_DTIM + TIMH_INC; /* main TIMH */
if(pTIM_h->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER)
FatalError(TIMNotFound, "DLB", 1);
pTimInfo = FindImageInTIM(pTIM_h, TIMIDENTIFIER);
pObmInfo = FindImageInTIM(pTIM_h, OBMIDENTIFIER);
if(pTimInfo == NULL || pObmInfo == NULL)
FatalError(ImageNotFound, "DLB", 2);
TimOBMLen = pImage_11->length + pTimInfo->ImageSize;
#if MMC_CODE
if(TimOBMLen > MAX_OBM_SIZE)
#else
if(TimOBMLen > GetFlashProperties(BOOT_FLASH)->BlockSize)
#endif
obm_printf("Warning :OBM may be too big for Dual-TIM\n\r");
TmpBuf = malloc(TimOBMLen);
if(TmpBuf == NULL)
return HeapExhaustedError;
memset(TmpBuf, 0, TimOBMLen);
memcpy(TmpBuf, loadAddr+(pImage_11->First_Sector<<12), pImage_11->length);
#if MMC_CODE
if (pImage_11->Flash_partition == MMC_SD_BOOT_PARTITION) {
#else
if (pObmInfo->FlashEntryAddr == pImage_11->Flash_Start_Address) {
#endif
pTIM_h = pTIM_DTIM + TIMH_RECOVERY_INC;
memcpy(TmpBuf+pImage_11->length, pTIM_h->pConsTIM, pTimInfo->ImageSize);
}
else {
memcpy(TmpBuf+pImage_11->length, pTIM_h->pConsTIM, pTimInfo->ImageSize);
}
Retval = WriteFlash( pImage_11->Flash_Start_Address,
TmpBuf,
TimOBMLen, BOOT_FLASH);
free(TmpBuf);
} else if(pImage_11->Image_ID == TIMIDENTIFIER &&
pImage_11->Image_In_TIM == TIMH_RECOVERY_INC &&
DualTimIsEqual())
{
pTIM_h = pTIM_DTIM + TIMH_INC; /* main TIMH */
Retval = WriteFlash( pImage_11->Flash_Start_Address,
pTIM_h->pConsTIM,
pImage_11->length, BOOT_FLASH);
}else
#endif
{
Retval = WriteFlash( pImage_11->Flash_Start_Address,
loadAddr+(pImage_11->First_Sector<<12),
pImage_11->length, BOOT_FLASH);
if(AB_DL && (pImage_11->Flash_Start_Address_B != 0xFFFFFFFF)) {
Retval |= WriteFlash( pImage_11->Flash_Start_Address_B,
loadAddr+(pImage_11->First_Sector<<12),
pImage_11->length, BOOT_FLASH);
}
}
read_back_check:
#if IMG_RBC
if(Retval == NoError && DownloadReadBackCRC == IMAGE_READ_BACK_CRC_ENABLED)
{
Retval = ImageReadBackAndCRC(pImage_11);
}
#else
; //do nothing, avoid "label at end of compound statement" error
#endif
} /* not MMC_CODE */
return Retval;
}
//////////////////////////////////////////////////////////////////////
// This is the actual image downloading function for the TIM based
// download mode.
//
// Inputs: TIM which includes a list of all the images that will be
// downloaded.
// Outputs: Returns the OBM image to whom we will trasfer control to.
//
// It mainly iterates through all the images listed in the TIM and
// 1) If NOT TIM, downloads the image.
// 2) Validates the image.
// 3) Calls the Erase and Write function for this image.
// 4) Finally, finds the OBM image in the TIM and returns it.
//////////////////////////////////////////////////////////////////////
pIMAGE_INFO_3_4_0 DownloadTIMImages (pFUSE_SET pFuses, pTIM pTIM_h)
{
UINT_T Retval = NoError;
UINT_T ImageSize;
pIMAGE_INFO_3_4_0 pImageInfo = NULL, pNextImageInfo = NULL;
UINT_T NumImages;
UINT_T loadAddr = 0;
UINT_T OKtoErase = 1;
MasterBlockHeader* pMasterHeader = NULL;
PDeviceHeader_11 pDevHeader_11=NULL;
PImageStruct_11 pImage_11 = NULL;
UINT_T imagenum, i, skip_blocks;
UINT_T temp_p = NULL;
UINT_T NandID_Right;
UINT_T OBMFlashAddr;
P_FOTA_Info pFOTAInfo = &FOTAInfo;
INT_T TIMHLoaded = 0;
CHAR MVersionStr[128];
CHAR *PStr = NULL;
INT_T MVersionInFbf = 0;
P_FOTA_Firmware pFOTA_T = NULL;
// Depending on the version of the TIM, determine the size of each image in bytes.
// We will use this size to iterate through the TIM binary from image to image.
if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_4_00)
ImageSize = sizeof(IMAGE_INFO_3_4_0);
else
ImageSize = sizeof(IMAGE_INFO_3_2_0);
// This is the very initial TIM image! Assumes that the TIM image is located at the top of the
// TIM file. Otherwise, we would skip images.
NumImages = pTIM_h->pConsTIM->NumImages;
pImageInfo = (IMAGE_INFO_3_4_0*)((unsigned char*)pTIM_h->pImg + (NumImages-1)*ImageSize); // index to last image info record.
// For each image, download, validate and copy
while (NumImages && (Retval == NoError))
{
if (NumImages > 1)
{
loadAddr = malloc(pImageInfo->ImageSize + 0x20000);
if(loadAddr == 0)
return HeapExhaustedError;
Retval = PM_ReceiveImage(NULL, loadAddr, pImageInfo->ImageSize, pImageInfo->ImageID);
if(Retval == UnknownImageError)
{
Retval = NoError;
goto nextimage;
}
if (Retval != NoError)
FatalError(Retval, "DTI", 1);
}
else loadAddr = (UINT_T)(pTIM_h->pConsTIM); // first image, TIM. use the address provided by caller.
#if COPYIMAGESTOFLASH
if(pImageInfo->FlashEntryAddr == 0xFFFFFFFF)
goto nextimage;
// Copy the Image
AddMessageError(REPORT_NOTIFICATION, PlatformBusy);
if ((pImageInfo->ImageID & 0xFFFFFF00) == FBFIDENTIFIER0)
{
Retval = PlatfromFBFBoundaryScan(pImageInfo);
if (Retval != NoError)
FatalError(Retval, "DTI", 2);
pMasterHeader = (MasterBlockHeader*)loadAddr;
if ((pMasterHeader->Format_Version != 11))
FatalError(FBF_VersionNotMatch, "DTI", 3);
if (pMasterHeader->nOfDevices != 1)
FatalError(FBF_DeviceMoreThanOne, "DTI", 4);
temp_p = pMasterHeader->deviceHeaderOffset[0] + loadAddr;
pDevHeader_11 = (PDeviceHeader_11)temp_p;
AB_DL = pDevHeader_11->DeviceParameters[2];
if(AB_DL)
obm_printf("AB system Downloading\n\r");
Retval = PlatformFBFCheckSWDVersion(pDevHeader_11);
if(Retval != NoError)
FatalError(Retval, "DTI", 5);
// check nand ID
#if NAND_CODE
NandID_Right = pDevHeader_11->FlashOpt.NandID;
obm_printf("NandID: 0x%x\n\r", NandID);
if (NandID_Right != 0xFFFF && NandID != NandID_Right)
{
#if (!NEZHA701)
FatalError(NANDIDDISMATCH, "DTI", 6);
#endif
}
for ( imagenum = 0; imagenum < pDevHeader_11->nOfImages; imagenum++ )
{
temp_p = (UINT_T)&pDevHeader_11->imageStruct_11[imagenum];
pImage_11 = (PImageStruct_11)temp_p;
if(pImage_11->Image_ID == OBMIDENTIFIER) //OBMI
{
OBMFlashAddr = pImage_11->Flash_Start_Address;
//To word around the issue that BootROM disable sprare area
DisableSpareAreaForOBM(pImage_11->Flash_Start_Address, pImage_11->length);
}
}
#endif
#if SPINOR_CODE
AddMessageError(REPORT_FLASH_SIZE_NOTIFICATION, Flash_size);
#endif
// skip blocks
skip_blocks = pDevHeader_11->FlashOpt.Skip_Blocks_Struct.Total_Number_Of_SkipBlocks;
if (skip_blocks > 0)
pSkipAddress = &pDevHeader_11->FlashOpt.Skip_Blocks_Struct;
else
pSkipAddress = NULL;
// productMode = pDevHeader_11->ProductMode;
Reset = pDevHeader_11->OptValue;
/* Check if FBF package is right for this platform */
PlatformFBFCheckDownload(pTIM_h, pDevHeader_11);
pTIM_DTIM = (TIM *)malloc(DTIM_CUSTMOZIED_MAX*sizeof(TIM));
if ( pTIM_DTIM == NULL )
return HeapExhaustedError;
memset(pTIM_DTIM, 0, DTIM_CUSTMOZIED_MAX*sizeof(TIM));
// find out all TIMH and DTIM for secured download)
for (imagenum = 0; imagenum < pDevHeader_11->nOfImages; imagenum++)
{
temp_p = (UINT_T)&pDevHeader_11->imageStruct_11[imagenum];
pImage_11= (PImageStruct_11)temp_p;
if (!ImageIsTIM(pImage_11->Image_ID))
continue;
switch (pImage_11->Image_In_TIM)
{
case TIMH_NOTINC: /* NTIM */
break;
case TIMH_INC: /* TIMH */
TIMHLoaded = 1;
case TIMH_RECOVERY_INC: /* backup TIMH */
default: /* Other TIMs */
Retval = ValidateTIMInFBF(loadAddr, pImage_11, pImage_11->Image_In_TIM, pFuses->bits.SBE);
if (Retval != NoError) {
ASRFlag_DLStatus_Update(pTIM_h, 0, 0);
FatalError(InvalidTIMImageError, "VTIF", Retval);
}
break;
}
}
if (OKtoErase)
{
if (pDevHeader_11->FlashOpt.EraseAll == 2) // erase all flash partition without burning
{
#if PRODUCT_BUILD
if (pFuses->bits.SBE == 1) {
ASRFlag_DLStatus_Update(pTIM_h, 0, 0);
FatalError(NotSupportedError, "DTI", 12);
}
#endif
AddMessageError(REPORT_NOTIFICATION, PlatformEraseAllFlashWithoutBurn); // notify SWD
Retval = EraseAllFlashWithoutBurn(BOOT_FLASH);
if (Retval != NoError)
{
FatalError(Retval, "DTI", 7);
}
//Force ASR flag re-init later.
pFOTAInfo->InitFlag = 0;
AddMessageError(REPORT_NOTIFICATION, PlatformEraseAllFlashWithoutBurnDone); // notify SWD
AddMessageError(REPORT_NOTIFICATION, PlatformReady);
break;
}
// check erase all flag
if (pDevHeader_11->FlashOpt.EraseAll == 1) // erase user partition with burning
{
// check reset BBT flag
if (pDevHeader_11->FlashOpt.ResetBBT)
{
AddMessageError(REPORT_NOTIFICATION, PlatformResetBBT); // notify SWD that OBM/flasher will reset BBT
ResetBBT();
//After BBT is reset, OBM start address need to be updated, too.
#if NAND_CODE //To word around the issue that BootROM disable sprare area
DisableSpareAreaForOBM(OBMFlashAddr, 0);
#endif
}
AddMessageError(REPORT_NOTIFICATION, PlatformEraseAllFlash); // notify SWD that OBM/flasher will erase all flash
Retval = EraseAllFlash(BOOT_FLASH);
if (Retval != NoError)
{
FatalError(Retval, "DTI", 8);
}
//Force ASR flag re-init later.
pFOTAInfo->InitFlag = 0;
OKtoErase = 0;
AddMessageError(REPORT_NOTIFICATION, PlatformEraseAllFlashDone); // notify SWD that OBM/flasher erases all flash done
}
}
for ( imagenum = 0; imagenum < pDevHeader_11->nOfImages; imagenum++ )
{
temp_p = (UINT_T)&pDevHeader_11->imageStruct_11[imagenum];
pImage_11 = (PImageStruct_11)temp_p;
#if TRUSTED && SECURE_DOWNLOAD
if (pFuses->bits.SBE)
{
switch (pImage_11->Image_In_TIM)
{
case TIMH_NOTINC:
break;
default:
ValidateImageInTIM(loadAddr, pImage_11, (pTIM_DTIM + pImage_11->Image_In_TIM));
break;
}
}
#endif
if(pImage_11->Image_ID == FOTA_FBFVERSION_IMAGEID)
{
memset(MVersionStr, 0, 128);
PStr = (CHAR *)( loadAddr + (pImage_11->First_Sector << 12) );
if(strcmpl(PStr, "OTA0", 4) == 0) {
PStr += 4;
for( i = 0; i < 128 && *PStr != ';'; i++)
MVersionStr[i] = *PStr++;
if(i < 128) {
MVersionInFbf = 1;
obm_printf("Download to: %s\n\r", MVersionStr);
}
}
continue;
}
#if MMC_CODE
if((pTIM_h->pConsTIM->VersionBind.Version) >= TIM_3_2_00)
{
Retval = SetPartition(pImage_11->Flash_partition, BOOT_FLASH);
if (Retval != NoError)
{
FatalError(Retval, "DTI", 9);
}
}
#endif
if(OKtoErase && (pImage_11->commands & DLCMD_DO_ERASE_BLOCKS) )
{
Retval = DLEraseFlashToBurnImage(pImage_11);
}
//if ((pImage_11->commands & 0xF) == 2) //erase only
// continue;
if(pImage_11->commands & DLCMD_DO_VERIFY_WRITE) {
if (!IsDLImageDTIM(pImage_11)) {
Retval = DLBurnImageToFlash(pImage_11, loadAddr);
if(Retval != NoError )
FatalError(Retval, "DTI", 10);
AddMessageError(REPORT_BURNT_IMAGE_LENGTH, pImage_11->length); // report burnt image length
}
#if BURN_DTIM_LAST
else{
SaveDTIMs2Memory(pImage_11, loadAddr);
}
#endif
}
}
#if IMG_RBC
if(DownloadReadBackCRC == IMAGE_READ_BACK_CRC_ENABLED){
DownloadReadBackCRC = IMAGE_READ_BACK_CRC_DONE;
AllImageCRCInfo.MCPID = ((NandID & 0xFF) << 16) | (ddr_id_update_with_crc & 0xFF);
}
#endif
if (TIMHLoaded) { /* TIMH is loaded and parsed in pTIM_DTIM */
Retval = ProvisionPlatform(pFuses, pTIM_DTIM + TIMH_INC);
// If ProvisionPlatform() returned an error, this means that an error occurred
// during fuse burning. So stop booting and go to Fatal Error.
if (Retval != NoError)
{
FatalError(Retval, "DTI", 11);
}
TIMHLoaded = 0;
}
} /* FBF */
pNextImageInfo = (IMAGE_INFO_3_4_0*)((unsigned char*)pImageInfo - ImageSize);
/* Last FBF is handled, update DL flag as DLDONE */
if (NumImages == 2 /* FBF0(current) and TIMH, */
&& pNextImageInfo->ImageID == TIMIDENTIFIER) {
#if BURN_DTIM_LAST
BurnDTIMs2Flash();
#endif
if(MVersionInFbf == 1) {
pFOTA_T = OTAGetConfig(pTIM_h);
memset(pFOTA_T->MVersion, 0, sizeof(pFOTA_T->MVersion));
memcpy(pFOTA_T->MVersion, MVersionStr, strlen(MVersionStr));
#ifdef CONFIG_AB_SYSTEM
memset(pFOTA_T->MVersion_B, 0, sizeof(pFOTA_T->MVersion_B));
memcpy(pFOTA_T->MVersion_B, MVersionStr, strlen(MVersionStr));
#endif
}
ASRFlag_DLStatus_Update(pTIM_h, DLFLG, DLDONE);
free(pTIM_DTIM);
UpdateBBT();
}
AddMessageError(REPORT_NOTIFICATION, PlatformReady);
#endif /* end of COPYIMAGESTOFLASH */
nextimage:
NumImages--;
pImageInfo = (IMAGE_INFO_3_4_0*)((unsigned char*)pImageInfo - ImageSize); // index to previous image info record.
if(NumImages != 0)
free(loadAddr);
loadAddr = 0;
} // end WHILE
#if NAND_CODE
SetUseSpareArea( FALSE, BOOT_FLASH );
#endif
UpdateBBT();
#if SPINOR_CODE
SPINOR_Disable4BytesMode();
#endif
return NULL;
}
INT_T ImageReadBackAndCRC(PImageStruct_11 pImage_11)
{
UINT_T * Buffer = NULL;
INT_T Retval = NoError;
UINT_T Len = 0;
#if NZAC
UINT_T Temp1 = 0, Temp2 = 0;
P_FlashProperties_T pFlashP = GetFlashProperties(BOOT_FLASH);
#endif
if(DownloadReadBackCRC != IMAGE_READ_BACK_CRC_ENABLED){
return NotSupportedError;
}
if(AllImageCRCInfo.ImageNum >= CRC_MAX_IMAGE_NUM)
{
obm_printf("No more CRC buffer for 0x%08x\n\r", pImage_11->Image_ID);
return NotSupportedError;
}
if(DTIM_PPSETTING == pImage_11->Image_ID)
{
AllImageCRCInfo.ImageCRC[AllImageCRCInfo.ImageNum].ImageID = pImage_11->Image_ID;
//CRC of DTim.PPsetting
AllImageCRCInfo.ImageCRC[AllImageCRCInfo.ImageNum].CRC32 = 0xc3751676;
AllImageCRCInfo.ImageNum++;
return Retval;
}
Len = pImage_11->length;
#if NZAC
if(PlatformIsNezhac() && (pImage_11->Image_ID == OBMIDENTIFIER) && (pFlashP->FlashType == SPI_FLASH)
&& (pImage_11->length > 0x1df88))
Len += (pImage_11->length/0x1df88)*4;
#endif
Buffer = malloc(Len);
if(Buffer == NULL)
return HeapExhaustedError;
Retval = ReadFlash( pImage_11->Flash_Start_Address, Buffer, Len, BOOT_FLASH);
if(Retval != NoError){
DownloadReadBackCRC = IMAGE_READ_BACK_CRC_FAIL;
free(Buffer);
return Retval;
}
#if NZAC
//To workaroud the issue that 1802SL BootROM miss a word when OBM size is bigger than 0x1df88 in SPI-NOR
if(PlatformIsNezhac() && (pImage_11->Image_ID == OBMIDENTIFIER) && (pFlashP->FlashType == SPI_FLASH)
&& (pImage_11->length > 0x1df88))
{
Len = pImage_11->length;
Temp1 = Buffer;
Temp2 = malloc(256*1024);
if(Temp2 == NULL)
return HeapExhaustedError;
while(Len)
{
memcpy((void *)Temp2, (void *)Temp1, 0x1df88);
Temp1 += 0x1df88;
Temp2 += 0x1df88;
Temp1 += 4; //Ignore the extra word added to workaourd BootROM SPINOR read issue
Len -= 0x1df88;
if(Len <= 0x1df88){
memcpy((void *)Temp2, (void *)Temp1, Len);
break;
}
}
Buffer = Temp2;
}
#endif
AllImageCRCInfo.ImageCRC[AllImageCRCInfo.ImageNum].ImageID = pImage_11->Image_ID;
AllImageCRCInfo.ImageCRC[AllImageCRCInfo.ImageNum].CRC32 = CalcCRC32(Buffer, pImage_11->length, 0xFFFFFFFF);
AllImageCRCInfo.ImageNum++;
if(AB_DL && (pImage_11->Flash_Start_Address_B != 0xFFFFFFFF))
{
Retval = ReadFlash( pImage_11->Flash_Start_Address_B, Buffer, Len, BOOT_FLASH);
if(Retval != NoError){
DownloadReadBackCRC = IMAGE_READ_BACK_CRC_FAIL;
#if NZAC
if(Temp2) free(Temp2);
#endif
free(Buffer);
return Retval;
}
AllImageCRCInfo.ImageCRC[AllImageCRCInfo.ImageNum].ImageID = pImage_11->Image_ID;
AllImageCRCInfo.ImageCRC[AllImageCRCInfo.ImageNum].CRC32 = CalcCRC32(Buffer, pImage_11->length, 0xFFFFFFFF);
AllImageCRCInfo.ImageNum++;
}
#if NZAC
if(Temp2) free(Temp2);
#endif
free(Buffer);
return Retval;
}
INT_T GetImageReadBackCrcBuffer(UINT_T *BufferAddr, INT_T *BufferLen)
{
int i;
if(DownloadReadBackCRC != IMAGE_READ_BACK_CRC_DONE)
{
return CRCFailedError;
}
*BufferAddr = (UINT_T)(&AllImageCRCInfo);
*BufferLen = sizeof(ImageCRCInfo);
return NoError;
}