提到分区就不得不提到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, 如果该标志错误系统就不能启动。
0000-0088
Master Boot Record
主引导程序
主引导
程序
0089-01BD
出错信息数据区
数据区
01BE-01CD
分区项1 (16 字节)
分区表
01CE-01DD
分区项2 (16 字节)
01DE-01ED
分区项3 (16 字节)
01EE-01FD
分区项4 (16 字节)
01FE
55
结束标志
01FF
AA
图6-15 MBR 的组成结构图
MBR 中的分区信息结构
占用512 个字节的MBR 中,偏移地址01BEH--01FDH 的64 个字节,为4 个分区项内容(分区信息表)。它是由磁盘介质类型及用户在使用 FDISK 定义分区说确定的。在实际应用中,FDISK 对一个磁盘划分的主分区可少于4 个,但最多不超过4 个。每个分区表的项目是16 个字节,其内容含义 如表6-19 所示。
表6-19 分区项表(16 字节)内容及含义
存贮字节位
内容及含义
第1 字节
引导标志。若值为80H 表示活动分区,若值为00H 表示非活动分区。
第2 、3 、4 字节
本分区的起始磁头号、扇区号、柱面号。其中:
磁头号—— 第2 字节;
扇区号—— 第3 字节的低6 位;
柱面号—— 为第3 字节高2 位+ 第4 字节8 位。
第5 字节
分区类型符。
00H—— 表示该分区未用(即没有指定);
06H——FAT16 基本分区;
0BH——FAT32 基本分区;
05H—— 扩展分区;
07H——NTFS 分区;
0FH—— (LBA 模式)扩展分区(83H 为Linux 分区等)。
第6 、7 、8 字节
本分区的结束磁头号、扇区号、柱面号。其中:
磁头号—— 第6 字节;
扇区号—— 第7 字节的低6 位;
柱面号—— 第7 字节的高2 位+ 第8 字节。
第9 、10 、11 、12 字节
本分区之前已用了的扇区数。
第13 、14 、15 、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/wu_ye_zhou/archive/2010/06/12/5667136.aspx