blob: fdf8273f9fd597f6d3e16e84de03cb23bf53fa8d [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.
*
******************************************************************************
*
*
* FILENAME: BootMode.c
*
* PURPOSE: Contains BootLoader's BootMode Code. Mainly handles the
* SINGLE and DUAL TIM MODE boot functions.
*
******************************************************************************/
//////////////////////////////////////////////////////////////////////
// Library Support for the BootMode.c
// Include any shared libraries in the BootMode.h file to keep this
// code clean.
//////////////////////////////////////////////////////////////////////
#include "BootMode.h"
#include "loadoffsets.h"
#include "obm2osl.h"
#if LZMA_SUPPORT
#include "LzmaDecode.h"
#endif
pIMAGE_INFO_3_4_0 pNextImageToTransferTo = NULL; // the next image we want to transfer control to
pIMAGE_INFO_3_4_0 pImageNsEntry = NULL;
extern OBM2OSL *pOBM2OSL_h;
extern UINT8_T FlashInitDone;
//////////////////////////////////////////////////////////////////////
// This is the entry point for the Boot Mode.
//
// Inputs: Current TIM pointer, BootMode(SINGLE or DUAL)
// Outputs: Returns the next image that we will transfer the control to.
//
// It mainly functions as following depending on the BOOT MODE:
// 1) SINGLE TIM BOOT MODE:
// a) Configures the Flashes and Initializes the Flash Management
// b) Loads (and validates) all the images using a loop.
// c) If TRUSTED, provisions the platform before finishing
// d) Returns the next image that we will transfer the control to.
// 2) DUAL TIM BOOT MODE:
// a) Configures the Flashes and Initializes the Flash Management
// b) Loads (and validates) the second TIM.
// c) Configures the Flashes and Initializes the Flash Management
// using the new TIM.
// d) Loads (and validates) all the images using a loop.
// e) If TRUSTED, provisions the platform before finishing
// f) Returns the next image that we will transfer the control to.
//////////////////////////////////////////////////////////////////////
pIMAGE_INFO_3_4_0 BootModeMain(pTIM pTIM_h, OPERATING_MODE_T BootMode, pFUSE_SET pFuses)
{
UINT_T Retval = NoError;
pIMAGE_INFO_3_4_0 pBootImageInfo = NULL;
Retval = PlatformInitFlash(pTIM_h);
if( Retval != NoError)
FatalError(Retval, "BMM", 1);
#if ENABLE_MMU
EnableDataCache();
#endif
#if TRUSTED
DisplayFuses();
#endif
#if EMMD_SUPPORT
if (PlatformCheckEMMDStatus()) {
pBootImageInfo = LoadAllImages(pFuses, pTIM_h);
#if ENABLE_MMU
DisableDataCache();
#endif
return pBootImageInfo;
}
#endif
PlatformReleaseEMMDStatus();
Retval = fota_upgrade(pTIM_h, pFuses);
obm_printf("FOTA return: 0x%x\n\r", Retval);
if (Retval == NoError)
{
PlatformReleaseEMMDStatus();
PlatformSetFOTAFlag();
do_wdt_reset();
}
else
{
pBootImageInfo = LoadAllImages(pFuses, pTIM_h);
}
#if TRUSTED
Retval = ProvisionPlatform(pFuses, pTIM_h);
// 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, "BMM", 2);
}
#endif
#if ENABLE_MMU
DisableDataCache();
#endif
return pBootImageInfo;
}
//////////////////////////////////////////////////////////////////////
// This function mainly loads ALL the images available in the TIM
// (except TIM, DUALTIM, and OBM) and validates them.
// It essentially returns the next image that we will transfer the
// control to.
//
// Inputs: Current TIM pointer, BootMode(SINGLE or DUAL)
// Outputs: Returns the next image that we will transfer the control to.
//////////////////////////////////////////////////////////////////////
pIMAGE_INFO_3_4_0 LoadAllImages(pFUSE_SET pFuses, pTIM pTIM_h)
{
UINT_T Retval = NoError, decompressLength;
UINT_T ImageID = 0; // Initialize it as an invalid image
UINT_T ImageIndex, ImageSize;
pIMAGE_INFO_3_4_0 pImageInfo = NULL;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
pTransfer_Info_PACKAGE pInfo = NULL;
UINT_T i;
OBM2OSL_Init(pFuses, pTIM_h);
// no need to validate TIM since it's validated by BootROM already
// 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.
pImageInfo = pTIM_h->pImg;
// Read in the number of images from the TIM and iterate through each of these images.
// We load them and we validate them.
for( ImageIndex = 0; ImageIndex < pTIM_h->pConsTIM->NumImages; ImageIndex++ )
{
// We skip the TIM, DUALTIM, and OBM images. We load/validate all the others.
if( (pImageInfo->ImageID != TIMIDENTIFIER) &&
(pImageInfo->ImageID != OBMIDENTIFIER) &&
(pImageInfo->ImageID != OBM2IDENTIFIER) &&
(pImageInfo->ImageID != TZIIDENTIFIER) &&
(pImageInfo->ImageID != OUMIDENTIFIER) &&
(pImageInfo->LoadAddr != 0xFFFFFFFF)
)
{
Retval = Loadimage(pImageInfo, pFuses, pTIM_h, 0);
if(Retval != NoError) {
obm_printf("Load %s error: 0x%x\n\r", ImageID2String(pImageInfo->ImageID), Retval);
pImageInfo = (IMAGE_INFO_3_4_0*)((UCHAR *)pImageInfo + ImageSize);
continue;
}
switch(pImageInfo->ImageID)
{
case TZSWIDENTIFIER:
obm_printf("Trusted OS in TIM\n\r");
pNextImageToTransferTo = pImageInfo;
break;
case OSLOADERID:
obm_printf("Uboot in TIM\n\r");
if(pNextImageToTransferTo == NULL)
pNextImageToTransferTo = pImageInfo;
if(pImageNsEntry == NULL)
pImageNsEntry = pImageInfo;
break;
}
}
#if SPINOR_CODE
if (pImageInfo->ImageID == TIMIDENTIFIER)
{
TransCITA_2_OBM2OSLO(pTIM_h, pOBM2OSL_h);
}
#endif
// Get a pointer to the next image we will load.
// For the last iteration (e.g. after the last image), we won't find an image.
// However, this is OK because pImageInfo is not used again.
pImageInfo = (IMAGE_INFO_3_4_0*)((UCHAR *)pImageInfo + ImageSize);
}
// system needs to boot up if there is no IMAP
LoadImagesOTA(pFuses, pTIM_h);
if(pNextImageToTransferTo == NULL) {
obm_printf("No Next Image to transfer to\n\r");
FatalError(ImageNotFound, "LAI", NULL);
}
#if SPINOR_CODE
SPINOR_Disable4BytesMode();
#endif
return pNextImageToTransferTo;
}
unsigned int GetNsEntryLoadAddress()
{
unsigned int addr = 0;
if(pImageNsEntry)
addr = pImageNsEntry->LoadAddr;
return addr;
}
INT_T Loadimage(pIMAGE_INFO_3_4_0 pImageInfo, pFUSE_SET pFuses, pTIM pTIM_h, INT_T TimType)
{
UINT_T Retval = NoError;
UINT_T offset;
UINT_T decompressLength;
UINT_T imgValidate = 1;
UINT_T AB_system = 0;
#ifdef CONFIG_AB_SYSTEM
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
pABSP_INFO pABSP_info = NULL;
AB_system = 1;
#endif
#if MMC_CODE
if((pTIM_h->pConsTIM->VersionBind.Version) >= TIM_3_2_00)
{
SetPartition(pImageInfo->PartitionNumber.bits.PartitionNumber, BOOT_FLASH);
}
#endif
#ifdef CONFIG_AB_SYSTEM
if(TimType == RecoveryImage) {
pWRAH = FindPackageInReserved (&Retval, pTIM_h, ABSPID);
if (Retval != NoError) {
obm_printf("ABSP Package Not Found\n\r");
return ImageLoadError;
}
pABSP_info = (pABSP_INFO) pWRAH;
offset = pImageInfo->PartitionNumber.bits.Reserved << pABSP_info->FlashAddrShift;
#if MMC_CODE
offset /= 512;
#endif
} else
#endif
{
offset = pImageInfo->FlashEntryAddr;
}
#ifdef CONFIG_ASR_SDTIM
TIM *pSDTIM_h = NULL;
CHAR *SDTimBuf = NULL;
pIMAGE_INFO_3_4_0 pSdtimImageInfo = NULL;
if (ImageIsSDTIMIncluded(pImageInfo)) {
SDTimBuf = malloc(SDTIM_MAX_SIZE);
pSDTIM_h = malloc(sizeof(TIM));
if(SDTimBuf == NULL || pSDTIM_h == NULL)
return HeapExhaustedError;
Retval = ReadFlash(offset, SDTimBuf, SDTIM_MAX_SIZE, BOOT_FLASH);
if(Retval != NoError) {
free(SDTimBuf); free(pSDTIM_h);
return ImageLoadError;
}
Retval = SetTIMPointers( SDTimBuf, pSDTIM_h);
if(Retval)
return ImageLoadError;
pSdtimImageInfo = FindImageInTIM(pSDTIM_h, SDTIM);
if(pSdtimImageInfo == NULL) {
free(SDTimBuf); free(pSDTIM_h);
return ImageLoadError;
}
imgValidate = GetSDTimSecureConfig(pSdtimImageInfo);
#if MMC_CODE
offset += GetSDTimSpaceSize(pSdtimImageInfo)/512;
#else
offset += GetSDTimSpaceSize(pSdtimImageInfo);
#endif
pImageInfo = FindImageInTIM(pSDTIM_h, pImageInfo->ImageID);
if(pImageInfo == NULL) {
free(SDTimBuf); free(pSDTIM_h);
return ImageLoadError;
}
} else {
pSDTIM_h = pTIM_h; /* old way, SDTIM and DTIM is equal */
}
#endif
#if LZMA_SUPPORT
if (pImageInfo->PartitionNumber.bits.ImageType == DLCMD_IMG_LZMA_IMAGE_TYPE)
{
UINT_T *DecompressBuff = NULL;
DecompressBuff = malloc(pImageInfo->ImageSizeToHash);
if(DecompressBuff == NULL)
return HeapExhaustedError;
if(PlatformCheckEMMDStatus() == 1) {
decompressLength = DECOMPRESS_LENGTH_RDP; /* TODO */
} else {
decompressLength = DECOMPRESS_LENGTH;
}
Retval = ReadFlash(offset, DecompressBuff, pImageInfo->ImageSize, BOOT_FLASH);
if (Retval != NoError)
{
free(DecompressBuff);
obm_printf("%s Load Error: 0x%x\n\r", ImageID2String(pImageInfo->ImageID), Retval);
return ImageLoadError;
}
decompressLength = DECOMPRESS_LENGTH;
Retval = LZMA_Decompress((UINT_T *)pImageInfo->LoadAddr,
&decompressLength,
(UINT_T *)DecompressBuff,
pImageInfo->ImageSize,
0x0);
if (Retval != NoError)
{
free(DecompressBuff);
obm_printf("%s LZMA decompress Error: 0x%x\n\r", ImageID2String(pImageInfo->ImageID), Retval);
return ImageLoadError;
}
free(DecompressBuff);
goto img_validate;
}
#endif
#if XZ_SUPPORT || XZDEC_SUPPORT
if (pImageInfo->PartitionNumber.bits.ImageType == DLCMD_IMG_MXZ_IMAGE_TYPE) {
CHAR *DecompressBuff = NULL;
UINT_T outLen = 0x2000000; /* 32MB */
CHAR *inBuf, *inEnd, *outBuf, *outEnd;
VOID *nextInBuf = NULL;
INT compressed = 0;
UINT_T i = 0;
UINT_T outSize;
DecompressBuff = malloc(pImageInfo->ImageSizeToHash);
if(DecompressBuff == NULL)
return HeapExhaustedError;
Retval = ReadFlash(offset, (UINT_T)DecompressBuff, pImageInfo->ImageSize, BOOT_FLASH);
if (Retval != NoError)
{
free(DecompressBuff);
obm_printf("%s Load Error: 0x%x\n\r", ImageID2String(pImageInfo->ImageID), Retval);
return ImageLoadError;
}
inBuf = DecompressBuff;
inEnd = DecompressBuff + pImageInfo->ImageSize;
outBuf = (CHAR *)pImageInfo->LoadAddr;
outEnd = (CHAR *)(pImageInfo->LoadAddr + outLen);
//obm_printf("Image info: 0x%x 0x%x 0x%x\n\r", pImageInfo->LoadAddr, pImageInfo->ImageSize, pImageInfo->ImageSizeToHash);
while (inBuf != inEnd)
{
outSize = outEnd - outBuf;
Retval = xz_decompress(inBuf, inEnd - inBuf,
outBuf, &outSize,
&nextInBuf, &compressed);
if (Retval)
{
FatalError(XZDecodeError, "LI", NULL);
}
if(!compressed)
break;
//obm_printf("MXZ dec loop: %d 0x%x\n\r", i, outSize);
++i;
outBuf += outSize;
inBuf = (CHAR *) nextInBuf;
}
free(DecompressBuff);
goto img_validate;
}
#endif
Retval = ReadFlash(offset, pImageInfo->LoadAddr, pImageInfo->ImageSize, BOOT_FLASH);
if (Retval != NoError)
return ImageLoadError;
img_validate:
if (imgValidate || AB_system)
{
#ifdef CONFIG_ASR_SDTIM
Retval = ValidateImage(pImageInfo->LoadAddr, pImageInfo->ImageID, pSDTIM_h);
if(SDTimBuf) free(SDTimBuf);if(pSDTIM_h) free(pSDTIM_h);
#else
Retval = ValidateImage(pImageInfo->LoadAddr, pImageInfo->ImageID, pTIM_h);
#endif
if (Retval != NoError){
obm_printf("%s Validation Error: 0x%x\n\r", ImageID2String(pImageInfo->ImageID), Retval);
return ImageValidationError;
}
}
return Retval;
}
#if 0 /* Deprecated */
//////////////////////////////////////////////////////////////////////
// This function loads uboot only for EMMD
//////////////////////////////////////////////////////////////////////
pIMAGE_INFO_3_4_0 LoadUboot(pFUSE_SET pFuses, pTIM pTIM_h)
{
pIMAGE_INFO_3_4_0 pImageInfo = NULL;
OBM2OSL_Init(pFuses, pTIM_h);
#if QSPINOR_CODE
TransCITA_2_OBM2OSLO(pTIM_h, pOBM2OSL_h);
ASRFlag_ParseCfgToOBM2OSLO(pTIM_h);
#endif
pImageInfo = FindImageInTIM(pTIM_h, OSLOADERID);
if (pImageInfo != NULL)
{
pNextImageToTransferTo = pImageInfo;
Loadimage(pImageInfo, pFuses, pTIM_h, 0);
}
else
{
LoadUbootOTA(pFuses, pTIM_h);
}
// Return the OSLO image.
return pNextImageToTransferTo;
}
#endif