CE5.0 - eboot创建MBR主分区进行LowLevelFormat低格的详细流程
eboot
==>main PLATFORM\SMDK2440A\Src\Bootloader\Eboot_usb\main.c|96| BootloaderMain(); //应该是这个
==>BootloaderMain PLATFORM\SMDK2440A\Src\Bootloader\Eboot_usb\blcommon.c|106| if (!OEMPlatformInit ()) //应该是这个
==>OEMPlatformInit PLATFORM\SMDK2440A\Src\Bootloader\Eboot\main.c|722| if ( !BP_Init((LPBYTE)BINFS_RAM_START, BINFS_RAM_LENGTH, NULL, NULL, NULL) )
=>g_dwImageStartBlock = IMAGE_START_BLOCK;
=>BP_Init((LPBYTE)BINFS_RAM_START, BINFS_RAM_LENGTH, NULL, NULL, NULL)
#define BINFS_RAM_START (0x8c021000 | CACHED_TO_UNCACHED_OFFSET) // uncached 在boot.bib中有定义[luther.gliethttp]:BINFS 8c021000 00005000 RESERVED
g_pbMBRSector = pMemory; //size = g_FlashInfo.wDataBytesPerSector;
g_pbBlock = pMemory + g_FlashInfo.wDataBytesPerSector; //size = g_dwDataBytesPerBlock;
g_pSectorInfoBuf = (PSectorInfo)(g_pbBlock + g_dwDataBytesPerBlock); //size = g_FlashInfo.wSectorsPerBlock * sizeof(SectorInfo);
=>FMD_Init
=>g_pbMBRSector = pMemory;
==>TOC_Read
=>FMD_ReadSector(TOC_SECTOR, (PUCHAR)g_pTOC, &si, 1);//从TOC_SECTOR处读取TOC,我定义的是32,即第2个block开始地址
=>VALID_TOC(g_pTOC)如果TOC无效,那么直接return false;然后OEMPlatformInit将调用TOC_Init()初始化默认数值给TOC;[luther.gliethttp]
否则
// update our boot config
g_pBootCfg = &g_pTOC->BootCfg;
// update our index
g_dwTocEntry = g_pBootCfg->ImageIndex;
// debugger enabled?
g_bWaitForConnect = (g_pBootCfg->ConfigFlags & CONFIG_FLAGS_DEBUGGER) ? TRUE : FALSE;
// cache image type
g_ImageType = g_pTOC->id[g_dwTocEntry].dwImageType;
=>每个block块第一个sector的info数据区存放了所在block的状态信息
typedef struct _SectorInfo
{
DWORD dwReserved1; // Reserved - used by FAL
BYTE bOEMReserved; // For use by OEM
BYTE bBadBlock; // Indicates if block is BAD
WORD wReserved2; // Reserved - used by FAL
}SectorInfo, *PSectorInfo;
==>TOC_Init(DEFAULT_IMAGE_DESCRIPTOR, (IMAGE_TYPE_RAMIMAGE), 0, 0, 0);
// Default image descriptor to load.
// We store Eboot as image 0, nk.nb0 as image 1
#define DEFAULT_IMAGE_DESCRIPTOR 1
=>memset(g_pTOC, 0, sizeof(g_TOC));
=>BootConfigInit(dwEntry);
static void BootConfigInit(DWORD dwIndex)
{
EdbgOutputDebugString("+BootConfigInit\r\n");
g_pBootCfg = &g_pTOC->BootCfg;
memset(g_pBootCfg, 0, sizeof(BOOT_CFG));
g_pBootCfg->ImageIndex = dwIndex;
g_pBootCfg->ConfigFlags = BOOT_TYPE_MULTISTAGE | CONFIG_FLAGS_DEBUGGER;
g_pBootCfg->BootDelay = CONFIG_BOOTDELAY_DEFAULT;
g_pBootCfg->SubnetMask = inet_addr("255.255.255.0");
EdbgOutputDebugString("-BootConfigInit\r\n");
return;
}
==>dwStartTime = OEMEthGetSecs();//读取2440内部RTC时间
==>while((dwCurrTime - dwStartTime) < g_pBootCfg->BootDelay) //等待BootDelay时间到来,如果debug口有数据输入,那么将退出该while
==>MainMenu(g_pBootCfg);//通过debug口输入格式化命令'F',然后输入format BinFS命令'9'
case 'F':
case 'f':
// low-level format
// N.B: this erases images, BinFs, FATFS, user data, etc.
// However, we don't format Bootloaders & TOC bolcks; use JTAG for this.
if ( !g_bBootMediaExist ) {
OALMSG(OAL_ERROR, (TEXT("ERROR: BootMonitor: boot media does not exist.\r\n")));
continue;
} else {
DWORD i;
SectorInfo si;
// to keep bootpart off of our reserved blocks we must mark it as bad, reserved & read-only
si.bOEMReserved = OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY;
si.bBadBlock = BADBLOCKMARK;
si.dwReserved1 = 0xffffffff;
si.wReserved2 = 0xffff;
OALMSG(TRUE, (TEXT("Reserving Blocks [0x%x - 0x%x] ...\r\n"), 0, IMAGE_START_BLOCK-1));
for (i = 0; i < IMAGE_START_SECTOR; i++) {//0块--NBOOT;1块--TOC;2块~17块--EBOOT.nb0;IMAGE_START_SECTOR等于18块[luther.gliethttp]
FMD_WriteSector(i, NULL, &si, 1);//写0~17块的info区,这样来保留0~17块.
}
OALMSG(TRUE, (TEXT("...reserve complete.\r\n")));
OALMSG(TRUE, (TEXT("Low-level format Blocks [0x%x - 0x%x] ...\r\n"), IMAGE_START_BLOCK, NAND_BLOCK_CNT-1));
for (i = IMAGE_START_BLOCK; i < NAND_BLOCK_CNT; i++) { //我的一共有64M,即:4K/32/512
FMD_EraseBlock(i);//发出erase指令之后,该块是否已经损坏的info信息会被NAND控制器自动存放到了每块的第1个扇区的info空间,未损坏将全部为0xff[luther.gliethttp]
}
OALMSG(TRUE, (TEXT("...erase complete.\r\n")));
} break;
case '9':
// format the boot media for BinFS
// N.B: this does not destroy our OEM reserved sections (TOC, bootloaders, etc)
if ( !g_bBootMediaExist ) {
OALMSG(OAL_ERROR, (TEXT("ERROR: BootMonitor: boot media does not exist.\r\n")));
continue;
}
// N.B: format offset by # of reserved blocks,
// decrease the ttl # blocks available by that amount.
//低格除0块--NBOOT;1块--TOC;2块~17块--EBOOT.nb0;IMAGE_START_SECTOR等于18块
//从18块开始格
if ( !BP_LowLevelFormat( g_dwImageStartBlock,
NAND_BLOCK_CNT - g_dwImageStartBlock,
0) )
{
OALMSG(OAL_ERROR, (TEXT("ERROR: BootMonitor: Low-level boot media format failed.\r\n")));
continue;
}
break;
/*
BOOL BP_LowLevelFormat(DWORD dwStartBlock, DWORD dwNumBlocks, DWORD dwFlags)
{
dwNumBlocks = min (dwNumBlocks, g_FlashInfo.dwNumBlocks);
RETAILMSG(1,(TEXT("Enter LowLevelFormat [0x%x, 0x%x].\r\n"), dwStartBlock, dwStartBlock + dwNumBlocks - 1));
// Erase all the flash blocks.
if (!EraseBlocks(dwStartBlock, dwNumBlocks, dwFlags))
return(FALSE);
// Determine first good starting block
//如果dwStartBlock是坏块,那么一直往下找,知道找到第一个好块为止[luther.gliethttp]
while (IS_BLOCK_UNUSABLE (dwStartBlock) && dwStartBlock < g_FlashInfo.dwNumBlocks) {
dwStartBlock++;
}
if (dwStartBlock >= g_FlashInfo.dwNumBlocks) {
//说明最变态的情况发生了,竟然全坏了,shit了[luthre.gliethttp]
RETAILMSG(1,(TEXT("BP_LowLevelFormat: no good blocks\r\n")));
return FALSE;
}
// MBR goes in the first sector of the starting block. This will be logical sector 0.
// 那么MBR的逻辑扇区就从这个块开始[luther.gliethttp]
g_dwMBRSectorNum = dwStartBlock * g_FlashInfo.wSectorsPerBlock;
// Create an MBR.
CreateMBR();
RETAILMSG (1, (TEXT("Done.\r\n\r\n")));
return(TRUE);
}
BOOL EraseBlocks(DWORD dwStartBlock, DWORD dwNumBlocks, DWORD dwFlags)
{
DWORD dwSector;
USHORT nCount;
LPBYTE WriteSect = g_pbBlock + g_FlashInfo.wDataBytesPerSector;//其地址在在boot.bib中有定义BINFS 8c021000 00005000 RESERVED,分析见上面[luther.gliethttp]
LPBYTE ReadSect = g_pbBlock + 2 * g_FlashInfo.wDataBytesPerSector;
SectorInfo WriteSectInfo, ReadSectInfo;
if (dwStartBlock >= g_FlashInfo.dwNumBlocks || (dwStartBlock + dwNumBlocks - 1) >= g_FlashInfo.dwNumBlocks)
{
RETAILMSG (1, (TEXT("EraseBlocks: block number outside valid range [0x%x, 0x%x].\r\n"), dwStartBlock, (dwStartBlock + dwNumBlocks - 1)));
return(FALSE);
}
RETAILMSG (1, (TEXT("Erasing flash block(s) [0x%x, 0x%x] (please wait): "), dwStartBlock, (dwStartBlock + dwNumBlocks - 1)));
while (dwNumBlocks--)
{
DWORD dwStatus = FMD_GetBlockStatus (dwStartBlock);//获取block所在第1扇区的info信息[luther.gliethttp]
BOOL fBadBlock = FALSE;
// If the block has already been marked bad, skip it and increase the total number of blocks to be erased by a block. Note that bad
// blocks do count against the total number of blocks to be erased since the caller has max constraints on the erase region size.
if (dwStatus & BLOCK_STATUS_BAD)
{
RETAILMSG (1, (TEXT("EraseBlocks: found a bad block (0x%x) - skipping...\r\n"), dwStartBlock));
++dwStartBlock;//坏块,继续
continue;
}
if ((dwStatus & BLOCK_STATUS_RESERVED) && (dwFlags & FORMAT_SKIP_RESERVED))
{
RETAILMSG (1, (TEXT("EraseBlocks: preserving reserved block (0x%x) \r\n"), dwStartBlock));
++dwStartBlock;//保留块,继续
continue;
}
if (!FMD_EraseBlock(dwStartBlock))
{
RETAILMSG (1, (TEXT("EraseBlocks: unable to erase block (0x%x). Marking bad..\r\n"), dwStartBlock));
FMD_SetBlockStatus(dwStartBlock, BLOCK_STATUS_BAD);
++dwStartBlock;//擦除出现异常,继续
continue;
}
// Optionally skip the bad block check - this speeds up the erase process, especially on NOR flash.
if (dwFlags & FORMAT_SKIP_BLOCK_CHECK)
{
++dwStartBlock;//不需要进行块检查,比如nor flash
continue;
}
// Because the bits denoting a bad block can be erased, we take the cautious approach - we'll write an read-verify each sector in this
// block to make sure the block is good. If it's good, we'll re-erase else we'll mark the block bad.
//使用1.写入 2.读出 3.比较 的方式对该block下的所有扇区进行全方位检测块[luther.gliethttp]
dwSector = (dwStartBlock * g_FlashInfo.wSectorsPerBlock);
for (nCount = 0 ; nCount < g_FlashInfo.wSectorsPerBlock ; nCount++)
{
// Make sure erase set all bits high.
//位于BinFS空间的写缓冲区全置1
memset(WriteSect, 0xFF, g_FlashInfo.wDataBytesPerSector);
memset(&WriteSectInfo, 0xFF, sizeof(SectorInfo));
//读该扇区
FMD_ReadSector((dwSector + nCount), ReadSect, &ReadSectInfo, 1);
if (memcmp(ReadSect, WriteSect, g_FlashInfo.wDataBytesPerSector) ||
memcmp(&ReadSectInfo, &WriteSectInfo, sizeof(SectorInfo)))//如果不全1,那么说明该block为坏块,break出去[luther.gliethttp]
{
RETAILMSG (1, (TEXT("EraseBlocks: erase didn't set all bits high (marking block 0x%x bad).\r\n"), dwStartBlock));
FMD_SetBlockStatus(dwStartBlock, BLOCK_STATUS_BAD);
fBadBlock = TRUE;
break;
}
// Now, make sure we can store zero - this is meant to check for bad blocks (in the event that the bad block marker was erased).
// Note that we *don't* write sector info data here - this is where bad block data is stored.
memset(WriteSect, 0, g_FlashInfo.wDataBytesPerSector);//全置0
if (!FMD_WriteSector((dwSector + nCount), WriteSect, NULL, 1))//在数据区写全0
{
RETAILMSG (1, (TEXT("EraseBlocks: write test low data failed (marking block 0x%x bad).\r\n"), dwStartBlock));
FMD_SetBlockStatus(dwStartBlock, BLOCK_STATUS_BAD);
fBadBlock = TRUE;
break;
}
// Read back the value and make sure it stored correctly.
if (!FMD_ReadSector((dwSector + nCount), ReadSect, NULL, 1) ||
memcmp(ReadSect, WriteSect, g_FlashInfo.wDataBytesPerSector))
{
RETAILMSG (1, (TEXT("EraseBlocks: erase didn't set all bits low (marking block 0x%x bad).\r\n"), dwStartBlock));
FMD_SetBlockStatus(dwStartBlock, BLOCK_STATUS_BAD);
fBadBlock = TRUE;//如果写全0存在问题,那么说明该block对写全0存在问题,所以标记该block为坏块[luther.gliethttp]
break;
}
}
// If the block has already been marked bad, skip it and increase the total number of blocks to be erased by a block. Note that bad
// blocks do count against the total number of blocks to be erased since the caller has max constraints on the erase region size.
if (fBadBlock)
{
RETAILMSG (1, (TEXT("\r\nEraseBlocks: found a bad block (0x%x) - skipping...\r\n"), dwStartBlock));
++dwStartBlock;
continue;
}
if (!FMD_EraseBlock(dwStartBlock))
{
RETAILMSG (1, (TEXT("EraseBlocks: unable to erase block (0x%x). Marking bad..\r\n"), dwStartBlock));
FMD_SetBlockStatus(dwStartBlock, BLOCK_STATUS_BAD);
}
++dwStartBlock;//进入下一个block块的检测工作[luthre.gliethtp]
}
RETAILMSG (1, (TEXT("Done.\r\n")));
return(TRUE);
}
static BOOL CreateMBR()
{
// This, plus a valid partition table, is all the CE partition manager needs to recognize
// the MBR as valid. It does not contain boot code.
//g_pbMBRSector地址定义见上面
//g_pbMBRSector = pMemory = BINFS_RAM_START;位于boot.bib
memset (g_pbMBRSector, 0xff, g_FlashInfo.wDataBytesPerSector);//置全0xff
g_pbMBRSector[0] = 0xE9;
g_pbMBRSector[1] = 0xfd;
g_pbMBRSector[2] = 0xff;
g_pbMBRSector[SECTOR_SIZE-2] = 0x55;
g_pbMBRSector[SECTOR_SIZE-1] = 0xAA;
// Zero out partition table so that mspart treats entries as empty.
// 全置0分区表,这样mspart才知道分区表空[lutehr.gliethttp]
memset (g_pbMBRSector+PARTTABLE_OFFSET, 0, sizeof(PARTENTRY) * NUM_PARTS);
return WriteMBR();//回写MBR到nand存储器
}
static BOOL WriteMBR()
{
DWORD dwMBRBlockNum = g_dwMBRSectorNum / g_FlashInfo.wSectorsPerBlock; //g_dwMBRSectorNum为第一个18块开始之后的第一个好块,对该原因的分析见上面[luther.gliethttp]
RETAILMSG(1, (TEXT("WriteMBR: MBR block = 0x%x.\r\n"), dwMBRBlockNum));
//置全0xff
memset (g_pbBlock, 0xff, g_dwDataBytesPerBlock);
memset (g_pSectorInfoBuf, 0xff, sizeof(SectorInfo) * g_FlashInfo.wSectorsPerBlock);
// No need to check return, since a failed read means data hasn't been written yet.
// 读到BinFS空间[luther.gliethttp]
ReadBlock (dwMBRBlockNum, g_pbBlock, g_pSectorInfoBuf);
if (!FMD_EraseBlock (dwMBRBlockNum)) {//尝试擦,以备后患
RETAILMSG (1, (TEXT("CreatePartition: error erasing block 0x%x\r\n"), dwMBRBlockNum));
return FALSE;
}
//拷贝g_pbMBRSector中数据,一般g_dwMBRSectorNum % g_FlashInfo.wSectorsPerBlock值为0
memcpy (g_pbBlock + (g_dwMBRSectorNum % g_FlashInfo.wSectorsPerBlock) * g_FlashInfo.wDataBytesPerSector, g_pbMBRSector, g_FlashInfo.wDataBytesPerSector);
g_pSectorInfoBuf->bOEMReserved &= ~OEM_BLOCK_READONLY;
g_pSectorInfoBuf->wReserved2 &= ~SECTOR_WRITE_COMPLETED;
g_pSectorInfoBuf->dwReserved1 = 0;
//好了将MBR回写到那个block块,这样我们创建MBR的操作也就到此高一段落了[luther.gliethttp]
if (!WriteBlock (dwMBRBlockNum, g_pbBlock, g_pSectorInfoBuf)) {
RETAILMSG (1, (TEXT("CreatePartition: could not write to block 0x%x\r\n"), dwMBRBlockNum));
return FALSE;
}
return TRUE;
}
*/
|