[轉]NandFlash的分區實現

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
  1. /*  BP_OpenPartition
  2. *
  3. *  Opens/creates a partition depending on the creation flags.  If it is opening
  4. *  and the partition has already been opened, then it returns a handle to the
  5. *  opened partition.  Otherwise, it loads the state information of that partition
  6. *  into memory and returns a handle.
  7. *
  8. *  ENTRY
  9. *      dwStartSector - Logical sector to start the partition.  NEXT_FREE_LOC if none
  10. *          specified.  Ignored if opening existing partition.
  11. *      dwNumSectors - Number of logical sectors of the partition.  USE_REMAINING_SPACE
  12. *          to indicate to take up the rest of the space on the flash for that partition (should
  13. *          only be used when creating extended partitions).  This parameter is ignored
  14. *          if opening existing partition.
  15. *      dwPartType - Type of partition to create/open.
  16. *      fActive - TRUE indicates to create/open the active partition.  FALSE for
  17. *          inactive.
  18. *      dwCreationFlags - PART_CREATE_NEW to create only.  Fail if it already
  19. *          exists.  PART_OPEN_EXISTING to open only.  Fail if it doesn't exist.
  20. *          PART_OPEN_ALWAYS creates if it does not exist and opens if it
  21. *          does exist.
  22. *
  23. *  EXIT
  24. *      Handle to the partition on success.  INVALID_HANDLE_VALUE on error.
  25. */
  26.  
  27. HANDLE BP_OpenPartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags)
  28. //£¨×¢£ºÊ¾Àý´úÂëΪ±¾ÈË/uc1EBOOTÖзÖÇøʵÏÖÔ´Â루/uc1WINCE5.0+S3C2440+128MNAND,MBRдÔÚµÚ¸ö/uc1BLOCK£¬·ÖÒ»¸ö/uc1BINFS¸ñʽ·ÖÇøºÍÒ»¸ö/uc1FAT¸ñʽ·ÖÇø£©¡££©
  29. 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
  1. HANDLE BP_OpenPartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags)
  2. {
  3.         DWORD dwPartIndex;
  4.         BOOL fExists;
  5.         ASSERT (g_pbMBRSector);
  6.         if (!IsValidMBR()) {
  7.             DWORD dwFlags = 0;
  8.             //fly
  9.              RETAILMSG(1, (TEXT("BP_OpenPartition:: dwStartSector=0x%x ,dwNumSectors= 0x%x.,dwPartType = 0x%x/r/n"), dwStartSector, dwNumSectors,dwPartType));
  10.             if (dwCreationFlags == PART_OPEN_EXISTING) {
  11.                 RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR.  Cannot open existing partition 0x%x./r/n"), dwPartType));
  12.                 return INVALID_HANDLE_VALUE;
  13.             }
  14.             RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR.  Formatting flash./r/n")));
  15.             if (g_FlashInfo.flashType == NOR) {
  16.                 dwFlags |= FORMAT_SKIP_BLOCK_CHECK;
  17.             }
  18.             //fly
  19.             RETAILMSG(1, (TEXT("BP_LowLevelFormat: g_pbMBRSector=0x%x, g_dwMBRSectorNum= 0x%x./r/n"), *g_pbMBRSector, g_dwMBRSectorNum));
  20.             BP_LowLevelFormat (SECTOR_TO_BLOCK(dwStartSector), SECTOR_TO_BLOCK(dwNumSectors), dwFlags);
  21.             dwPartIndex = 0;
  22.             fExists = FALSE;
  23.         }
  24.         else {
  25.             fExists = GetPartitionTableIndex(dwPartType, fActive, &dwPartIndex);       
  26.         }
  27.         RETAILMSG(1, (TEXT("OpenPartition: Partition Exists=0x%x for part 0x%x./r/n"), fExists, dwPartType));
  28.         if (fExists) {
  29.             // Partition was found.
  30.             if (dwCreationFlags == PART_CREATE_NEW)
  31.                 return INVALID_HANDLE_VALUE;
  32.             if (g_partStateTable[dwPartIndex].pPartEntry == NULL) {
  33.                 // Open partition.  If this is the boot section partition, then file pointer starts after MBR
  34.                 g_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);
  35.                 g_partStateTable[dwPartIndex].dwDataPointer = 0;
  36.             }
  37.            if ( dwNumSectors > g_partStateTable[dwPartIndex].pPartEntry->Part_TotalSectors )
  38.               return CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);
  39.            else         
  40.                    return (HANDLE)&g_partStateTable[dwPartIndex];           
  41.         }
  42.         else {
  43.             // If there are already 4 partitions, or creation flag specified OPEN_EXISTING, fail.
  44.             if ((dwPartIndex == NUM_PARTS) || (dwCreationFlags == PART_OPEN_EXISTING))
  45.                 return INVALID_HANDLE_VALUE;
  46.             // Create new partition
  47.             return CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);
  48.         }
  49.         return INVALID_HANDLE_VALUE;
  50. }
 
