Eboot 中给nandflash分区实现
提到分區就不得不提到MBR,不得不提到分區表。
什么是MBR
硬盤的0柱面、0磁頭、1扇區稱為主引導扇區,NANDFLASH由BLOCK和Sector組成,所以NANDFLASH的第0 BLOCK,第1 Sector為主引導扇區,FDISK程序寫到該扇區的內容稱為主引導記錄(MBR)。該記錄占用512個字節,它用于硬盤啟動時將系統控制權交給用戶指定的,并在分區表中登記了的某個操作系統區。
?
MBR的組成
一個扇區的硬盤主引導記錄MBR由如圖6-15所示的4個部分組成。
·主引導程序(偏移地址0000H--0088H),它負責從活動分區中裝載,并運行系統引導程序。
·出錯信息數據區,偏移地址0089H--00E1H為出錯信息,00E2H--01BDH全為0字節。
·分區表(DPT,Disk Partition Table)含4個分區項,偏移地址01BEH--01FDH,每個分區表項長16個字節,共64字節為分區項1、分區項2、分區項3、分區項4。
·結束標志字,偏移地址01FE--01FF的2個字節值為結束標志55AA,如果該標志錯誤系統就不能啟動。
圖6-15 MBR的組成結構圖
MBR中的分區信息結構
??? 占用512個字節的MBR中,偏移地址01BEH--01FDH的64個字節,為4個分區項內容(分區信息表)。它是由磁盤介質類型及用戶在使用 FDISK定義分區說確定的。在實際應用中,FDISK對一個磁盤劃分的主分區可少于4個,但最多不超過4個。每個分區表的項目是16個字節,其內容含義 如表6-19所示。
表6-19 分區項表(16字節)內容及含義
?
?
EBOOT中對NAND分區主要代碼,eboot目錄下的fmd.cpp文件,與NAND驅動基本相同,所以,要對NAND進行分區,就得對NAND驅動非常熟悉。透徹了解。然后就是
E:/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/ETHDBG/BOOTPART/bootpart.cpp文件了。該文件主要通過調用NANDFLASH的讀寫操作來寫入MBR,也是今天主要的分析對象。
?
主要函數。
?
/*? BP_OpenPartition
?*
?*? Opens/creates a partition depending on the creation flags.? If it is opening
?*? and the partition has already been opened, then it returns a handle to the
?*? opened partition.? Otherwise, it loads the state information of that partition
?*? into memory and returns a handle.
?*
?*? ENTRY
?*????? dwStartSector - Logical sector to start the partition.? NEXT_FREE_LOC if none
?*????????? specified.? Ignored if opening existing partition.
?*????? dwNumSectors - Number of logical sectors of the partition.? USE_REMAINING_SPACE
?*????????? to indicate to take up the rest of the space on the flash for that partition (should
?*????????? only be used when creating extended partitions).? This parameter is ignored
?*????????? if opening existing partition.
?*????? dwPartType - Type of partition to create/open.
?*????? fActive - TRUE indicates to create/open the active partition.? FALSE for
?*????????? inactive.
?*????? dwCreationFlags - PART_CREATE_NEW to create only.? Fail if it already
?*????????? exists.? PART_OPEN_EXISTING to open only.? Fail if it doesn't exist.
?*????????? PART_OPEN_ALWAYS creates if it does not exist and opens if it
?*????????? does exist.
?*
?*? EXIT
?*????? Handle to the partition on success.? INVALID_HANDLE_VALUE on error.
?*/
HANDLE BP_OpenPartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags)
?
注:示例代碼為本人EBOOT中分區實現源碼(WINCE5.0+S3C2440+128MNAND,MBR寫在第4個BLOCK,分一個BINFS格式分區和一個FAT格式分區)。
?
BOOL WriteRegionsToBootMedia(DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr)
在把SDRAM中的NK燒寫到NAND中去之前,先創建一個BINFS分區。
hPart = BP_OpenPartition( (NK_START_BLOCK+1)*PAGES_PER_BLOCK,? // next block of MBR???? BINFS_BLOCK*PAGES_PER_BLOCK,//SECTOR_TO_BLOCK_SIZE(FILE_TO_SECTOR_SIZE(dwBINFSPartLength))*PAGES_PER_BLOCK,? //align to block
????????????????????????????? PART_BINFS,
????????????????????????????? TRUE,
????????????????????????????? PART_OPEN_ALWAYS);
第一個參數分區的起始sector 為(NK_START_BLOCK+1)*PAGES_PER_BLOCK,
第二個參數分區的結束 sector為BINFS_BLOCK*PAGES_PER_BLOCK,
第三個參數分區的格式為PART_BINFS,即BINFS格式,
第四個參數指示該分區為活動分區,fActive = TURE,
第五個參數PART_OPEN_ALWAYS指示如果分區不存在就創建該分區,存在就OPEN該分區,返回分區句柄。
?
HANDLE BP_OpenPartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags)
{
??????? DWORD dwPartIndex;
??????? BOOL fExists;
?
??????? ASSERT (g_pbMBRSector);
???????
??????? if (!IsValidMBR()) {
??????????? DWORD dwFlags = 0;
??????????
??????????? //fly
???????????? RETAILMSG(1, (TEXT("BP_OpenPartition:: dwStartSector=0x%x ,dwNumSectors= 0x%x.,dwPartType = 0x%x/r/n"), dwStartSector, dwNumSectors,dwPartType));
??????????? if (dwCreationFlags == PART_OPEN_EXISTING) {
??????????????? RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR.? Cannot open existing partition 0x%x./r/n"), dwPartType));
??????????????? return INVALID_HANDLE_VALUE;
??????????? }
???????????
??????????? RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR.? Formatting flash./r/n")));
??????????? if (g_FlashInfo.flashType == NOR) {
??????????????? dwFlags |= FORMAT_SKIP_BLOCK_CHECK;
??????????? }
??????????? //fly
???????????? RETAILMSG(1, (TEXT("BP_LowLevelFormat: g_pbMBRSector=0x%x, g_dwMBRSectorNum= 0x%x./r/n"), *g_pbMBRSector, g_dwMBRSectorNum));
??????????? BP_LowLevelFormat (SECTOR_TO_BLOCK(dwStartSector), SECTOR_TO_BLOCK(dwNumSectors), dwFlags);
??????????? dwPartIndex = 0;
??????????? fExists = FALSE;
??????? }
??????? else {
??????????? fExists = GetPartitionTableIndex(dwPartType, fActive, &dwPartIndex);???????
??????? }
?
??????? RETAILMSG(1, (TEXT("OpenPartition: Partition Exists=0x%x for part 0x%x./r/n"), fExists, dwPartType));
??????? if (fExists) {
??????????? // Partition was found.?
??????????? if (dwCreationFlags == PART_CREATE_NEW)
??????????????? return INVALID_HANDLE_VALUE;
???????????
??????????? if (g_partStateTable[dwPartIndex].pPartEntry == NULL) {
??????????????? // Open partition.? If this is the boot section partition, then file pointer starts after MBR
??????????????? g_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);
??????????????? g_partStateTable[dwPartIndex].dwDataPointer = 0;
??????????? }?
?????????? if ( dwNumSectors > g_partStateTable[dwPartIndex].pPartEntry->Part_TotalSectors )
????????????? return CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);
?????????? else?????????
?????????????????? return (HANDLE)&g_partStateTable[dwPartIndex];???????????
??????? }
??????? else {
?
??????????? // If there are already 4 partitions, or creation flag specified OPEN_EXISTING, fail.
??????????? if ((dwPartIndex == NUM_PARTS) || (dwCreationFlags == PART_OPEN_EXISTING))
??????????????? return INVALID_HANDLE_VALUE;
?
??????????? // Create new partition
??????????? return CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);
??????? }
?
??????? return INVALID_HANDLE_VALUE;
???????
}
進入函數,首先做的事就是檢測MBR的有效性。通過函數IsValidMBR()實現。
檢測MBR的有效性,首先要知道MBR保存在哪里,前面說過NANDFLASH的第0 BLOCK,第1 Sector為主引導扇區,也就是MBR,但是NAND如果被當作啟動芯片,○地址一般被BOOTLOADER代碼占據,MBR只有放在后面的BLOCK中。所以我把第0 個BLOCK放NBOOT,第1個BLOCK放TOC,第2個BLOCK放EBOOT,第3個BLOCK保留,第4個BLOCK就放MBR。
static BOOL IsValidMBR()
{
??? // Check to see if the MBR is valid
??? // MBR block is always located at logical sector 0
??? g_dwMBRSectorNum = GetMBRSectorNum();???????
?
??? RETAILMSG (1, (TEXT("IsValidMBR: MBR sector = 0x%x/r/n"), g_dwMBRSectorNum));
??
??? if ((g_dwMBRSectorNum == INVALID_ADDR) || !FMD_ReadSector (g_dwMBRSectorNum, g_pbMBRSector, NULL, 1)) {
?????? RETAILMSG (1, (TEXT("IsValidMBR-----return FALSE-------------------/r/n")));
??????? return FALSE;?
??? }???
??? return ((g_pbMBRSector[0] == 0xE9) &&
???????? (g_pbMBRSector[1] == 0xfd) &&
???????? (g_pbMBRSector[2] == 0xff) &&
???????? (g_pbMBRSector[SECTOR_SIZE_FS-2] == 0x55) &&
???????? (g_pbMBRSector[SECTOR_SIZE_FS-1] == 0xAA));
}?
IsValidMBR()實現的第一行就是給全局變量g_dwMBRSectorNum 賦值,顯而易見,g_dwMBRSectorNum就是指示保存MBR的那個Sector了。
g_dwMBRSectorNum = GetMBRSectorNum();?? //是獲得保存MBR的那個Sector
static DWORD GetMBRSectorNum ()
{
??? DWORD dwBlockNum = 3, dwSector = 0;
??? SectorInfo si;
???????
??? while (dwBlockNum < g_FlashInfo.dwNumBlocks) {
?
??????? if (!IS_BLOCK_UNUSABLE (dwBlockNum)) {
??????????? dwSector = dwBlockNum * g_FlashInfo.wSectorsPerBlock;
???????????
??????????? if (!FMD_ReadSector (dwSector, NULL, &si, 1)) {
??????????????? RETAILMSG(1, (TEXT("GetMBRSectorNum: Could not read sector 0x%x./r/n"), dwSector));
??????????????? return INVALID_ADDR;
??????????? }
??????????? // Check to see if logical sector number is 0
??????????? if (si.dwReserved1 == 0) {
????????????? //RETAILMSG(1,(TEXT("dwBlockNum=%d/r/n"),dwBlockNum));
??????????????? return dwSector;
??????????? }
??????? }
?
??????? dwBlockNum++;
?
??? }
?
??? return INVALID_ADDR;
}
這里dwBlockNum直接給了個3,因為NBOOT,TOC,EBOOT已經把前三個BLOCK用了。所以MBR的選擇直接排除了前三個BLOCK了。
#define IS_BLOCK_UNUSABLE(blockID) ((FMD_GetBlockStatus (blockID) & (BLOCK_STATUS_BAD|BLOCK_STATUS_RESERVED)) > 0)
然后確定BLOCK是否可使用的BLOCK,最后通si.dwReserved1 == 0來判斷是不是選擇這個Sector來保存MBR。
IsValidMBR()中還有一個重要的結構就是g_pbMBRSector數組,它就是MBR了。
函數返回時,MBR必須符合下列記錄。
??? return ((g_pbMBRSector[0] == 0xE9) &&
???????? (g_pbMBRSector[1] == 0xfd) &&
???????? (g_pbMBRSector[2] == 0xff) &&
???????? (g_pbMBRSector[SECTOR_SIZE_FS-2] == 0x55) &&
???????? (g_pbMBRSector[SECTOR_SIZE_FS-1] == 0xAA));
可以看到只有開始三個字節為0XE9,FD,FF,當然,還有熟悉的結束標志符0X55AA。
?
如果沒有檢測到MBR,則先對NANDFLASH進行低級格式化。BP_LowLevelFormat (SECTOR_TO_BLOCK(dwStartSector), SECTOR_TO_BLOCK(dwNumSectors), dwFlags);再創建分區,CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);。
?
BOOL BP_LowLevelFormat(DWORD dwStartBlock, DWORD dwNumBlocks, DWORD dwFlags)
{
??? dwNumBlocks = min (dwNumBlocks, g_FlashInfo.dwNumBlocks);
?
??? RETAILMSG(1,(TEXT("fly::Enter LowLevelFormat [0x%x, 0x%x]./r/n"), dwStartBlock,dwNumBlocks));// dwStartBlock + dwNumBlocks - 1));
?
??? // Erase all the flash blocks.
??? if (!EraseBlocks(dwStartBlock, dwNumBlocks, dwFlags))
??????? return(FALSE);
?
??? // Determine first good starting block
??? while (IS_BLOCK_UNUSABLE (dwStartBlock) && dwStartBlock < g_FlashInfo.dwNumBlocks) {
??????? dwStartBlock++;
??? }
?
??? if (dwStartBlock >= g_FlashInfo.dwNumBlocks) {
??????? 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.
??? g_dwMBRSectorNum = dwStartBlock * g_FlashInfo.wSectorsPerBlock;
?
??? RETAILMSG(1,(TEXT("fly:g_dwMBRSectorNum=%d/r/n"),g_dwMBRSectorNum));
?
??? // Create an MBR.
??? CreateMBR();
??? return(TRUE);
}
在對NANDFLASH進行低格時,主要對壞塊的處理。if (!EraseBlocks(dwStartBlock, dwNumBlocks, dwFlags))檢測每一個Sector,每個BLOCK只要有一個Sector不能讀寫這個塊都會被處理成壞塊,這樣才能保證系統的穩定性。在函數的最后調用了??? CreateMBR();來創建一個MBR。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.
?
??? memset (g_pbMBRSector, 0xff, g_FlashInfo.wDataBytesPerSector);
??? g_pbMBRSector[0] = 0xE9;
??? g_pbMBRSector[1] = 0xfd;
??? g_pbMBRSector[2] = 0xff;
??? g_pbMBRSector[SECTOR_SIZE_FS-2] = 0x55;
??? g_pbMBRSector[SECTOR_SIZE_FS-1] = 0xAA;
?
??? // Zero out partition table so that mspart treats entries as empty.
??? memset (g_pbMBRSector+PARTTABLE_OFFSET, 0, sizeof(PARTENTRY) * NUM_PARTS);
?
??? return WriteMBR();
?
}? 當然。因為還沒有進行分區,這里寫入的MBR分區表部分是空的。static BOOL WriteMBR()
{
??? DWORD dwMBRBlockNum = g_dwMBRSectorNum / g_FlashInfo.wSectorsPerBlock;
?
??? //dwMBRBlockNum = 1 ;
?
??? RETAILMSG(1, (TEXT("WriteMBR: MBR block = 0x%x,g_dwMBRSectorNum = 0x%x./r/n"), dwMBRBlockNum,g_dwMBRSectorNum));
?
??? 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.
??? ReadBlock (dwMBRBlockNum, g_pbBlock, g_pSectorInfoBuf);
?
??? if (!FMD_EraseBlock (dwMBRBlockNum)) {
??????? RETAILMSG (1, (TEXT("CreatePartition: error erasing block 0x%x/r/n"), dwMBRBlockNum));
??????? return FALSE;
??? }
?
??? 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;
?
??? RETAILMSG(1, (TEXT("fly::WriteMBR: MBR block = 0x%x./r/n"), dwMBRBlockNum));
?
??? 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;
???
}
在WriteMBR()函數中,就寫入了判斷MBR 的一些標志到BLOCK,??? g_pSectorInfoBuf->bOEMReserved &= ~OEM_BLOCK_READONLY;
??? g_pSectorInfoBuf->wReserved2 &= ~SECTOR_WRITE_COMPLETED;
??? g_pSectorInfoBuf->dwReserved1 = 0;
Wince系統啟動時,具體是NANDFLASH驅動加載成功后,MOUNT文件系統到NANDFLASH之前,也會通過讀取這些SectorInfo來得到MBR 保存的BLOCK,進而讀取MBR,獲得分區信息,從而把各分區MOUNT到相應文件系統。格式化完成,MBR也寫入成功后就可以開始新建分區了。
/*? CreatePartition
?*
?*? Creates a new partition.? If it is a boot section partition, then it formats
?*? flash.
?*
?*? ENTRY
?*????? dwStartSector - Logical sector to start the partition.? NEXT_FREE_LOC if?
?*????????? none specified.?
?*????? dwNumSectors - Number of logical sectors of the partition.? USE_REMAINING_SPACE
?*????????? to indicate to take up the rest of the space on the flash for that partition.
?*????? dwPartType - Type of partition to create.
?*????? fActive - TRUE indicates to create the active partition.? FALSE for
?*????????? inactive.
?*????? dwPartIndex - Index of the partition entry on the MBR
?*
?*? EXIT
?*????? Handle to the partition on success.? INVALID_HANDLE_VALUE on error.
?*/
?
static HANDLE CreatePartition (DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwPartIndex)
{
??? DWORD dwBootInd = 0;
?
??? RETAILMSG(1, (TEXT("CreatePartition: Enter CreatePartition for 0x%x./r/n"), dwPartType));
???
??? if (fActive)
??????? dwBootInd |= PART_IND_ACTIVE;
??? if (dwPartType == PART_BOOTSECTION || dwPartType == PART_BINFS || dwPartType == PART_XIP)
??????? dwBootInd |= PART_IND_READ_ONLY;???
?
???? // If start sector is invalid, it means find next free sector
??? if (dwStartSector == NEXT_FREE_LOC) {???????
??????? dwStartSector = FindFreeSector();
??????? if (dwStartSector == INVALID_ADDR) {
??????????? RETAILMSG(1, (TEXT("CreatePartition: can't find free sector./r/n")));
??????????? return INVALID_HANDLE_VALUE;
??????? }
?
??????? // Start extended partition on a block boundary
??????? if ((dwPartType == PART_EXTENDED) && (dwStartSector % g_FlashInfo.wSectorsPerBlock)) {
??????????? dwStartSector = (dwStartSector / g_FlashInfo.wSectorsPerBlock + 1) * g_FlashInfo.wSectorsPerBlock;
??????? }
??? }
?
??? // If num sectors is invalid, fill the rest of the space up
??? if (dwNumSectors == USE_REMAINING_SPACE) {
?
??????? DWORD dwLastLogSector = LastLogSector();
??????? if (dwLastLogSector == INVALID_ADDR)
??????????? return INVALID_HANDLE_VALUE;
?
??????? // Determine the number of blocks to reserve for the FAL compaction when creating an extended partition.
??????? DWORD dwReservedBlocks = g_FlashInfo.dwNumBlocks / PERCENTAGE_OF_MEDIA_TO_RESERVE;
??????? if((dwReservedBlocks = g_FlashInfo.dwNumBlocks / PERCENTAGE_OF_MEDIA_TO_RESERVE) < MINIMUM_FLASH_BLOCKS_TO_RESERVE) {
??????????? dwReservedBlocks = MINIMUM_FLASH_BLOCKS_TO_RESERVE;
??????? }
???????
??????? dwNumSectors = dwLastLogSector - dwStartSector + 1 - dwReservedBlocks * g_FlashInfo.wSectorsPerBlock;
??? }
??
??? if (!AreSectorsFree (dwStartSector, dwNumSectors)){
??????? RETAILMSG (1, (TEXT("fly:::::CreatePartition: sectors [0x%x, 0x%x] requested are out of range or taken by another partition/r/n"), dwStartSector, dwNumSectors));
??????? return INVALID_HANDLE_VALUE;
??? }
?
??? RETAILMSG(1, (TEXT("CreatePartition: Start = 0x%x, Num = 0x%x./r/n"), dwStartSector, dwNumSectors));
???
??? AddPartitionTableEntry (dwPartIndex, dwStartSector, dwNumSectors, (BYTE)dwPartType, (BYTE)dwBootInd);
?
??? if (dwBootInd & PART_IND_READ_ONLY) {
??????? if (!WriteLogicalNumbers (dwStartSector, dwNumSectors, TRUE)) {
??????????? RETAILMSG(1, (TEXT("CreatePartition: can't mark sector info./r/n")));
??????????? return INVALID_HANDLE_VALUE;
??????? }
??? }
?
??? if (!WriteMBR())
??????? return INVALID_HANDLE_VALUE;
?
??? g_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);
??? g_partStateTable[dwPartIndex].dwDataPointer = 0;
?
??? return (HANDLE)&g_partStateTable[dwPartIndex];???????????
}
如果第二個參數為-1,則視為將余下的所有空間劃為一個分區。LastLogSector();函數獲得最后一個邏輯Sector。static DWORD LastLogSector()
{
??? if (g_dwLastLogSector) {
?????? return g_dwLastLogSector;
??? }
?
??? DWORD dwMBRBlock = g_dwMBRSectorNum / g_FlashInfo.wSectorsPerBlock;
??? DWORD dwUnusableBlocks = dwMBRBlock;
?
??? for (DWORD i = dwMBRBlock; i < g_FlashInfo.dwNumBlocks; i++) {
??????? if (IS_BLOCK_UNUSABLE (i))
??????????? dwUnusableBlocks++;
??? }
???
??? g_dwLastLogSector = (g_FlashInfo.dwNumBlocks - dwUnusableBlocks) * g_FlashInfo.wSectorsPerBlock - 1;
?
??? RETAILMSG(1, (TEXT("fly:::LastLogSector: Last log sector is: 0x%x./r/n"), g_dwLastLogSector));
???
??? return g_dwLastLogSector;
}
即g_dwLastLogSector = (g_FlashInfo.dwNumBlocks - dwUnusableBlocks) * g_FlashInfo.wSectorsPerBlock - 1;//(NAND 的BLOCK總數 – MBR保存的那個BLOCK)* 每個BLOCK的Sector數 – 保存MBR的那個Sector。得到的就是從MBR那個Sector之后的所有Sector,即邏輯大小。
AreSectorsFree (dwStartSector, dwNumSectors)函數判斷參數提供的起始Sector和個數有沒有超出來NAND的界限,或者邏輯分區的界限。???
重頭戲開始了。通過AddPartitionTableEntry (dwPartIndex, dwStartSector, dwNumSectors, (BYTE)dwPartType, (BYTE)dwBootInd); 準備分區信息寫入分區表。
/*? AddPartitionTableEntry
?*
?*? Generates the partition entry for the partition table and copies the entry
?*? into the MBR that is stored in memory.
?*?
?*
?*? ENTRY
?*????? entry - index into partition table
?*????? startSector - starting logical sector
?*????? totalSectors - total logical sectors
?*????? fileSystem - type of partition
?*????? bootInd - byte in partition entry that stores various flags such as
?*????????? active and read-only status.
?*
?*? EXIT
?*/
?
static void AddPartitionTableEntry(DWORD entry, DWORD startSector, DWORD totalSectors, BYTE fileSystem, BYTE bootInd)
{
??? PARTENTRY partentry = {0};
??? Addr startAddr;
??? Addr endAddr;
?
??? ASSERT(entry < 4);
?
??? // no checking with disk info and start/total sectors because we allow
??? // bogus partitions for testing purposes
?
??? // initially known partition table entry
??? partentry.Part_BootInd = bootInd;
??? partentry.Part_FileSystem = fileSystem;
??? partentry.Part_StartSector = startSector;
??? partentry.Part_TotalSectors = totalSectors;
?
??? // logical block addresses for the first and final sector (start on the second head)
??? startAddr.type = LBA;
??? startAddr.lba = partentry.Part_StartSector;
??? endAddr.type = LBA;
??? endAddr.lba = partentry.Part_StartSector + partentry.Part_TotalSectors-1;
?
??? // translate the LBA addresses to CHS addresses
??? startAddr = LBAtoCHS(&g_FlashInfo, startAddr);
??? endAddr = LBAtoCHS(&g_FlashInfo, endAddr);
?
??? // starting address
??? partentry.Part_FirstTrack = (BYTE)(startAddr.chs.cylinder & 0xFF);
??? partentry.Part_FirstHead = (BYTE)(startAddr.chs.head & 0xFF);
??? // lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
??? partentry.Part_FirstSector = (BYTE)((startAddr.chs.sector & 0x3F) | ((startAddr.chs.cylinder & 0x0300) >> 2));
?
??? // ending address:
??? partentry.Part_LastTrack = (BYTE)(endAddr.chs.cylinder & 0xFF);
??? partentry.Part_LastHead = (BYTE)(endAddr.chs.head & 0xFF);
??? // lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
??? partentry.Part_LastSector = (BYTE)((endAddr.chs.sector & 0x3F) | ((endAddr.chs.cylinder & 0x0300) >> 2));
?
??? memcpy(g_pbMBRSector+PARTTABLE_OFFSET+(sizeof(PARTENTRY)*entry), &partentry, sizeof(PARTENTRY));
}
這里面的地址信息是一種叫CHS(Cyinder/Head/Sector)的地址。eboot中有將邏輯地址LBS(Logical Block Addr)與這種地址互相轉換的函數LBAtoCHS,CHSToLBA。
Addr LBAtoCHS(FlashInfo *pFlashInfo, Addr lba)
{
??? Addr chs;
??? DWORD tmp = pFlashInfo->dwNumBlocks * pFlashInfo->wSectorsPerBlock;
??? chs.type = CHS;
??? chs.chs.cylinder = (WORD)(lba.lba / tmp);????????????????????????????????????? // 柱面,應該始終是0
??? tmp = lba.lba % tmp;
??? chs.chs.head = (WORD)(tmp / pFlashInfo->wSectorsPerBlock);???????????????????? // 塊地址
??? chs.chs.sector = (WORD)((tmp % pFlashInfo->wSectorsPerBlock) + 1);???? // 扇區+1
??? return chs;
}
Addr CHStoLBA(FlashInfo *pFlashInfo, Addr chs)
{
??? Addr lba;
??? lba.type = LBA;
??? lba.lba = ((chs.chs.cylinder * pFlashInfo->dwNumBlocks + chs.chs.head)
??????? * pFlashInfo->wSectorsPerBlock)+ chs.chs.sector - 1;
return lba;
}
如果分區的格式有只讀屬性,則通過WriteLogicalNumbers()函數寫分區的Sectorinfo,把這部分空間保護起來。
static BOOL WriteLogicalNumbers (DWORD dwStartSector, DWORD dwNumSectors, BOOL fReadOnly)
{
??? DWORD dwNumSectorsWritten = 0;
?
??? DWORD dwPhysSector = Log2Phys (dwStartSector);
??? DWORD dwBlockNum = dwPhysSector / g_FlashInfo.wSectorsPerBlock;
??? DWORD dwOffset = dwPhysSector % g_FlashInfo.wSectorsPerBlock;
???
??? while (dwNumSectorsWritten < dwNumSectors) {
?
??????? // If bad block, move to the next block
??????? if (IS_BLOCK_UNUSABLE (dwBlockNum)) {
??????????? dwBlockNum++;
??????????? continue;
??????? }
?
??????? 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.
??????? ReadBlock (dwBlockNum, g_pbBlock, g_pSectorInfoBuf);
??????? if (!FMD_EraseBlock (dwBlockNum)) {
??????????? return FALSE;
??????? }
?
??????? DWORD dwSectorsToWrite = g_FlashInfo.wSectorsPerBlock - dwOffset;
??????? PSectorInfo pSectorInfo = g_pSectorInfoBuf + dwOffset;
?
??????? // If this is the last block, then calculate sectors to write if there isn't a full block to update
??????? if ((dwSectorsToWrite + dwNumSectorsWritten) > dwNumSectors)
??????????? dwSectorsToWrite = dwNumSectors - dwNumSectorsWritten;
???????
??????? for (DWORD iSector = 0; iSector < dwSectorsToWrite; iSector++, pSectorInfo++, dwNumSectorsWritten++) {
??????????? // Assert read only by setting bit to 0 to prevent wear-leveling by FAL
??????????? if (fReadOnly)
??????????????? pSectorInfo->bOEMReserved &= ~OEM_BLOCK_READONLY;
??????????? // Set to write completed so FAL can map the sector?
??????????? pSectorInfo->wReserved2 &= ~SECTOR_WRITE_COMPLETED;???????
??????????? // Write the logical sector number
??????????? pSectorInfo->dwReserved1 = dwStartSector + dwNumSectorsWritten;???????????
??????? }
??????? if (!WriteBlock (dwBlockNum, g_pbBlock, g_pSectorInfoBuf))
??????????? return FALSE;
???????
??????? dwOffset = 0;
??????? dwBlockNum++;
??? }
??? return TRUE;
}
這就是為什么系統啟動后,我們無法寫入文件的BINFS文件系統格式分區的原因了。而FAT格式就可以。最后調用WriteMBR()完全MBR的寫入,分區完畢。
讓我們繼續回到BP_OpenPartition函數中,如果從一開始IsValidMBR()就檢測到有效的MBR,GetPartitionTableIndex(dwPartType, fActive, &dwPartIndex);獲得分區表。和dwPartIndex分區表的索引號。
static BOOL GetPartitionTableIndex (DWORD dwPartType, BOOL fActive, PDWORD pdwIndex)
{
??? PPARTENTRY pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET);
??? DWORD iEntry = 0;
???
??? for (iEntry = 0; iEntry < NUM_PARTS; iEntry++, pPartEntry++) {
??????? if ((pPartEntry->Part_FileSystem == dwPartType) && (((pPartEntry->Part_BootInd & PART_IND_ACTIVE) != 0) == fActive)) {
??????????? *pdwIndex = iEntry;
??????????? return TRUE;
??????? }
??????? if (!IsValidPart (pPartEntry)) {
??????????? *pdwIndex = iEntry;
??????????? return FALSE;
??????? }
??? }
?
??? return FALSE;
}
?
重要結構:PARTENTRY
// end of master boot record contains 4 partition entries
typedef struct _PARTENTRY {
??????? BYTE??????????? Part_BootInd;?????????? // If 80h means this is boot partition
??????? BYTE??????????? Part_FirstHead;???????? // Partition starting head based 0
??????? BYTE??????????? Part_FirstSector;?????? // Partition starting sector based 1
??????? BYTE??????????? Part_FirstTrack;??????? // Partition starting track based 0
??????? BYTE??????????? Part_FileSystem;??????? // Partition type signature field
??????? BYTE??????????? Part_LastHead;????????? // Partition ending head based 0
??????? BYTE??????????? Part_LastSector;??????? // Partition ending sector based 1
??????? BYTE??????????? Part_LastTrack;???????? // Partition ending track based 0
??????? DWORD?????????? Part_StartSector;?????? // Logical starting sector based 0
??????? DWORD?????????? Part_TotalSectors;????? // Total logical sectors in partition
} PARTENTRY;
分區表就是通過這個結構寫入MBR,起始地址,分區大小,分區格式,對應結構寫入MBR所在的Sector就可以了。在檢測有效分區時static BOOL IsValidPart (PPARTENTRY pPartEntry)
{
??? return (pPartEntry->Part_FileSystem != 0xff) && (pPartEntry->Part_FileSystem != 0);
}
就是通過對分區表文件系統格式的判斷了。
?
?
把NAND后面的空間,全部分為一個FAT格式的分區。
??? //
??? // create extended partition in whatever is left
??? //
??? hPartEx = BP_OpenPartition( (NK_START_BLOCK+1+BINFS_BLOCK) * PAGES_PER_BLOCK,
??????????????????????????????? NEXT_FREE_LOC,?? // (1024 - (NK_START_BLOCK+1+SECTOR_TO_BLOCK_SIZE(FILE_TO_SECTOR_SIZE(dwBINFSPartLength)))) * PAGES_PER_BLOCK,
??????????????????????????????? PART_DOS32,
??????????????????????????????? TRUE,
??????????????????????????????? PART_OPEN_ALWAYS);
?
??? if (hPartEx == INVALID_HANDLE_VALUE )
??? {
??????? EdbgOutputDebugString("*** WARN: StoreImageToBootMedia: Failed to open/create Extended partition ***/r/n");
??? }
?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/hugohong/archive/2009/05/20/4204700.aspx
總結
以上是生活随笔為你收集整理的Eboot 中给nandflash分区实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安装RVDS2.2破解版
- 下一篇: WINCE6.0+S3C2443的启动过