b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | #include "Typedef.h" |
| 2 | #include "FM.h" |
| 3 | #include "Partition.h" |
| 4 | #include "Errors.h" |
| 5 | #include "Flash.h" |
| 6 | #include "misc.h" |
| 7 | #include "loadoffsets.h" |
| 8 | #include "tim.h" |
| 9 | #include "malloc.h" |
| 10 | |
| 11 | #if COPYIMAGESTOFLASH |
| 12 | #include "BootLoader.h" |
| 13 | #endif |
| 14 | |
| 15 | extern UINT_T *pFM_SPACE; |
| 16 | |
| 17 | #ifdef BBM_LEGACY_EXT |
| 18 | static int EntryIsBlockInfo(void *Entry) |
| 19 | { |
| 20 | P_BlockState_T pBlkInfo = (P_BlockState_T)Entry; |
| 21 | |
| 22 | if((pBlkInfo->State >= BLOCK_RECYCLED) && |
| 23 | (pBlkInfo->State != BLK_FLIP_COUNT)) |
| 24 | return 1; |
| 25 | else |
| 26 | return 0; |
| 27 | } |
| 28 | |
| 29 | static int EntryIsReloPair(void *Entry) |
| 30 | { |
| 31 | P_ReloPair_T pRelo = (P_ReloPair_T)Entry; |
| 32 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 33 | if(pRelo->From < pFlashProp->NumBlocks) |
| 34 | return 1; |
| 35 | else |
| 36 | return 0; |
| 37 | } |
| 38 | |
| 39 | void SetABBTState(ReloState_T newState, FlashBootType_T fbt) |
| 40 | { |
| 41 | UINT_T BlkSize, PageSize; |
| 42 | P_FMProperties_T pFMProps = GetFMProperties(); |
| 43 | |
| 44 | //make sure this device uses BBM |
| 45 | if(GetFlashProperties(fbt)->FlashSettings.UseBBM == 0) |
| 46 | return; |
| 47 | // Now set some values that will work |
| 48 | PageSize = GetPageSize(fbt); |
| 49 | BlkSize = GetBlockSize(fbt); |
| 50 | |
| 51 | //check if the BBT got erase. If so, set the slot numbers back to their starting slot |
| 52 | if ( newState == BBT_ERASED ) |
| 53 | { |
| 54 | if (pFMProps->ABBT_Reverse) |
| 55 | pFMProps->ABBT_CurSlot = (BlkSize / PageSize) - 1; |
| 56 | else |
| 57 | pFMProps->ABBT_CurSlot = 0; |
| 58 | } |
| 59 | |
| 60 | pFMProps->ABBT_State &= ~ABBT_STATE_MASK; |
| 61 | pFMProps->ABBT_State |= newState; |
| 62 | } |
| 63 | |
| 64 | UINT_T GetABBTState(FlashBootType_T fbt) |
| 65 | { |
| 66 | P_FMProperties_T pFMProps = GetFMProperties(); |
| 67 | |
| 68 | //make sure this device uses BBM |
| 69 | if(GetFlashProperties(fbt)->FlashSettings.UseBBM == 0) |
| 70 | return 0; |
| 71 | |
| 72 | return (pFMProps->ABBT_State & ABBT_STATE_MASK); |
| 73 | } |
| 74 | |
| 75 | void SetBBTStates(ReloState_T bbtState, ReloState_T abbtState, FlashBootType_T fbt) |
| 76 | { |
| 77 | SetBBTState(bbtState, fbt); |
| 78 | SetABBTState(abbtState, fbt); |
| 79 | } |
| 80 | |
| 81 | static void UpdateBBTCrc(P_ReloTable_T pBBT) |
| 82 | { |
| 83 | UINT_T CRC, ABBTVersion, BBTLen; |
| 84 | BBT_INFO BBTInfo; |
| 85 | BBTLen = BBT_HEADER_SIZE + pBBT->NumReloc * sizeof(ReloPair_T); |
| 86 | |
| 87 | ABBTVersion = BU_REG_READ((UINT_T)pBBT + BBTLen); |
| 88 | if (ABBTVersion != ABBT_VERSION_2001){ |
| 89 | //obm_printf("Upgrade BBT for CRC!!!\n\r"); |
| 90 | BU_REG_WRITE((UINT_T)pBBT + BBTLen, ABBT_VERSION_2001); |
| 91 | } |
| 92 | |
| 93 | BBTInfo.Value = 0; |
| 94 | BBTInfo.Bits.Owner = BBT_OBM; |
| 95 | BU_REG_WRITE((UINT_T)pBBT + BBTLen + 4, BBTInfo.Value); |
| 96 | BBTLen = BBTLen + 4 /* version */ + 2 /* half info */; |
| 97 | CRC = malbrain_crc32(0, pBBT, BBTLen); |
| 98 | BBTInfo.Bits.CRC = from32to16(CRC); |
| 99 | BU_REG_WRITE16((UINT_T)pBBT + BBTLen, BBTInfo.Bits.CRC); |
| 100 | } |
| 101 | |
| 102 | INT_T IsBBTValid(P_ReloTable_T pBBT) |
| 103 | { |
| 104 | UINT_T CRC1, CRC2, ABBTVersion, BBTLen; |
| 105 | BBTLen = BBT_HEADER_SIZE + pBBT->NumReloc * sizeof(ReloPair_T); |
| 106 | |
| 107 | ABBTVersion = BU_REG_READ((UINT_T)pBBT + BBTLen); |
| 108 | |
| 109 | switch(ABBTVersion) |
| 110 | { |
| 111 | case 0xFFFFFFFF: |
| 112 | return (pBBT->Header == BBT_TYPE_LEGACY); |
| 113 | default: |
| 114 | obm_printf("Warning: unexpected version: 0x%x\n\r", ABBTVersion); |
| 115 | case ABBT_VERSION_2001: |
| 116 | CRC1 = BU_REG_READ16((UINT_T)pBBT + BBTLen + 6); |
| 117 | CRC2 = malbrain_crc32(0, pBBT, BBTLen + 6); |
| 118 | CRC2 = from32to16(CRC2); |
| 119 | return (CRC1 == CRC2); |
| 120 | } |
| 121 | |
| 122 | return 0; |
| 123 | } |
| 124 | |
| 125 | static void UpdateABBTCrc(P_ABBT_Table_T pABBT) |
| 126 | { |
| 127 | UINT_T CRC, CrcLen; |
| 128 | if (pABBT->Version != ABBT_VERSION_2001) { |
| 129 | obm_printf("Upgrade ABBT for CRC!!!\n\r"); |
| 130 | pABBT->Version = ABBT_VERSION_2001; |
| 131 | } |
| 132 | |
| 133 | CrcLen = ABBT_HEADER_SIZE + pABBT->NumReloc * sizeof(ReloPair_T); |
| 134 | pABBT->Info.Value = 0; |
| 135 | pABBT->Info.Bits.Owner = BBT_OBM; |
| 136 | CRC = malbrain_crc32(0, pABBT, CrcLen); |
| 137 | pABBT->Info.Bits.CRC = from32to16(CRC); |
| 138 | } |
| 139 | |
| 140 | static INT_T IsABBTValid(P_ABBT_Table_T pABBT) |
| 141 | { |
| 142 | UINT_T CrcLen, CRC1, CRC2; |
| 143 | switch(pABBT->Version) |
| 144 | { |
| 145 | case ABBT_VERSION: |
| 146 | case ABBT_VERSION_1002: |
| 147 | return (pABBT->Identifier == BBT_TYPE_ASR); |
| 148 | default: |
| 149 | obm_printf("Warning: unexpected ABBT version: 0x%x\n\r", pABBT->Version); |
| 150 | case ABBT_VERSION_2001: |
| 151 | CrcLen = ABBT_HEADER_SIZE + pABBT->NumReloc * sizeof(ReloPair_T); |
| 152 | CRC1 = pABBT->Info.Bits.CRC; |
| 153 | pABBT->Info.Bits.CRC = 0; |
| 154 | CRC2 = malbrain_crc32(0, pABBT, CrcLen); |
| 155 | CRC2 = from32to16(CRC2); |
| 156 | return (CRC1 == CRC2); |
| 157 | } |
| 158 | |
| 159 | return 0; |
| 160 | } |
| 161 | |
| 162 | INT CheckMagicBBT(UINT_T Magic, VOID *BbtBuffer) |
| 163 | { |
| 164 | P_ReloTable_T pBBT = NULL; |
| 165 | P_ABBT_Table_T pABBT = NULL; |
| 166 | |
| 167 | switch(Magic) { |
| 168 | case BBT_TYPE_LEGACY: |
| 169 | pBBT = (P_ReloTable_T)BbtBuffer; |
| 170 | return IsBBTValid(pBBT); |
| 171 | case BBT_TYPE_ASR: |
| 172 | pABBT = (P_ABBT_Table_T)BbtBuffer; |
| 173 | return IsABBTValid(pABBT); |
| 174 | default: |
| 175 | obm_printf("Invalid BBT magic: 0x%x\n\r", Magic); |
| 176 | return 1; //??? |
| 177 | } |
| 178 | |
| 179 | return 0; |
| 180 | } |
| 181 | |
| 182 | /* This is the blocks are maintained by L1 BBT */ |
| 183 | static INT_T L1BbtBlocks[L1_BBT_BLOCK_NUM]; |
| 184 | static UINT_T L1BbtBlockNum = 0; |
| 185 | |
| 186 | VOID InitL1BBTBlocks(VOID) |
| 187 | { |
| 188 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 189 | |
| 190 | INT_T i = 0; |
| 191 | #if DUAL_TIM |
| 192 | if (DualTimEnabled()) { |
| 193 | pAsrDualTimInfo pDualTimInfo = GetDualTimInfo(); |
| 194 | L1BbtBlocks[i++] = pDualTimInfo->MainObmBlock; //Main OBM block |
| 195 | L1BbtBlocks[i++] = pDualTimInfo->BackupTimBlock; //Backup TIM block |
| 196 | L1BbtBlocks[i++] = pDualTimInfo->BackupObmBlock; //Backup OBM Block |
| 197 | L1BbtBlocks[i++] = pFlashProp->NumBlocks - 2; //main ABBT |
| 198 | L1BbtBlocks[i++] = pFlashProp->NumBlocks - 1; //backup ABBT |
| 199 | L1BbtBlocks[i++] = 0; //Main TIM |
| 200 | L1BbtBlockNum = i; |
| 201 | } else |
| 202 | #endif |
| 203 | { |
| 204 | L1BbtBlocks[i++] = 1; //OBM Block |
| 205 | L1BbtBlocks[i++] = pFlashProp->NumBlocks - 2; //main ABBT |
| 206 | L1BbtBlocks[i++] = pFlashProp->NumBlocks - 1; //backup ABBT |
| 207 | L1BbtBlockNum = i; |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | INT_T IsLogicBlockInL1BBT(UINT_T BlockNum) { |
| 212 | INT_T i; |
| 213 | |
| 214 | for (i = 0 ; i < L1BbtBlockNum; i++) |
| 215 | { |
| 216 | if(L1BbtBlocks[i] == BlockNum) |
| 217 | return 1; |
| 218 | } |
| 219 | |
| 220 | return 0; |
| 221 | } |
| 222 | |
| 223 | INT_T IsTimBlock(UINT_T BlockNum) { |
| 224 | #if DUAL_TIM |
| 225 | if (DualTimEnabled()) { |
| 226 | pAsrDualTimInfo pDualTimInfo = GetDualTimInfo(); |
| 227 | if(BlockNum == 0 || BlockNum == pDualTimInfo->BackupTimBlock) |
| 228 | return 1; |
| 229 | } else |
| 230 | #endif |
| 231 | { |
| 232 | return (BlockNum == 0); |
| 233 | } |
| 234 | |
| 235 | return 0; |
| 236 | } |
| 237 | |
| 238 | INT_T IsBlockRelocated(UINT_T BlockNum) { |
| 239 | UINT_T BlockTo = BlockNum; |
| 240 | |
| 241 | BlockTo = ScanBBT_LegacyExt(BlockNum); |
| 242 | |
| 243 | if (BlockTo != BlockNum) |
| 244 | return 1; |
| 245 | |
| 246 | return 0; |
| 247 | } |
| 248 | |
| 249 | void CreateBBT_LegacyExt(P_PartitionInfo_T pPI) |
| 250 | { |
| 251 | #if COPYIMAGESTOFLASH |
| 252 | int i; |
| 253 | UINT_T Retval = NoError; |
| 254 | UINT_T PageSize, BlkSize, mask, TIMpagesUsed; |
| 255 | |
| 256 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 257 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 258 | |
| 259 | //If this flash device does not use BBM, just return |
| 260 | if(pFlashProp->FlashSettings.UseBBM == 0) |
| 261 | return; |
| 262 | |
| 263 | //Initialize FMProperties structure: |
| 264 | SetBBTStates(BBT_INVALID, BBT_INVALID, BOOT_FLASH); |
| 265 | |
| 266 | PageSize = pFlashProp->PageSize; |
| 267 | BlkSize = pFlashProp->BlockSize; |
| 268 | |
| 269 | //One page for BBT, the other for ABBT |
| 270 | //pFM_SPACE need to be valued before(in ClearFM) |
| 271 | memset(pFM_SPACE, 0xFF, PageSize*2); |
| 272 | |
| 273 | pFMProp->pLBBT = (P_ReloTable_T) pFM_SPACE; |
| 274 | pFMProp->pLBBT->Header = (USHORT) BBT_TYPE_LEGACY; |
| 275 | pFMProp->pLBBT->NumReloc = 0; |
| 276 | pFMProp->BBT_type = BBT_TYPE_LEGACY; |
| 277 | //NOTE:: SET THE STARTING SLOT HERE!!! |
| 278 | // For now use the last page in block zero to match XDB |
| 279 | #ifdef BBT_ORDER_REVERSE |
| 280 | pFMProp->BBT_Slot = (BlkSize / PageSize) - 1; |
| 281 | pFMProp->BBT_NextSlot = pFMProp->BBT_Slot - 1; |
| 282 | pFMProp->BBT_Reverse = 1; |
| 283 | #else |
| 284 | TIMpagesUsed = (max_tim_size_byte + PageSize - 1) / PageSize; |
| 285 | pFMProp->BBT_Slot = TIMpagesUsed; |
| 286 | pFMProp->BBT_NextSlot = pFMProp->BBT_Slot + 1; |
| 287 | pFMProp->BBT_Reverse = 0; |
| 288 | #endif |
| 289 | pFMProp->BBT_location = pFMProp->BBT_Slot * PageSize; |
| 290 | SetBBTState(BBT_CHANGED, BOOT_FLASH); |
| 291 | |
| 292 | pFMProp->pABBT = (P_ABBT_Table_T) (((UINT_T)pFM_SPACE)+PageSize); |
| 293 | pFMProp->pABBT->Identifier = BBT_TYPE_ASR; |
| 294 | pFMProp->pABBT->Type = BBT_TYPE_MBBT_RUN; |
| 295 | pFMProp->pABBT->NumReloc = 0; |
| 296 | pFMProp->pABBT->RefCounter = 0; |
| 297 | pFMProp->pABBT->NumBlockRecyled = 0; |
| 298 | pFMProp->pABBT->NumBlockToRecyle = 0; |
| 299 | #if DUAL_TIM |
| 300 | if(DualTimEnabled()) { |
| 301 | pAsrDualTimInfo pDualTimInfo = GetDualTimInfo(); |
| 302 | pFMProp->pABBT->BackupBBTLoc = pDualTimInfo->BackupTimBlock * BlkSize; |
| 303 | } |
| 304 | else |
| 305 | #endif |
| 306 | { |
| 307 | pFMProp->pABBT->BackupBBTLoc = 0; |
| 308 | } |
| 309 | pFMProp->pABBT->Version = ABBT_VERSION_2001; |
| 310 | pFMProp->ABBT_block0 = pFlashProp->NumBlocks - 1; |
| 311 | pFMProp->ABBT_block1 = pFlashProp->NumBlocks - 2; |
| 312 | |
| 313 | //Start with the last page |
| 314 | #ifdef BBT_ORDER_REVERSE |
| 315 | pFMProp->ABBT_CurSlot = (BlkSize / PageSize) - 1; |
| 316 | pFMProp->ABBT_Reverse = 1; |
| 317 | #else |
| 318 | pFMProp->ABBT_CurSlot = 0; |
| 319 | pFMProp->ABBT_Reverse = 0; |
| 320 | #endif |
| 321 | pFMProp->ScanBBT = &ScanBBT_LegacyExt; |
| 322 | |
| 323 | SetABBTState(BBT_CHANGED, BOOT_FLASH); |
| 324 | #endif |
| 325 | return; |
| 326 | } |
| 327 | |
| 328 | /* This function is only for TIM block, which are never relocated |
| 329 | * Logic block number is always equal to physical block number |
| 330 | */ |
| 331 | static UINT_T EraseBlockAndRestoreTIM(P_FlashProperties_T pFlashProp, UINT_T BlockNum, INT_T RestoreBBT) |
| 332 | { |
| 333 | UINT_T Retval = NoError, BlkSize; |
| 334 | EraseFlash_F erase = pFlashProp->EraseFlash; |
| 335 | ReadFlash_F read = pFlashProp->ReadFromFlash; |
| 336 | WriteFlash_F write = pFlashProp->WriteToFlash; |
| 337 | P_FMProperties_T pFMProps = NULL; |
| 338 | UINT8_T *ptemp = 0; |
| 339 | UINT_T ReadSize, WriteOffset, BBTWriteLen, PageSize; |
| 340 | UINT_T BlockOffset; |
| 341 | |
| 342 | ptemp = malloc(pFlashProp->BlockSize); |
| 343 | |
| 344 | if(ptemp == NULL) |
| 345 | return HeapExhaustedError; |
| 346 | |
| 347 | BlkSize = GetBlockSize(BOOT_FLASH); |
| 348 | |
| 349 | BlockOffset = BlkSize * BlockNum; |
| 350 | |
| 351 | if(RestoreBBT) |
| 352 | ReadSize = BlkSize; |
| 353 | else |
| 354 | ReadSize = max_tim_size_byte; |
| 355 | |
| 356 | Retval = read(BlockOffset, ptemp, ReadSize, BOOT_FLASH); |
| 357 | if(Retval != NoError && Retval != ReadDisturbError) |
| 358 | Retval = read(BlockOffset, ptemp, ReadSize, BOOT_FLASH); |
| 359 | |
| 360 | if(Retval != NoError && Retval != ReadDisturbError){ |
| 361 | free(ptemp); |
| 362 | return Retval; |
| 363 | } |
| 364 | |
| 365 | //erase all the block |
| 366 | Retval = erase(BlockOffset, BlkSize, BOOT_FLASH); |
| 367 | |
| 368 | if(Retval != NoError) |
| 369 | Retval = erase(BlockOffset, BlkSize, BOOT_FLASH); |
| 370 | |
| 371 | if(Retval != NoError){ |
| 372 | free(ptemp); |
| 373 | return Retval; |
| 374 | } |
| 375 | |
| 376 | //restore TIM data in lower portion of the block |
| 377 | Retval = write(BlockOffset, ptemp, max_tim_size_byte, BOOT_FLASH); |
| 378 | if(Retval != NoError){ //write fail, erase and try another time |
| 379 | Retval = erase(BlockOffset, BlkSize, BOOT_FLASH); |
| 380 | if(Retval != NoError){ |
| 381 | free(ptemp); |
| 382 | return Retval; |
| 383 | } |
| 384 | Retval = write(BlockOffset, ptemp, max_tim_size_byte, BOOT_FLASH); |
| 385 | } |
| 386 | |
| 387 | if (RestoreBBT) { |
| 388 | PageSize = GetPageSize(BOOT_FLASH); |
| 389 | pFMProps = GetFMProperties(); |
| 390 | if (pFMProps->BBT_Reverse) { |
| 391 | WriteOffset = (pFMProps->BBT_Slot + 1) * PageSize; |
| 392 | BBTWriteLen = BlkSize - WriteOffset; |
| 393 | Retval = write(BlockOffset+WriteOffset, ptemp+WriteOffset, BBTWriteLen, BOOT_FLASH); |
| 394 | } else { |
| 395 | WriteOffset = max_tim_size_byte; |
| 396 | BBTWriteLen = pFMProps->BBT_Slot * PageSize - max_tim_size_byte; |
| 397 | Retval = write(BlockOffset+WriteOffset, ptemp+WriteOffset, BBTWriteLen, BOOT_FLASH); |
| 398 | } |
| 399 | } |
| 400 | |
| 401 | free(ptemp); |
| 402 | return Retval; |
| 403 | } |
| 404 | |
| 405 | static UINT_T WriteABBT2Flash(UINT_T Block2Write, INT_T NeedErase, INT_T *ABBT_changed) |
| 406 | { |
| 407 | UINT_T Retval = NoError; |
| 408 | P_FMProperties_T pFMProps = GetFMProperties(); |
| 409 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 410 | EraseFlash_F erase = pFlashProp->EraseFlash; |
| 411 | WriteFlash_F write = pFlashProp->WriteToFlash; |
| 412 | ReadFlash_F read = pFlashProp->ReadFromFlash; |
| 413 | UINT_T BlockIdx, BlockAddr, PageAddr; |
| 414 | UINT_T BlkSize, PageSize, NumPages, StartPage, EndPage; |
| 415 | INT_T i, Retry = TRUE; |
| 416 | P_ABBT_Table_T pABBT = pFMProps->pABBT; |
| 417 | UINT8_T *ptemp = 0; |
| 418 | |
| 419 | BlkSize = pFlashProp->BlockSize; |
| 420 | PageSize = pFlashProp->PageSize; |
| 421 | NumPages = BlkSize/PageSize; |
| 422 | |
| 423 | BlockIdx = ScanBBT_LegacyExt(Block2Write); |
| 424 | ptemp = malloc(BlkSize); |
| 425 | if(ptemp == NULL) |
| 426 | return HeapExhaustedError; |
| 427 | |
| 428 | while(NeedErase) |
| 429 | { |
| 430 | BlockAddr = BlockIdx * BlkSize; |
| 431 | Retval = erase(BlockAddr, BlkSize, BOOT_FLASH); |
| 432 | if(Retval != NoError) //retry again |
| 433 | Retval = erase(BlockAddr, BlkSize, BOOT_FLASH); |
| 434 | if(Retval != NoError){ |
| 435 | Retval = RelocateBlock_LegacyExt(BlockIdx, &BlockIdx, 0); |
| 436 | UpdateABBTCrc(pABBT); |
| 437 | |
| 438 | if(Retval != NoError){ |
| 439 | free(ptemp); |
| 440 | return Retval; |
| 441 | } |
| 442 | else |
| 443 | *ABBT_changed = TRUE; //relocation causes BBTs changed |
| 444 | |
| 445 | continue; |
| 446 | } |
| 447 | break; //Erase succeeds |
| 448 | } |
| 449 | |
| 450 | StartPage = pFMProps->ABBT_CurSlot; |
| 451 | EndPage = pFMProps->ABBT_CurSlot + 1; //only need to write one page |
| 452 | BlockAddr =BlockIdx * BlkSize; |
| 453 | |
| 454 | for(i = StartPage; i < EndPage; i++) |
| 455 | { |
| 456 | PageAddr = i * PageSize; |
| 457 | Retval = read(BlockAddr+PageAddr, ptemp, PageSize, BOOT_FLASH); |
| 458 | if(Retval == NoError) { |
| 459 | if(CheckPattern(ptemp, 0xFF, PageSize) == 1) //All 0xFFs |
| 460 | Retval = write(BlockAddr+PageAddr, (UINT_T)pABBT, PageSize, BOOT_FLASH); |
| 461 | else |
| 462 | Retval = FlashReadError; //Page to read is not All 0xFF |
| 463 | |
| 464 | /* ABBT read back and check */ |
| 465 | if (Retval == NoError) { |
| 466 | Retval = read(BlockAddr+PageAddr, ptemp, PageSize, BOOT_FLASH); |
| 467 | if(Retval == NoError){ |
| 468 | if (memcmp(ptemp, pABBT, PageSize)) { |
| 469 | Retval = FlashReadError; //ABBT Read back mismatch |
| 470 | } |
| 471 | } |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | if(Retval != NoError) { |
| 476 | if(Retry == TRUE){ |
| 477 | Retry = FALSE; |
| 478 | Retval = erase(BlockAddr, BlkSize, BOOT_FLASH); |
| 479 | if(Retval == NoError){ |
| 480 | //succeed to erase, need to write the previous page with valid(latest) ABBT |
| 481 | if (pFMProps->ABBT_Reverse) { |
| 482 | i = StartPage - 1; //i++ still works, write ABBT from StartPage to last page of ABBT_block |
| 483 | EndPage = NumPages; |
| 484 | } else { |
| 485 | i = - 1; //i++ still works, write ABBT from page 0 to StartPage |
| 486 | EndPage = StartPage + 1; |
| 487 | } |
| 488 | continue; |
| 489 | } |
| 490 | //If erase fails, go through to relocate |
| 491 | } |
| 492 | Retry = TRUE; |
| 493 | Retval = RelocateBlock_LegacyExt(BlockIdx, &BlockIdx, 0); |
| 494 | UpdateABBTCrc(pABBT); |
| 495 | if(Retval != NoError){ |
| 496 | free(ptemp); |
| 497 | //Relocation fails, return with Error |
| 498 | return Retval; |
| 499 | } |
| 500 | else{ |
| 501 | if (pFMProps->ABBT_Reverse) { |
| 502 | i = StartPage - 1; //i++ still works |
| 503 | //need to write the previous page with valid(latest) ABBT |
| 504 | EndPage = NumPages; |
| 505 | } else { |
| 506 | i = -1; |
| 507 | EndPage = StartPage + 1; |
| 508 | } |
| 509 | BlockAddr = BlockIdx * BlkSize; |
| 510 | *ABBT_changed = TRUE; //relocation causes BBTs changed |
| 511 | } |
| 512 | //retry writing, with the relocated block |
| 513 | } |
| 514 | } |
| 515 | |
| 516 | free(ptemp); |
| 517 | return Retval; |
| 518 | } |
| 519 | |
| 520 | static VOID BBT_RemoveDummyEntries(P_ReloTable_T pBBT) |
| 521 | { |
| 522 | INT_T i; |
| 523 | |
| 524 | for (i = 0; i < pBBT->NumReloc; i++) |
| 525 | { |
| 526 | if ((pBBT->Relo[i].From == BLOCK_BAD) && |
| 527 | (pBBT->Relo[i].To == BLOCK_BAD)) |
| 528 | { |
| 529 | pBBT->Relo[i].From = pBBT->Relo[pBBT->NumReloc - 1].From; |
| 530 | pBBT->Relo[i].To = pBBT->Relo[pBBT->NumReloc - 1].To; |
| 531 | pBBT->NumReloc --; |
| 532 | i--; |
| 533 | } |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | static UINT_T WriteBBT2Flash(UINT_T Block2Write, INT_T BBTNeedRestore) |
| 538 | { |
| 539 | UINT_T Retval = NoError, BlkSize, PageSize; |
| 540 | P_FMProperties_T pFMProps = GetFMProperties(); |
| 541 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 542 | WriteFlash_F write = pFlashProp->WriteToFlash; |
| 543 | ReadFlash_F read = pFlashProp->ReadFromFlash; |
| 544 | EraseFlash_F erase = pFlashProp->EraseFlash; |
| 545 | UINT_T Addr = 0; |
| 546 | P_ReloTable_T pBBT; |
| 547 | UINT_T pBuffer; |
| 548 | |
| 549 | PageSize = pFlashProp->PageSize; |
| 550 | BlkSize = pFlashProp->BlockSize; |
| 551 | //NumPages = BlkSize / PageSize; |
| 552 | pBBT = pFMProps->pLBBT; |
| 553 | |
| 554 | if (IsBlockRelocated(Block2Write)) |
| 555 | { |
| 556 | //obm_printf("Try to write a relocated TIM block\n\r"); |
| 557 | return NoError; |
| 558 | } |
| 559 | |
| 560 | if (BBTNeedRestore) |
| 561 | { |
| 562 | BBT_RemoveDummyEntries(pBBT); |
| 563 | Retval = EraseBlockAndRestoreTIM(pFlashProp, Block2Write, 0); |
| 564 | if(Retval != NoError){ |
| 565 | obm_printf("Erase and restore backup TIM error\n\r"); |
| 566 | return BBTWriteError; |
| 567 | } |
| 568 | } |
| 569 | |
| 570 | pBuffer = malloc(PageSize); |
| 571 | if (pBuffer == NULL) { |
| 572 | obm_printf("Warning: no buffer for BBT RBC\n\r"); |
| 573 | return NoError; |
| 574 | } |
| 575 | |
| 576 | #if DUAL_TIM |
| 577 | if (DualTimEnabled()) { |
| 578 | Addr = pFMProps->BBT_Slot * PageSize; //offset in TIM block |
| 579 | Addr += (Block2Write * BlkSize); |
| 580 | |
| 581 | /* write BBT to TIM block */ |
| 582 | if (IsBlockRelocated(Block2Write)) { |
| 583 | ; //Do nothing if TIM block is already relocated |
| 584 | } else { |
| 585 | Retval = read(Addr, pBuffer, PageSize, BOOT_FLASH); |
| 586 | if (Retval != NoError) { |
| 587 | free(pBuffer); |
| 588 | return BBTReadError; |
| 589 | } |
| 590 | if (CheckPattern(pBuffer, 0xFF, PageSize) == 0) { |
| 591 | free(pBuffer); |
| 592 | //obm_printf("CheckPattern fails\n\r"); |
| 593 | return BBTReadError; |
| 594 | } |
| 595 | Retval = WriteFlash(Addr, (UINT_T)pBBT, PageSize, BOOT_FLASH); |
| 596 | if(Retval != NoError){ |
| 597 | obm_printf("BBT Write TIM block%d Error\n\r", Block2Write); |
| 598 | } |
| 599 | if(IsBlockRelocated(Block2Write)) { |
| 600 | EraseFlash((Block2Write * BlkSize) , BlkSize, BOOT_FLASH); |
| 601 | erase((Block2Write * BlkSize) , BlkSize, BOOT_FLASH); |
| 602 | } |
| 603 | } |
| 604 | } else |
| 605 | #endif |
| 606 | { |
| 607 | //get the block offset from BBT_location |
| 608 | Addr = pFMProps->BBT_location & ~(BlkSize - 1); |
| 609 | //get the page offset from SLot |
| 610 | Addr |= pFMProps->BBT_Slot * PageSize; |
| 611 | Retval = write(Addr, (UINT_T)pBBT, PageSize, BOOT_FLASH); |
| 612 | if(Retval != NoError){ |
| 613 | //as block0 is always good, should never reach here |
| 614 | obm_printf("BBT Write Error, %s %d!!!\n\r", __FUNCTION__, __LINE__); |
| 615 | free(pBuffer); |
| 616 | //FatalError(BBTWriteError, NULL, NULL); |
| 617 | return BBTWriteError; |
| 618 | } |
| 619 | } |
| 620 | |
| 621 | Retval = read(Addr, (UINT_T)pBuffer, PageSize, BOOT_FLASH); |
| 622 | if (Retval != NoError) { |
| 623 | Retval = BBTReadError; |
| 624 | } |
| 625 | |
| 626 | /* BBT read back check */ |
| 627 | if (Retval == NoError && memcmp(pBBT, pBuffer, PageSize)){ |
| 628 | Retval = BBTReadError; |
| 629 | } |
| 630 | |
| 631 | free(pBuffer); |
| 632 | return Retval; |
| 633 | } |
| 634 | |
| 635 | void UpdateBBT_LegacyExt() |
| 636 | { |
| 637 | #if COPYIMAGESTOFLASH |
| 638 | UINT_T Retval = NoError, BlkSize, PageSize, NumPages, TIMpagesUsed; |
| 639 | P_FMProperties_T pFMProps = GetFMProperties(); |
| 640 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 641 | P_ReloTable_T pBBT; |
| 642 | UINT_T maxBlockNum, Retval1 = NoError; |
| 643 | UINT_T PrimaryBlock, MirrorBlock; |
| 644 | INT_T i, NeedErase = FALSE, ABBT_changed = FALSE; |
| 645 | INT_T BBTNeedRestore = FALSE; |
| 646 | INT_T BBTRetry = 0; |
| 647 | #if DUAL_TIM |
| 648 | pAsrDualTimInfo pDualTimInfo; |
| 649 | #endif |
| 650 | |
| 651 | //If this flash device does not use BBM, just return |
| 652 | if(pFlashProp->FlashSettings.UseBBM == 0) |
| 653 | return; |
| 654 | |
| 655 | //update BBT (only if there are changes) |
| 656 | if((pFMProps->BBT_State == BBT_UNCHANGED) && |
| 657 | (GetABBTState(BOOT_FLASH) == BBT_UNCHANGED)) |
| 658 | return; |
| 659 | |
| 660 | //if we never found a BBT, just return |
| 661 | if(pFMProps->BBT_State == BBT_INVALID) |
| 662 | return; |
| 663 | |
| 664 | // Now set some values that will work |
| 665 | PageSize = pFlashProp->PageSize; |
| 666 | BlkSize = pFlashProp->BlockSize; |
| 667 | NumPages = BlkSize / PageSize; |
| 668 | |
| 669 | #if DUAL_TIM |
| 670 | if (DualTimEnabled()) { |
| 671 | pDualTimInfo = GetDualTimInfo(); |
| 672 | pFMProps->pABBT->BackupBBTLoc = pDualTimInfo->BackupTimBlock * BlkSize; |
| 673 | } |
| 674 | #endif |
| 675 | |
| 676 | update_bbts_again: |
| 677 | //During updating ABBT, BBT could be changed, therefore, update ABBT before BBT |
| 678 | if(GetABBTState(BOOT_FLASH) == BBT_CHANGED || |
| 679 | GetABBTState(BOOT_FLASH) == BBT_ERASED) |
| 680 | { |
| 681 | do{ |
| 682 | ABBT_changed = FALSE; |
| 683 | if(pFMProps->pABBT->RefCounter % 2){ |
| 684 | PrimaryBlock = pFMProps->ABBT_block0; |
| 685 | MirrorBlock = pFMProps->ABBT_block1; |
| 686 | }else{ |
| 687 | PrimaryBlock = pFMProps->ABBT_block1; |
| 688 | MirrorBlock = pFMProps->ABBT_block0; |
| 689 | } |
| 690 | |
| 691 | if(pFMProps->ABBT_CurSlot == INVALID_PAGE) { |
| 692 | NeedErase = TRUE; |
| 693 | if (pFMProps->ABBT_Reverse) |
| 694 | pFMProps->ABBT_CurSlot = NumPages - 1; |
| 695 | else |
| 696 | pFMProps->ABBT_CurSlot = 0; |
| 697 | } |
| 698 | |
| 699 | pFMProps->pABBT->RefCounter++; |
| 700 | |
| 701 | UpdateABBTCrc(pFMProps->pABBT); |
| 702 | |
| 703 | //Write ABBT to the two blocks |
| 704 | Retval1 = WriteABBT2Flash(PrimaryBlock, NeedErase, &ABBT_changed); |
| 705 | if(Retval1 != NoError) |
| 706 | { |
| 707 | obm_printf("Warning: fail to update ABBT in one block\n\r"); |
| 708 | } |
| 709 | |
| 710 | Retval = WriteABBT2Flash(MirrorBlock, NeedErase, &ABBT_changed); |
| 711 | if(Retval1 != NoError && Retval != NoError) |
| 712 | { |
| 713 | //Neither block of ABBT is correctly updated. |
| 714 | obm_printf("Error: fail to update ABBT in both blocks\n\r"); |
| 715 | } |
| 716 | |
| 717 | if ((pFMProps->ABBT_CurSlot == (NumPages - 1) && !pFMProps->ABBT_Reverse) || |
| 718 | (pFMProps->ABBT_CurSlot == 0 && pFMProps->ABBT_Reverse) || |
| 719 | pFMProps->ABBT_CurSlot >= NumPages /*unexpected*/) { |
| 720 | pFMProps->ABBT_CurSlot = INVALID_PAGE; |
| 721 | } else { |
| 722 | if (pFMProps->ABBT_Reverse) |
| 723 | pFMProps->ABBT_CurSlot--; |
| 724 | else |
| 725 | pFMProps->ABBT_CurSlot++; |
| 726 | } |
| 727 | |
| 728 | }while(ABBT_changed); |
| 729 | |
| 730 | SetABBTState(BBT_UNCHANGED, BOOT_FLASH); |
| 731 | } |
| 732 | |
| 733 | //Legacy way to update BBT |
| 734 | if(pFMProps->BBT_State == BBT_CHANGED || pFMProps->BBT_State == BBT_ERASED || |
| 735 | pFMProps->BBT_State == BBT_NEED_SYNC) |
| 736 | { |
| 737 | //Find and read first page after the TIM |
| 738 | TIMpagesUsed = (max_tim_size_byte + PageSize - 1) / PageSize; |
| 739 | UpdateBBTCrc(pFMProps->pLBBT); |
| 740 | //Did we run out of BBT Slots? |
| 741 | if( pFMProps->BBT_Slot < TIMpagesUsed || pFMProps->BBT_Slot >= NumPages || |
| 742 | pFMProps->BBT_State == BBT_NEED_SYNC ) |
| 743 | { |
| 744 | BBTNeedRestore = TRUE; |
| 745 | //reset slot counters |
| 746 | if (pFMProps->BBT_Reverse) { |
| 747 | pFMProps->BBT_Slot = NumPages - 1; |
| 748 | pFMProps->BBT_NextSlot = NumPages - 2; |
| 749 | } else { |
| 750 | pFMProps->BBT_Slot = TIMpagesUsed; |
| 751 | pFMProps->BBT_NextSlot = pFMProps->BBT_Slot + 1; |
| 752 | } |
| 753 | pFMProps->BBT_location = pFMProps->BBT_Slot*PageSize; |
| 754 | |
| 755 | } |
| 756 | |
| 757 | Retval = WriteBBT2Flash(0, BBTNeedRestore); |
| 758 | #if DUAL_TIM |
| 759 | if (DualTimEnabled()) { |
| 760 | Retval1 = WriteBBT2Flash(pDualTimInfo->BackupTimBlock, BBTNeedRestore); |
| 761 | if (Retval == BBTReadError || Retval1 == BBTReadError) { |
| 762 | if (BBTRetry < 2) { /* read-back-check fails, retry twice */ |
| 763 | BBTRetry ++; |
| 764 | SetBBTState(BBT_NEED_SYNC, BOOT_FLASH); |
| 765 | goto update_bbts_again; |
| 766 | } |
| 767 | } else { |
| 768 | if (Retval != NoError && Retval1 != NoError) |
| 769 | FatalError(BBTWriteError, "DualWriteErr", 0); |
| 770 | } |
| 771 | if(IsBlockRelocated(pDualTimInfo->BackupTimBlock) && IsBlockRelocated(0)) |
| 772 | FatalError(BBTWriteError, "DUAL_TIM_RELOCATED", 0); |
| 773 | } |
| 774 | #endif |
| 775 | |
| 776 | //update slot info |
| 777 | if (pFMProps->BBT_Reverse) { |
| 778 | pFMProps->BBT_Slot--; |
| 779 | pFMProps->BBT_NextSlot--; |
| 780 | } else { |
| 781 | pFMProps->BBT_Slot++; |
| 782 | pFMProps->BBT_NextSlot++; |
| 783 | } |
| 784 | |
| 785 | /* If relocations happens to TIM blocks when update BBT */ |
| 786 | if (GetABBTState(BOOT_FLASH) == BBT_CHANGED) |
| 787 | goto update_bbts_again; |
| 788 | |
| 789 | //set the state back to unchanged |
| 790 | SetBBTState(BBT_UNCHANGED, BOOT_FLASH); |
| 791 | } |
| 792 | |
| 793 | #endif |
| 794 | return; |
| 795 | } |
| 796 | |
| 797 | UINT_T ScanBBT_LegacyExt(UINT_T BlockNum) |
| 798 | { |
| 799 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 800 | P_ReloTable_T pBBT = pFMProp->pLBBT; |
| 801 | P_ABBT_Table_T pABBT = pFMProp->pABBT; |
| 802 | UINT_T i; |
| 803 | |
| 804 | //if no BBT was loaded, return original block num. No BBT, No ABBT either. |
| 805 | if(pFMProp->BBT_State == BBT_INVALID ) |
| 806 | return BlockNum; |
| 807 | |
| 808 | /* No relocation needed for Block0 if DualTIM is not enabled */ |
| 809 | if(BlockNum == 0 && !DualTimEnabled()) |
| 810 | return 0; |
| 811 | |
| 812 | //Scan First level BBT if the block is used for ABBT |
| 813 | if(IsLogicBlockInL1BBT(BlockNum)) |
| 814 | { |
| 815 | for (i = 0; i < pBBT->NumReloc; i++) |
| 816 | { |
| 817 | if (pBBT->Relo[i].From == BlockNum) |
| 818 | return pBBT->Relo[i].To; |
| 819 | } |
| 820 | |
| 821 | //No matched relocate pair found |
| 822 | if(i == pBBT->NumReloc) |
| 823 | return BlockNum; |
| 824 | } |
| 825 | |
| 826 | if(GetABBTState(BOOT_FLASH) == BBT_INVALID) |
| 827 | return BlockNum; |
| 828 | |
| 829 | for (i = 0; i < pABBT->NumReloc; i++) |
| 830 | { |
| 831 | if (pABBT->Relo[i].From == BlockNum) |
| 832 | { |
| 833 | return pABBT->Relo[i].To; |
| 834 | //We make sure that the remapped block is always good, |
| 835 | //which means there is no A--Relocated-To-->B--Relocated-To-->C like map |
| 836 | //Don't need to start over any more. |
| 837 | //i = 0; // Start over in case remapped block is now bad |
| 838 | //continue; |
| 839 | } |
| 840 | } |
| 841 | |
| 842 | return BlockNum; |
| 843 | } |
| 844 | |
| 845 | static INT_T BlockIsBad(UINT_T BlockNum) |
| 846 | { |
| 847 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 848 | P_ABBT_Table_T pABBT = pFMProp->pABBT; |
| 849 | INT_T i; |
| 850 | for(i = 0; i < pABBT->NumReloc; i++) |
| 851 | { |
| 852 | if(pABBT->BlkInfo[i].Index == BlockNum && pABBT->BlkInfo[i].State == BLOCK_BAD) |
| 853 | return TRUE; |
| 854 | } |
| 855 | |
| 856 | return FALSE; |
| 857 | |
| 858 | } |
| 859 | /* |
| 860 | * RelocateBlock_Legacy |
| 861 | */ |
| 862 | extern UINT_T All_FF_flag; |
| 863 | UINT_T __RelocateBlock_LegacyExt(UINT_T BlockNum, UINT_T* ReloBlock, UINT_T isBitFlip, UINT_T NeedErase) |
| 864 | { |
| 865 | UINT_T Retval = NoError; |
| 866 | UINT_T BlockRelocatedTo, BlockToRead; |
| 867 | UINT_T NumRelo, BlkSize, initial_blk, end_blk, i; |
| 868 | INT_T idx = -1, RelocatedBlockEntry = -1; |
| 869 | INT_T RecyledBlock = -1; |
| 870 | UINT8_T *pBuffer = 0; |
| 871 | UINT8_T *pReadBuffer = 0; |
| 872 | UINT_T BlockAddr1, BlockAddr2, Addr, PageSize, All_FF_flag_restore, BitflipEntryNum, PoolBlockNum; |
| 873 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 874 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 875 | P_ReloTable_T pBBT = pFMProp->pLBBT; |
| 876 | P_ABBT_Table_T pABBT = pFMProp->pABBT; |
| 877 | EraseFlash_F erase = pFlashProp->EraseFlash; |
| 878 | ReadFlash_F read = pFlashProp->ReadFromFlash; |
| 879 | WriteFlash_F write = pFlashProp->WriteToFlash; |
| 880 | |
| 881 | /* |
| 882 | * Block0 is guaranteed by manufacturer. |
| 883 | * And there is no need to relocate other TIM blocks. |
| 884 | */ |
| 885 | if(BlockNum == 0 && !DualTimEnabled()) |
| 886 | { |
| 887 | *ReloBlock = 0; |
| 888 | return TIMBlocksEraseWriteFail; |
| 889 | } |
| 890 | |
| 891 | if (DualTimEnabled() && IsTimBlock(BlockNum) && !isBitFlip) { |
| 892 | obm_printf("TIM blocks relocation happens\n\r"); |
| 893 | } |
| 894 | |
| 895 | //if our BBT is not valid |
| 896 | if((pBBT == NULL) || ((UINT16)BBT_TYPE_LEGACY != pBBT->Header)) |
| 897 | return BBTReadError; |
| 898 | |
| 899 | BlkSize = pFlashProp->BlockSize; |
| 900 | BlockToRead = BlockNum; |
| 901 | |
| 902 | //get RP boundaries |
| 903 | initial_blk = pFlashProp->NumBlocks - 1 - ABBT_BLOCK_NUM; |
| 904 | |
| 905 | //TODO end_blk+1 should be the last valid reserved block? |
| 906 | end_blk = initial_blk - (pFlashProp->NumBlocks * LEGACY_BBM_RELOC_PERCENTAGE + 99) / 100; |
| 907 | |
| 908 | SearchBlockForRelocation: |
| 909 | |
| 910 | NumRelo = pABBT->NumReloc; |
| 911 | //start at first RP block |
| 912 | BlockRelocatedTo = initial_blk; |
| 913 | |
| 914 | if ( isBitFlip ) { |
| 915 | PoolBlockNum = initial_blk - end_blk; |
| 916 | BitflipEntryNum = 0; |
| 917 | for ( i = 0 ; i < pABBT->NumReloc; i++ ) { |
| 918 | if ( (pABBT->Relo[i].To <= end_blk) && (pABBT->BlkInfo[i].State != BLOCK_BAD) ) |
| 919 | BitflipEntryNum++; |
| 920 | } |
| 921 | |
| 922 | if ( pFMProp->ABBT_MaxNum && |
| 923 | (BitflipEntryNum + PoolBlockNum * 2) >= pFMProp->ABBT_MaxNum) { |
| 924 | obm_printf("Too much bitflip blocks: %d %d %d\n\r", |
| 925 | BitflipEntryNum, PoolBlockNum, pFMProp->ABBT_MaxNum); |
| 926 | return BBTToMuchBitflips; |
| 927 | } |
| 928 | } |
| 929 | |
| 930 | if ( NumRelo >= (pFMProp->ABBT_MaxNum - 2) ) { |
| 931 | obm_printf("Warning: ABBT Entry exhausted\n\r"); |
| 932 | return NoError; |
| 933 | } |
| 934 | |
| 935 | //if the table is not empty, we need to find the next available RP block |
| 936 | if (NumRelo != 0) |
| 937 | { |
| 938 | //run through all the entries to find that smallest 'To' entry |
| 939 | for (i = 0; i < pABBT->NumReloc; i++) { |
| 940 | if((pABBT->Relo[i].To > end_blk && pABBT->Relo[i].To <= initial_blk) //in RP |
| 941 | && (BlockRelocatedTo > pABBT->Relo[i].To)) |
| 942 | //ignore the factory bad block here |
| 943 | if(pABBT->BlkInfo[i].State != BLOCK_BAD) |
| 944 | BlockRelocatedTo = pABBT->Relo[i].To; |
| 945 | } |
| 946 | |
| 947 | for(i = 0; i < pABBT->NumReloc; i++){ |
| 948 | //There may be 0xFFFx->BlockNum Map here, pABBT->Relo[i].From should be valid block |
| 949 | if(BlockNum == pABBT->Relo[i].To && EntryIsReloPair(&pABBT->Relo[i])){ |
| 950 | //The block to be relocated is a block relocated to other block before |
| 951 | //To avoid the map A--relocated to-->B--relocated to-->C |
| 952 | //Just A--relocacted to-->C and BLOCK_BAD--relocated to-->B |
| 953 | BlockToRead = BlockNum; |
| 954 | BlockNum = pABBT->Relo[i].From; |
| 955 | if(isBitFlip){ |
| 956 | //If the relocation is for bitflip, we record the entry |
| 957 | //and handle it after the copy succeeds(mark it as BLOCK_TO_RECYCLE) |
| 958 | RelocatedBlockEntry = i; |
| 959 | } |
| 960 | else |
| 961 | pABBT->BlkInfo[i].State = BLOCK_BAD; |
| 962 | break; |
| 963 | } |
| 964 | } |
| 965 | |
| 966 | //since we just found the last 'used' RP block, try the next one |
| 967 | //and make sure it is not a bad block. |
| 968 | do{ |
| 969 | BlockRelocatedTo--; |
| 970 | }while(BlockIsBad(BlockRelocatedTo)); |
| 971 | |
| 972 | //lastly, make sure we didn't exceed RP |
| 973 | if(BlockRelocatedTo <= end_blk) |
| 974 | { |
| 975 | /* If the reserved pool is exhausted, check if there is |
| 976 | * recycled block introduced by bitflips scrubbing. |
| 977 | */ |
| 978 | #ifdef BITFLIPS_SCRUBBING |
| 979 | //There is no recylced blocks, relocation fails |
| 980 | if(pABBT->NumBlockRecyled == 0) |
| 981 | { |
| 982 | obm_printf("BBT Exhausted Error, %s %d\n\r", __FUNCTION__, __LINE__); |
| 983 | return BBTExhaustedError; |
| 984 | } |
| 985 | for(i = 0; i < pABBT->NumReloc; i++) { |
| 986 | //Find the first recycled block |
| 987 | if(pABBT->BlkInfo[i].State == BLOCK_RECYCLED) |
| 988 | { |
| 989 | RecyledBlock = i; //reuse the relo entry |
| 990 | BlockRelocatedTo = pABBT->BlkInfo[i].Index; |
| 991 | break; |
| 992 | } |
| 993 | } |
| 994 | #else |
| 995 | obm_printf("BBT Exhausted Error, %s %d\n\r", __FUNCTION__, __LINE__); |
| 996 | return BBTExhaustedError; |
| 997 | #endif |
| 998 | } |
| 999 | } |
| 1000 | |
| 1001 | if(NeedErase){ |
| 1002 | //If OBM, need to disable spare area for following erase |
| 1003 | #if NAND_CODE //To word around the issue that BootROM disable sprare area |
| 1004 | if(BlockNum == OBM_BLOCK){ |
| 1005 | DisableSpareAreaForOBM(BlockRelocatedTo*BlkSize, 0); |
| 1006 | } |
| 1007 | #endif |
| 1008 | |
| 1009 | Retval = erase(BlockRelocatedTo*BlkSize, BlkSize, BOOT_FLASH); |
| 1010 | |
| 1011 | if(Retval != NoError) //try again |
| 1012 | Retval = erase(BlockRelocatedTo*BlkSize, BlkSize, BOOT_FLASH); |
| 1013 | |
| 1014 | if(Retval != NoError) { |
| 1015 | //If erase fails, mark BlockRelocatedTo as bad block and re-search |
| 1016 | if(RecyledBlock == -1){ |
| 1017 | pABBT->NumReloc++; |
| 1018 | //mark it as bad |
| 1019 | pABBT->BlkInfo[NumRelo].Index = BlockRelocatedTo; |
| 1020 | pABBT->BlkInfo[NumRelo].State = BLOCK_BAD; |
| 1021 | } |
| 1022 | else{ |
| 1023 | pABBT->NumBlockRecyled --; |
| 1024 | pABBT->BlkInfo[RecyledBlock].State = BLOCK_BAD; |
| 1025 | } |
| 1026 | SetABBTState(BBT_CHANGED, BOOT_FLASH); |
| 1027 | goto SearchBlockForRelocation; |
| 1028 | } |
| 1029 | } |
| 1030 | |
| 1031 | //Back up the block before the relocation is done |
| 1032 | //Here we need to use the low level erase/read/write without scan BBT. |
| 1033 | if(isBitFlip) |
| 1034 | { |
| 1035 | BlockAddr1 = BlockToRead*BlkSize; |
| 1036 | BlockAddr2 = BlockRelocatedTo*BlkSize; |
| 1037 | PageSize = pFlashProp->PageSize; |
| 1038 | |
| 1039 | All_FF_flag_restore = All_FF_flag; |
| 1040 | All_FF_flag = 1; //Don't write all 0xFFFFFFFF pages |
| 1041 | pBuffer = malloc(PageSize << 1); |
| 1042 | if(pBuffer == 0) |
| 1043 | return HeapExhaustedError; |
| 1044 | pReadBuffer = pBuffer + PageSize; |
| 1045 | for(Addr = 0; Addr < BlkSize; Addr += PageSize) |
| 1046 | { |
| 1047 | Retval = read(BlockAddr1+Addr, (UINT_T)pBuffer, PageSize, BOOT_FLASH); |
| 1048 | if(Retval != NoError && Retval != ReadDisturbError) |
| 1049 | Retval = read(BlockAddr1+Addr, (UINT_T)pBuffer, PageSize, BOOT_FLASH); |
| 1050 | if(Retval != NoError && Retval != ReadDisturbError){ |
| 1051 | //Tiny possibility reach here |
| 1052 | free(pBuffer); |
| 1053 | return Retval; |
| 1054 | } |
| 1055 | Retval = write(BlockAddr2+Addr, (UINT_T)pBuffer, PageSize, BOOT_FLASH); |
| 1056 | if (Retval == NoError) { |
| 1057 | Retval = read(BlockAddr2+Addr, (UINT_T)pReadBuffer, PageSize, BOOT_FLASH); |
| 1058 | if (Retval != NoError || memcmp(pBuffer, pReadBuffer, PageSize)) |
| 1059 | { |
| 1060 | Retval = ProgramError; |
| 1061 | BlockNum = BLOCK_TO_RECYCLE; /* read back fail, mark as to recyled */ |
| 1062 | free(pBuffer); |
| 1063 | goto RelocateDone; |
| 1064 | } |
| 1065 | } else { //write fails, mark BlockRelocatedTo as bad block and return |
| 1066 | Retval = ProgramError; |
| 1067 | BlockNum = BLOCK_BAD; |
| 1068 | free(pBuffer); |
| 1069 | goto RelocateDone; |
| 1070 | } |
| 1071 | } |
| 1072 | free(pBuffer); |
| 1073 | All_FF_flag = All_FF_flag_restore; |
| 1074 | |
| 1075 | //Block to relocate is relocated to another block |
| 1076 | if(RelocatedBlockEntry != -1) |
| 1077 | { |
| 1078 | pABBT->BlkInfo[RelocatedBlockEntry].State = BLOCK_TO_RECYCLE; |
| 1079 | } |
| 1080 | } |
| 1081 | |
| 1082 | if(IsLogicBlockInL1BBT(BlockNum)) { |
| 1083 | //If it's not the first time to relocate this block |
| 1084 | //overwrite the old relocation pair with a useless entry just to increase the NumReloc |
| 1085 | for(i = 0; i < pBBT->NumReloc; i++){ |
| 1086 | if(pBBT->Relo[i].From == BlockNum) |
| 1087 | { |
| 1088 | //To be compatible with Legacy BBT |
| 1089 | pBBT->Relo[i].From = BLOCK_BAD; |
| 1090 | break; |
| 1091 | } |
| 1092 | } |
| 1093 | pBBT->Relo[pBBT->NumReloc].To = BlockRelocatedTo; |
| 1094 | pBBT->Relo[pBBT->NumReloc].From = BlockNum; |
| 1095 | pBBT->NumReloc++; |
| 1096 | SetBBTState(BBT_CHANGED, BOOT_FLASH); |
| 1097 | } |
| 1098 | |
| 1099 | *ReloBlock = (UINT) BlockRelocatedTo; |
| 1100 | |
| 1101 | RelocateDone: |
| 1102 | SetABBTState(BBT_CHANGED, BOOT_FLASH); |
| 1103 | |
| 1104 | #ifdef BITFLIPS_SCRUBBING |
| 1105 | if(RecyledBlock == -1){ |
| 1106 | pABBT->NumReloc++; |
| 1107 | // Relocate it |
| 1108 | pABBT->Relo[NumRelo].To = BlockRelocatedTo; |
| 1109 | pABBT->Relo[NumRelo].From = BlockNum; |
| 1110 | } |
| 1111 | else{ |
| 1112 | pABBT->NumBlockRecyled --; |
| 1113 | pABBT->Relo[RecyledBlock].To = BlockRelocatedTo; |
| 1114 | // if the copy for bitflips fails, mark a bad block(BlockNum = BLOCK_BAD) |
| 1115 | pABBT->Relo[RecyledBlock].From = BlockNum; |
| 1116 | //remove the redundant entry(A-->A) |
| 1117 | if(pABBT->Relo[RecyledBlock].From == pABBT->Relo[RecyledBlock].To) |
| 1118 | { |
| 1119 | for(i = RecyledBlock; i < pABBT->NumReloc - 1; i++) |
| 1120 | { |
| 1121 | pABBT->ReloValue[i] = pABBT->ReloValue[i+1]; |
| 1122 | } |
| 1123 | pABBT->NumReloc--; |
| 1124 | } |
| 1125 | } |
| 1126 | #else |
| 1127 | pABBT->NumReloc++; |
| 1128 | pABBT->Relo[NumRelo].To = BlockRelocatedTo; |
| 1129 | pABBT->Relo[NumRelo].From = BlockNum; |
| 1130 | #endif |
| 1131 | obm_printf("Relocation: %d to %d, bitflip: %s\n\r", BlockNum, BlockRelocatedTo, isBitFlip?"yes":"no"); |
| 1132 | |
| 1133 | return Retval; |
| 1134 | } |
| 1135 | |
| 1136 | UINT_T RelocateBlock_LegacyExt(UINT_T BlockNum, UINT_T* ReloBlock, UINT_T isBitFlip) |
| 1137 | { |
| 1138 | return __RelocateBlock_LegacyExt(BlockNum, ReloBlock, isBitFlip, 1); |
| 1139 | } |
| 1140 | |
| 1141 | UINT_T FindBBT_LegacyExt_Order(UINT_T AbbtBlock, FlashBootType_T fbt) |
| 1142 | { |
| 1143 | UINT_T PageSize, BlkSize, NumPages; |
| 1144 | UINT_T *pBuffer1 = 0; //MAX_PAGE_SIZE_WORDS |
| 1145 | UINT_T *pBuffer2 = 0; //MAX_PAGE_SIZE_WORDS |
| 1146 | P_ABBT_Table_T pTempBBT = NULL, pTempBBT1, pTempBBT2; |
| 1147 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 1148 | P_FlashProperties_T pFlashProp = GetFlashProperties(fbt); |
| 1149 | UINT_T CurrentPageOffset; |
| 1150 | UINT_T Retval1, Retval2; |
| 1151 | INT_T CurrentSlot; |
| 1152 | INT_T Low_Valid, High_Valid; |
| 1153 | INT_T Order_Reverse = 1; |
| 1154 | |
| 1155 | PageSize = pFlashProp->PageSize; |
| 1156 | BlkSize = pFlashProp->BlockSize; |
| 1157 | NumPages = BlkSize / PageSize; |
| 1158 | |
| 1159 | pBuffer1 = malloc(PageSize); |
| 1160 | pBuffer2 = malloc(PageSize); |
| 1161 | if(pBuffer1 == NULL || pBuffer2 == NULL) |
| 1162 | return HeapExhaustedError; |
| 1163 | |
| 1164 | pTempBBT1 = (P_ABBT_Table_T)pBuffer1; |
| 1165 | pTempBBT2 = (P_ABBT_Table_T)pBuffer2; |
| 1166 | |
| 1167 | //read the first slot |
| 1168 | CurrentSlot = 0; |
| 1169 | do { |
| 1170 | CurrentPageOffset = ((UINT_T)CurrentSlot * PageSize) + AbbtBlock*BlkSize; |
| 1171 | Retval1 = ReadFlash(CurrentPageOffset, (UINT_T)pTempBBT1, PageSize, fbt); |
| 1172 | if (Retval1 == NoError) |
| 1173 | break; |
| 1174 | } while (++CurrentSlot < NumPages); |
| 1175 | |
| 1176 | //read the last slot |
| 1177 | Retval2 = ReadFlash((BlkSize - PageSize) + AbbtBlock*BlkSize, |
| 1178 | (UINT_T)pTempBBT2, PageSize, fbt); |
| 1179 | CurrentSlot = NumPages - 1; |
| 1180 | do { |
| 1181 | CurrentPageOffset = ((UINT_T)CurrentSlot * PageSize) + AbbtBlock*BlkSize; |
| 1182 | Retval2 = ReadFlash(CurrentPageOffset, (UINT_T)pTempBBT2, PageSize, fbt); |
| 1183 | if (Retval2 == NoError) |
| 1184 | break; |
| 1185 | } while (--CurrentSlot >= 0); |
| 1186 | |
| 1187 | if((Retval1 == NoError) && (pTempBBT1->Identifier == BBT_TYPE_ASR)) |
| 1188 | Low_Valid = 1; |
| 1189 | else |
| 1190 | Low_Valid = 0; |
| 1191 | |
| 1192 | if((Retval2 == NoError) && (pTempBBT2->Identifier == BBT_TYPE_ASR)) |
| 1193 | High_Valid = 1; |
| 1194 | else |
| 1195 | High_Valid = 0; |
| 1196 | |
| 1197 | if (Low_Valid && !High_Valid) { |
| 1198 | Order_Reverse = 0; |
| 1199 | } else if (!Low_Valid && High_Valid) { |
| 1200 | Order_Reverse = 1; |
| 1201 | } else if (Low_Valid && High_Valid) { |
| 1202 | if (pTempBBT1->RefCounter < pTempBBT2->RefCounter) |
| 1203 | Order_Reverse = 0; |
| 1204 | else |
| 1205 | Order_Reverse = 1; |
| 1206 | } else { |
| 1207 | obm_printf("ERR: No valid ABBT in block %d\n\r", AbbtBlock); |
| 1208 | free(pBuffer1); |
| 1209 | free(pBuffer2); |
| 1210 | return BBTReadError; |
| 1211 | } |
| 1212 | |
| 1213 | obm_printf("ABBT order: %s\n\r", Order_Reverse ? "reverse" : "positive"); |
| 1214 | pFMProp->ABBT_Reverse = Order_Reverse; |
| 1215 | free(pBuffer1); |
| 1216 | free(pBuffer2); |
| 1217 | return NoError; |
| 1218 | } |
| 1219 | |
| 1220 | UINT_T FindBBT_LegacyExt(UINT_T BlockOffset, FlashBootType_T fbt) |
| 1221 | { |
| 1222 | UINT_T Retval, Retval1, Retval2; |
| 1223 | UINT_T i, Slot1 = 0, Slot2 = 0, StartSlot, EndSlot, NewABBTState; |
| 1224 | UINT_T AbbtBlock0, AbbtBlock1, ReloBlock, Block2Update = INVALID_BLOCK; |
| 1225 | UINT_T PageSize, BlkSize, NumPages, id, CurSlot = INVALID_PAGE, Retry = TRUE; |
| 1226 | UINT_T *pBuffer1 = 0; //MAX_PAGE_SIZE_WORDS |
| 1227 | UINT_T *pBuffer2 = 0; //MAX_PAGE_SIZE_WORDS |
| 1228 | P_ABBT_Table_T pTempBBT = NULL, pTempBBT1, pTempBBT2; |
| 1229 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 1230 | P_FlashProperties_T pFlashProp = GetFlashProperties(fbt); |
| 1231 | EraseFlash_F erase = pFlashProp->EraseFlash; |
| 1232 | WriteFlash_F write = pFlashProp->WriteToFlash; |
| 1233 | P_ReloTable_T pBBT; |
| 1234 | P_ABBT_Table_T pABBT; |
| 1235 | INT_T NeedEraseNext = 0; |
| 1236 | INT_T CrcError1 = 0, CrcError2 = 0; |
| 1237 | INT_T BBTNotFound = 0; |
| 1238 | |
| 1239 | //If this flash device does not use BBM, just return |
| 1240 | if(pFlashProp->FlashSettings.UseBBM == 0) |
| 1241 | return NoError; |
| 1242 | |
| 1243 | SetABBTState(BBT_INVALID, fbt); |
| 1244 | |
| 1245 | Retval = FindBBT_Legacy(BlockOffset, fbt); |
| 1246 | //ScanBBT needs to be overwritten no matter if BBT is found |
| 1247 | pFMProp->ScanBBT = &ScanBBT_LegacyExt; |
| 1248 | |
| 1249 | if(Retval != NoError){ |
| 1250 | BBTNotFound = 1; |
| 1251 | SetBBTState(BBT_INVALID, fbt); |
| 1252 | } else { |
| 1253 | //The first level BBT is valid now, go find the second level |
| 1254 | //During this, the first level BBT could be updated, need to handle carefully |
| 1255 | pBBT= pFMProp->pLBBT; |
| 1256 | } |
| 1257 | |
| 1258 | // Now set some values that will work |
| 1259 | PageSize = pFlashProp->PageSize; |
| 1260 | BlkSize = pFlashProp->BlockSize; |
| 1261 | NumPages = BlkSize / PageSize; |
| 1262 | id = (UINT_T) BBT_TYPE_ASR; |
| 1263 | |
| 1264 | pBuffer1 = malloc(PageSize); |
| 1265 | pBuffer2 = malloc(PageSize); |
| 1266 | if(pBuffer1 == NULL || pBuffer2 == NULL) |
| 1267 | return HeapExhaustedError; |
| 1268 | |
| 1269 | pTempBBT1 = (P_ABBT_Table_T)pBuffer1; |
| 1270 | pTempBBT2 = (P_ABBT_Table_T)pBuffer2; |
| 1271 | |
| 1272 | if(pFMProp->pABBT != NULL){ |
| 1273 | pABBT = pFMProp->pABBT; |
| 1274 | AbbtBlock0 = pFMProp->ABBT_block0; |
| 1275 | AbbtBlock1 = pFMProp->ABBT_block1; |
| 1276 | } |
| 1277 | else{ |
| 1278 | pABBT = pFMProp->pABBT = (P_ABBT_Table_T)((UINT_T)pFM_SPACE + PageSize); |
| 1279 | AbbtBlock0 = pFMProp->ABBT_block0 = pFlashProp->NumBlocks - 1; |
| 1280 | AbbtBlock1 = pFMProp->ABBT_block1 = pFlashProp->NumBlocks - 2; |
| 1281 | } |
| 1282 | |
| 1283 | #ifdef BBT_ORDER_REVERSE |
| 1284 | pFMProp->ABBT_Reverse = 1; |
| 1285 | #else |
| 1286 | pFMProp->ABBT_Reverse = 0; |
| 1287 | #endif |
| 1288 | Retval1 = FindBBT_LegacyExt_Order(AbbtBlock0, fbt); |
| 1289 | if (Retval1 != NoError) |
| 1290 | Retval1 = FindBBT_LegacyExt_Order(AbbtBlock1, fbt); |
| 1291 | |
| 1292 | if (Retval1 != NoError) |
| 1293 | goto creat_new_abbt; |
| 1294 | |
| 1295 | //Search second level BBT |
| 1296 | if (pFMProp->ABBT_Reverse) { |
| 1297 | StartSlot = NumPages - 1; |
| 1298 | EndSlot = 0; |
| 1299 | } else { |
| 1300 | StartSlot = 0; |
| 1301 | EndSlot = NumPages - 1; |
| 1302 | } |
| 1303 | |
| 1304 | search_abbt: |
| 1305 | Block2Update = INVALID_BLOCK; |
| 1306 | //Search first block |
| 1307 | Retval1 = BinarySearch((StartSlot * PageSize) + AbbtBlock0*BlkSize, |
| 1308 | (EndSlot * PageSize) + AbbtBlock0*BlkSize, |
| 1309 | (UINT_T)pTempBBT1, |
| 1310 | &Slot1, |
| 1311 | (UINT8_T*)&id, |
| 1312 | 4, |
| 1313 | 0, |
| 1314 | fbt, |
| 1315 | &CrcError1); |
| 1316 | //search the backup block |
| 1317 | Retval2 = BinarySearch((StartSlot * PageSize) + AbbtBlock1*BlkSize, |
| 1318 | (EndSlot * PageSize) + AbbtBlock1*BlkSize, |
| 1319 | (UINT_T)pTempBBT2, |
| 1320 | &Slot2, |
| 1321 | (UINT8_T*)&id, |
| 1322 | 4, |
| 1323 | 0, |
| 1324 | fbt, |
| 1325 | &CrcError2); |
| 1326 | |
| 1327 | NewABBTState = BBT_UNCHANGED; |
| 1328 | if(Retval1 != NoError && Retval2 != NoError) { |
| 1329 | creat_new_abbt: |
| 1330 | if (BBTNotFound) |
| 1331 | return NotFoundError; |
| 1332 | |
| 1333 | //As we found the father BBT, should reach here. |
| 1334 | //Any way, restructure ABBT according to BBT |
| 1335 | memset(pABBT, 0xFF, PageSize); |
| 1336 | pABBT->Identifier = BBT_TYPE_ASR; |
| 1337 | pABBT->Version = ABBT_VERSION_2001; |
| 1338 | pABBT->Type = BBT_TYPE_MBBT_RUN; |
| 1339 | pABBT->NumReloc = 0; |
| 1340 | pABBT->RefCounter = 0; //RefCounter >= NumRelo |
| 1341 | pABBT->NumBlockRecyled = 0; |
| 1342 | pABBT->NumBlockToRecyle = 0; |
| 1343 | pABBT->BackupBBTLoc = 0; |
| 1344 | #if DUAL_TIM |
| 1345 | if(DualTimEnabled()) { |
| 1346 | pAsrDualTimInfo pDualTimInfo = GetDualTimInfo(); |
| 1347 | pABBT->BackupBBTLoc = pDualTimInfo->BackupTimBlock * BlkSize; |
| 1348 | } |
| 1349 | #endif |
| 1350 | for (i = 0; i < pBBT->NumReloc; i++){ |
| 1351 | if(pBBT->Relo[i].From != BLOCK_BAD && pBBT->Relo[i].To != BLOCK_BAD) { |
| 1352 | pABBT->Relo[pABBT->NumReloc].From = pBBT->Relo[i].From; |
| 1353 | pABBT->Relo[pABBT->NumReloc].To = pBBT->Relo[i].To; |
| 1354 | pABBT->NumReloc++; |
| 1355 | } |
| 1356 | } |
| 1357 | UpdateABBTCrc(pABBT); |
| 1358 | if (NeedEraseNext) |
| 1359 | pFMProp->ABBT_CurSlot = INVALID_PAGE; |
| 1360 | else { |
| 1361 | pFMProp->ABBT_CurSlot = (pFMProp->ABBT_Reverse)? (NumPages - 1) : 0; |
| 1362 | } |
| 1363 | SetABBTState(BBT_CHANGED, fbt); |
| 1364 | free(pBuffer1); free(pBuffer2); |
| 1365 | return NoError; |
| 1366 | }else if(Retval1 == NoError && Retval2 != NoError){ |
| 1367 | //ABBT BLOCK0 has valid BBT, but ABBT Block1 doesn't |
| 1368 | pTempBBT = pTempBBT1; |
| 1369 | if (pFMProp->ABBT_Reverse) { |
| 1370 | StartSlot = Slot1; |
| 1371 | EndSlot = NumPages; |
| 1372 | } else { |
| 1373 | StartSlot = 0;//Slot1; |
| 1374 | EndSlot = Slot1 + 1;//NumPages; |
| 1375 | } |
| 1376 | Block2Update = AbbtBlock1; |
| 1377 | CurSlot = Slot1; |
| 1378 | }else if(Retval1 != NoError && Retval2 == NoError){ |
| 1379 | //ABBT BLOCK1 has valid BBT, but ABBT Block0 doesn't |
| 1380 | pTempBBT = pTempBBT2; |
| 1381 | if (pFMProp->ABBT_Reverse) { |
| 1382 | StartSlot = Slot2; |
| 1383 | EndSlot = NumPages; |
| 1384 | } else { |
| 1385 | StartSlot = 0;//Slot2; |
| 1386 | EndSlot = Slot2 + 1;// NumPages; |
| 1387 | } |
| 1388 | Block2Update = AbbtBlock0; |
| 1389 | CurSlot = Slot2; |
| 1390 | }else{//Both ABBT BLOCK0 and ABBT BLOCK1 have valid BBT |
| 1391 | //ABBT BLOCK0 has more recent BBT |
| 1392 | if(Slot2 > Slot1){ |
| 1393 | if (pFMProp->ABBT_Reverse) { |
| 1394 | pTempBBT = pTempBBT1; |
| 1395 | StartSlot = Slot1; |
| 1396 | EndSlot = Slot2; |
| 1397 | Block2Update = AbbtBlock1; |
| 1398 | CurSlot = Slot1; |
| 1399 | } else { |
| 1400 | pTempBBT = pTempBBT2; |
| 1401 | StartSlot = Slot1 + 1; |
| 1402 | EndSlot = Slot2 + 1; |
| 1403 | Block2Update = AbbtBlock0; |
| 1404 | CurSlot = Slot2; |
| 1405 | } |
| 1406 | }else if(Slot2 < Slot1){ |
| 1407 | if (pFMProp->ABBT_Reverse) { |
| 1408 | pTempBBT = pTempBBT2; |
| 1409 | StartSlot = Slot2; |
| 1410 | EndSlot = Slot1; |
| 1411 | Block2Update = AbbtBlock0; |
| 1412 | CurSlot = Slot2; |
| 1413 | } else { |
| 1414 | pTempBBT = pTempBBT1; |
| 1415 | StartSlot = Slot2 + 1; |
| 1416 | EndSlot = Slot1 + 1; |
| 1417 | Block2Update = AbbtBlock1; |
| 1418 | CurSlot = Slot1; |
| 1419 | } |
| 1420 | }else{ |
| 1421 | CurSlot = Slot1; |
| 1422 | //Even both blocks have valid ABBT in same page, they may be different |
| 1423 | if(pTempBBT1->RefCounter > pTempBBT2->RefCounter){ |
| 1424 | pTempBBT = pTempBBT1; |
| 1425 | NewABBTState = BBT_CHANGED; |
| 1426 | }else if(pTempBBT1->RefCounter < pTempBBT2->RefCounter){ |
| 1427 | pTempBBT = pTempBBT2; |
| 1428 | NewABBTState = BBT_CHANGED; |
| 1429 | }else{ |
| 1430 | if(pTempBBT1->NumReloc > pTempBBT2->NumReloc){ |
| 1431 | pTempBBT = pTempBBT1; |
| 1432 | NewABBTState = BBT_CHANGED; |
| 1433 | }else if(pTempBBT1->NumReloc < pTempBBT2->NumReloc){ |
| 1434 | pTempBBT = pTempBBT2; |
| 1435 | NewABBTState = BBT_CHANGED; |
| 1436 | }else{ |
| 1437 | pTempBBT = pTempBBT1; |
| 1438 | } |
| 1439 | } |
| 1440 | } |
| 1441 | } |
| 1442 | |
| 1443 | if(pTempBBT != NULL) |
| 1444 | memcpy(pABBT, pTempBBT, PageSize); |
| 1445 | |
| 1446 | if (CurSlot != INVALID_PAGE) { |
| 1447 | if (pFMProp->ABBT_Reverse) { |
| 1448 | if (CurSlot == 0) |
| 1449 | pFMProp->ABBT_CurSlot = INVALID_PAGE; |
| 1450 | else |
| 1451 | pFMProp->ABBT_CurSlot = CurSlot -1; |
| 1452 | } |
| 1453 | else { |
| 1454 | if (CurSlot >= (NumPages - 1)) |
| 1455 | pFMProp->ABBT_CurSlot = INVALID_PAGE; |
| 1456 | else |
| 1457 | pFMProp->ABBT_CurSlot = CurSlot + 1; |
| 1458 | } |
| 1459 | } else { |
| 1460 | pFMProp->ABBT_CurSlot = INVALID_PAGE; |
| 1461 | } |
| 1462 | |
| 1463 | //Set valid ABBT state, CHANGED or UNCHANGED, denpends on the search result |
| 1464 | SetABBTState(NewABBTState, fbt); |
| 1465 | |
| 1466 | if ((CrcError2 == 0) && (CrcError1 == 0)) { |
| 1467 | #ifdef BITFLIPS_SCRUBBING |
| 1468 | //If Bitflip happens during read ABBT_Block0 |
| 1469 | if(pFMProp->ABBT_State & ABBT_BITFLIP0){ |
| 1470 | Retval = ScrubBlock_LegacyExt(ScanBBT_LegacyExt(AbbtBlock0), &ReloBlock); |
| 1471 | if(Retval != NoError){ |
| 1472 | obm_printf("abbt block0 bitflip, no relocation\n\r"); |
| 1473 | Retval = NoError; |
| 1474 | } |
| 1475 | else |
| 1476 | pFMProp->ABBT_State &= ~ABBT_BITFLIP0; |
| 1477 | UpdateABBTCrc(pABBT); |
| 1478 | } |
| 1479 | |
| 1480 | //If Bitflip happens during read ABBT_Block1 |
| 1481 | if(pFMProp->ABBT_State & ABBT_BITFLIP1){ |
| 1482 | Retval = ScrubBlock_LegacyExt(ScanBBT_LegacyExt(AbbtBlock1), &ReloBlock); |
| 1483 | if(Retval != NoError){ |
| 1484 | obm_printf("abbt block1 bitflip, no relocation\n\r"); |
| 1485 | Retval = NoError; |
| 1486 | } |
| 1487 | else |
| 1488 | pFMProp->ABBT_State &= ~ABBT_BITFLIP1; |
| 1489 | UpdateABBTCrc(pABBT); |
| 1490 | } |
| 1491 | #endif |
| 1492 | |
| 1493 | //Fill the holes of Block2Update |
| 1494 | if((Block2Update != INVALID_BLOCK) && (StartSlot < EndSlot)) |
| 1495 | { |
| 1496 | Block2Update = ScanBBT_LegacyExt(Block2Update); |
| 1497 | //Most time, we should not reach here |
| 1498 | for(i = StartSlot; i < EndSlot; i++) |
| 1499 | { |
| 1500 | Retval = write(Block2Update*BlkSize+i*PageSize, (UINT_T)pTempBBT, PageSize, fbt); |
| 1501 | if(Retval != NoError){ |
| 1502 | if(Retry == TRUE){ |
| 1503 | Retry = FALSE; |
| 1504 | Retval = erase(Block2Update*BlkSize, BlkSize, fbt); |
| 1505 | if(Retval == NoError) |
| 1506 | { |
| 1507 | if (pFMProp->ABBT_Reverse) { |
| 1508 | // copy from start to block end |
| 1509 | EndSlot = NumPages; |
| 1510 | i = StartSlot - 1; //restart the copy, i++ |
| 1511 | } else { |
| 1512 | // copy from block 0 to latest slot |
| 1513 | i = - 1; //restart the copy, i++ |
| 1514 | } |
| 1515 | continue; |
| 1516 | } |
| 1517 | } |
| 1518 | Retry = TRUE; |
| 1519 | Retval = RelocateBlock_LegacyExt(Block2Update, &Block2Update, 0); |
| 1520 | UpdateABBTCrc(pABBT); |
| 1521 | if(Retval != NoError){ |
| 1522 | /* If Relocate fails, break the loop。 |
| 1523 | * Block2Update doesn't have the latest invalid BBT |
| 1524 | * but we can live with this. |
| 1525 | */ |
| 1526 | break; |
| 1527 | } |
| 1528 | else{ |
| 1529 | if (pFMProp->ABBT_Reverse) { |
| 1530 | // copy from start to block end |
| 1531 | EndSlot = NumPages; |
| 1532 | i = StartSlot - 1; //restart the copy, i++ |
| 1533 | } else { |
| 1534 | // copy from block 0 to latest slot |
| 1535 | i = - 1; //restart the copy, i++ |
| 1536 | } |
| 1537 | } |
| 1538 | } |
| 1539 | } |
| 1540 | } |
| 1541 | } /* if ((CrcError2 == 0) && (CrcError1 == 0)) */ |
| 1542 | |
| 1543 | if (CrcError1 || CrcError2) { |
| 1544 | pFMProp->ABBT_CurSlot = INVALID_PAGE; //erase due to CRC error |
| 1545 | SetABBTState(BBT_CHANGED, BOOT_FLASH); |
| 1546 | } |
| 1547 | |
| 1548 | free(pBuffer1); free(pBuffer2); |
| 1549 | if (BBTNotFound) { |
| 1550 | /* Restore BBT based on ABBT, corner case */ |
| 1551 | CreateBBT_Legacy(NULL); |
| 1552 | pBBT = pFMProp->pLBBT; |
| 1553 | for (i = 0; i < pABBT->NumReloc; i++) { |
| 1554 | if (IsLogicBlockInL1BBT(pABBT->Relo[i].From) ) { |
| 1555 | pBBT->Relo[pBBT->NumReloc].From = pABBT->Relo[i].From; |
| 1556 | pBBT->Relo[pBBT->NumReloc].To = pABBT->Relo[i].To; |
| 1557 | pBBT->NumReloc ++; |
| 1558 | } |
| 1559 | } |
| 1560 | } |
| 1561 | return NoError; |
| 1562 | } |
| 1563 | |
| 1564 | UINT_T ScrubBlock_LegacyExt(UINT_T BlockNum, UINT_T* ReloBlock) |
| 1565 | { |
| 1566 | UINT_T Retval = NoError; |
| 1567 | |
| 1568 | #ifdef BITFLIPS_SCRUBBING |
| 1569 | UINT_T RelocateBlock; |
| 1570 | INT_T i, ABBT_updated = FALSE; |
| 1571 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 1572 | P_ReloTable_T pBBT = pFMProp->pLBBT; |
| 1573 | P_ABBT_Table_T pABBT = pFMProp->pABBT; |
| 1574 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 1575 | |
| 1576 | if(pBBT == NULL || pFMProp->BBT_State == BBT_INVALID) |
| 1577 | return NoError; |
| 1578 | |
| 1579 | /* If bitflip happens in Tim Blocks, do nothing. Block0 should be always good. |
| 1580 | * If dual TIM is enabled, should ignore bitflips in block1(back up TIM) too. |
| 1581 | */ |
| 1582 | if(IsTimBlock(BlockNum)){ |
| 1583 | obm_printf("Warning: bitflip in Tim Block%d\n\r", BlockNum); |
| 1584 | #if DUAL_TIM |
| 1585 | if (DualTimEnabled()) { |
| 1586 | EraseBlockAndRestoreTIM(pFlashProp, BlockNum, 1); |
| 1587 | } |
| 1588 | #endif |
| 1589 | return NoError; |
| 1590 | } |
| 1591 | |
| 1592 | //When bitflip happens when reading ABBT from Flash(BBT is OK, but ABBT is not), |
| 1593 | //then we don't handle it immediately, record the state and handle it when ABBT is OK, |
| 1594 | //This should only happens during finding bbt from flash |
| 1595 | if( (pABBT == NULL) || (GetABBTState(BOOT_FLASH) == BBT_INVALID) ) |
| 1596 | { |
| 1597 | *ReloBlock = BlockNum; |
| 1598 | //Backward Search the block index |
| 1599 | for(i = 0; i < pBBT->NumReloc; i++) |
| 1600 | { |
| 1601 | if((pBBT->Relo[i].To == BlockNum) && EntryIsReloPair(&pBBT->Relo[i])) |
| 1602 | { |
| 1603 | BlockNum = pBBT->Relo[i].From; |
| 1604 | break; |
| 1605 | } |
| 1606 | } |
| 1607 | if(pFMProp->ABBT_block0 == BlockNum){ |
| 1608 | pFMProp->ABBT_State |= ABBT_BITFLIP0; |
| 1609 | } |
| 1610 | else if(pFMProp->ABBT_block1 == BlockNum){ |
| 1611 | pFMProp->ABBT_State |= ABBT_BITFLIP1; |
| 1612 | }else{ |
| 1613 | //Most times, ABBT should be OK when bitflip happens, |
| 1614 | //except when reading ABBT_block0 or ABBT_block1. |
| 1615 | //Just return error here. |
| 1616 | return BBTReadError; |
| 1617 | } |
| 1618 | return NoError; |
| 1619 | } |
| 1620 | |
| 1621 | do{ |
| 1622 | //Need back up before relocate |
| 1623 | Retval = RelocateBlock_LegacyExt(BlockNum, ReloBlock, 1); |
| 1624 | |
| 1625 | }while(Retval == ProgramError); |
| 1626 | |
| 1627 | if (Retval == BBTToMuchBitflips) { |
| 1628 | return NoError; |
| 1629 | } |
| 1630 | |
| 1631 | if(Retval != NoError) |
| 1632 | return Retval; |
| 1633 | |
| 1634 | RelocateBlock = *ReloBlock; |
| 1635 | |
| 1636 | //Check the recycled block info if already updated in RelocateBlock API |
| 1637 | for(i = 0; i < pABBT->NumReloc; i++) |
| 1638 | { |
| 1639 | if((pABBT->BlkInfo[i].State == BLOCK_TO_RECYCLE) && |
| 1640 | (pABBT->BlkInfo[i].Index == BlockNum)) |
| 1641 | { |
| 1642 | ABBT_updated = TRUE; |
| 1643 | break; |
| 1644 | } |
| 1645 | } |
| 1646 | |
| 1647 | if(ABBT_updated == FALSE){ |
| 1648 | pABBT->BlkInfo[pABBT->NumReloc].State = BLOCK_TO_RECYCLE; |
| 1649 | pABBT->BlkInfo[pABBT->NumReloc].Index = BlockNum; |
| 1650 | pABBT->NumReloc++; |
| 1651 | } |
| 1652 | |
| 1653 | pABBT->NumBlockToRecyle++; |
| 1654 | |
| 1655 | /* record the bitflip times */ |
| 1656 | for(i = 0; i < pABBT->NumReloc; i++) |
| 1657 | { |
| 1658 | if(pABBT->BlkInfo[i].State == BLK_FLIP_COUNT) |
| 1659 | { |
| 1660 | pABBT->BlkInfo[i].Index++; |
| 1661 | break; |
| 1662 | } |
| 1663 | } |
| 1664 | if (i == pABBT->NumReloc) { |
| 1665 | pABBT->BlkInfo[pABBT->NumReloc].State = BLK_FLIP_COUNT; |
| 1666 | pABBT->BlkInfo[pABBT->NumReloc].Index = 1; |
| 1667 | pABBT->NumReloc ++; |
| 1668 | } |
| 1669 | |
| 1670 | SetABBTState(BBT_CHANGED, BOOT_FLASH); |
| 1671 | #endif |
| 1672 | |
| 1673 | return Retval; |
| 1674 | } |
| 1675 | |
| 1676 | INT_T RawCopyFlashBlock(UINT_T BlockFrom, UINT_T BlockTo, INT_T NeedErase) |
| 1677 | { |
| 1678 | UINT_T Retval = NoError; |
| 1679 | UINT_T BlkSize, PageSize, PageOff, SrcAddr, DstAddr; |
| 1680 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 1681 | EraseFlash_F erase = pFlashProp->EraseFlash; |
| 1682 | ReadFlash_F read = pFlashProp->ReadFromFlash; |
| 1683 | WriteFlash_F write = pFlashProp->WriteToFlash; |
| 1684 | UINT8_T *ptemp = 0; |
| 1685 | |
| 1686 | BlkSize = GetBlockSize(BOOT_FLASH); |
| 1687 | PageSize = GetPageSize(BOOT_FLASH); |
| 1688 | |
| 1689 | DstAddr = BlockTo * BlkSize; |
| 1690 | SrcAddr = BlockFrom * BlkSize; |
| 1691 | |
| 1692 | if (NeedErase) { |
| 1693 | Retval = erase(DstAddr, BlkSize, BOOT_FLASH); |
| 1694 | if(Retval != NoError) //retry again |
| 1695 | Retval = erase(DstAddr, BlkSize, BOOT_FLASH); |
| 1696 | if(Retval) |
| 1697 | return EraseError; |
| 1698 | } |
| 1699 | |
| 1700 | ptemp = malloc(pFlashProp->BlockSize); |
| 1701 | if(ptemp == NULL) |
| 1702 | return HeapExhaustedError; |
| 1703 | |
| 1704 | Retval = read(SrcAddr, ptemp, BlkSize, BOOT_FLASH); |
| 1705 | if (Retval != NoError && Retval != ReadDisturbError){ |
| 1706 | free(ptemp); |
| 1707 | return ReadError; |
| 1708 | } |
| 1709 | |
| 1710 | for (PageOff = 0; PageOff < BlkSize; PageOff += PageSize) { |
| 1711 | if(CheckPattern(ptemp+PageOff, 0xFF, PageSize) == 1){ |
| 1712 | continue; //skip the 0xFF pages |
| 1713 | } |
| 1714 | else |
| 1715 | { |
| 1716 | Retval = write(DstAddr+PageOff, ptemp+PageOff, PageSize, BOOT_FLASH); |
| 1717 | if(Retval != NoError) { |
| 1718 | free(ptemp); |
| 1719 | return WriteError; |
| 1720 | } |
| 1721 | } |
| 1722 | } |
| 1723 | |
| 1724 | free(ptemp); |
| 1725 | return NoError; |
| 1726 | } |
| 1727 | |
| 1728 | UINT_T RemapRecycledBlocks(void) |
| 1729 | { |
| 1730 | INT_T i, j, k; |
| 1731 | UINT_T Retval = NoError; |
| 1732 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 1733 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 1734 | P_ABBT_Table_T pABBT = pFMProp->pABBT; |
| 1735 | P_ReloTable_T pBBT = pFMProp->pLBBT; |
| 1736 | EraseFlash_F erase = pFlashProp->EraseFlash; |
| 1737 | UINT_T BlkSize = GetBlockSize(BOOT_FLASH); |
| 1738 | INT_T BlockToErase = -1; |
| 1739 | |
| 1740 | if (pFlashProp->FlashSettings.UseBBM == 0 || pABBT->NumReloc == 0) |
| 1741 | return NoError; |
| 1742 | |
| 1743 | for ( i = 0; i < pABBT->NumReloc; i ++) |
| 1744 | { |
| 1745 | if(pABBT->BlkInfo[i].State == BLOCK_RECYCLED) { |
| 1746 | for ( j = 0; j < pABBT->NumReloc; j++) |
| 1747 | { |
| 1748 | if (pABBT->Relo[j].From == pABBT->BlkInfo[i].Index) { |
| 1749 | Retval = RawCopyFlashBlock(pABBT->Relo[j].To, pABBT->BlkInfo[i].Index, 1); |
| 1750 | if(Retval == ReadError) { |
| 1751 | Retval = NoError; |
| 1752 | continue; /* Do nothing if read error, should never happens*/ |
| 1753 | } |
| 1754 | else if (Retval == EraseError || Retval == WriteError) { |
| 1755 | pABBT->BlkInfo[i].State = BLOCK_BAD; |
| 1756 | pABBT->RefCounter ++; |
| 1757 | pABBT->NumBlockRecyled --; |
| 1758 | pFMProp->ABBT_State = BBT_CHANGED; |
| 1759 | UpdateBBT_LegacyExt(); |
| 1760 | Retval = NoError; |
| 1761 | } else { /* Retval == NoError */ |
| 1762 | if(IsLogicBlockInL1BBT(pABBT->Relo[j].From)) { |
| 1763 | for (k = 0; k <pBBT->NumReloc; k++) { |
| 1764 | if(pBBT->Relo[k].From == pABBT->Relo[j].From) { |
| 1765 | pBBT->Relo[k].From = BLOCK_BAD; |
| 1766 | pBBT->Relo[k].To = BLOCK_BAD; |
| 1767 | pFMProp->BBT_State = BBT_CHANGED; |
| 1768 | break; |
| 1769 | } |
| 1770 | } |
| 1771 | } |
| 1772 | pABBT->BlkInfo[j].State = BLOCK_RECYCLED; |
| 1773 | BlockToErase = pABBT->BlkInfo[j].Index; |
| 1774 | pABBT->Relo[i].From = pABBT->Relo[pABBT->NumReloc-1].From; |
| 1775 | pABBT->Relo[i].To = pABBT->Relo[pABBT->NumReloc-1].To; |
| 1776 | pABBT->Relo[pABBT->NumReloc-1].From = 0xFFFF; |
| 1777 | pABBT->Relo[pABBT->NumReloc-1].To = 0xFFFF; //delete an entry |
| 1778 | pABBT->NumReloc --; |
| 1779 | pABBT->RefCounter ++; |
| 1780 | pFMProp->ABBT_State = BBT_CHANGED; |
| 1781 | UpdateBBT_LegacyExt(); |
| 1782 | i--; |
| 1783 | if (BlockToErase > 0) { |
| 1784 | Retval = erase(BlockToErase*BlkSize, BlkSize, BOOT_FLASH); |
| 1785 | if(Retval != NoError) |
| 1786 | Retval = erase(BlockToErase*BlkSize, BlkSize, BOOT_FLASH); |
| 1787 | } |
| 1788 | } |
| 1789 | break; |
| 1790 | } |
| 1791 | } |
| 1792 | } |
| 1793 | } |
| 1794 | |
| 1795 | return Retval; |
| 1796 | } |
| 1797 | |
| 1798 | UINT_T RecyleBlocks_LegacyExt(void) |
| 1799 | { |
| 1800 | UINT_T Retval = NoError; |
| 1801 | #ifdef BITFLIPS_SCRUBBING |
| 1802 | INT_T i; |
| 1803 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 1804 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 1805 | P_ABBT_Table_T pABBT = pFMProp->pABBT; |
| 1806 | |
| 1807 | if(pFlashProp->FlashSettings.UseBBM == 0 || |
| 1808 | pABBT->NumBlockToRecyle == 0) |
| 1809 | return NoError; |
| 1810 | for(i = 0; i < pABBT->NumReloc; i++) |
| 1811 | { |
| 1812 | if(pABBT->BlkInfo[i].State == BLOCK_TO_RECYCLE) |
| 1813 | { |
| 1814 | Retval = TortureBlock(pABBT->BlkInfo[i].Index); |
| 1815 | if(Retval == NoError){ |
| 1816 | pABBT->NumBlockRecyled ++; |
| 1817 | pABBT->BlkInfo[i].State = BLOCK_RECYCLED; |
| 1818 | } |
| 1819 | else |
| 1820 | pABBT->BlkInfo[i].State = BLOCK_RECYCLE_FAILED; |
| 1821 | if(pABBT->NumBlockToRecyle) |
| 1822 | pABBT->NumBlockToRecyle--; |
| 1823 | } |
| 1824 | } |
| 1825 | SetABBTState(BBT_CHANGED, BOOT_FLASH); |
| 1826 | if(pABBT->NumBlockToRecyle) |
| 1827 | Retval = FlashBlockRecycleError; |
| 1828 | else |
| 1829 | Retval = NoError; |
| 1830 | #endif |
| 1831 | return Retval; |
| 1832 | } |
| 1833 | |
| 1834 | static UINT8_T Patterns[] = {0xa5, 0x5a, 0x0}; |
| 1835 | |
| 1836 | INT_T CheckPattern(const VOID *buf, UINT8_T patt, INT_T size) |
| 1837 | { |
| 1838 | INT_T i; |
| 1839 | |
| 1840 | for (i = 0; i < size; i++) |
| 1841 | if (((const UINT8_T *)buf)[i] != patt) |
| 1842 | return 0; |
| 1843 | return 1; |
| 1844 | } |
| 1845 | |
| 1846 | INT_T TortureBlock(UINT_T BlockNum) |
| 1847 | { |
| 1848 | INT_T Retval = NoError, i, PattCount; |
| 1849 | UINT_T BlockSize, BlockAddr; |
| 1850 | UINT8_T *pBuffer = 0; |
| 1851 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 1852 | BlockSize = pFlashProp->BlockSize; |
| 1853 | EraseFlash_F erase = pFlashProp->EraseFlash; |
| 1854 | ReadFlash_F read = pFlashProp->ReadFromFlash; |
| 1855 | WriteFlash_F write = pFlashProp->WriteToFlash; |
| 1856 | UINT_T TotalBlockNum = pFlashProp->NumBlocks; |
| 1857 | |
| 1858 | if(BlockNum >= pFlashProp->NumBlocks) { |
| 1859 | obm_printf("Torture invalid block %d\n\r", BlockNum); |
| 1860 | return InvalidAddressRangeError; |
| 1861 | } |
| 1862 | |
| 1863 | PattCount = sizeof(Patterns)/sizeof(Patterns[0]); |
| 1864 | BlockAddr = BlockNum*BlockSize; |
| 1865 | |
| 1866 | pBuffer = malloc(BlockSize); |
| 1867 | if(pBuffer == 0) |
| 1868 | return HeapExhaustedError; |
| 1869 | |
| 1870 | /*Here we need to use the low level erase/read/write interface without scan |
| 1871 | *BBT, as the block itself is relocated to another one. |
| 1872 | */ |
| 1873 | for (i = 0; i < PattCount; i++){ |
| 1874 | Retval = erase(BlockAddr, BlockSize, BOOT_FLASH); |
| 1875 | if(Retval != NoError){ |
| 1876 | free(pBuffer); |
| 1877 | return Retval; |
| 1878 | } |
| 1879 | Retval = read(BlockAddr, (UINT_T)pBuffer, BlockSize, BOOT_FLASH); |
| 1880 | if(Retval != NoError){ |
| 1881 | free(pBuffer); |
| 1882 | return Retval; |
| 1883 | } |
| 1884 | Retval = CheckPattern(pBuffer, 0xFF, BlockSize); |
| 1885 | if(Retval == 0) {//Erased, but a non-0xFF byte found |
| 1886 | free(pBuffer); |
| 1887 | return EraseError; |
| 1888 | } |
| 1889 | /* Write a pattern and check it */ |
| 1890 | memset(pBuffer, Patterns[i], BlockSize); |
| 1891 | Retval = write(BlockAddr, (UINT_T)pBuffer, BlockSize, BOOT_FLASH); |
| 1892 | if(Retval != NoError){ |
| 1893 | free(pBuffer); |
| 1894 | return Retval; |
| 1895 | } |
| 1896 | memset(pBuffer, ~Patterns[i], BlockSize); |
| 1897 | Retval = read(BlockAddr, (UINT_T)pBuffer, BlockSize, BOOT_FLASH); |
| 1898 | if(Retval != NoError){ |
| 1899 | free(pBuffer); |
| 1900 | return Retval; |
| 1901 | } |
| 1902 | Retval = CheckPattern(pBuffer, Patterns[i], BlockSize); |
| 1903 | if(Retval == 0){ |
| 1904 | free(pBuffer); |
| 1905 | return FlashReadError; |
| 1906 | } |
| 1907 | Retval = erase(BlockAddr, BlockSize, BOOT_FLASH); |
| 1908 | if(Retval != NoError){ |
| 1909 | free(pBuffer); |
| 1910 | return Retval; |
| 1911 | } |
| 1912 | } |
| 1913 | if(i == PattCount) |
| 1914 | Retval = NoError; |
| 1915 | |
| 1916 | free(pBuffer); |
| 1917 | return Retval; |
| 1918 | } |
| 1919 | |
| 1920 | void SCAN_FactoryBadBlockLegacyExt(void) |
| 1921 | { |
| 1922 | UINT16 i, badblocklist[100]; |
| 1923 | UINT fBBNum, NewBlock, initial_blk, end_blk, num_relo; |
| 1924 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 1925 | P_FMProperties_T pFMP = GetFMProperties(); |
| 1926 | GenerateFBBT_F Gen_FBBT = pFlashProp->GenerateFBBT; |
| 1927 | P_ABBT_Table_T pABBT = pFMP->pABBT; |
| 1928 | P_ReloTable_T pBBT = pFMP->pLBBT; |
| 1929 | |
| 1930 | //return early if not supported |
| 1931 | if( (Gen_FBBT == NULL) || (pFlashProp->FlashSettings.UseBBM == 0) ) |
| 1932 | return; |
| 1933 | |
| 1934 | if((pBBT == NULL) || (pABBT == NULL) || ((UINT16)BBT_TYPE_LEGACY != pBBT->Header)) |
| 1935 | return; |
| 1936 | |
| 1937 | //get RP boundaries |
| 1938 | #if defined(NAND_CODE) || defined(SPINAND_CODE) |
| 1939 | initial_blk = pFlashProp->NumBlocks - 1 - ABBT_BLOCK_NUM; |
| 1940 | #endif |
| 1941 | |
| 1942 | end_blk = initial_blk - (pFlashProp->NumBlocks * LEGACY_BBM_RELOC_PERCENTAGE + 99) / 100; |
| 1943 | |
| 1944 | fBBNum = Gen_FBBT(badblocklist); |
| 1945 | |
| 1946 | num_relo = pABBT->NumReloc; |
| 1947 | |
| 1948 | for(i = 0; i < fBBNum; i++){ |
| 1949 | //if the block is in reserved pool, just mark it as bad block |
| 1950 | if(badblocklist[i] > end_blk && badblocklist[i] <= initial_blk) |
| 1951 | { |
| 1952 | pABBT->BlkInfo[pABBT->NumReloc].Index = badblocklist[i]; |
| 1953 | pABBT->BlkInfo[pABBT->NumReloc].State = BLOCK_BAD; |
| 1954 | pABBT->NumReloc++; |
| 1955 | } |
| 1956 | } |
| 1957 | |
| 1958 | if(num_relo != pBBT->NumReloc) |
| 1959 | SetABBTState(BBT_CHANGED, BOOT_FLASH); |
| 1960 | |
| 1961 | for(i = 0; i < fBBNum; i++){ |
| 1962 | if(badblocklist[i] <= end_blk || badblocklist[i] > initial_blk) |
| 1963 | RelocateBlock_LegacyExt(badblocklist[i], &NewBlock, 0); |
| 1964 | } |
| 1965 | } |
| 1966 | |
| 1967 | static VOID DetectScrubBitflipBlock(UINT32 Block) |
| 1968 | { |
| 1969 | pIMAGE_INFO_3_4_0 pImageInfo; |
| 1970 | UINT_T BlkSize, Retval, BlockNum, BlockToRecyle, i; |
| 1971 | P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH); |
| 1972 | EraseFlash_F erase = pFlashProp->EraseFlash; |
| 1973 | ReadFlash_F read = pFlashProp->ReadFromFlash; |
| 1974 | WriteFlash_F write = pFlashProp->WriteToFlash; |
| 1975 | P_FMProperties_T pFMP = GetFMProperties(); |
| 1976 | P_ABBT_Table_T pABBT = pFMP->pABBT; |
| 1977 | UCHAR *pBuffer = 0; |
| 1978 | |
| 1979 | BlkSize = pFlashProp->BlockSize; |
| 1980 | |
| 1981 | #if NAND_CODE //To word around the issue that BootROM disable sprare area |
| 1982 | if(Block == OBM_BLOCK) |
| 1983 | DisableSpareAreaForOBM(Block*BlkSize, BlkSize); |
| 1984 | #endif |
| 1985 | BlockNum = ScanBBT_LegacyExt(Block); |
| 1986 | pBuffer = malloc(BlkSize); |
| 1987 | if(pBuffer == NULL) |
| 1988 | return HeapExhaustedError; |
| 1989 | |
| 1990 | Retval = read(BlockNum*BlkSize, pBuffer, BlkSize, BOOT_FLASH); |
| 1991 | if ( Retval == ReadDisturbError ) { |
| 1992 | ScrubBlock_LegacyExt(BlockNum, &BlockNum); |
| 1993 | SetBBTStates(BBT_CHANGED, BBT_CHANGED, BOOT_FLASH); |
| 1994 | UpdateBBT(); |
| 1995 | } |
| 1996 | free(pBuffer); |
| 1997 | |
| 1998 | return; |
| 1999 | } |
| 2000 | |
| 2001 | /* This is to detect the bitflip of the blocks which are only read by BootROM */ |
| 2002 | VOID DetectScrubBitflipBlocks(VOID) |
| 2003 | { |
| 2004 | #if MMC_CODE |
| 2005 | return; |
| 2006 | #endif |
| 2007 | |
| 2008 | if(!DualTimEnabled()) |
| 2009 | { |
| 2010 | /* As BootROM can't transfer the read disturb error of OBM block to OBM, |
| 2011 | * OBM read itself instead, if bitflip happens on OBM block, it will be handled, |
| 2012 | * so that BootROM will not meet read disturb error when reading OBM. |
| 2013 | * If Dual TIM is enabled, both OBM blocks are read in InitializeDualTimLate() |
| 2014 | */ |
| 2015 | DetectScrubBitflipBlock(OBM_BLOCK); /* OBM block */ |
| 2016 | } |
| 2017 | |
| 2018 | return; |
| 2019 | } |
| 2020 | |
| 2021 | UINT_T GetBadBlockNumExt(void) |
| 2022 | { |
| 2023 | UINT_T BlockNum; |
| 2024 | INT_T i; |
| 2025 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 2026 | P_ABBT_Table_T pABBT = pFMProp->pABBT; |
| 2027 | |
| 2028 | BlockNum = pABBT->NumReloc; |
| 2029 | |
| 2030 | for (i = 0; i < pABBT->NumReloc; ++i) |
| 2031 | { |
| 2032 | //The block which is recycled is good block now |
| 2033 | if(pABBT->BlkInfo[i].State == BLOCK_RECYCLED) |
| 2034 | BlockNum--; |
| 2035 | } |
| 2036 | |
| 2037 | return BlockNum; |
| 2038 | } |
| 2039 | |
| 2040 | void Dump_FM_Info(void) |
| 2041 | { |
| 2042 | INT_T i; |
| 2043 | P_FMProperties_T pFMProp = GetFMProperties(); |
| 2044 | P_ReloTable_T pBBT = pFMProp->pLBBT; |
| 2045 | P_ABBT_Table_T pABBT = pFMProp->pABBT; |
| 2046 | obm_printf("FM:\n\r"); |
| 2047 | obm_printf("BBT_State: 0x%x\n\r", pFMProp->BBT_State); |
| 2048 | obm_printf("ABBT_State: 0x%x\n\r", pFMProp->ABBT_State); |
| 2049 | obm_printf("BBT_Slot: 0x%x\n\r", pFMProp->BBT_Slot); |
| 2050 | obm_printf("BBT_NextSlot: 0x%x\n\r", pFMProp->BBT_NextSlot); |
| 2051 | obm_printf("BBT_location: 0x%x\n\r", pFMProp->BBT_location); |
| 2052 | obm_printf("BBT_Reverse: %d\n\r", pFMProp->BBT_Reverse); |
| 2053 | obm_printf("ABBT_Reverse: %d\n\r", pFMProp->ABBT_Reverse); |
| 2054 | obm_printf("ABBT_CurSlot: 0x%x\n\r", pFMProp->ABBT_CurSlot); |
| 2055 | |
| 2056 | obm_printf("BBT:\n\r"); |
| 2057 | obm_printf("Header: 0x%x\n\r", pBBT->Header); |
| 2058 | obm_printf("NumReloc: %d\n\r", pBBT->NumReloc); |
| 2059 | for (i = 0; i < pBBT->NumReloc; i++) |
| 2060 | { |
| 2061 | obm_printf("%d: block %d ---> %d\n\r", i, pBBT->Relo[i].From, pBBT->Relo[i].To); |
| 2062 | } |
| 2063 | |
| 2064 | obm_printf("ABBT:\n\r"); |
| 2065 | obm_printf("Identifier: 0x%x\n\r", pABBT->Identifier); |
| 2066 | obm_printf("Version: 0x%x\n\r", pABBT->Version); |
| 2067 | obm_printf("Type: 0x%x\n\r", pABBT->Type); |
| 2068 | obm_printf("RefCounter: %d\n\r", pABBT->RefCounter); |
| 2069 | obm_printf("NumReloc: %d\n\r", pABBT->NumReloc); |
| 2070 | obm_printf("NumBlockRecyled: %d\n\r", pABBT->NumBlockRecyled); |
| 2071 | obm_printf("NumBlockToRecyle: %d\n\r", pABBT->NumBlockToRecyle); |
| 2072 | |
| 2073 | for (i = 0; i < pABBT->NumReloc; i++) |
| 2074 | { |
| 2075 | obm_printf("%d: block %d ---> %d\n\r", i, pABBT->Relo[i].From, pABBT->Relo[i].To); |
| 2076 | } |
| 2077 | } |
| 2078 | |
| 2079 | #endif |