進入函數,首先做的事就是檢測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
  1. static BOOL IsValidMBR()
  2. {
  3.     // Check to see if the MBR is valid
  4.     // MBR block is always located at logical sector 0
  5.     g_dwMBRSectorNum = GetMBRSectorNum();       
  6.     RETAILMSG (1, (TEXT("IsValidMBR: MBR sector = 0x%x/r/n"), g_dwMBRSectorNum));
  7.     if ((g_dwMBRSectorNum == INVALID_ADDR) || !FMD_ReadSector (g_dwMBRSectorNum, g_pbMBRSector, NULL, 1)) {
  8.        RETAILMSG (1, (TEXT("IsValidMBR-----return FALSE-------------------/r/n")));
  9.         return FALSE;
  10.     }   
  11.     return ((g_pbMBRSector[0] == 0xE9) &&
  12.          (g_pbMBRSector[1] == 0xfd) &&
  13.          (g_pbMBRSector[2] == 0xff) &&
  14.          (g_pbMBRSector[SECTOR_SIZE_FS-2] == 0x55) &&
  15.          (g_pbMBRSector[SECTOR_SIZE_FS-1] == 0xAA));
  16. }
 
IsValidMBR()實現的第一行就是給全局變量g_dwMBRSectorNum 賦值,顯而易見,g_dwMBRSectorNum就是指示保存MBR的那個Sector了。
g_dwMBRSectorNum = GetMBRSectorNum();   //是獲得保存MBR的那個Sector
 
Code Snippet
  1. static DWORD GetMBRSectorNum ()
  2. {
  3.     DWORD dwBlockNum = 3, dwSector = 0;
  4.     SectorInfo si;
  5.     
  6.     while (dwBlockNum < g_FlashInfo.dwNumBlocks) {
  7.         if (!IS_BLOCK_UNUSABLE (dwBlockNum)) {
  8.             dwSector = dwBlockNum * g_FlashInfo.wSectorsPerBlock;
  9.             if (!FMD_ReadSector (dwSector, NULL, &si, 1)) {
  10.                 RETAILMSG(1, (TEXT("GetMBRSectorNum: Could not read sector 0x%x./r/n"), dwSector));
  11.                 return INVALID_ADDR;
  12.             }
  13.             // Check to see if logical sector number is 0
  14.             if (si.dwReserved1 == 0) {
  15.               //RETAILMSG(1,(TEXT("dwBlockNum=%d/r/n"),dwBlockNum));
  16.                 return dwSector;
  17.             }
  18.         }
  19.         dwBlockNum++;
  20.     }
  21.     return INVALID_ADDR;
  22. }
 
這裏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
  1. BOOL BP_LowLevelFormat(DWORD dwStartBlock, DWORD dwNumBlocks, DWORD dwFlags)
  2. {
  3.     dwNumBlocks = min (dwNumBlocks, g_FlashInfo.dwNumBlocks);
  4.     RETAILMSG(1,(TEXT("fly::Enter LowLevelFormat [0x%x, 0x%x]./r/n"), dwStartBlock,dwNumBlocks));// dwStartBlock + dwNumBlocks - 1));
  5.     // Erase all the flash blocks.
  6.     if (!EraseBlocks(dwStartBlock, dwNumBlocks, dwFlags))
  7.         return(FALSE);
  8.     // Determine first good starting block
  9.     while (IS_BLOCK_UNUSABLE (dwStartBlock) && dwStartBlock < g_FlashInfo.dwNumBlocks) {
  10.         dwStartBlock++;
  11.     }
  12.     if (dwStartBlock >= g_FlashInfo.dwNumBlocks) {
  13.         RETAILMSG(1,(TEXT("BP_LowLevelFormat: no good blocks/r/n")));       
  14.         return FALSE;
  15.     }
  16.     // MBR goes in the first sector of the starting block.  This will be logical sector 0.
  17.     g_dwMBRSectorNum = dwStartBlock * g_FlashInfo.wSectorsPerBlock;
  18.     RETAILMSG(1,(TEXT("fly:g_dwMBRSectorNum=%d/r/n"),g_dwMBRSectorNum));
  19.     // Create an MBR.
  20.     CreateMBR();
  21.     return(TRUE);
  22. }
 
