blob: e7181541463b019f882c5b21ad3526467fb6b09b [file] [log] [blame]
#include "Typedef.h"
#include "FM.h"
#include "Partition.h"
#include "Errors.h"
#include "Flash.h"
#include "misc.h"
#include "loadoffsets.h"
#include "tim.h"
#include "malloc.h"
#if COPYIMAGESTOFLASH
#include "BootLoader.h"
#endif
extern UINT_T *pFM_SPACE;
#ifdef BBM_LEGACY_EXT
static int EntryIsBlockInfo(void *Entry)
{
P_BlockState_T pBlkInfo = (P_BlockState_T)Entry;
if((pBlkInfo->State >= BLOCK_RECYCLED) &&
(pBlkInfo->State != BLK_FLIP_COUNT))
return 1;
else
return 0;
}
static int EntryIsReloPair(void *Entry)
{
P_ReloPair_T pRelo = (P_ReloPair_T)Entry;
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
if(pRelo->From < pFlashProp->NumBlocks)
return 1;
else
return 0;
}
void SetABBTState(ReloState_T newState, FlashBootType_T fbt)
{
UINT_T BlkSize, PageSize;
P_FMProperties_T pFMProps = GetFMProperties();
//make sure this device uses BBM
if(GetFlashProperties(fbt)->FlashSettings.UseBBM == 0)
return;
// Now set some values that will work
PageSize = GetPageSize(fbt);
BlkSize = GetBlockSize(fbt);
//check if the BBT got erase. If so, set the slot numbers back to their starting slot
if ( newState == BBT_ERASED )
{
if (pFMProps->ABBT_Reverse)
pFMProps->ABBT_CurSlot = (BlkSize / PageSize) - 1;
else
pFMProps->ABBT_CurSlot = 0;
}
pFMProps->ABBT_State &= ~ABBT_STATE_MASK;
pFMProps->ABBT_State |= newState;
}
UINT_T GetABBTState(FlashBootType_T fbt)
{
P_FMProperties_T pFMProps = GetFMProperties();
//make sure this device uses BBM
if(GetFlashProperties(fbt)->FlashSettings.UseBBM == 0)
return 0;
return (pFMProps->ABBT_State & ABBT_STATE_MASK);
}
void SetBBTStates(ReloState_T bbtState, ReloState_T abbtState, FlashBootType_T fbt)
{
SetBBTState(bbtState, fbt);
SetABBTState(abbtState, fbt);
}
static void UpdateBBTCrc(P_ReloTable_T pBBT)
{
UINT_T CRC, ABBTVersion, BBTLen;
BBT_INFO BBTInfo;
BBTLen = BBT_HEADER_SIZE + pBBT->NumReloc * sizeof(ReloPair_T);
ABBTVersion = BU_REG_READ((UINT_T)pBBT + BBTLen);
if (ABBTVersion != ABBT_VERSION_2001){
//obm_printf("Upgrade BBT for CRC!!!\n\r");
BU_REG_WRITE((UINT_T)pBBT + BBTLen, ABBT_VERSION_2001);
}
BBTInfo.Value = 0;
BBTInfo.Bits.Owner = BBT_OBM;
BU_REG_WRITE((UINT_T)pBBT + BBTLen + 4, BBTInfo.Value);
BBTLen = BBTLen + 4 /* version */ + 2 /* half info */;
CRC = malbrain_crc32(0, pBBT, BBTLen);
BBTInfo.Bits.CRC = from32to16(CRC);
BU_REG_WRITE16((UINT_T)pBBT + BBTLen, BBTInfo.Bits.CRC);
}
INT_T IsBBTValid(P_ReloTable_T pBBT)
{
UINT_T CRC1, CRC2, ABBTVersion, BBTLen;
BBTLen = BBT_HEADER_SIZE + pBBT->NumReloc * sizeof(ReloPair_T);
ABBTVersion = BU_REG_READ((UINT_T)pBBT + BBTLen);
switch(ABBTVersion)
{
case 0xFFFFFFFF:
return (pBBT->Header == BBT_TYPE_LEGACY);
default:
obm_printf("Warning: unexpected version: 0x%x\n\r", ABBTVersion);
case ABBT_VERSION_2001:
CRC1 = BU_REG_READ16((UINT_T)pBBT + BBTLen + 6);
CRC2 = malbrain_crc32(0, pBBT, BBTLen + 6);
CRC2 = from32to16(CRC2);
return (CRC1 == CRC2);
}
return 0;
}
static void UpdateABBTCrc(P_ABBT_Table_T pABBT)
{
UINT_T CRC, CrcLen;
if (pABBT->Version != ABBT_VERSION_2001) {
obm_printf("Upgrade ABBT for CRC!!!\n\r");
pABBT->Version = ABBT_VERSION_2001;
}
CrcLen = ABBT_HEADER_SIZE + pABBT->NumReloc * sizeof(ReloPair_T);
pABBT->Info.Value = 0;
pABBT->Info.Bits.Owner = BBT_OBM;
CRC = malbrain_crc32(0, pABBT, CrcLen);
pABBT->Info.Bits.CRC = from32to16(CRC);
}
static INT_T IsABBTValid(P_ABBT_Table_T pABBT)
{
UINT_T CrcLen, CRC1, CRC2;
switch(pABBT->Version)
{
case ABBT_VERSION:
case ABBT_VERSION_1002:
return (pABBT->Identifier == BBT_TYPE_ASR);
default:
obm_printf("Warning: unexpected ABBT version: 0x%x\n\r", pABBT->Version);
case ABBT_VERSION_2001:
CrcLen = ABBT_HEADER_SIZE + pABBT->NumReloc * sizeof(ReloPair_T);
CRC1 = pABBT->Info.Bits.CRC;
pABBT->Info.Bits.CRC = 0;
CRC2 = malbrain_crc32(0, pABBT, CrcLen);
CRC2 = from32to16(CRC2);
return (CRC1 == CRC2);
}
return 0;
}
INT CheckMagicBBT(UINT_T Magic, VOID *BbtBuffer)
{
P_ReloTable_T pBBT = NULL;
P_ABBT_Table_T pABBT = NULL;
switch(Magic) {
case BBT_TYPE_LEGACY:
pBBT = (P_ReloTable_T)BbtBuffer;
return IsBBTValid(pBBT);
case BBT_TYPE_ASR:
pABBT = (P_ABBT_Table_T)BbtBuffer;
return IsABBTValid(pABBT);
default:
obm_printf("Invalid BBT magic: 0x%x\n\r", Magic);
return 1; //???
}
return 0;
}
/* This is the blocks are maintained by L1 BBT */
static INT_T L1BbtBlocks[L1_BBT_BLOCK_NUM];
static UINT_T L1BbtBlockNum = 0;
VOID InitL1BBTBlocks(VOID)
{
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
INT_T i = 0;
#if DUAL_TIM
if (DualTimEnabled()) {
pAsrDualTimInfo pDualTimInfo = GetDualTimInfo();
L1BbtBlocks[i++] = pDualTimInfo->MainObmBlock; //Main OBM block
L1BbtBlocks[i++] = pDualTimInfo->BackupTimBlock; //Backup TIM block
L1BbtBlocks[i++] = pDualTimInfo->BackupObmBlock; //Backup OBM Block
L1BbtBlocks[i++] = pFlashProp->NumBlocks - 2; //main ABBT
L1BbtBlocks[i++] = pFlashProp->NumBlocks - 1; //backup ABBT
L1BbtBlocks[i++] = 0; //Main TIM
L1BbtBlockNum = i;
} else
#endif
{
L1BbtBlocks[i++] = 1; //OBM Block
L1BbtBlocks[i++] = pFlashProp->NumBlocks - 2; //main ABBT
L1BbtBlocks[i++] = pFlashProp->NumBlocks - 1; //backup ABBT
L1BbtBlockNum = i;
}
}
INT_T IsLogicBlockInL1BBT(UINT_T BlockNum) {
INT_T i;
for (i = 0 ; i < L1BbtBlockNum; i++)
{
if(L1BbtBlocks[i] == BlockNum)
return 1;
}
return 0;
}
INT_T IsTimBlock(UINT_T BlockNum) {
#if DUAL_TIM
if (DualTimEnabled()) {
pAsrDualTimInfo pDualTimInfo = GetDualTimInfo();
if(BlockNum == 0 || BlockNum == pDualTimInfo->BackupTimBlock)
return 1;
} else
#endif
{
return (BlockNum == 0);
}
return 0;
}
INT_T IsBlockRelocated(UINT_T BlockNum) {
UINT_T BlockTo = BlockNum;
BlockTo = ScanBBT_LegacyExt(BlockNum);
if (BlockTo != BlockNum)
return 1;
return 0;
}
void CreateBBT_LegacyExt(P_PartitionInfo_T pPI)
{
#if COPYIMAGESTOFLASH
int i;
UINT_T Retval = NoError;
UINT_T PageSize, BlkSize, mask, TIMpagesUsed;
P_FMProperties_T pFMProp = GetFMProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
//If this flash device does not use BBM, just return
if(pFlashProp->FlashSettings.UseBBM == 0)
return;
//Initialize FMProperties structure:
SetBBTStates(BBT_INVALID, BBT_INVALID, BOOT_FLASH);
PageSize = pFlashProp->PageSize;
BlkSize = pFlashProp->BlockSize;
//One page for BBT, the other for ABBT
//pFM_SPACE need to be valued before(in ClearFM)
memset(pFM_SPACE, 0xFF, PageSize*2);
pFMProp->pLBBT = (P_ReloTable_T) pFM_SPACE;
pFMProp->pLBBT->Header = (USHORT) BBT_TYPE_LEGACY;
pFMProp->pLBBT->NumReloc = 0;
pFMProp->BBT_type = BBT_TYPE_LEGACY;
//NOTE:: SET THE STARTING SLOT HERE!!!
// For now use the last page in block zero to match XDB
#ifdef BBT_ORDER_REVERSE
pFMProp->BBT_Slot = (BlkSize / PageSize) - 1;
pFMProp->BBT_NextSlot = pFMProp->BBT_Slot - 1;
pFMProp->BBT_Reverse = 1;
#else
TIMpagesUsed = (max_tim_size_byte + PageSize - 1) / PageSize;
pFMProp->BBT_Slot = TIMpagesUsed;
pFMProp->BBT_NextSlot = pFMProp->BBT_Slot + 1;
pFMProp->BBT_Reverse = 0;
#endif
pFMProp->BBT_location = pFMProp->BBT_Slot * PageSize;
SetBBTState(BBT_CHANGED, BOOT_FLASH);
pFMProp->pABBT = (P_ABBT_Table_T) (((UINT_T)pFM_SPACE)+PageSize);
pFMProp->pABBT->Identifier = BBT_TYPE_ASR;
pFMProp->pABBT->Type = BBT_TYPE_MBBT_RUN;
pFMProp->pABBT->NumReloc = 0;
pFMProp->pABBT->RefCounter = 0;
pFMProp->pABBT->NumBlockRecyled = 0;
pFMProp->pABBT->NumBlockToRecyle = 0;
#if DUAL_TIM
if(DualTimEnabled()) {
pAsrDualTimInfo pDualTimInfo = GetDualTimInfo();
pFMProp->pABBT->BackupBBTLoc = pDualTimInfo->BackupTimBlock * BlkSize;
}
else
#endif
{
pFMProp->pABBT->BackupBBTLoc = 0;
}
pFMProp->pABBT->Version = ABBT_VERSION_2001;
pFMProp->ABBT_block0 = pFlashProp->NumBlocks - 1;
pFMProp->ABBT_block1 = pFlashProp->NumBlocks - 2;
//Start with the last page
#ifdef BBT_ORDER_REVERSE
pFMProp->ABBT_CurSlot = (BlkSize / PageSize) - 1;
pFMProp->ABBT_Reverse = 1;
#else
pFMProp->ABBT_CurSlot = 0;
pFMProp->ABBT_Reverse = 0;
#endif
pFMProp->ScanBBT = &ScanBBT_LegacyExt;
SetABBTState(BBT_CHANGED, BOOT_FLASH);
#endif
return;
}
/* This function is only for TIM block, which are never relocated
* Logic block number is always equal to physical block number
*/
static UINT_T EraseBlockAndRestoreTIM(P_FlashProperties_T pFlashProp, UINT_T BlockNum, INT_T RestoreBBT)
{
UINT_T Retval = NoError, BlkSize;
EraseFlash_F erase = pFlashProp->EraseFlash;
ReadFlash_F read = pFlashProp->ReadFromFlash;
WriteFlash_F write = pFlashProp->WriteToFlash;
P_FMProperties_T pFMProps = NULL;
UINT8_T *ptemp = 0;
UINT_T ReadSize, WriteOffset, BBTWriteLen, PageSize;
UINT_T BlockOffset;
ptemp = malloc(pFlashProp->BlockSize);
if(ptemp == NULL)
return HeapExhaustedError;
BlkSize = GetBlockSize(BOOT_FLASH);
BlockOffset = BlkSize * BlockNum;
if(RestoreBBT)
ReadSize = BlkSize;
else
ReadSize = max_tim_size_byte;
Retval = read(BlockOffset, ptemp, ReadSize, BOOT_FLASH);
if(Retval != NoError && Retval != ReadDisturbError)
Retval = read(BlockOffset, ptemp, ReadSize, BOOT_FLASH);
if(Retval != NoError && Retval != ReadDisturbError){
free(ptemp);
return Retval;
}
//erase all the block
Retval = erase(BlockOffset, BlkSize, BOOT_FLASH);
if(Retval != NoError)
Retval = erase(BlockOffset, BlkSize, BOOT_FLASH);
if(Retval != NoError){
free(ptemp);
return Retval;
}
//restore TIM data in lower portion of the block
Retval = write(BlockOffset, ptemp, max_tim_size_byte, BOOT_FLASH);
if(Retval != NoError){ //write fail, erase and try another time
Retval = erase(BlockOffset, BlkSize, BOOT_FLASH);
if(Retval != NoError){
free(ptemp);
return Retval;
}
Retval = write(BlockOffset, ptemp, max_tim_size_byte, BOOT_FLASH);
}
if (RestoreBBT) {
PageSize = GetPageSize(BOOT_FLASH);
pFMProps = GetFMProperties();
if (pFMProps->BBT_Reverse) {
WriteOffset = (pFMProps->BBT_Slot + 1) * PageSize;
BBTWriteLen = BlkSize - WriteOffset;
Retval = write(BlockOffset+WriteOffset, ptemp+WriteOffset, BBTWriteLen, BOOT_FLASH);
} else {
WriteOffset = max_tim_size_byte;
BBTWriteLen = pFMProps->BBT_Slot * PageSize - max_tim_size_byte;
Retval = write(BlockOffset+WriteOffset, ptemp+WriteOffset, BBTWriteLen, BOOT_FLASH);
}
}
free(ptemp);
return Retval;
}
static UINT_T WriteABBT2Flash(UINT_T Block2Write, INT_T NeedErase, INT_T *ABBT_changed)
{
UINT_T Retval = NoError;
P_FMProperties_T pFMProps = GetFMProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
EraseFlash_F erase = pFlashProp->EraseFlash;
WriteFlash_F write = pFlashProp->WriteToFlash;
ReadFlash_F read = pFlashProp->ReadFromFlash;
UINT_T BlockIdx, BlockAddr, PageAddr;
UINT_T BlkSize, PageSize, NumPages, StartPage, EndPage;
INT_T i, Retry = TRUE;
P_ABBT_Table_T pABBT = pFMProps->pABBT;
UINT8_T *ptemp = 0;
BlkSize = pFlashProp->BlockSize;
PageSize = pFlashProp->PageSize;
NumPages = BlkSize/PageSize;
BlockIdx = ScanBBT_LegacyExt(Block2Write);
ptemp = malloc(BlkSize);
if(ptemp == NULL)
return HeapExhaustedError;
while(NeedErase)
{
BlockAddr = BlockIdx * BlkSize;
Retval = erase(BlockAddr, BlkSize, BOOT_FLASH);
if(Retval != NoError) //retry again
Retval = erase(BlockAddr, BlkSize, BOOT_FLASH);
if(Retval != NoError){
Retval = RelocateBlock_LegacyExt(BlockIdx, &BlockIdx, 0);
UpdateABBTCrc(pABBT);
if(Retval != NoError){
free(ptemp);
return Retval;
}
else
*ABBT_changed = TRUE; //relocation causes BBTs changed
continue;
}
break; //Erase succeeds
}
StartPage = pFMProps->ABBT_CurSlot;
EndPage = pFMProps->ABBT_CurSlot + 1; //only need to write one page
BlockAddr =BlockIdx * BlkSize;
for(i = StartPage; i < EndPage; i++)
{
PageAddr = i * PageSize;
Retval = read(BlockAddr+PageAddr, ptemp, PageSize, BOOT_FLASH);
if(Retval == NoError) {
if(CheckPattern(ptemp, 0xFF, PageSize) == 1) //All 0xFFs
Retval = write(BlockAddr+PageAddr, (UINT_T)pABBT, PageSize, BOOT_FLASH);
else
Retval = FlashReadError; //Page to read is not All 0xFF
/* ABBT read back and check */
if (Retval == NoError) {
Retval = read(BlockAddr+PageAddr, ptemp, PageSize, BOOT_FLASH);
if(Retval == NoError){
if (memcmp(ptemp, pABBT, PageSize)) {
Retval = FlashReadError; //ABBT Read back mismatch
}
}
}
}
if(Retval != NoError) {
if(Retry == TRUE){
Retry = FALSE;
Retval = erase(BlockAddr, BlkSize, BOOT_FLASH);
if(Retval == NoError){
//succeed to erase, need to write the previous page with valid(latest) ABBT
if (pFMProps->ABBT_Reverse) {
i = StartPage - 1; //i++ still works, write ABBT from StartPage to last page of ABBT_block
EndPage = NumPages;
} else {
i = - 1; //i++ still works, write ABBT from page 0 to StartPage
EndPage = StartPage + 1;
}
continue;
}
//If erase fails, go through to relocate
}
Retry = TRUE;
Retval = RelocateBlock_LegacyExt(BlockIdx, &BlockIdx, 0);
UpdateABBTCrc(pABBT);
if(Retval != NoError){
free(ptemp);
//Relocation fails, return with Error
return Retval;
}
else{
if (pFMProps->ABBT_Reverse) {
i = StartPage - 1; //i++ still works
//need to write the previous page with valid(latest) ABBT
EndPage = NumPages;
} else {
i = -1;
EndPage = StartPage + 1;
}
BlockAddr = BlockIdx * BlkSize;
*ABBT_changed = TRUE; //relocation causes BBTs changed
}
//retry writing, with the relocated block
}
}
free(ptemp);
return Retval;
}
static VOID BBT_RemoveDummyEntries(P_ReloTable_T pBBT)
{
INT_T i;
for (i = 0; i < pBBT->NumReloc; i++)
{
if ((pBBT->Relo[i].From == BLOCK_BAD) &&
(pBBT->Relo[i].To == BLOCK_BAD))
{
pBBT->Relo[i].From = pBBT->Relo[pBBT->NumReloc - 1].From;
pBBT->Relo[i].To = pBBT->Relo[pBBT->NumReloc - 1].To;
pBBT->NumReloc --;
i--;
}
}
}
static UINT_T WriteBBT2Flash(UINT_T Block2Write, INT_T BBTNeedRestore)
{
UINT_T Retval = NoError, BlkSize, PageSize;
P_FMProperties_T pFMProps = GetFMProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
WriteFlash_F write = pFlashProp->WriteToFlash;
ReadFlash_F read = pFlashProp->ReadFromFlash;
EraseFlash_F erase = pFlashProp->EraseFlash;
UINT_T Addr = 0;
P_ReloTable_T pBBT;
UINT_T pBuffer;
PageSize = pFlashProp->PageSize;
BlkSize = pFlashProp->BlockSize;
//NumPages = BlkSize / PageSize;
pBBT = pFMProps->pLBBT;
if (IsBlockRelocated(Block2Write))
{
//obm_printf("Try to write a relocated TIM block\n\r");
return NoError;
}
if (BBTNeedRestore)
{
BBT_RemoveDummyEntries(pBBT);
Retval = EraseBlockAndRestoreTIM(pFlashProp, Block2Write, 0);
if(Retval != NoError){
obm_printf("Erase and restore backup TIM error\n\r");
return BBTWriteError;
}
}
pBuffer = malloc(PageSize);
if (pBuffer == NULL) {
obm_printf("Warning: no buffer for BBT RBC\n\r");
return NoError;
}
#if DUAL_TIM
if (DualTimEnabled()) {
Addr = pFMProps->BBT_Slot * PageSize; //offset in TIM block
Addr += (Block2Write * BlkSize);
/* write BBT to TIM block */
if (IsBlockRelocated(Block2Write)) {
; //Do nothing if TIM block is already relocated
} else {
Retval = read(Addr, pBuffer, PageSize, BOOT_FLASH);
if (Retval != NoError) {
free(pBuffer);
return BBTReadError;
}
if (CheckPattern(pBuffer, 0xFF, PageSize) == 0) {
free(pBuffer);
//obm_printf("CheckPattern fails\n\r");
return BBTReadError;
}
Retval = WriteFlash(Addr, (UINT_T)pBBT, PageSize, BOOT_FLASH);
if(Retval != NoError){
obm_printf("BBT Write TIM block%d Error\n\r", Block2Write);
}
if(IsBlockRelocated(Block2Write)) {
EraseFlash((Block2Write * BlkSize) , BlkSize, BOOT_FLASH);
erase((Block2Write * BlkSize) , BlkSize, BOOT_FLASH);
}
}
} else
#endif
{
//get the block offset from BBT_location
Addr = pFMProps->BBT_location & ~(BlkSize - 1);
//get the page offset from SLot
Addr |= pFMProps->BBT_Slot * PageSize;
Retval = write(Addr, (UINT_T)pBBT, PageSize, BOOT_FLASH);
if(Retval != NoError){
//as block0 is always good, should never reach here
obm_printf("BBT Write Error, %s %d!!!\n\r", __FUNCTION__, __LINE__);
free(pBuffer);
//FatalError(BBTWriteError, NULL, NULL);
return BBTWriteError;
}
}
Retval = read(Addr, (UINT_T)pBuffer, PageSize, BOOT_FLASH);
if (Retval != NoError) {
Retval = BBTReadError;
}
/* BBT read back check */
if (Retval == NoError && memcmp(pBBT, pBuffer, PageSize)){
Retval = BBTReadError;
}
free(pBuffer);
return Retval;
}
void UpdateBBT_LegacyExt()
{
#if COPYIMAGESTOFLASH
UINT_T Retval = NoError, BlkSize, PageSize, NumPages, TIMpagesUsed;
P_FMProperties_T pFMProps = GetFMProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
P_ReloTable_T pBBT;
UINT_T maxBlockNum, Retval1 = NoError;
UINT_T PrimaryBlock, MirrorBlock;
INT_T i, NeedErase = FALSE, ABBT_changed = FALSE;
INT_T BBTNeedRestore = FALSE;
INT_T BBTRetry = 0;
#if DUAL_TIM
pAsrDualTimInfo pDualTimInfo;
#endif
//If this flash device does not use BBM, just return
if(pFlashProp->FlashSettings.UseBBM == 0)
return;
//update BBT (only if there are changes)
if((pFMProps->BBT_State == BBT_UNCHANGED) &&
(GetABBTState(BOOT_FLASH) == BBT_UNCHANGED))
return;
//if we never found a BBT, just return
if(pFMProps->BBT_State == BBT_INVALID)
return;
// Now set some values that will work
PageSize = pFlashProp->PageSize;
BlkSize = pFlashProp->BlockSize;
NumPages = BlkSize / PageSize;
#if DUAL_TIM
if (DualTimEnabled()) {
pDualTimInfo = GetDualTimInfo();
pFMProps->pABBT->BackupBBTLoc = pDualTimInfo->BackupTimBlock * BlkSize;
}
#endif
update_bbts_again:
//During updating ABBT, BBT could be changed, therefore, update ABBT before BBT
if(GetABBTState(BOOT_FLASH) == BBT_CHANGED ||
GetABBTState(BOOT_FLASH) == BBT_ERASED)
{
do{
ABBT_changed = FALSE;
if(pFMProps->pABBT->RefCounter % 2){
PrimaryBlock = pFMProps->ABBT_block0;
MirrorBlock = pFMProps->ABBT_block1;
}else{
PrimaryBlock = pFMProps->ABBT_block1;
MirrorBlock = pFMProps->ABBT_block0;
}
if(pFMProps->ABBT_CurSlot == INVALID_PAGE) {
NeedErase = TRUE;
if (pFMProps->ABBT_Reverse)
pFMProps->ABBT_CurSlot = NumPages - 1;
else
pFMProps->ABBT_CurSlot = 0;
}
pFMProps->pABBT->RefCounter++;
UpdateABBTCrc(pFMProps->pABBT);
//Write ABBT to the two blocks
Retval1 = WriteABBT2Flash(PrimaryBlock, NeedErase, &ABBT_changed);
if(Retval1 != NoError)
{
obm_printf("Warning: fail to update ABBT in one block\n\r");
}
Retval = WriteABBT2Flash(MirrorBlock, NeedErase, &ABBT_changed);
if(Retval1 != NoError && Retval != NoError)
{
//Neither block of ABBT is correctly updated.
obm_printf("Error: fail to update ABBT in both blocks\n\r");
}
if ((pFMProps->ABBT_CurSlot == (NumPages - 1) && !pFMProps->ABBT_Reverse) ||
(pFMProps->ABBT_CurSlot == 0 && pFMProps->ABBT_Reverse) ||
pFMProps->ABBT_CurSlot >= NumPages /*unexpected*/) {
pFMProps->ABBT_CurSlot = INVALID_PAGE;
} else {
if (pFMProps->ABBT_Reverse)
pFMProps->ABBT_CurSlot--;
else
pFMProps->ABBT_CurSlot++;
}
}while(ABBT_changed);
SetABBTState(BBT_UNCHANGED, BOOT_FLASH);
}
//Legacy way to update BBT
if(pFMProps->BBT_State == BBT_CHANGED || pFMProps->BBT_State == BBT_ERASED ||
pFMProps->BBT_State == BBT_NEED_SYNC)
{
//Find and read first page after the TIM
TIMpagesUsed = (max_tim_size_byte + PageSize - 1) / PageSize;
UpdateBBTCrc(pFMProps->pLBBT);
//Did we run out of BBT Slots?
if( pFMProps->BBT_Slot < TIMpagesUsed || pFMProps->BBT_Slot >= NumPages ||
pFMProps->BBT_State == BBT_NEED_SYNC )
{
BBTNeedRestore = TRUE;
//reset slot counters
if (pFMProps->BBT_Reverse) {
pFMProps->BBT_Slot = NumPages - 1;
pFMProps->BBT_NextSlot = NumPages - 2;
} else {
pFMProps->BBT_Slot = TIMpagesUsed;
pFMProps->BBT_NextSlot = pFMProps->BBT_Slot + 1;
}
pFMProps->BBT_location = pFMProps->BBT_Slot*PageSize;
}
Retval = WriteBBT2Flash(0, BBTNeedRestore);
#if DUAL_TIM
if (DualTimEnabled()) {
Retval1 = WriteBBT2Flash(pDualTimInfo->BackupTimBlock, BBTNeedRestore);
if (Retval == BBTReadError || Retval1 == BBTReadError) {
if (BBTRetry < 2) { /* read-back-check fails, retry twice */
BBTRetry ++;
SetBBTState(BBT_NEED_SYNC, BOOT_FLASH);
goto update_bbts_again;
}
} else {
if (Retval != NoError && Retval1 != NoError)
FatalError(BBTWriteError, "DualWriteErr", 0);
}
if(IsBlockRelocated(pDualTimInfo->BackupTimBlock) && IsBlockRelocated(0))
FatalError(BBTWriteError, "DUAL_TIM_RELOCATED", 0);
}
#endif
//update slot info
if (pFMProps->BBT_Reverse) {
pFMProps->BBT_Slot--;
pFMProps->BBT_NextSlot--;
} else {
pFMProps->BBT_Slot++;
pFMProps->BBT_NextSlot++;
}
/* If relocations happens to TIM blocks when update BBT */
if (GetABBTState(BOOT_FLASH) == BBT_CHANGED)
goto update_bbts_again;
//set the state back to unchanged
SetBBTState(BBT_UNCHANGED, BOOT_FLASH);
}
#endif
return;
}
UINT_T ScanBBT_LegacyExt(UINT_T BlockNum)
{
P_FMProperties_T pFMProp = GetFMProperties();
P_ReloTable_T pBBT = pFMProp->pLBBT;
P_ABBT_Table_T pABBT = pFMProp->pABBT;
UINT_T i;
//if no BBT was loaded, return original block num. No BBT, No ABBT either.
if(pFMProp->BBT_State == BBT_INVALID )
return BlockNum;
/* No relocation needed for Block0 if DualTIM is not enabled */
if(BlockNum == 0 && !DualTimEnabled())
return 0;
//Scan First level BBT if the block is used for ABBT
if(IsLogicBlockInL1BBT(BlockNum))
{
for (i = 0; i < pBBT->NumReloc; i++)
{
if (pBBT->Relo[i].From == BlockNum)
return pBBT->Relo[i].To;
}
//No matched relocate pair found
if(i == pBBT->NumReloc)
return BlockNum;
}
if(GetABBTState(BOOT_FLASH) == BBT_INVALID)
return BlockNum;
for (i = 0; i < pABBT->NumReloc; i++)
{
if (pABBT->Relo[i].From == BlockNum)
{
return pABBT->Relo[i].To;
//We make sure that the remapped block is always good,
//which means there is no A--Relocated-To-->B--Relocated-To-->C like map
//Don't need to start over any more.
//i = 0; // Start over in case remapped block is now bad
//continue;
}
}
return BlockNum;
}
static INT_T BlockIsBad(UINT_T BlockNum)
{
P_FMProperties_T pFMProp = GetFMProperties();
P_ABBT_Table_T pABBT = pFMProp->pABBT;
INT_T i;
for(i = 0; i < pABBT->NumReloc; i++)
{
if(pABBT->BlkInfo[i].Index == BlockNum && pABBT->BlkInfo[i].State == BLOCK_BAD)
return TRUE;
}
return FALSE;
}
/*
* RelocateBlock_Legacy
*/
extern UINT_T All_FF_flag;
UINT_T __RelocateBlock_LegacyExt(UINT_T BlockNum, UINT_T* ReloBlock, UINT_T isBitFlip, UINT_T NeedErase)
{
UINT_T Retval = NoError;
UINT_T BlockRelocatedTo, BlockToRead;
UINT_T NumRelo, BlkSize, initial_blk, end_blk, i;
INT_T idx = -1, RelocatedBlockEntry = -1;
INT_T RecyledBlock = -1;
UINT8_T *pBuffer = 0;
UINT8_T *pReadBuffer = 0;
UINT_T BlockAddr1, BlockAddr2, Addr, PageSize, All_FF_flag_restore, BitflipEntryNum, PoolBlockNum;
P_FMProperties_T pFMProp = GetFMProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
P_ReloTable_T pBBT = pFMProp->pLBBT;
P_ABBT_Table_T pABBT = pFMProp->pABBT;
EraseFlash_F erase = pFlashProp->EraseFlash;
ReadFlash_F read = pFlashProp->ReadFromFlash;
WriteFlash_F write = pFlashProp->WriteToFlash;
/*
* Block0 is guaranteed by manufacturer.
* And there is no need to relocate other TIM blocks.
*/
if(BlockNum == 0 && !DualTimEnabled())
{
*ReloBlock = 0;
return TIMBlocksEraseWriteFail;
}
if (DualTimEnabled() && IsTimBlock(BlockNum) && !isBitFlip) {
obm_printf("TIM blocks relocation happens\n\r");
}
//if our BBT is not valid
if((pBBT == NULL) || ((UINT16)BBT_TYPE_LEGACY != pBBT->Header))
return BBTReadError;
BlkSize = pFlashProp->BlockSize;
BlockToRead = BlockNum;
//get RP boundaries
initial_blk = pFlashProp->NumBlocks - 1 - ABBT_BLOCK_NUM;
//TODO end_blk+1 should be the last valid reserved block?
end_blk = initial_blk - (pFlashProp->NumBlocks * LEGACY_BBM_RELOC_PERCENTAGE + 99) / 100;
SearchBlockForRelocation:
NumRelo = pABBT->NumReloc;
//start at first RP block
BlockRelocatedTo = initial_blk;
if ( isBitFlip ) {
PoolBlockNum = initial_blk - end_blk;
BitflipEntryNum = 0;
for ( i = 0 ; i < pABBT->NumReloc; i++ ) {
if ( (pABBT->Relo[i].To <= end_blk) && (pABBT->BlkInfo[i].State != BLOCK_BAD) )
BitflipEntryNum++;
}
if ( pFMProp->ABBT_MaxNum &&
(BitflipEntryNum + PoolBlockNum * 2) >= pFMProp->ABBT_MaxNum) {
obm_printf("Too much bitflip blocks: %d %d %d\n\r",
BitflipEntryNum, PoolBlockNum, pFMProp->ABBT_MaxNum);
return BBTToMuchBitflips;
}
}
if ( NumRelo >= (pFMProp->ABBT_MaxNum - 2) ) {
obm_printf("Warning: ABBT Entry exhausted\n\r");
return NoError;
}
//if the table is not empty, we need to find the next available RP block
if (NumRelo != 0)
{
//run through all the entries to find that smallest 'To' entry
for (i = 0; i < pABBT->NumReloc; i++) {
if((pABBT->Relo[i].To > end_blk && pABBT->Relo[i].To <= initial_blk) //in RP
&& (BlockRelocatedTo > pABBT->Relo[i].To))
//ignore the factory bad block here
if(pABBT->BlkInfo[i].State != BLOCK_BAD)
BlockRelocatedTo = pABBT->Relo[i].To;
}
for(i = 0; i < pABBT->NumReloc; i++){
//There may be 0xFFFx->BlockNum Map here, pABBT->Relo[i].From should be valid block
if(BlockNum == pABBT->Relo[i].To && EntryIsReloPair(&pABBT->Relo[i])){
//The block to be relocated is a block relocated to other block before
//To avoid the map A--relocated to-->B--relocated to-->C
//Just A--relocacted to-->C and BLOCK_BAD--relocated to-->B
BlockToRead = BlockNum;
BlockNum = pABBT->Relo[i].From;
if(isBitFlip){
//If the relocation is for bitflip, we record the entry
//and handle it after the copy succeeds(mark it as BLOCK_TO_RECYCLE)
RelocatedBlockEntry = i;
}
else
pABBT->BlkInfo[i].State = BLOCK_BAD;
break;
}
}
//since we just found the last 'used' RP block, try the next one
//and make sure it is not a bad block.
do{
BlockRelocatedTo--;
}while(BlockIsBad(BlockRelocatedTo));
//lastly, make sure we didn't exceed RP
if(BlockRelocatedTo <= end_blk)
{
/* If the reserved pool is exhausted, check if there is
* recycled block introduced by bitflips scrubbing.
*/
#ifdef BITFLIPS_SCRUBBING
//There is no recylced blocks, relocation fails
if(pABBT->NumBlockRecyled == 0)
{
obm_printf("BBT Exhausted Error, %s %d\n\r", __FUNCTION__, __LINE__);
return BBTExhaustedError;
}
for(i = 0; i < pABBT->NumReloc; i++) {
//Find the first recycled block
if(pABBT->BlkInfo[i].State == BLOCK_RECYCLED)
{
RecyledBlock = i; //reuse the relo entry
BlockRelocatedTo = pABBT->BlkInfo[i].Index;
break;
}
}
#else
obm_printf("BBT Exhausted Error, %s %d\n\r", __FUNCTION__, __LINE__);
return BBTExhaustedError;
#endif
}
}
if(NeedErase){
//If OBM, need to disable spare area for following erase
#if NAND_CODE //To word around the issue that BootROM disable sprare area
if(BlockNum == OBM_BLOCK){
DisableSpareAreaForOBM(BlockRelocatedTo*BlkSize, 0);
}
#endif
Retval = erase(BlockRelocatedTo*BlkSize, BlkSize, BOOT_FLASH);
if(Retval != NoError) //try again
Retval = erase(BlockRelocatedTo*BlkSize, BlkSize, BOOT_FLASH);
if(Retval != NoError) {
//If erase fails, mark BlockRelocatedTo as bad block and re-search
if(RecyledBlock == -1){
pABBT->NumReloc++;
//mark it as bad
pABBT->BlkInfo[NumRelo].Index = BlockRelocatedTo;
pABBT->BlkInfo[NumRelo].State = BLOCK_BAD;
}
else{
pABBT->NumBlockRecyled --;
pABBT->BlkInfo[RecyledBlock].State = BLOCK_BAD;
}
SetABBTState(BBT_CHANGED, BOOT_FLASH);
goto SearchBlockForRelocation;
}
}
//Back up the block before the relocation is done
//Here we need to use the low level erase/read/write without scan BBT.
if(isBitFlip)
{
BlockAddr1 = BlockToRead*BlkSize;
BlockAddr2 = BlockRelocatedTo*BlkSize;
PageSize = pFlashProp->PageSize;
All_FF_flag_restore = All_FF_flag;
All_FF_flag = 1; //Don't write all 0xFFFFFFFF pages
pBuffer = malloc(PageSize << 1);
if(pBuffer == 0)
return HeapExhaustedError;
pReadBuffer = pBuffer + PageSize;
for(Addr = 0; Addr < BlkSize; Addr += PageSize)
{
Retval = read(BlockAddr1+Addr, (UINT_T)pBuffer, PageSize, BOOT_FLASH);
if(Retval != NoError && Retval != ReadDisturbError)
Retval = read(BlockAddr1+Addr, (UINT_T)pBuffer, PageSize, BOOT_FLASH);
if(Retval != NoError && Retval != ReadDisturbError){
//Tiny possibility reach here
free(pBuffer);
return Retval;
}
Retval = write(BlockAddr2+Addr, (UINT_T)pBuffer, PageSize, BOOT_FLASH);
if (Retval == NoError) {
Retval = read(BlockAddr2+Addr, (UINT_T)pReadBuffer, PageSize, BOOT_FLASH);
if (Retval != NoError || memcmp(pBuffer, pReadBuffer, PageSize))
{
Retval = ProgramError;
BlockNum = BLOCK_TO_RECYCLE; /* read back fail, mark as to recyled */
free(pBuffer);
goto RelocateDone;
}
} else { //write fails, mark BlockRelocatedTo as bad block and return
Retval = ProgramError;
BlockNum = BLOCK_BAD;
free(pBuffer);
goto RelocateDone;
}
}
free(pBuffer);
All_FF_flag = All_FF_flag_restore;
//Block to relocate is relocated to another block
if(RelocatedBlockEntry != -1)
{
pABBT->BlkInfo[RelocatedBlockEntry].State = BLOCK_TO_RECYCLE;
}
}
if(IsLogicBlockInL1BBT(BlockNum)) {
//If it's not the first time to relocate this block
//overwrite the old relocation pair with a useless entry just to increase the NumReloc
for(i = 0; i < pBBT->NumReloc; i++){
if(pBBT->Relo[i].From == BlockNum)
{
//To be compatible with Legacy BBT
pBBT->Relo[i].From = BLOCK_BAD;
break;
}
}
pBBT->Relo[pBBT->NumReloc].To = BlockRelocatedTo;
pBBT->Relo[pBBT->NumReloc].From = BlockNum;
pBBT->NumReloc++;
SetBBTState(BBT_CHANGED, BOOT_FLASH);
}
*ReloBlock = (UINT) BlockRelocatedTo;
RelocateDone:
SetABBTState(BBT_CHANGED, BOOT_FLASH);
#ifdef BITFLIPS_SCRUBBING
if(RecyledBlock == -1){
pABBT->NumReloc++;
// Relocate it
pABBT->Relo[NumRelo].To = BlockRelocatedTo;
pABBT->Relo[NumRelo].From = BlockNum;
}
else{
pABBT->NumBlockRecyled --;
pABBT->Relo[RecyledBlock].To = BlockRelocatedTo;
// if the copy for bitflips fails, mark a bad block(BlockNum = BLOCK_BAD)
pABBT->Relo[RecyledBlock].From = BlockNum;
//remove the redundant entry(A-->A)
if(pABBT->Relo[RecyledBlock].From == pABBT->Relo[RecyledBlock].To)
{
for(i = RecyledBlock; i < pABBT->NumReloc - 1; i++)
{
pABBT->ReloValue[i] = pABBT->ReloValue[i+1];
}
pABBT->NumReloc--;
}
}
#else
pABBT->NumReloc++;
pABBT->Relo[NumRelo].To = BlockRelocatedTo;
pABBT->Relo[NumRelo].From = BlockNum;
#endif
obm_printf("Relocation: %d to %d, bitflip: %s\n\r", BlockNum, BlockRelocatedTo, isBitFlip?"yes":"no");
return Retval;
}
UINT_T RelocateBlock_LegacyExt(UINT_T BlockNum, UINT_T* ReloBlock, UINT_T isBitFlip)
{
return __RelocateBlock_LegacyExt(BlockNum, ReloBlock, isBitFlip, 1);
}
UINT_T FindBBT_LegacyExt_Order(UINT_T AbbtBlock, FlashBootType_T fbt)
{
UINT_T PageSize, BlkSize, NumPages;
UINT_T *pBuffer1 = 0; //MAX_PAGE_SIZE_WORDS
UINT_T *pBuffer2 = 0; //MAX_PAGE_SIZE_WORDS
P_ABBT_Table_T pTempBBT = NULL, pTempBBT1, pTempBBT2;
P_FMProperties_T pFMProp = GetFMProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(fbt);
UINT_T CurrentPageOffset;
UINT_T Retval1, Retval2;
INT_T CurrentSlot;
INT_T Low_Valid, High_Valid;
INT_T Order_Reverse = 1;
PageSize = pFlashProp->PageSize;
BlkSize = pFlashProp->BlockSize;
NumPages = BlkSize / PageSize;
pBuffer1 = malloc(PageSize);
pBuffer2 = malloc(PageSize);
if(pBuffer1 == NULL || pBuffer2 == NULL)
return HeapExhaustedError;
pTempBBT1 = (P_ABBT_Table_T)pBuffer1;
pTempBBT2 = (P_ABBT_Table_T)pBuffer2;
//read the first slot
CurrentSlot = 0;
do {
CurrentPageOffset = ((UINT_T)CurrentSlot * PageSize) + AbbtBlock*BlkSize;
Retval1 = ReadFlash(CurrentPageOffset, (UINT_T)pTempBBT1, PageSize, fbt);
if (Retval1 == NoError)
break;
} while (++CurrentSlot < NumPages);
//read the last slot
Retval2 = ReadFlash((BlkSize - PageSize) + AbbtBlock*BlkSize,
(UINT_T)pTempBBT2, PageSize, fbt);
CurrentSlot = NumPages - 1;
do {
CurrentPageOffset = ((UINT_T)CurrentSlot * PageSize) + AbbtBlock*BlkSize;
Retval2 = ReadFlash(CurrentPageOffset, (UINT_T)pTempBBT2, PageSize, fbt);
if (Retval2 == NoError)
break;
} while (--CurrentSlot >= 0);
if((Retval1 == NoError) && (pTempBBT1->Identifier == BBT_TYPE_ASR))
Low_Valid = 1;
else
Low_Valid = 0;
if((Retval2 == NoError) && (pTempBBT2->Identifier == BBT_TYPE_ASR))
High_Valid = 1;
else
High_Valid = 0;
if (Low_Valid && !High_Valid) {
Order_Reverse = 0;
} else if (!Low_Valid && High_Valid) {
Order_Reverse = 1;
} else if (Low_Valid && High_Valid) {
if (pTempBBT1->RefCounter < pTempBBT2->RefCounter)
Order_Reverse = 0;
else
Order_Reverse = 1;
} else {
obm_printf("ERR: No valid ABBT in block %d\n\r", AbbtBlock);
free(pBuffer1);
free(pBuffer2);
return BBTReadError;
}
obm_printf("ABBT order: %s\n\r", Order_Reverse ? "reverse" : "positive");
pFMProp->ABBT_Reverse = Order_Reverse;
free(pBuffer1);
free(pBuffer2);
return NoError;
}
UINT_T FindBBT_LegacyExt(UINT_T BlockOffset, FlashBootType_T fbt)
{
UINT_T Retval, Retval1, Retval2;
UINT_T i, Slot1 = 0, Slot2 = 0, StartSlot, EndSlot, NewABBTState;
UINT_T AbbtBlock0, AbbtBlock1, ReloBlock, Block2Update = INVALID_BLOCK;
UINT_T PageSize, BlkSize, NumPages, id, CurSlot = INVALID_PAGE, Retry = TRUE;
UINT_T *pBuffer1 = 0; //MAX_PAGE_SIZE_WORDS
UINT_T *pBuffer2 = 0; //MAX_PAGE_SIZE_WORDS
P_ABBT_Table_T pTempBBT = NULL, pTempBBT1, pTempBBT2;
P_FMProperties_T pFMProp = GetFMProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(fbt);
EraseFlash_F erase = pFlashProp->EraseFlash;
WriteFlash_F write = pFlashProp->WriteToFlash;
P_ReloTable_T pBBT;
P_ABBT_Table_T pABBT;
INT_T NeedEraseNext = 0;
INT_T CrcError1 = 0, CrcError2 = 0;
INT_T BBTNotFound = 0;
//If this flash device does not use BBM, just return
if(pFlashProp->FlashSettings.UseBBM == 0)
return NoError;
SetABBTState(BBT_INVALID, fbt);
Retval = FindBBT_Legacy(BlockOffset, fbt);
//ScanBBT needs to be overwritten no matter if BBT is found
pFMProp->ScanBBT = &ScanBBT_LegacyExt;
if(Retval != NoError){
BBTNotFound = 1;
SetBBTState(BBT_INVALID, fbt);
} else {
//The first level BBT is valid now, go find the second level
//During this, the first level BBT could be updated, need to handle carefully
pBBT= pFMProp->pLBBT;
}
// Now set some values that will work
PageSize = pFlashProp->PageSize;
BlkSize = pFlashProp->BlockSize;
NumPages = BlkSize / PageSize;
id = (UINT_T) BBT_TYPE_ASR;
pBuffer1 = malloc(PageSize);
pBuffer2 = malloc(PageSize);
if(pBuffer1 == NULL || pBuffer2 == NULL)
return HeapExhaustedError;
pTempBBT1 = (P_ABBT_Table_T)pBuffer1;
pTempBBT2 = (P_ABBT_Table_T)pBuffer2;
if(pFMProp->pABBT != NULL){
pABBT = pFMProp->pABBT;
AbbtBlock0 = pFMProp->ABBT_block0;
AbbtBlock1 = pFMProp->ABBT_block1;
}
else{
pABBT = pFMProp->pABBT = (P_ABBT_Table_T)((UINT_T)pFM_SPACE + PageSize);
AbbtBlock0 = pFMProp->ABBT_block0 = pFlashProp->NumBlocks - 1;
AbbtBlock1 = pFMProp->ABBT_block1 = pFlashProp->NumBlocks - 2;
}
#ifdef BBT_ORDER_REVERSE
pFMProp->ABBT_Reverse = 1;
#else
pFMProp->ABBT_Reverse = 0;
#endif
Retval1 = FindBBT_LegacyExt_Order(AbbtBlock0, fbt);
if (Retval1 != NoError)
Retval1 = FindBBT_LegacyExt_Order(AbbtBlock1, fbt);
if (Retval1 != NoError)
goto creat_new_abbt;
//Search second level BBT
if (pFMProp->ABBT_Reverse) {
StartSlot = NumPages - 1;
EndSlot = 0;
} else {
StartSlot = 0;
EndSlot = NumPages - 1;
}
search_abbt:
Block2Update = INVALID_BLOCK;
//Search first block
Retval1 = BinarySearch((StartSlot * PageSize) + AbbtBlock0*BlkSize,
(EndSlot * PageSize) + AbbtBlock0*BlkSize,
(UINT_T)pTempBBT1,
&Slot1,
(UINT8_T*)&id,
4,
0,
fbt,
&CrcError1);
//search the backup block
Retval2 = BinarySearch((StartSlot * PageSize) + AbbtBlock1*BlkSize,
(EndSlot * PageSize) + AbbtBlock1*BlkSize,
(UINT_T)pTempBBT2,
&Slot2,
(UINT8_T*)&id,
4,
0,
fbt,
&CrcError2);
NewABBTState = BBT_UNCHANGED;
if(Retval1 != NoError && Retval2 != NoError) {
creat_new_abbt:
if (BBTNotFound)
return NotFoundError;
//As we found the father BBT, should reach here.
//Any way, restructure ABBT according to BBT
memset(pABBT, 0xFF, PageSize);
pABBT->Identifier = BBT_TYPE_ASR;
pABBT->Version = ABBT_VERSION_2001;
pABBT->Type = BBT_TYPE_MBBT_RUN;
pABBT->NumReloc = 0;
pABBT->RefCounter = 0; //RefCounter >= NumRelo
pABBT->NumBlockRecyled = 0;
pABBT->NumBlockToRecyle = 0;
pABBT->BackupBBTLoc = 0;
#if DUAL_TIM
if(DualTimEnabled()) {
pAsrDualTimInfo pDualTimInfo = GetDualTimInfo();
pABBT->BackupBBTLoc = pDualTimInfo->BackupTimBlock * BlkSize;
}
#endif
for (i = 0; i < pBBT->NumReloc; i++){
if(pBBT->Relo[i].From != BLOCK_BAD && pBBT->Relo[i].To != BLOCK_BAD) {
pABBT->Relo[pABBT->NumReloc].From = pBBT->Relo[i].From;
pABBT->Relo[pABBT->NumReloc].To = pBBT->Relo[i].To;
pABBT->NumReloc++;
}
}
UpdateABBTCrc(pABBT);
if (NeedEraseNext)
pFMProp->ABBT_CurSlot = INVALID_PAGE;
else {
pFMProp->ABBT_CurSlot = (pFMProp->ABBT_Reverse)? (NumPages - 1) : 0;
}
SetABBTState(BBT_CHANGED, fbt);
free(pBuffer1); free(pBuffer2);
return NoError;
}else if(Retval1 == NoError && Retval2 != NoError){
//ABBT BLOCK0 has valid BBT, but ABBT Block1 doesn't
pTempBBT = pTempBBT1;
if (pFMProp->ABBT_Reverse) {
StartSlot = Slot1;
EndSlot = NumPages;
} else {
StartSlot = 0;//Slot1;
EndSlot = Slot1 + 1;//NumPages;
}
Block2Update = AbbtBlock1;
CurSlot = Slot1;
}else if(Retval1 != NoError && Retval2 == NoError){
//ABBT BLOCK1 has valid BBT, but ABBT Block0 doesn't
pTempBBT = pTempBBT2;
if (pFMProp->ABBT_Reverse) {
StartSlot = Slot2;
EndSlot = NumPages;
} else {
StartSlot = 0;//Slot2;
EndSlot = Slot2 + 1;// NumPages;
}
Block2Update = AbbtBlock0;
CurSlot = Slot2;
}else{//Both ABBT BLOCK0 and ABBT BLOCK1 have valid BBT
//ABBT BLOCK0 has more recent BBT
if(Slot2 > Slot1){
if (pFMProp->ABBT_Reverse) {
pTempBBT = pTempBBT1;
StartSlot = Slot1;
EndSlot = Slot2;
Block2Update = AbbtBlock1;
CurSlot = Slot1;
} else {
pTempBBT = pTempBBT2;
StartSlot = Slot1 + 1;
EndSlot = Slot2 + 1;
Block2Update = AbbtBlock0;
CurSlot = Slot2;
}
}else if(Slot2 < Slot1){
if (pFMProp->ABBT_Reverse) {
pTempBBT = pTempBBT2;
StartSlot = Slot2;
EndSlot = Slot1;
Block2Update = AbbtBlock0;
CurSlot = Slot2;
} else {
pTempBBT = pTempBBT1;
StartSlot = Slot2 + 1;
EndSlot = Slot1 + 1;
Block2Update = AbbtBlock1;
CurSlot = Slot1;
}
}else{
CurSlot = Slot1;
//Even both blocks have valid ABBT in same page, they may be different
if(pTempBBT1->RefCounter > pTempBBT2->RefCounter){
pTempBBT = pTempBBT1;
NewABBTState = BBT_CHANGED;
}else if(pTempBBT1->RefCounter < pTempBBT2->RefCounter){
pTempBBT = pTempBBT2;
NewABBTState = BBT_CHANGED;
}else{
if(pTempBBT1->NumReloc > pTempBBT2->NumReloc){
pTempBBT = pTempBBT1;
NewABBTState = BBT_CHANGED;
}else if(pTempBBT1->NumReloc < pTempBBT2->NumReloc){
pTempBBT = pTempBBT2;
NewABBTState = BBT_CHANGED;
}else{
pTempBBT = pTempBBT1;
}
}
}
}
if(pTempBBT != NULL)
memcpy(pABBT, pTempBBT, PageSize);
if (CurSlot != INVALID_PAGE) {
if (pFMProp->ABBT_Reverse) {
if (CurSlot == 0)
pFMProp->ABBT_CurSlot = INVALID_PAGE;
else
pFMProp->ABBT_CurSlot = CurSlot -1;
}
else {
if (CurSlot >= (NumPages - 1))
pFMProp->ABBT_CurSlot = INVALID_PAGE;
else
pFMProp->ABBT_CurSlot = CurSlot + 1;
}
} else {
pFMProp->ABBT_CurSlot = INVALID_PAGE;
}
//Set valid ABBT state, CHANGED or UNCHANGED, denpends on the search result
SetABBTState(NewABBTState, fbt);
if ((CrcError2 == 0) && (CrcError1 == 0)) {
#ifdef BITFLIPS_SCRUBBING
//If Bitflip happens during read ABBT_Block0
if(pFMProp->ABBT_State & ABBT_BITFLIP0){
Retval = ScrubBlock_LegacyExt(ScanBBT_LegacyExt(AbbtBlock0), &ReloBlock);
if(Retval != NoError){
obm_printf("abbt block0 bitflip, no relocation\n\r");
Retval = NoError;
}
else
pFMProp->ABBT_State &= ~ABBT_BITFLIP0;
UpdateABBTCrc(pABBT);
}
//If Bitflip happens during read ABBT_Block1
if(pFMProp->ABBT_State & ABBT_BITFLIP1){
Retval = ScrubBlock_LegacyExt(ScanBBT_LegacyExt(AbbtBlock1), &ReloBlock);
if(Retval != NoError){
obm_printf("abbt block1 bitflip, no relocation\n\r");
Retval = NoError;
}
else
pFMProp->ABBT_State &= ~ABBT_BITFLIP1;
UpdateABBTCrc(pABBT);
}
#endif
//Fill the holes of Block2Update
if((Block2Update != INVALID_BLOCK) && (StartSlot < EndSlot))
{
Block2Update = ScanBBT_LegacyExt(Block2Update);
//Most time, we should not reach here
for(i = StartSlot; i < EndSlot; i++)
{
Retval = write(Block2Update*BlkSize+i*PageSize, (UINT_T)pTempBBT, PageSize, fbt);
if(Retval != NoError){
if(Retry == TRUE){
Retry = FALSE;
Retval = erase(Block2Update*BlkSize, BlkSize, fbt);
if(Retval == NoError)
{
if (pFMProp->ABBT_Reverse) {
// copy from start to block end
EndSlot = NumPages;
i = StartSlot - 1; //restart the copy, i++
} else {
// copy from block 0 to latest slot
i = - 1; //restart the copy, i++
}
continue;
}
}
Retry = TRUE;
Retval = RelocateBlock_LegacyExt(Block2Update, &Block2Update, 0);
UpdateABBTCrc(pABBT);
if(Retval != NoError){
/* If Relocate fails, break the loop。
* Block2Update doesn't have the latest invalid BBT
* but we can live with this.
*/
break;
}
else{
if (pFMProp->ABBT_Reverse) {
// copy from start to block end
EndSlot = NumPages;
i = StartSlot - 1; //restart the copy, i++
} else {
// copy from block 0 to latest slot
i = - 1; //restart the copy, i++
}
}
}
}
}
} /* if ((CrcError2 == 0) && (CrcError1 == 0)) */
if (CrcError1 || CrcError2) {
pFMProp->ABBT_CurSlot = INVALID_PAGE; //erase due to CRC error
SetABBTState(BBT_CHANGED, BOOT_FLASH);
}
free(pBuffer1); free(pBuffer2);
if (BBTNotFound) {
/* Restore BBT based on ABBT, corner case */
CreateBBT_Legacy(NULL);
pBBT = pFMProp->pLBBT;
for (i = 0; i < pABBT->NumReloc; i++) {
if (IsLogicBlockInL1BBT(pABBT->Relo[i].From) ) {
pBBT->Relo[pBBT->NumReloc].From = pABBT->Relo[i].From;
pBBT->Relo[pBBT->NumReloc].To = pABBT->Relo[i].To;
pBBT->NumReloc ++;
}
}
}
return NoError;
}
UINT_T ScrubBlock_LegacyExt(UINT_T BlockNum, UINT_T* ReloBlock)
{
UINT_T Retval = NoError;
#ifdef BITFLIPS_SCRUBBING
UINT_T RelocateBlock;
INT_T i, ABBT_updated = FALSE;
P_FMProperties_T pFMProp = GetFMProperties();
P_ReloTable_T pBBT = pFMProp->pLBBT;
P_ABBT_Table_T pABBT = pFMProp->pABBT;
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
if(pBBT == NULL || pFMProp->BBT_State == BBT_INVALID)
return NoError;
/* If bitflip happens in Tim Blocks, do nothing. Block0 should be always good.
* If dual TIM is enabled, should ignore bitflips in block1(back up TIM) too.
*/
if(IsTimBlock(BlockNum)){
obm_printf("Warning: bitflip in Tim Block%d\n\r", BlockNum);
#if DUAL_TIM
if (DualTimEnabled()) {
EraseBlockAndRestoreTIM(pFlashProp, BlockNum, 1);
}
#endif
return NoError;
}
//When bitflip happens when reading ABBT from Flash(BBT is OK, but ABBT is not),
//then we don't handle it immediately, record the state and handle it when ABBT is OK,
//This should only happens during finding bbt from flash
if( (pABBT == NULL) || (GetABBTState(BOOT_FLASH) == BBT_INVALID) )
{
*ReloBlock = BlockNum;
//Backward Search the block index
for(i = 0; i < pBBT->NumReloc; i++)
{
if((pBBT->Relo[i].To == BlockNum) && EntryIsReloPair(&pBBT->Relo[i]))
{
BlockNum = pBBT->Relo[i].From;
break;
}
}
if(pFMProp->ABBT_block0 == BlockNum){
pFMProp->ABBT_State |= ABBT_BITFLIP0;
}
else if(pFMProp->ABBT_block1 == BlockNum){
pFMProp->ABBT_State |= ABBT_BITFLIP1;
}else{
//Most times, ABBT should be OK when bitflip happens,
//except when reading ABBT_block0 or ABBT_block1.
//Just return error here.
return BBTReadError;
}
return NoError;
}
do{
//Need back up before relocate
Retval = RelocateBlock_LegacyExt(BlockNum, ReloBlock, 1);
}while(Retval == ProgramError);
if (Retval == BBTToMuchBitflips) {
return NoError;
}
if(Retval != NoError)
return Retval;
RelocateBlock = *ReloBlock;
//Check the recycled block info if already updated in RelocateBlock API
for(i = 0; i < pABBT->NumReloc; i++)
{
if((pABBT->BlkInfo[i].State == BLOCK_TO_RECYCLE) &&
(pABBT->BlkInfo[i].Index == BlockNum))
{
ABBT_updated = TRUE;
break;
}
}
if(ABBT_updated == FALSE){
pABBT->BlkInfo[pABBT->NumReloc].State = BLOCK_TO_RECYCLE;
pABBT->BlkInfo[pABBT->NumReloc].Index = BlockNum;
pABBT->NumReloc++;
}
pABBT->NumBlockToRecyle++;
/* record the bitflip times */
for(i = 0; i < pABBT->NumReloc; i++)
{
if(pABBT->BlkInfo[i].State == BLK_FLIP_COUNT)
{
pABBT->BlkInfo[i].Index++;
break;
}
}
if (i == pABBT->NumReloc) {
pABBT->BlkInfo[pABBT->NumReloc].State = BLK_FLIP_COUNT;
pABBT->BlkInfo[pABBT->NumReloc].Index = 1;
pABBT->NumReloc ++;
}
SetABBTState(BBT_CHANGED, BOOT_FLASH);
#endif
return Retval;
}
INT_T RawCopyFlashBlock(UINT_T BlockFrom, UINT_T BlockTo, INT_T NeedErase)
{
UINT_T Retval = NoError;
UINT_T BlkSize, PageSize, PageOff, SrcAddr, DstAddr;
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
EraseFlash_F erase = pFlashProp->EraseFlash;
ReadFlash_F read = pFlashProp->ReadFromFlash;
WriteFlash_F write = pFlashProp->WriteToFlash;
UINT8_T *ptemp = 0;
BlkSize = GetBlockSize(BOOT_FLASH);
PageSize = GetPageSize(BOOT_FLASH);
DstAddr = BlockTo * BlkSize;
SrcAddr = BlockFrom * BlkSize;
if (NeedErase) {
Retval = erase(DstAddr, BlkSize, BOOT_FLASH);
if(Retval != NoError) //retry again
Retval = erase(DstAddr, BlkSize, BOOT_FLASH);
if(Retval)
return EraseError;
}
ptemp = malloc(pFlashProp->BlockSize);
if(ptemp == NULL)
return HeapExhaustedError;
Retval = read(SrcAddr, ptemp, BlkSize, BOOT_FLASH);
if (Retval != NoError && Retval != ReadDisturbError){
free(ptemp);
return ReadError;
}
for (PageOff = 0; PageOff < BlkSize; PageOff += PageSize) {
if(CheckPattern(ptemp+PageOff, 0xFF, PageSize) == 1){
continue; //skip the 0xFF pages
}
else
{
Retval = write(DstAddr+PageOff, ptemp+PageOff, PageSize, BOOT_FLASH);
if(Retval != NoError) {
free(ptemp);
return WriteError;
}
}
}
free(ptemp);
return NoError;
}
UINT_T RemapRecycledBlocks(void)
{
INT_T i, j, k;
UINT_T Retval = NoError;
P_FMProperties_T pFMProp = GetFMProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
P_ABBT_Table_T pABBT = pFMProp->pABBT;
P_ReloTable_T pBBT = pFMProp->pLBBT;
EraseFlash_F erase = pFlashProp->EraseFlash;
UINT_T BlkSize = GetBlockSize(BOOT_FLASH);
INT_T BlockToErase = -1;
if (pFlashProp->FlashSettings.UseBBM == 0 || pABBT->NumReloc == 0)
return NoError;
for ( i = 0; i < pABBT->NumReloc; i ++)
{
if(pABBT->BlkInfo[i].State == BLOCK_RECYCLED) {
for ( j = 0; j < pABBT->NumReloc; j++)
{
if (pABBT->Relo[j].From == pABBT->BlkInfo[i].Index) {
Retval = RawCopyFlashBlock(pABBT->Relo[j].To, pABBT->BlkInfo[i].Index, 1);
if(Retval == ReadError) {
Retval = NoError;
continue; /* Do nothing if read error, should never happens*/
}
else if (Retval == EraseError || Retval == WriteError) {
pABBT->BlkInfo[i].State = BLOCK_BAD;
pABBT->RefCounter ++;
pABBT->NumBlockRecyled --;
pFMProp->ABBT_State = BBT_CHANGED;
UpdateBBT_LegacyExt();
Retval = NoError;
} else { /* Retval == NoError */
if(IsLogicBlockInL1BBT(pABBT->Relo[j].From)) {
for (k = 0; k <pBBT->NumReloc; k++) {
if(pBBT->Relo[k].From == pABBT->Relo[j].From) {
pBBT->Relo[k].From = BLOCK_BAD;
pBBT->Relo[k].To = BLOCK_BAD;
pFMProp->BBT_State = BBT_CHANGED;
break;
}
}
}
pABBT->BlkInfo[j].State = BLOCK_RECYCLED;
BlockToErase = pABBT->BlkInfo[j].Index;
pABBT->Relo[i].From = pABBT->Relo[pABBT->NumReloc-1].From;
pABBT->Relo[i].To = pABBT->Relo[pABBT->NumReloc-1].To;
pABBT->Relo[pABBT->NumReloc-1].From = 0xFFFF;
pABBT->Relo[pABBT->NumReloc-1].To = 0xFFFF; //delete an entry
pABBT->NumReloc --;
pABBT->RefCounter ++;
pFMProp->ABBT_State = BBT_CHANGED;
UpdateBBT_LegacyExt();
i--;
if (BlockToErase > 0) {
Retval = erase(BlockToErase*BlkSize, BlkSize, BOOT_FLASH);
if(Retval != NoError)
Retval = erase(BlockToErase*BlkSize, BlkSize, BOOT_FLASH);
}
}
break;
}
}
}
}
return Retval;
}
UINT_T RecyleBlocks_LegacyExt(void)
{
UINT_T Retval = NoError;
#ifdef BITFLIPS_SCRUBBING
INT_T i;
P_FMProperties_T pFMProp = GetFMProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
P_ABBT_Table_T pABBT = pFMProp->pABBT;
if(pFlashProp->FlashSettings.UseBBM == 0 ||
pABBT->NumBlockToRecyle == 0)
return NoError;
for(i = 0; i < pABBT->NumReloc; i++)
{
if(pABBT->BlkInfo[i].State == BLOCK_TO_RECYCLE)
{
Retval = TortureBlock(pABBT->BlkInfo[i].Index);
if(Retval == NoError){
pABBT->NumBlockRecyled ++;
pABBT->BlkInfo[i].State = BLOCK_RECYCLED;
}
else
pABBT->BlkInfo[i].State = BLOCK_RECYCLE_FAILED;
if(pABBT->NumBlockToRecyle)
pABBT->NumBlockToRecyle--;
}
}
SetABBTState(BBT_CHANGED, BOOT_FLASH);
if(pABBT->NumBlockToRecyle)
Retval = FlashBlockRecycleError;
else
Retval = NoError;
#endif
return Retval;
}
static UINT8_T Patterns[] = {0xa5, 0x5a, 0x0};
INT_T CheckPattern(const VOID *buf, UINT8_T patt, INT_T size)
{
INT_T i;
for (i = 0; i < size; i++)
if (((const UINT8_T *)buf)[i] != patt)
return 0;
return 1;
}
INT_T TortureBlock(UINT_T BlockNum)
{
INT_T Retval = NoError, i, PattCount;
UINT_T BlockSize, BlockAddr;
UINT8_T *pBuffer = 0;
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
BlockSize = pFlashProp->BlockSize;
EraseFlash_F erase = pFlashProp->EraseFlash;
ReadFlash_F read = pFlashProp->ReadFromFlash;
WriteFlash_F write = pFlashProp->WriteToFlash;
UINT_T TotalBlockNum = pFlashProp->NumBlocks;
if(BlockNum >= pFlashProp->NumBlocks) {
obm_printf("Torture invalid block %d\n\r", BlockNum);
return InvalidAddressRangeError;
}
PattCount = sizeof(Patterns)/sizeof(Patterns[0]);
BlockAddr = BlockNum*BlockSize;
pBuffer = malloc(BlockSize);
if(pBuffer == 0)
return HeapExhaustedError;
/*Here we need to use the low level erase/read/write interface without scan
*BBT, as the block itself is relocated to another one.
*/
for (i = 0; i < PattCount; i++){
Retval = erase(BlockAddr, BlockSize, BOOT_FLASH);
if(Retval != NoError){
free(pBuffer);
return Retval;
}
Retval = read(BlockAddr, (UINT_T)pBuffer, BlockSize, BOOT_FLASH);
if(Retval != NoError){
free(pBuffer);
return Retval;
}
Retval = CheckPattern(pBuffer, 0xFF, BlockSize);
if(Retval == 0) {//Erased, but a non-0xFF byte found
free(pBuffer);
return EraseError;
}
/* Write a pattern and check it */
memset(pBuffer, Patterns[i], BlockSize);
Retval = write(BlockAddr, (UINT_T)pBuffer, BlockSize, BOOT_FLASH);
if(Retval != NoError){
free(pBuffer);
return Retval;
}
memset(pBuffer, ~Patterns[i], BlockSize);
Retval = read(BlockAddr, (UINT_T)pBuffer, BlockSize, BOOT_FLASH);
if(Retval != NoError){
free(pBuffer);
return Retval;
}
Retval = CheckPattern(pBuffer, Patterns[i], BlockSize);
if(Retval == 0){
free(pBuffer);
return FlashReadError;
}
Retval = erase(BlockAddr, BlockSize, BOOT_FLASH);
if(Retval != NoError){
free(pBuffer);
return Retval;
}
}
if(i == PattCount)
Retval = NoError;
free(pBuffer);
return Retval;
}
void SCAN_FactoryBadBlockLegacyExt(void)
{
UINT16 i, badblocklist[100];
UINT fBBNum, NewBlock, initial_blk, end_blk, num_relo;
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
P_FMProperties_T pFMP = GetFMProperties();
GenerateFBBT_F Gen_FBBT = pFlashProp->GenerateFBBT;
P_ABBT_Table_T pABBT = pFMP->pABBT;
P_ReloTable_T pBBT = pFMP->pLBBT;
//return early if not supported
if( (Gen_FBBT == NULL) || (pFlashProp->FlashSettings.UseBBM == 0) )
return;
if((pBBT == NULL) || (pABBT == NULL) || ((UINT16)BBT_TYPE_LEGACY != pBBT->Header))
return;
//get RP boundaries
#if defined(NAND_CODE) || defined(SPINAND_CODE)
initial_blk = pFlashProp->NumBlocks - 1 - ABBT_BLOCK_NUM;
#endif
end_blk = initial_blk - (pFlashProp->NumBlocks * LEGACY_BBM_RELOC_PERCENTAGE + 99) / 100;
fBBNum = Gen_FBBT(badblocklist);
num_relo = pABBT->NumReloc;
for(i = 0; i < fBBNum; i++){
//if the block is in reserved pool, just mark it as bad block
if(badblocklist[i] > end_blk && badblocklist[i] <= initial_blk)
{
pABBT->BlkInfo[pABBT->NumReloc].Index = badblocklist[i];
pABBT->BlkInfo[pABBT->NumReloc].State = BLOCK_BAD;
pABBT->NumReloc++;
}
}
if(num_relo != pBBT->NumReloc)
SetABBTState(BBT_CHANGED, BOOT_FLASH);
for(i = 0; i < fBBNum; i++){
if(badblocklist[i] <= end_blk || badblocklist[i] > initial_blk)
RelocateBlock_LegacyExt(badblocklist[i], &NewBlock, 0);
}
}
static VOID DetectScrubBitflipBlock(UINT32 Block)
{
pIMAGE_INFO_3_4_0 pImageInfo;
UINT_T BlkSize, Retval, BlockNum, BlockToRecyle, i;
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
EraseFlash_F erase = pFlashProp->EraseFlash;
ReadFlash_F read = pFlashProp->ReadFromFlash;
WriteFlash_F write = pFlashProp->WriteToFlash;
P_FMProperties_T pFMP = GetFMProperties();
P_ABBT_Table_T pABBT = pFMP->pABBT;
UCHAR *pBuffer = 0;
BlkSize = pFlashProp->BlockSize;
#if NAND_CODE //To word around the issue that BootROM disable sprare area
if(Block == OBM_BLOCK)
DisableSpareAreaForOBM(Block*BlkSize, BlkSize);
#endif
BlockNum = ScanBBT_LegacyExt(Block);
pBuffer = malloc(BlkSize);
if(pBuffer == NULL)
return HeapExhaustedError;
Retval = read(BlockNum*BlkSize, pBuffer, BlkSize, BOOT_FLASH);
if ( Retval == ReadDisturbError ) {
ScrubBlock_LegacyExt(BlockNum, &BlockNum);
SetBBTStates(BBT_CHANGED, BBT_CHANGED, BOOT_FLASH);
UpdateBBT();
}
free(pBuffer);
return;
}
/* This is to detect the bitflip of the blocks which are only read by BootROM */
VOID DetectScrubBitflipBlocks(VOID)
{
#if MMC_CODE
return;
#endif
if(!DualTimEnabled())
{
/* As BootROM can't transfer the read disturb error of OBM block to OBM,
* OBM read itself instead, if bitflip happens on OBM block, it will be handled,
* so that BootROM will not meet read disturb error when reading OBM.
* If Dual TIM is enabled, both OBM blocks are read in InitializeDualTimLate()
*/
DetectScrubBitflipBlock(OBM_BLOCK); /* OBM block */
}
return;
}
UINT_T GetBadBlockNumExt(void)
{
UINT_T BlockNum;
INT_T i;
P_FMProperties_T pFMProp = GetFMProperties();
P_ABBT_Table_T pABBT = pFMProp->pABBT;
BlockNum = pABBT->NumReloc;
for (i = 0; i < pABBT->NumReloc; ++i)
{
//The block which is recycled is good block now
if(pABBT->BlkInfo[i].State == BLOCK_RECYCLED)
BlockNum--;
}
return BlockNum;
}
void Dump_FM_Info(void)
{
INT_T i;
P_FMProperties_T pFMProp = GetFMProperties();
P_ReloTable_T pBBT = pFMProp->pLBBT;
P_ABBT_Table_T pABBT = pFMProp->pABBT;
obm_printf("FM:\n\r");
obm_printf("BBT_State: 0x%x\n\r", pFMProp->BBT_State);
obm_printf("ABBT_State: 0x%x\n\r", pFMProp->ABBT_State);
obm_printf("BBT_Slot: 0x%x\n\r", pFMProp->BBT_Slot);
obm_printf("BBT_NextSlot: 0x%x\n\r", pFMProp->BBT_NextSlot);
obm_printf("BBT_location: 0x%x\n\r", pFMProp->BBT_location);
obm_printf("BBT_Reverse: %d\n\r", pFMProp->BBT_Reverse);
obm_printf("ABBT_Reverse: %d\n\r", pFMProp->ABBT_Reverse);
obm_printf("ABBT_CurSlot: 0x%x\n\r", pFMProp->ABBT_CurSlot);
obm_printf("BBT:\n\r");
obm_printf("Header: 0x%x\n\r", pBBT->Header);
obm_printf("NumReloc: %d\n\r", pBBT->NumReloc);
for (i = 0; i < pBBT->NumReloc; i++)
{
obm_printf("%d: block %d ---> %d\n\r", i, pBBT->Relo[i].From, pBBT->Relo[i].To);
}
obm_printf("ABBT:\n\r");
obm_printf("Identifier: 0x%x\n\r", pABBT->Identifier);
obm_printf("Version: 0x%x\n\r", pABBT->Version);
obm_printf("Type: 0x%x\n\r", pABBT->Type);
obm_printf("RefCounter: %d\n\r", pABBT->RefCounter);
obm_printf("NumReloc: %d\n\r", pABBT->NumReloc);
obm_printf("NumBlockRecyled: %d\n\r", pABBT->NumBlockRecyled);
obm_printf("NumBlockToRecyle: %d\n\r", pABBT->NumBlockToRecyle);
for (i = 0; i < pABBT->NumReloc; i++)
{
obm_printf("%d: block %d ---> %d\n\r", i, pABBT->Relo[i].From, pABBT->Relo[i].To);
}
}
#endif