观's profileTo the world,you may jus...PhotosBlogListsMore Tools Help

Blog


    04/11/2009

    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,也是今天主要的分析对象。

    主要函数。
    /*  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");
        }

    Comments

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.

    To add a comment, sign in with your Windows Live ID (if you use Hotmail, Messenger, or Xbox LIVE, you have a Windows Live ID). Sign in


    Don't have a Windows Live ID? Sign up

    Trackbacks

    The trackback URL for this entry is:
    http://giwawe.spaces.live.com/blog/cns!92AFEF096943066B!260.trak
    Weblogs that reference this entry
    • None