在對NANDFLASH進行低格時,主要對壞塊的處理。if (!EraseBlocks(dwStartBlock, dwNumBlocks, dwFlags))檢測每一個Sector,每個BLOCK只要有一個Sector不能讀寫這個塊都會被處理成壞塊,這樣才能保證系統的穩定性。在函數的最後調用了    CreateMBR();來創建一個MBR。
 
Code Snippet
  1. static BOOL CreateMBR()
  2. {
  3.     // This, plus a valid partition table, is all the CE partition manager needs to recognize
  4.     // the MBR as valid. It does not contain boot code.
  5.     memset (g_pbMBRSector, 0xff, g_FlashInfo.wDataBytesPerSector);
  6.     g_pbMBRSector[0] = 0xE9;
  7.     g_pbMBRSector[1] = 0xfd;
  8.     g_pbMBRSector[2] = 0xff;
  9.     g_pbMBRSector[SECTOR_SIZE_FS-2] = 0x55;
  10.     g_pbMBRSector[SECTOR_SIZE_FS-1] = 0xAA;
  11.     // Zero out partition table so that mspart treats entries as empty.
  12.     memset (g_pbMBRSector+PARTTABLE_OFFSET, 0, sizeof(PARTENTRY) * NUM_PARTS);
  13.     return WriteMBR();
  14. }
當然。因爲還沒有進行分區,這裏寫入的MBR分區表部分是空的。
 
Code Snippet
  1. static BOOL WriteMBR()
  2. {
  3.     DWORD dwMBRBlockNum = g_dwMBRSectorNum / g_FlashInfo.wSectorsPerBlock;
  4.     //dwMBRBlockNum = 1 ;
  5.     RETAILMSG(1, (TEXT("WriteMBR: MBR block = 0x%x,g_dwMBRSectorNum = 0x%x./r/n"), dwMBRBlockNum,g_dwMBRSectorNum));
  6.     memset (g_pbBlock, 0xff, g_dwDataBytesPerBlock);
  7.     memset (g_pSectorInfoBuf, 0xff, sizeof(SectorInfo) * g_FlashInfo.wSectorsPerBlock);
  8.     // No need to check return, since a failed read means data hasn't been written yet.
  9.     ReadBlock (dwMBRBlockNum, g_pbBlock, g_pSectorInfoBuf);
  10.     if (!FMD_EraseBlock (dwMBRBlockNum)) {
  11.         RETAILMSG (1, (TEXT("CreatePartition: error erasing block 0x%x/r/n"), dwMBRBlockNum));
  12.         return FALSE;
  13.     }
  14.     memcpy (g_pbBlock + (g_dwMBRSectorNum % g_FlashInfo.wSectorsPerBlock) * g_FlashInfo.wDataBytesPerSector, g_pbMBRSector, g_FlashInfo.wDataBytesPerSector);
  15.     g_pSectorInfoBuf->bOEMReserved &= ~OEM_BLOCK_READONLY;
  16.     g_pSectorInfoBuf->wReserved2 &= ~SECTOR_WRITE_COMPLETED;
  17.     g_pSectorInfoBuf->dwReserved1 = 0;
  18.     RETAILMSG(1, (TEXT("fly::WriteMBR: MBR block = 0x%x./r/n"), dwMBRBlockNum));
  19.     if (!WriteBlock (dwMBRBlockNum, g_pbBlock, g_pSectorInfoBuf)) {
  20.         RETAILMSG (1, (TEXT("CreatePartition: could not write to block 0x%x/r/n"), dwMBRBlockNum));
  21.         return FALSE;
  22.     }
  23.     return TRUE;
  24. }
 
