提到分区就不得不提到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分区实现相关推荐

  1. WinCE EBOOT中的BootPart分析

    应该说BootPart算是微软提供的一个用于分区的模块,可以在EBOOT中使用.不过说实话,我很少使用它,知道有些厂商的BSP里面支持这个功能,而且也算是EBOOT的一部分,所以还是介绍一下.先看一下 ...

  2. linux擦除nandflash分区,【Linux公开课】NAND Flash存储器分区、烧写流程图、格式化NAND Flash...

    摘要本章主要讲述EasyARM-iMX283A Linux固件的烧写方法,可以通过TF卡.USB两种方式进行整体固件烧写,也可以通过网络进行局部固件升级. 第9章 系统固件烧写 本章主要讲述EasyA ...

  3. linux nandflash分区,nandflash分区

    part add 命令用于添加一个MTD 分区. 命令的详细格式如下: part add name offset size flag 参数name 是要添加的分区的分区名称: 参数offset 是要添 ...

  4. Wince6 Eboot中加入开机画面

    昨天研究了一下wince开机时加入个性化的画面,折腾了一上午,不是花屏就是CE起不来--终于搞定,分享一下经验吧... Wince加入开机画面方法一般有以下两种: 1. 在文件中下定义一个常量大数组, ...

  5. linux显示磁盘使用情况命令,Linux中监控磁盘分区和使用情况的几个工具

    导读 在文章中将讨论Linux中可用于监视磁盘使用情况的命令行实用程序,提供有关总大小容量.已用总量.文件系统信息和分区信息等.让我们看看这些工具如何帮助检索这些信息 df命令 df是一个Linux命 ...

  6. WinCE EBOOT中的Boot Args与Driver Globals (转)

    在EBOOT中包含的一个重要的缓冲区叫Driver Globals,它用于在设备驱动和WinCE OS之间共享数据.而在EBOOT中会用到的启动参数结构被称为Boot Args,是指用于EBOOT和W ...

  7. oracle 手动添加分区,如何在oracle中创建子分区?

    现在我开始学习oracle.some中的分区概念了.我现在如何管理分区,我试图在Oracle中创建子分区.我得到这个错误如何在oracle中创建子分区? SQL Error: ORA-14160: t ...

  8. Windows中的磁盘分区、MBR、GPT

    Windows中的磁盘分区: 1.分为主分区,扩展分区.其中拓展分区又包含若干个逻辑分区: 注意:如果拓展分区被删除或者破坏,则所有逻辑分区将会被删除. 2.分区时注意磁盘的连续性,建议将拓展分区放在 ...

  9. linux下读取ntfs数据,在Linux中读取NTFS分区上的数据

    在Linux中读取NTFS分区上的数据 在有些情况下,系统需要访问本地NTFS分区上的数据,也可能需要访问网络上NTFS文件格式的数据.而使用mount -t挂载文件系统时,系统报告不支持NTFS错误 ...

最新文章

  1. ubuntu+php+mysql+apache安装配置
  2. sse php,sse.php · Gitee 极速下载/modphp - Gitee.com
  3. (转载)MyEclipse github
  4. 计划完成提醒系统C语言,通信录管理计划系统C语言知识程序设计.doc
  5. 动态编译MySQL plugin
  6. boost::mpl::filter_view模块实现日历相关的测试程序
  7. Linux之CentOS防火墙及端口操作
  8. 转:EXCEL数据有效性设置
  9. 黑裙安装linux环境,黑群晖菜鸟安装教程(一)制作U盘引导及软洗白!
  10. Android Studio中XML注释错误问题
  11. 问卷分析SPSS+AMOS实证步骤
  12. JZOJ4722. 跳楼机
  13. 动态桌面软件测试简历,动态壁纸软件横评
  14. 2018.7.18 上半年课程总结 4- 高级英语
  15. ElasticSearch Java 客户端连接ElasticSearch
  16. uni-app在手机上背景图片不显示
  17. 执行vite run dev时的spawn error问题
  18. “啪”一炮就通!管道疏通神器终于诞生,马桶、下水道再也不怕堵!
  19. 赛扬处理器_J4015处理器!品铂新款X10上市!_IT业界行情
  20. 农村环境保护之平时作业一

热门文章

  1. 005_Button按钮
  2. 039_CSS3边框
  3. c++tcp接收文件缓存多大合适_必知必会的TCP/IP知识
  4. 目前在线教育发展情况介绍
  5. 新闻频道管理的炫酷实现
  6. Android性能优化典范 - 第6季
  7. java线程的创建和启动深度解析
  8. 学多门计算机语言的好处,多学一门语言的19大好处
  9. 笔记本x31搭建家用win服务器系统,Thinkpad X31怎么硬盘安装win7系统
  10. php 企业号文本消息推送,Python如何实现微信企业号文本消息推送功能的示例