blob: e7181541463b019f882c5b21ad3526467fb6b09b [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#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
15extern UINT_T *pFM_SPACE;
16
17#ifdef BBM_LEGACY_EXT
18static 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
29static 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
39void 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
64UINT_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
75void SetBBTStates(ReloState_T bbtState, ReloState_T abbtState, FlashBootType_T fbt)
76{
77 SetBBTState(bbtState, fbt);
78 SetABBTState(abbtState, fbt);
79}
80
81static 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
102INT_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
125static 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
140static 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
162INT 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 */
183static INT_T L1BbtBlocks[L1_BBT_BLOCK_NUM];
184static UINT_T L1BbtBlockNum = 0;
185
186VOID 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
211INT_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
223INT_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
238INT_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
249void 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*/
331static 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
405static 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
520static 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
537static 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
635void 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
676update_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
797UINT_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
845static 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 */
862extern UINT_T All_FF_flag;
863UINT_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
908SearchBlockForRelocation:
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
1101RelocateDone:
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
1136UINT_T RelocateBlock_LegacyExt(UINT_T BlockNum, UINT_T* ReloBlock, UINT_T isBitFlip)
1137{
1138 return __RelocateBlock_LegacyExt(BlockNum, ReloBlock, isBitFlip, 1);
1139}
1140
1141UINT_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
1220UINT_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
1304search_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) {
1329creat_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
1564UINT_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
1676INT_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
1728UINT_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
1798UINT_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
1834static UINT8_T Patterns[] = {0xa5, 0x5a, 0x0};
1835
1836INT_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
1846INT_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
1920void 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
1967static 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 */
2002VOID 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
2021UINT_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
2040void 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