在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
  1. /*  CreatePartition
  2. *
  3. *  Creates a new partition.  If it is a boot section partition, then it formats
  4. *  flash.
  5. *
  6. *  ENTRY
  7. *      dwStartSector - Logical sector to start the partition.  NEXT_FREE_LOC if
  8. *          none specified.
  9. *      dwNumSectors - Number of logical sectors of the partition.  USE_REMAINING_SPACE
  10. *          to indicate to take up the rest of the space on the flash for that partition.
  11. *      dwPartType - Type of partition to create.
  12. *      fActive - TRUE indicates to create the active partition.  FALSE for
  13. *          inactive.
  14. *      dwPartIndex - Index of the partition entry on the MBR
  15. *
  16. *  EXIT
  17. *      Handle to the partition on success.  INVALID_HANDLE_VALUE on error.
  18. */
  19. static HANDLE CreatePartition (DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwPartIndex)
  20. {
  21.     DWORD dwBootInd = 0;
  22.     RETAILMSG(1, (TEXT("CreatePartition: Enter CreatePartition for 0x%x./r/n"), dwPartType));
  23.     if (fActive)
  24.         dwBootInd |= PART_IND_ACTIVE;
  25.     if (dwPartType == PART_BOOTSECTION || dwPartType == PART_BINFS || dwPartType == PART_XIP)
  26.         dwBootInd |= PART_IND_READ_ONLY;   
  27.      // If start sector is invalid, it means find next free sector
  28.     if (dwStartSector == NEXT_FREE_LOC) {       
  29.         dwStartSector = FindFreeSector();
  30.         if (dwStartSector == INVALID_ADDR) {
  31.             RETAILMSG(1, (TEXT("CreatePartition: can't find free sector./r/n")));
  32.             return INVALID_HANDLE_VALUE;
  33.         }
  34.         // Start extended partition on a block boundary
  35.         if ((dwPartType == PART_EXTENDED) && (dwStartSector % g_FlashInfo.wSectorsPerBlock)) {
  36.             dwStartSector = (dwStartSector / g_FlashInfo.wSectorsPerBlock + 1) * g_FlashInfo.wSectorsPerBlock;
  37.         }
  38.     }
  39.     // If num sectors is invalid, fill the rest of the space up
  40.     if (dwNumSectors == USE_REMAINING_SPACE) {
  41.         DWORD dwLastLogSector = LastLogSector();
  42.         if (dwLastLogSector == INVALID_ADDR)
  43.             return INVALID_HANDLE_VALUE;
  44.         // Determine the number of blocks to reserve for the FAL compaction when creating an extended partition.
  45.         DWORD dwReservedBlocks = g_FlashInfo.dwNumBlocks / PERCENTAGE_OF_MEDIA_TO_RESERVE;
  46.         if((dwReservedBlocks = g_FlashInfo.dwNumBlocks / PERCENTAGE_OF_MEDIA_TO_RESERVE) < MINIMUM_FLASH_BLOCKS_TO_RESERVE) {
  47.             dwReservedBlocks = MINIMUM_FLASH_BLOCKS_TO_RESERVE;
  48.         }
  49.         dwNumSectors = dwLastLogSector - dwStartSector + 1 - dwReservedBlocks * g_FlashInfo.wSectorsPerBlock;
  50.     }
  51.     if (!AreSectorsFree (dwStartSector, dwNumSectors)){
  52.         RETAILMSG (1, (TEXT("fly:::::CreatePartition: sectors [0x%x, 0x%x] requested are out of range or taken by another partition/r/n"), dwStartSector, dwNumSectors));
  53.         return INVALID_HANDLE_VALUE;
  54.     }
  55.     RETAILMSG(1, (TEXT("CreatePartition: Start = 0x%x, Num = 0x%x./r/n"), dwStartSector, dwNumSectors));
  56.     AddPartitionTableEntry (dwPartIndex, dwStartSector, dwNumSectors, (BYTE)dwPartType, (BYTE)dwBootInd);
  57.     if (dwBootInd & PART_IND_READ_ONLY) {
  58.         if (!WriteLogicalNumbers (dwStartSector, dwNumSectors, TRUE)) {
  59.             RETAILMSG(1, (TEXT("CreatePartition: can't mark sector info./r/n")));
  60.             return INVALID_HANDLE_VALUE;
  61.         }
  62.     }
  63.     if (!WriteMBR())
  64.         return INVALID_HANDLE_VALUE;
  65.     g_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);
  66.     g_partStateTable[dwPartIndex].dwDataPointer = 0;
  67.     return (HANDLE)&g_partStateTable[dwPartIndex];           
  68. }
 
