加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Eboot 中给nandflash分区实现

发布时间:2020-12-15 06:53:43 所属栏目:百科 来源:网络整理
导读:? 提到分区就不得不提到MBR ,不得不提到分区表。 什么是MBR 硬盘的0 柱面、0 磁头、1 扇区称为主引导扇区,NANDFLASH 由BLOCK 和Sector 组成,所以NANDFLASH 的第0 BLOCK ,第1 Sector 为主引导扇区,FDISK 程序写到该扇区的内容称为主引导记录(MBR )。该
?

提到分区就不得不提到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:WINCE500PUBLICCOMMONOAKDRIVERSETHDBGBOOTPARTbootpart.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 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%xrn"),dwStartSector,dwNumSectors,dwPartType));

??????????? if (dwCreationFlags == PART_OPEN_EXISTING) {

??????????????? RETAILMSG(1,(TEXT("OpenPartition: Invalid MBR.? Cannot open existing partition 0x%x.rn"),dwPartType));

??????????????? return INVALID_HANDLE_VALUE;

??????????? }

???????????

??????????? RETAILMSG(1,(TEXT("OpenPartition: Invalid MBR.? Formatting flash.rn")));

??????????? if (g_FlashInfo.flashType == NOR) {

??????????????? dwFlags |= FORMAT_SKIP_BLOCK_CHECK;

??????????? }

??????????? //fly

???????????? RETAILMSG(1,(TEXT("BP_LowLevelFormat: g_pbMBRSector=0x%x,g_dwMBRSectorNum= 0x%x.rn"),*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.rn"),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,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%xrn"),g_dwMBRSectorNum));

??

??? if ((g_dwMBRSectorNum == INVALID_ADDR) || !FMD_ReadSector (g_dwMBRSectorNum,g_pbMBRSector,NULL,1)) {

?????? RETAILMSG (1,(TEXT("IsValidMBR-----return FALSE-------------------rn")));

??????? 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,1)) {

??????????????? RETAILMSG(1,(TEXT("GetMBRSectorNum: Could not read sector 0x%x.rn"),dwSector));

??????????????? return INVALID_ADDR;

??????????? }

??????????? // Check to see if logical sector number is 0

??????????? if (si.dwReserved1 == 0) {

????????????? //RETAILMSG(1,(TEXT("dwBlockNum=%drn"),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].rn"),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 blocksrn")));???????

??????? 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=%drn"),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.rn"),dwMBRBlockNum,g_dwMBRSectorNum));


??? 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%xrn"),dwMBRBlockNum));

??????? return FALSE;

??? }


??? 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;


??? RETAILMSG(1,(TEXT("fly::WriteMBR: MBR block = 0x%x.rn"),dwMBRBlockNum));


??? if (!WriteBlock (dwMBRBlockNum,g_pSectorInfoBuf)) {

??????? RETAILMSG (1,(TEXT("CreatePartition: could not write to block 0x%xrn"),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;


??? RETAILMSG(1,(TEXT("CreatePartition: Enter CreatePartition for 0x%x.rn"),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.rn")));

??????????? 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 partitionrn"),dwNumSectors));

??????? return INVALID_HANDLE_VALUE;

??? }


??? RETAILMSG(1,(TEXT("CreatePartition: Start = 0x%x,Num = 0x%x.rn"),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.rn")));

??????????? 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.rn"),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.

?*

?*? 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,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++;

??? }

??? return TRUE;

}

这就是为什么系统启动后,我们无法写入文件的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;

??????? }

??? }


??? 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 ***rn");

??? }

?

本文来自CSDN博客,转载请标明出处:file:///D:/cellhunter/WinCE驱动开发教程/Eboot%20中给nandflash分区实现%20-%20wu_ye_zhou的专栏%20-%20CSDN博客.htm

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读