blob: bb595f1cbfe62cfdd1f3d25dc696112c4654618f [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.
*
******************************************************************************/
///////////////////////////////////////////////////////////////////
// Over-The-Air Related Functions
///////////////////////////////////////////////////////////////////
#include "LoadImagesOTA.h"
#include "obm2osl.h"
#include "loadoffsets.h"
#include "fota.h"
#if LZMA_SUPPORT
#include "LzmaDecode.h"
#endif
extern pIMAGE_INFO_3_4_0 pNextImageToTransferTo;
extern pIMAGE_INFO_3_4_0 pImageNsEntry;
extern OBM2OSL *pOBM2OSL_h;
TIM PDTIM_h;
#ifdef CONFIG_AB_SYSTEM
UINT_T DTIM_GetABSystemType(pIMG_MAP_INFO pImgMapInfo, pTIM pTIM_h)
{
UINT_T ImageType;
UINT_T AB = 0;
if(pImgMapInfo) {
ImageType = pImgMapInfo->ImageType;
switch(ImageType) {
case 10 ... 50:
if((ImageType % 2) == 1)
AB = 1;
break;
case 4: /* PPSetting_B */
case 1: /* DTIM.recovery */
AB = 1;
break;
}
}
return AB; /* 0: belong to system A, 1: belong to B */
}
#endif
#ifdef CONFIG_ASR_SDTIM
UINT_T LoadAllSDTIM(pFUSE_SET pFuses, pTIM pTIM_h, pTIM pDTIM_h, UINT_T AB)
{
#if TRUSTED || defined(CONFIG_AB_SYSTEM)
UINT_T Retval = NoError;
UINT_T ImageIndex = 0, ImageSize;
pIMAGE_INFO_3_4_0 pImageInfo = NULL;
UINT_T offset;
pImageInfo = pDTIM_h->pImg;
ImageSize = sizeof(IMAGE_INFO_3_4_0);
UINT_T *SDTimBuf = NULL;
TIM *pSDTIM_h = NULL;
if (pTIM_h->pConsTIM->VersionBind.Trusted == 0)
return NoError;
pSDTIM_h = malloc(sizeof(TIM));
SDTimBuf = malloc(SDTIM_MAX_SIZE);
if(SDTimBuf == NULL || pSDTIM_h == NULL)
return HeapExhaustedError;
for (ImageIndex = 0; ImageIndex < pDTIM_h->pConsTIM->NumImages; ImageIndex++)
{
if(ImageIsSDTIMIncluded(pImageInfo)) {
memset(pSDTIM_h, 0x0, sizeof(TIM));
memset(SDTimBuf, 0x0, SDTIM_MAX_SIZE);
offset = pImageInfo->FlashEntryAddr;
#ifdef CONFIG_AB_SYSTEM
if (AB) {
/* system b */
offset = pImageInfo->PartitionNumber.bits.Reserved << 17;
#if MMC_CODE
offset /= 512;
#endif
}
#endif
Retval = ReadFlash(offset, SDTimBuf, SDTIM_MAX_SIZE, BOOT_FLASH);
if(Retval != NoError) {
free(pSDTIM_h); free(SDTimBuf);
return FlashReadError;
}
Retval = SetTIMPointers( SDTimBuf, pSDTIM_h);
if (Retval != NoError) {
free(pSDTIM_h); free(SDTimBuf);
return IMAP_DTIMNotFound;
}
obm_printf("Verify %s SDTIM: ", ImageID2String(pImageInfo->ImageID));
Retval = ValiateDTIM(pSDTIM_h, pTIM_h);
if(Retval != NoError) {
obm_printf("FAIL\n\r");
free(pSDTIM_h); free(SDTimBuf);
return IMAP_DTIMValidationFailed;
} else {
obm_printf("PASS\n\r");
}
}
pImageInfo = (IMAGE_INFO_3_4_0 *)((UCHAR *)pImageInfo + ImageSize);
}
#endif
free(pSDTIM_h);
free(SDTimBuf);
return NoError;
}
#endif
/*
* this function will load all DTIMs except DTIM.primary and DTIM.recovery,
* these two DTIMs need to be handled specially.
*/
UINT_T LoadAllDTIM(pFUSE_SET pFuses, pTIM pTIM_h, OTA_IMAGE_TYPE DTIMType)
{
UINT_T Retval = NoError, i;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
pIMAGE_MAP pImgMap = NULL;
pIMG_MAP_INFO pImgMapInfo = NULL;
TIM DTIM_test;
TIM * pDTIM_test = &DTIM_test;
// Find the IMAP Package in the TIM.
pWRAH = FindPackageInReserved (&Retval, pTIM_h, IMAPID);
if (Retval != NoError || pWRAH == NULL) // IMAP package NOT found in the TIM
{
obm_printf("IMAP not found\n\r");
return NoError;
}
// IMAP package is found in the TIM
pImgMap = (pIMAGE_MAP) pWRAH;
obm_printf("Number of DTIM: %d\n\r", pImgMap->NumberOfMappedImages);
for (i = 0; i < pImgMap->NumberOfMappedImages; i++)
{
pImgMapInfo = &(pImgMap->pImgMapInfo[i]);
if ((pImgMapInfo->ImageType == PrimaryImage) || (pImgMapInfo->ImageType == RecoveryImage))
continue;
#ifdef CONFIG_AB_SYSTEM
if(DTIM_GetABSystemType(pImgMapInfo, NULL) != DTIMType)
continue;
#endif
// Load the DTIM from flash
Retval = LoadDTimOTA(pDTIM_test, pImgMapInfo, pImgMapInfo->ImageID);
if (Retval != NoError)
{
obm_printf("DTIM(0x%x @ 0x%x) load error %s %d: 0x%x\n\r", pImgMapInfo->ImageID,
pImgMapInfo->FlashEntryAddr[0], __FUNCTION__, __LINE__, Retval);
return IMAP_DTIMLoadError;
}
if (pImgMapInfo->ImageID == DTIM_PPSETTING)
{
obm_printf("Configure PP Setting @ 0x%x\n\r", pImgMapInfo->FlashEntryAddr[0]);
CheckAndConfigureDDR(pDTIM_test, NULL);
continue;
}
#if TRUSTED
if (pTIM_h->pConsTIM->VersionBind.Trusted)
{
obm_printf("Verify DTIM(%s): ", ImageID2String(pImgMapInfo->ImageID));
Retval = ValiateDTIM(pDTIM_test, pTIM_h);
if (Retval != NoError){
obm_printf("FAIL\n\r");
#ifndef CONFIG_AB_SYSTEM
ASRFlag_TrustBootStatus_Update(pTIM_h, pImgMapInfo->ImageID);
#endif
return Retval;
}else{
obm_printf("PASS\n\r");
}
}
#endif
/* TODO: In current design, should not get here. Maybe DTIM.CP??? */
Retval = LoadDTIMImages(pFuses, pDTIM_test, PrimaryImage);
if (Retval != NoError)
{
return IMAP_DTIMLoadError;
}
}
return NoError;
}
#ifdef CONFIG_AB_SYSTEM
UINT_T GetABSystemActiveSlot(pTIM pTIM_h)
{
UINT_T Retval = NoError;
UINT_T active_slot = 'a';
P_FOTA_Firmware pFOTA_T = OTAGetConfig(pTIM_h);
if (pFOTA_T->active_slot != 'a' && pFOTA_T->active_slot != 'b') {
if (pFOTA_T->active_slot == pFOTA_T->temp_active_slot) {
/* initial state, 1st powerup after burn flash */
/* default bringup system a */
active_slot = pFOTA_T->temp_active_slot = pFOTA_T->active_slot = 'a';
pFOTA_T->reboot_cnt = 0;
/* default two systems were synced already */
pFOTA_T->synced = 1;
/* write back to flash */
Retval = OTA_Save_Config(pTIM_h);
if (Retval != NoError) {
obm_printf("@@@ FATAL Error: Save initial state...\n\r");
FatalError(Retval, NULL, NULL);
} else {
obm_printf("@@@ Initial state saved OK...\n\r");
}
}
} else {
/* pFOTA_T->active_slot == 'a' or 'b' */
if (pFOTA_T->active_slot == pFOTA_T->temp_active_slot) {
/* normal power up */
active_slot = pFOTA_T->active_slot;
} else {
/* if run here, the system must be upgraded through otad once */
pFOTA_T->reboot_cnt++;
if (pFOTA_T->reboot_cnt >= 3) {
/* normally the userspace app(otad) will make this two flag same, eg. active_slot == temp_active_slot
* so if the two flag were not same after 3 reboot, we may consider the system doesn't boot up
* to the userspace app(otad), we can say the upgraded system was not validate.
* need to rollback to the prev system(represent by active_slot here).
*/
active_slot = pFOTA_T->temp_active_slot = pFOTA_T->active_slot; /* rollback to the old system */
pFOTA_T->reboot_cnt = 0;
/* must clear synced, then the otad will sync the two system */
pFOTA_T->synced = 0;
obm_printf("@@@ Rollback to system %c ...\n\r", active_slot);
} else {
/* boot the upgraded system, eg. temp_active_slot */
active_slot = pFOTA_T->temp_active_slot;
}
/* write back to flash */
Retval = OTA_Save_Config(pTIM_h);
if (Retval != NoError) {
obm_printf("@@@ FATAL Error: Save reboot cnt...\n\r");
FatalError(Retval, NULL, NULL);
} else {
obm_printf("@@@ Save Reboot count %d OK...\n\r", pFOTA_T->reboot_cnt);
}
}
}
return active_slot;
}
#endif
pIMAGE_INFO_3_4_0 LoadImagesOTA(pFUSE_SET pFuses, pTIM pTIM_h)
{
UINT_T Retval = NoError;
pIMAGE_INFO_3_4_0 pImageInfo = NULL;
UINT_T GoldenSystemFound = 0;
pTIM pPDTIM_h = &PDTIM_h; // DTIM.primary
OTA_IMAGE_TYPE image_type = PrimaryImage;
#ifdef CONFIG_AB_SYSTEM
INT_T validationErr = 0;
P_FOTA_Firmware pFOTA_T = OTAGetConfig(pTIM_h);
INT_T active_slot = GetABSystemActiveSlot(pTIM_h);
reload:
obm_printf("@@@ Bringup system %c\r\n", active_slot);
pOBM2OSL_h->info.cfg_numbers = 0;
image_type = active_slot == 'a' ? PrimaryImage : RecoveryImage;
#endif
/* Load all other DTIMs except DTIM.Primary */
Retval = LoadAllDTIM(pFuses, pTIM_h, image_type);
#ifdef CONFIG_AB_SYSTEM
if(Retval != NoError)
goto switch_system;
#endif
Retval = LoadDTIM(pFuses, pPDTIM_h, pTIM_h, DTIM_PRIMARY, image_type);
if(Retval == NoError)
{
#if NZAS || KSTR
ASR_DdrPatternTest(pTIM_h, pPDTIM_h, image_type);
#endif
pOBM2OSL_h->primary.valid_flag = 1;
Retval = LoadDTIMImages(pFuses, pPDTIM_h, image_type);
switch (Retval)
{
case ImageLoadError:
pOBM2OSL_h->primary.loading_status = LOADING_FAIL; // load fail
pOBM2OSL_h->primary.validation_status = NOT_VALIDATION; // not validate
break;
case ImageValidationError:
pOBM2OSL_h->primary.loading_status = LOADING_PASS; // load ok
pOBM2OSL_h->primary.validation_status = VALIDATION_FAIL; // validate fail
break;
case NoError:
default:
pOBM2OSL_h->primary.loading_status = LOADING_PASS; // load ok
pOBM2OSL_h->primary.validation_status = VALIDATION_PASS; // validate ok
GoldenSystemFound = 1;
break;
}
}
#ifdef CONFIG_AB_SYSTEM
switch_system:
if (Retval != NoError)
{
validationErr++;
if (validationErr == 2) {
obm_printf("@@@ FATAL Error: A&B systems are both corrupted...\n\r");
ASRFlag_TrustBootStatus_Update(pTIM_h, TB_AB_SYSTEM_BOOT_ERROR);
FatalError(IMAP_BootFailed, NULL, NULL);
}
obm_printf("@@@ System %c boot fails, try the other one...\n\r", active_slot);
active_slot = active_slot == 'a' ? 'b' : 'a';
goto reload;
}
#endif
if (GoldenSystemFound)
{
#ifdef CONFIG_AB_SYSTEM
if (validationErr) {
obm_printf("@@@ Uboot/TOS validation error(or DTIM load failed) occured once, rollback to system %c...\n\r", active_slot);
pFOTA_T->temp_active_slot = pFOTA_T->active_slot = active_slot;
pFOTA_T->reboot_cnt = 0;
/* one system is error, need to clear the synced flag, and then sync the two system in otad */
pFOTA_T->synced = 0;
Retval = OTA_Save_Config(pTIM_h);
if (Retval != NoError) {
obm_printf("@@@ FATAL Error: System rollback failed...\n\r");
ASRFlag_TrustBootStatus_Update(pTIM_h, TB_AB_SYSTEM_ROLLBACK_ERROR);
FatalError(IMAP_BootFailed, NULL, NULL);
} else {
obm_printf("@@@ System rollback OK...\n\r");
}
}
#endif
}
return pNextImageToTransferTo;
}
#if 0
pIMAGE_INFO_3_4_0 LoadUbootOTA(pFUSE_SET pFuses, pTIM pTIM_h)
{
UINT_T Retval = NoError;
pIMAGE_INFO_3_4_0 pImageInfo = NULL;
pTIM pPDTIM_h = &PDTIM_h; // DTIM.primary
// Load DTIM.primary from flash and set TIM pointers
Retval = LoadDTIM(pFuses, pPDTIM_h, pTIM_h, DTIM_PRIMARY, PrimaryImage);
if(Retval == NoError)
{
pImageInfo = FindImageInTIM(pPDTIM_h, OSLOADERID);
if (pImageInfo != NULL)
{
#ifdef CONFIG_ASR_SDTIM
if(ImageIsSDTIMIncluded(pImageInfo)) {
pNextImageToTransferTo = malloc(sizeof(IMAGE_INFO_3_4_0)); /* no need to free */
if(pNextImageToTransferTo == NULL)
return HeapExhaustedError;
SDTimImageInfoUpdate(pImageInfo, pNextImageToTransferTo, PrimaryImage);
} else
#endif
{
pNextImageToTransferTo = pImageInfo;
}
Loadimage(pImageInfo, pFuses, pPDTIM_h, 0);
return pNextImageToTransferTo; // return if got uboot from primary DTIM
}
}
#ifdef CONFIG_AB_SYSTEM
Retval = LoadDTIM(pFuses, pPDTIM_h, pTIM_h, DTIM_PRIMARY, RecoveryImage);
if(Retval == NoError)
{
pImageInfo = FindImageInTIM(pPDTIM_h, OSLOADERID);
if (pImageInfo != NULL)
{
#ifdef CONFIG_ASR_SDTIM
if(ImageIsSDTIMIncluded(pImageInfo)) {
pNextImageToTransferTo = malloc(sizeof(IMAGE_INFO_3_4_0)); /* no need to free */
if(pNextImageToTransferTo == NULL)
return HeapExhaustedError;
SDTimImageInfoUpdate(pImageInfo, pNextImageToTransferTo, PrimaryImage);
} else
#endif
{
pNextImageToTransferTo = pImageInfo;
}
Loadimage(pImageInfo, pFuses, pPDTIM_h, 1);
}
}
#endif
return pNextImageToTransferTo;
}
#endif
//////////////////////////////////////////////////////////////////////
// This function mainly loads the DTIM from flash.
//
// Inputs: Fuse Set, DTIM Image ID, OTA Image Type,
// DTIM pointer, and TIM pointer.
// Outputs: Returns an error code if there is one.
//
// This function mainly works as follows:
// 1) Sets the partition in the flash device
// 2) Reads the DTIM from flash into DDR
// 3) Sets the TIM pointers
// 4) In case of the TRUSTED operation, validate the public
// key of the DTIM and DTIM itself.
//////////////////////////////////////////////////////////////////////
UINT_T LoadDTIM(pFUSE_SET pFuses,
pTIM pDTIM_h,
pTIM pTIM_h,
UINT_T DTIMImageID,
OTA_IMAGE_TYPE DTIMType)
{
UINT_T i = 0, j = 0;
UINT_T Retval = NoError;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
pIMAGE_MAP pImgMap = NULL;
pIMG_MAP_INFO pImgMapInfo = NULL;
pTransfer_Info_PACKAGE pInfo = NULL;
UINT_T AB = 0;
ASRFlag_ParseCfgToOBM2OSLO(pTIM_h);
// Find the IMAP Package in the TIM.
pWRAH = FindPackageInReserved (&Retval, pTIM_h, IMAPID);
if (Retval != NoError) // IMAP package NOT found in the TIM
{
obm_printf("IMAP Package Not Found: %s %d\n\r", __FUNCTION__, __LINE__);
return IMAP_PackageNotFound;
}
// IMAP package is found in the TIM
pImgMap = (pIMAGE_MAP) pWRAH;
// Find the DTIM with the required "DTIM Type" and "DTIM ID" in the IMAP package
pImgMapInfo = FindImageMapInfoInIMAP (pImgMap, DTIMImageID, DTIMType);
// If this information is not in the TIM, then FAIL.
if(pImgMapInfo == NULL)
{
obm_printf("IMAP Error Format: %s %d\n\r", __FUNCTION__, __LINE__);
return IMAP_ErrorFormat;
}
// Load the DTIM from flash
#ifdef CONFIG_AB_SYSTEM
obm_printf("[DTIM Info] ID: 0x%x, Type: %d, Flash: 0x%x 0x%x, PartitionNumber: 0x%x\r\n",
pImgMapInfo->ImageID, pImgMapInfo->ImageType,
pImgMapInfo->FlashEntryAddr[0], pImgMapInfo->FlashEntryAddr[1],
pImgMapInfo->PartitionNumber);
#endif
Retval = LoadDTimOTA(pDTIM_h, pImgMapInfo, DTIMImageID);
// If LoadDTimOTA function fails, then we fail.
if (Retval != NoError)
{
obm_printf("IMAP DTIM Load Error: %s %d\n\r", __FUNCTION__, __LINE__);
return IMAP_DTIMLoadError;
}
#if TRUSTED
if (pTIM_h->pConsTIM->VersionBind.Trusted)
{
obm_printf("Verify DTIM(%s): ", ImageID2String(pImgMapInfo->ImageID));
Retval = ValiateDTIM(pDTIM_h, pTIM_h);
if (Retval != NoError) {
obm_printf("FAIL\n\r");
#ifndef CONFIG_AB_SYSTEM
ASRFlag_TrustBootStatus_Update(pTIM_h, DTIMImageID);
#endif
return Retval;
}else{
obm_printf("PASS\n\r");
}
}
#ifdef CONFIG_ASR_SDTIM
if(pImgMapInfo->ImageID == DTIM_PRIMARY)
{
#ifdef CONFIG_AB_SYSTEM
AB = DTIM_GetABSystemType(pImgMapInfo, NULL);
#endif
Retval = LoadAllSDTIM(pFuses, pTIM_h, pDTIM_h, AB);
if(Retval != NoError) {
#ifndef CONFIG_AB_SYSTEM
ASRFlag_TrustBootStatus_Update(pTIM_h, SDTIM);
#endif
return Retval;
}
}
#endif
#endif
#if !SPINOR_CODE
if (pImgMapInfo->ImageType == PrimaryImage || pImgMapInfo->ImageType == RecoveryImage)
{
TransCITA_2_OBM2OSLO(pDTIM_h, pOBM2OSL_h);
}
#endif
return NoError;
}
//////////////////////////////////////////////////////////////////////
// This function loads the images present in the tim
//
// Inputs: Pointer to the Tim, Pointer to the fuses, List of ImageIds array, Flag to track the validity
// of the images, Offset in the flag to be set based on image's validity
// Outputs: NONE.
//
// This function mainly works as follows:
// 1) Sets the partition in the flash device
// 2) Reads the image from flash to DDR
// 3) Validate the image
// 4) Set the validation flag based on output from (3)
//////////////////////////////////////////////////////////////////////
UINT_T LoadDTIMImages(pFUSE_SET pFuses, pTIM pTIM_h, OTA_IMAGE_TYPE DTIMType)
{
UINT_T Retval = NoError;
UINT_T ImageIndex = 0, ImageSize;
pIMAGE_INFO_3_4_0 pImageInfo = NULL;
UINT_T offset;
pImageInfo = pTIM_h->pImg;
ImageSize = sizeof(IMAGE_INFO_3_4_0);
for (ImageIndex = 0; ImageIndex < pTIM_h->pConsTIM->NumImages; ImageIndex++)
{
if(((pImageInfo->ImageID & 0xffffff00) == TIM_TYPE) ||
(pImageInfo->LoadAddr == 0xFFFFFFFF) )
goto skip_load_img;
/* Don't need to load OUMI, it's loaded if in fota process */
if(pImageInfo->ImageID == OUMIDENTIFIER)
goto skip_load_img;
#ifdef CONFIG_ASR_SDTIM
IMAGE_INFO_3_4_0 ImageInfoSDtim;
if(ImageIsSDTIMIncluded(pImageInfo)) {
if(SDTimImageInfoUpdate(pImageInfo, &ImageInfoSDtim, DTIMType) == NULL)
goto skip_load_img;
if(ImageInfoSDtim.LoadAddr == 0xFFFFFFFF)
goto skip_load_img;
}
#endif
Retval = Loadimage(pImageInfo, pFuses, pTIM_h, DTIMType);
if(Retval != NoError) {
err_msg("Load %s error: 0x%x\n\r", ImageID2String(pImageInfo->ImageID), Retval);
return Retval;
}
switch(pImageInfo->ImageID)
{
case TZSWIDENTIFIER:
obm_printf("Load TZ OS from Flash\n\r");
pIMAGE_INFO_3_4_0 pTzImageInfo = pImageInfo;
#ifdef CONFIG_ASR_SDTIM
if(ImageIsSDTIMIncluded(pImageInfo)) {
pTzImageInfo = malloc(sizeof(IMAGE_INFO_3_4_0));
if(pTzImageInfo == NULL)
return HeapExhaustedError;
memcpy(pTzImageInfo, &ImageInfoSDtim, sizeof(IMAGE_INFO_3_4_0));
}
#endif
pNextImageToTransferTo = pTzImageInfo;
break;
case OSLOADERID:
obm_printf("Load Uboot from Flash\n\r");
pIMAGE_INFO_3_4_0 pOsloImageInfo = pImageInfo;
#ifdef CONFIG_ASR_SDTIM
if(ImageIsSDTIMIncluded(pImageInfo)) {
pOsloImageInfo = malloc(sizeof(IMAGE_INFO_3_4_0));
if(pOsloImageInfo == NULL)
return HeapExhaustedError;
memcpy(pOsloImageInfo, &ImageInfoSDtim, sizeof(IMAGE_INFO_3_4_0));
}
#endif
if(pNextImageToTransferTo == NULL)
pNextImageToTransferTo = pOsloImageInfo;
if(pImageNsEntry == NULL)
pImageNsEntry = pOsloImageInfo;
break;
}
skip_load_img:
pImageInfo = (IMAGE_INFO_3_4_0 *)((UCHAR *)pImageInfo + ImageSize);
}
return NoError;
}