如果第二個參數爲-1,則視爲將餘下的所有空間劃爲一個分區。LastLogSector();函數獲得最後一個邏輯Sector。
 
Code Snippet
  1. static DWORD LastLogSector()
  2. {
  3.     if (g_dwLastLogSector) {
  4.        return g_dwLastLogSector;
  5.     }
  6.     DWORD dwMBRBlock = g_dwMBRSectorNum / g_FlashInfo.wSectorsPerBlock;
  7.     DWORD dwUnusableBlocks = dwMBRBlock;
  8.     for (DWORD i = dwMBRBlock; i < g_FlashInfo.dwNumBlocks; i++) {
  9.         if (IS_BLOCK_UNUSABLE (i))
  10.             dwUnusableBlocks++;
  11.     }
  12.     g_dwLastLogSector = (g_FlashInfo.dwNumBlocks - dwUnusableBlocks) * g_FlashInfo.wSectorsPerBlock - 1;
  13.     RETAILMSG(1, (TEXT("fly:::LastLogSector: Last log sector is: 0x%x./r/n"), g_dwLastLogSector));
  14.     return g_dwLastLogSector;
  15. }
 
即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
  1. /*  AddPartitionTableEntry
  2. *
  3. *  Generates the partition entry for the partition table and copies the entry
  4. *  into the MBR that is stored in memory.
  5. *
  6. *
  7. *  ENTRY
  8. *      entry - index into partition table
  9. *      startSector - starting logical sector
  10. *      totalSectors - total logical sectors
  11. *      fileSystem - type of partition
  12. *      bootInd - byte in partition entry that stores various flags such as
  13. *          active and read-only status.
  14. *
  15. *  EXIT
  16. */
  17. static void AddPartitionTableEntry(DWORD entry, DWORD startSector, DWORD totalSectors, BYTE fileSystem, BYTE bootInd)
  18. {
  19.     PARTENTRY partentry = {0};
  20.     Addr startAddr;
  21.     Addr endAddr;
  22.     ASSERT(entry < 4);
  23.     // no checking with disk info and start/total sectors because we allow
  24.     // bogus partitions for testing purposes
  25.     // initially known partition table entry
  26.     partentry.Part_BootInd = bootInd;
  27.     partentry.Part_FileSystem = fileSystem;
  28.     partentry.Part_StartSector = startSector;
  29.     partentry.Part_TotalSectors = totalSectors;
  30.     // logical block addresses for the first and final sector (start on the second head)
  31.     startAddr.type = LBA;
  32.     startAddr.lba = partentry.Part_StartSector;
  33.     endAddr.type = LBA;
  34.     endAddr.lba = partentry.Part_StartSector + partentry.Part_TotalSectors-1;
  35.     // translate the LBA addresses to CHS addresses
  36.     startAddr = LBAtoCHS(&g_FlashInfo, startAddr);
  37.     endAddr = LBAtoCHS(&g_FlashInfo, endAddr);
  38.     // starting address
  39.     partentry.Part_FirstTrack = (BYTE)(startAddr.chs.cylinder & 0xFF);
  40.     partentry.Part_FirstHead = (BYTE)(startAddr.chs.head & 0xFF);
  41.     // lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
  42.     partentry.Part_FirstSector = (BYTE)((startAddr.chs.sector & 0x3F) | ((startAddr.chs.cylinder & 0x0300) >> 2));
  43.     // ending address:
  44.     partentry.Part_LastTrack = (BYTE)(endAddr.chs.cylinder & 0xFF);
  45.     partentry.Part_LastHead = (BYTE)(endAddr.chs.head & 0xFF);
  46.     // lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
  47.     partentry.Part_LastSector = (BYTE)((endAddr.chs.sector & 0x3F) | ((endAddr.chs.cylinder & 0x0300) >> 2));
  48.     memcpy(g_pbMBRSector+PARTTABLE_OFFSET+(sizeof(PARTENTRY)*entry), &partentry, sizeof(PARTENTRY));
  49. }
 
