在网站上看到这篇文章,讲解的比较有逻辑性,转载了留着进一步研究!!
?复制网址:
http://blog.csdn.net/paul73022/article/details/6092897
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,如果该标志错误系统就不能启动。
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,也是今天主要的分析对象。
主要函数。
Code Snippet
- /*? 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)
- //£¨×¢£oê?ày′ú???a±?è?/uc1EBOOT?D·???êμ???′??£¨/uc1WINCE5.0+S3C2440+128MNAND,MBRD′?úμú??/uc1BLOCK£?·?ò???/uc1BINFS??ê?·???oíò???/uc1FAT??ê?·???£??££?
- 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 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"),243)">???????????????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,243)">??????? 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,dwPartType,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,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,&si,243)">??????????????? 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),dwFlags);再创建分区,CreatePartition (dwStartSector,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;
"fly:g_dwMBRSectorNum=%d/r/n"),g_dwMBRSectorNum));
??? // Create an MBR.
??? CreateMBR();
??? return(TRUE);
}
在对NANDFLASH进行低格时,主要对坏块的处理。if (!EraseBlocks(dwStartBlock,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,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,243)">??? memset (g_pbBlock,g_dwDataBytesPerBlock);
??? memset (g_pSectorInfoBuf, 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));
??? memcpy (g_pbBlock + (g_dwMBRSectorNum % g_FlashInfo.wSectorsPerBlock) * g_FlashInfo.wDataBytesPerSector,g_FlashInfo.wDataBytesPerSector);
??? g_pSectorInfoBuf->bOEMReserved &= ~OEM_BLOCK_READONLY;
??? g_pSectorInfoBuf->wReserved2 &= ~SECTOR_WRITE_COMPLETED;
??? g_pSectorInfoBuf->dwReserved1 = 0;
"fly::WriteMBR: MBR block = 0x%x./r/n"),dwMBRBlockNum));
??? if (!WriteBlock (dwMBRBlockNum,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 dwPartIndex)
{
??? DWORD dwBootInd = 0;
"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)){
"fly:::::CreatePartition: sectors [0x%x,0x%x] requested are out of range or taken by another partition/r/n"),dwNumSectors));
??????? return INVALID_HANDLE_VALUE;
??? }
??? RETAILMSG(1,(TEXT("CreatePartition: Start = 0x%x,Num = 0x%x./r/n"),dwNumSectors));
??? AddPartitionTableEntry (dwPartIndex,(BYTE)dwPartType,(BYTE)dwBootInd);
??? if (dwBootInd & PART_IND_READ_ONLY) {
??????? if (!WriteLogicalNumbers (dwStartSector,TRUE)) {
??????????? RETAILMSG(1,(TEXT("CreatePartition: can't mark sector info./r/n")));
??? }
??? 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,(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.
*/
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);?????????????????????????????// ?ù??,ó|??ê???ê?
??? 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,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,g_dwDataBytesPerBlock);
??????? memset (g_pSectorInfoBuf,sizeof(SectorInfo) * g_FlashInfo.wSectorsPerBlock);
??????? // No need to check return,since a failed read means data hasn't been written yet.
??????? ReadBlock (dwBlockNum,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_pSectorInfoBuf))
??????????? return FALSE;
??????? dwOffset = 0;
??????? dwBlockNum++;
}
这就是为什么系统启动后,我们无法写入文件的BINFS文件系统格式分区的原因了。而FAT格式就可以。最后调用WriteMBR()完全MBR的写入,分区完毕。
让我们继续回到BP_OpenPartition函数中,如果从一开始IsValidMBR()就检测到有效的MBR,GetPartitionTableIndex(dwPartType,&dwPartIndex);获得分区表。和dwPartIndex分区表的索引号。
static BOOL GetPartitionTableIndex (DWORD dwPartType,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;
}
重要结构:PARTENTRY
// end of master boot record contains 4 partition entries
typedefstruct _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");
}
引用通告
此日志的引用通告 URL 是:
http://giwawe.spaces.live.com/blog/cns!92AFEF096943066B!260.trak
引用此项的网络日志
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|