4827|2

853

帖子

0

TA的资源

五彩晶圆(中级)

楼主
 

wince NandFlash的分区实现 [复制链接]

在网站上看到这篇文章,讲解的比较有逻辑性,转载了留着进一步研究!!

复制网址: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该分区,返回分区句柄。Code Snippet
  • 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。Code Snippet
  • 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的那个SectorCode Snippet
  • 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);。Code Snippet
  • 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。Code Snippet
  • 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分区表部分是空的。Code Snippet
  • 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也写入成功后就可以开始新建分区了。Code Snippet
  • /*  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。Code Snippet
  • 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); 准备分区信息写入分区表。Code Snippet
  • /*  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。Code Snippet
  • 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,把这部分空间保护起来。Code Snippet
  • 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分区表的索引号。Code Snippet
  • 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
Code Snippet
  • // 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格式的分区。Code Snippet
  • // 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


最新回复

谢谢分享   详情 回复 发表于 2021-3-20 16:46
点赞 关注
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460

回复
举报

853

帖子

0

TA的资源

五彩晶圆(中级)

沙发
 
这篇文章写得真不错,给那些采用eboot 分区nandflash 的人很大参考,不过我的iNand uboot 就只是意识上的参考了,差别很大。不过linux 体系的uboot 写得封装性更好,更强大!更好用
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 

回复

661

帖子

0

TA的资源

纯净的硅(初级)

板凳
 

谢谢分享

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
Microchip 直播|利用motorBench开发套件高效开发电机磁场定向控制方案 报名中!
直播主题:利用motorBench开发套件高效开发电机磁场定向控制方案
直播时间:2025年3月25日(星期二)上午10:30-11:30
快来报名!

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表