這裏面的地址信息是一種叫CHS(Cyinder/Head/Sector)的地址。eboot中有將邏輯地址LBS(Logical Block Addr)與這種地址互相轉換的函數LBAtoCHS,CHSToLBA。
 
Code Snippet
  1. Addr LBAtoCHS(FlashInfo *pFlashInfo, Addr lba)
  2. {
  3.     Addr chs;
  4.     DWORD tmp = pFlashInfo->dwNumBlocks * pFlashInfo->wSectorsPerBlock;
  5.     chs.type = CHS;
  6.     chs.chs.cylinder = (WORD)(lba.lba / tmp);                              // ÖùÃæ,Ó¦¸ÃʼÖÕÊÇ
  7.     tmp = lba.lba % tmp;
  8.     chs.chs.head = (WORD)(tmp / pFlashInfo->wSectorsPerBlock);             // ¿éµØÖ·
  9.     chs.chs.sector = (WORD)((tmp % pFlashInfo->wSectorsPerBlock) + 1);     // ÉÈÇø+1
  10.     return chs;
  11. }
  12. Addr CHStoLBA(FlashInfo *pFlashInfo, Addr chs)
  13. {
  14.     Addr lba;
  15.     lba.type = LBA;
  16.     lba.lba = ((chs.chs.cylinder * pFlashInfo->dwNumBlocks + chs.chs.head)
  17.         * pFlashInfo->wSectorsPerBlock)+ chs.chs.sector - 1;
  18.     return lba;
  19. }
 
如果分區的格式有隻讀屬性,則通過WriteLogicalNumbers()函數寫分區的Sectorinfo,把這部分空間保護起來。
 
Code Snippet
  1. static BOOL WriteLogicalNumbers (DWORD dwStartSector, DWORD dwNumSectors, BOOL fReadOnly)
  2. {
  3.     DWORD dwNumSectorsWritten = 0;
  4.     DWORD dwPhysSector = Log2Phys (dwStartSector);
  5.     DWORD dwBlockNum = dwPhysSector / g_FlashInfo.wSectorsPerBlock;
  6.     DWORD dwOffset = dwPhysSector % g_FlashInfo.wSectorsPerBlock;
  7.     while (dwNumSectorsWritten < dwNumSectors) {
  8.         // If bad block, move to the next block
  9.         if (IS_BLOCK_UNUSABLE (dwBlockNum)) {
  10.             dwBlockNum++;
  11.             continue;
  12.         }
  13.         memset (g_pbBlock, 0xff, g_dwDataBytesPerBlock);
  14.         memset (g_pSectorInfoBuf, 0xff, sizeof(SectorInfo) * g_FlashInfo.wSectorsPerBlock);
  15.         // No need to check return, since a failed read means data hasn't been written yet.
  16.         ReadBlock (dwBlockNum, g_pbBlock, g_pSectorInfoBuf);
  17.         if (!FMD_EraseBlock (dwBlockNum)) {
  18.             return FALSE;
  19.         }
  20.         DWORD dwSectorsToWrite = g_FlashInfo.wSectorsPerBlock - dwOffset;
  21.         PSectorInfo pSectorInfo = g_pSectorInfoBuf + dwOffset;
  22.         // If this is the last block, then calculate sectors to write if there isn't a full block to update
  23.         if ((dwSectorsToWrite + dwNumSectorsWritten) > dwNumSectors)
  24.             dwSectorsToWrite = dwNumSectors - dwNumSectorsWritten;
  25.         for (DWORD iSector = 0; iSector < dwSectorsToWrite; iSector++, pSectorInfo++, dwNumSectorsWritten++) {
  26.             // Assert read only by setting bit to 0 to prevent wear-leveling by FAL
  27.             if (fReadOnly)
  28.                 pSectorInfo->bOEMReserved &= ~OEM_BLOCK_READONLY;
  29.             // Set to write completed so FAL can map the sector
  30.             pSectorInfo->wReserved2 &= ~SECTOR_WRITE_COMPLETED;       
  31.             // Write the logical sector number
  32.             pSectorInfo->dwReserved1 = dwStartSector + dwNumSectorsWritten;           
  33.         }
  34.         if (!WriteBlock (dwBlockNum, g_pbBlock, g_pSectorInfoBuf))
  35.             return FALSE;
  36.         dwOffset = 0;
  37.         dwBlockNum++;
  38.     }
  39.     return TRUE;
  40. }
 
這就是爲什麼系統啓動後,我們無法寫入文件的BINFS文件系統格式分區的原因了。而FAT格式就可以。最後調用WriteMBR()完全MBR的寫入,分區完畢。
讓我們繼續回到BP_OpenPartition函數中,如果從一開始IsValidMBR()就檢測到有效的MBR,GetPartitionTableIndex(dwPartType, fActive, &dwPartIndex);獲得分區表。和dwPartIndex分區表的索引號。
 
Code Snippet
  1. static BOOL GetPartitionTableIndex (DWORD dwPartType, BOOL fActive, PDWORD pdwIndex)
  2. {
  3.     PPARTENTRY pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET);
  4.     DWORD iEntry = 0;
  5.     for (iEntry = 0; iEntry < NUM_PARTS; iEntry++, pPartEntry++) {
  6.         if ((pPartEntry->Part_FileSystem == dwPartType) && (((pPartEntry->Part_BootInd & PART_IND_ACTIVE) != 0) == fActive)) {
  7.             *pdwIndex = iEntry;
  8.             return TRUE;
  9.         }
  10.         if (!IsValidPart (pPartEntry)) {
  11.             *pdwIndex = iEntry;
  12.             return FALSE;
  13.         }
  14.     }
  15.     return FALSE;
  16. }
 
重要結構:PARTENTRY

 

Code Snippet
  1. // end of master boot record contains 4 partition entries
  2. typedef struct _PARTENTRY {
  3.         BYTE            Part_BootInd;           // If 80h means this is boot partition
  4.         BYTE            Part_FirstHead;         // Partition starting head based 0
  5.         BYTE            Part_FirstSector;       // Partition starting sector based 1
  6.         BYTE            Part_FirstTrack;        // Partition starting track based 0
  7.         BYTE            Part_FileSystem;        // Partition type signature field
  8.         BYTE            Part_LastHead;          // Partition ending head based 0
  9.         BYTE            Part_LastSector;        // Partition ending sector based 1
  10.         BYTE            Part_LastTrack;         // Partition ending track based 0
  11.         DWORD           Part_StartSector;       // Logical starting sector based 0
  12.         DWORD           Part_TotalSectors;      // Total logical sectors in partition
  13. } PARTENTRY;

 

 

分區表就是通過這個結構寫入MBR,起始地址,分區大小,分區格式,對應結構寫入MBR所在的Sector就可以了。在檢測有效分區時static BOOL IsValidPart (PPARTENTRY pPartEntry)
{
    return (pPartEntry->Part_FileSystem != 0xff) && (pPartEntry->Part_FileSystem != 0);
}
就是通過對分區表文件系統格式的判斷了。
把NAND後面的空間,全部分爲一個FAT格式的分區。
Code Snippet
  1. // create extended partition in whatever is left
  2. hPartEx = BP_OpenPartition( (NK_START_BLOCK+1+BINFS_BLOCK) * PAGES_PER_BLOCK,
  3.                             NEXT_FREE_LOC,   // (1024 - (NK_START_BLOCK+1+SECTOR_TO_BLOCK_SIZE(FILE_TO_SECTOR_SIZE(dwBINFSPartLength)))) * PAGES_PER_BLOCK,
  4.                             PART_DOS32,
  5.                             TRUE,
  6.                             PART_OPEN_ALWAYS);
  7. if (hPartEx == INVALID_HANDLE_VALUE )
  8. {
  9.     EdbgOutputDebugString("*** WARN: StoreImageToBootMedia: Failed to open/create Extended partition ***/r/n");
  10. }

 

 

引用通告

此日誌的引用通告 URL 是:
http://giwawe.spaces.live.com/blog/cns!92AFEF096943066B!260.trak
引用此項的網絡日誌
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章