CE5.0 - eboot加载NK.nb0的详细流程(转)

http://blog.chinaunix.net/u1/38994/showart.php?id=1883739

CE5.0 - eboot加载NK.nb0的详细流程

可以参考《 CE5.0 - eboot烧写NK.nb0的详细流程》

eboot
==>main             PLATFORM/SMDK2440A/Src/Bootloader/Eboot_usb/main.c|96| BootloaderMain(); //应该是这个
==>BootloaderMain   PLATFORM/SMDK2440A/Src/Bootloader/Eboot_usb/blcommon.c|106| if (!OEMPlatformInit ()) //应该是这个
==>OEMPlatformInit  PLATFORM/SMDK2440A/Src/Bootloader/Eboot/main.c|722| if ( !BP_Init((LPBYTE)BINFS_RAM_START, BINFS_RAM_LENGTH, NULL, NULL, NULL) )
==>if ( !g_bDownloadImage ) {//如果不执行下载,那么执行下面的直接加载nk.nb0操作[luther.gliethttp]
    ...
        switch (g_ImageType) {
            ...
            case IMAGE_TYPE_RAMIMAGE:
                OALMSG(TRUE, (TEXT("OEMPlatformInit: IMAGE_TYPE_RAMIMAGE/r/n")));
                if ( !ReadOSImageFromBootMedia( ) ) //加载kernel
                {
                    OALMSG(OAL_ERROR, (TEXT("OEMPlatformInit ERROR: Failed to load kernel region into RAM./r/n")));
                    return FALSE;
                }
                break;
    ...
    }
来具体看看ReadOSImageFromBootMedia的代码实现[luther.gliethttp]
/*
    @func   BOOL | ReadKernelRegionFromBootMedia |
            BinFS support. Reads the kernel region from Boot Media into RAM.  The kernel region is fixed up
            to run from RAM and this is done just before jumping to the kernel entry point.
    @rdesc  TRUE = Success, FALSE = Failure.
    @comm
    @xref
*/
BOOL ReadOSImageFromBootMedia()
{
    HANDLE hPart;
    SectorInfo si;
    DWORD     chainaddr, flashaddr;
    DWORD i;

    OALMSG(OAL_FUNC, (TEXT("+ReadOSImageFromBootMedia/r/n")));

    if (!g_bBootMediaExist) //在/PLATFORM/SMDK2440A/Src/Bootloader/Eboot_usb/main.c|706| g_bBootMediaExist = TRUE;中如果BP_Init((LPBYTE)BINFS_RAM_START, BINFS_RAM_LENGTH, NULL, NULL, NULL)成功,那么true赋值[luther.gliethttp]
    {
        OALMSG(OAL_ERROR, (TEXT("ERROR: WriteRawImageToBootMedia: device doesn't exist./r/n")));
        return(FALSE);
    }

    if ( !VALID_TOC(g_pTOC) )
    {
        OALMSG(OAL_ERROR, (TEXT("ERROR: ReadOSImageFromBootMedia: INVALID_TOC/r/n")));
        return(FALSE);
    }

    if ( !VALID_IMAGE_DESCRIPTOR(&g_pTOC->id[g_dwTocEntry]) ) //在TOC_Read()中执行了g_dwTocEntry = g_pBootCfg->ImageIndex;赋值操作[lutehr.gleithttp]
    {
        OALMSG(OAL_ERROR, (TEXT("ReadOSImageFromBootMedia: ERROR_INVALID_IMAGE_DESCRIPTOR: 0x%x/r/n"),
            g_pTOC->id[g_dwTocEntry].dwSignature));
        return FALSE;
    }

    if ( !OEMVerifyMemory(g_pTOC->id[g_dwTocEntry].dwLoadAddress, sizeof(DWORD)) ||
         !OEMVerifyMemory(g_pTOC->id[g_dwTocEntry].dwJumpAddress, sizeof(DWORD)) ||//最后检查跳转到的虚拟地址同时执行g_ImageType = IMAGE_TYPE_RAMIMAGE;赋值[luther.gliethttp]
         !g_pTOC->id[g_dwTocEntry].dwTtlSectors )
    {
        OALMSG(OAL_ERROR, (TEXT("ReadOSImageFromBootMedia: ERROR_INVALID_ADDRESS: (address=0x%x, sectors=0x%x, launch address=0x%x).../r/n"),
            g_pTOC->id[g_dwTocEntry].dwLoadAddress, g_pTOC->id[g_dwTocEntry].dwTtlSectors, g_pTOC->id[g_dwTocEntry].dwJumpAddress));
        return FALSE;
    }

    // Open the BINFS partition (it must exist).
    //
    hPart = BP_OpenPartition( NEXT_FREE_LOC,
                              USE_REMAINING_SPACE,
                              PART_BINFS,
                              TRUE,
                              PART_OPEN_EXISTING);
//因为在WriteOSImageToBootMedia()时,执行如下语句,创建PART_BINFS分区[luther.gliethttp]
/*  //为nk.nb0建立主分区,管理(IMAGE_START_BLOCK+1)*PAGES_PER_BLOCK开始的扇区,管理大小为SECTOR_TO_BLOCK_SIZE(FILE_TO_SECTOR_SIZE(dwBINFSPartLength))*PAGES_PER_BLOCK
    //将该分区所有信息登记到了MBR中,hPart为申请到的主分区表指针[luther.gliethttp]
    hPart = BP_OpenPartition( (IMAGE_START_BLOCK+1)*PAGES_PER_BLOCK,    // next block of MBR
                              SECTOR_TO_BLOCK_SIZE(FILE_TO_SECTOR_SIZE(dwBINFSPartLength))*PAGES_PER_BLOCK, // align to block
                              PART_BINFS,
                              TRUE,
                              PART_OPEN_ALWAYS);
*/

    if (hPart == INVALID_HANDLE_VALUE )
    {
        OALMSG(OAL_ERROR, (TEXT("ERROR: ReadOSImageFromBootMedia: Failed to open existing partition./r/n")));
        return(FALSE);
    }

    // Set the partition file pointer to the correct offset for the kernel region.
    //
    //因为在WriteOSImageToBootMedia()时,执行如下语句,
    //g_pTOC->id[g_dwTocEntry].dwStoreOffset = dwStoreOffset;//对期望Toc进行写操作,那么保存它的存储逻辑地址(以字节为单位)[luther.gliethttp]
    //将nk.nb0烧写时在该主分区的逻辑扇区号保存在了g_pTOC->id[g_dwTocEntry].dwStoreOffset中,
    //所以g_pTOC->id[g_dwTocEntry].dwStoreOffset之后的数据就是nk.nb0的raw数据了[luther.gliethttp]
    if ( !BP_SetDataPointer(hPart, g_pTOC->id[g_dwTocEntry].dwStoreOffset) )
    {
        OALMSG(OAL_ERROR, (TEXT("ERROR: ReadOSImageFromBootMedia: Failed to set data pointer in partition (offset=0x%x)./r/n"),
            g_pTOC->id[g_dwTocEntry].dwStoreOffset));
        return(FALSE);
    }

    // Read the kernel region from the Boot Media into RAM.
    //g_pTOC->id[g_dwTocEntry].dwTtlSectors等于nk.nb0大小,即29M,对应29M/512=0xE800个扇区,所以g_pTOC->id[g_dwTocEntry].dwTtlSectors中存放的数值为0xE800.[luther.gliethttp]
    //之所以能够在2秒内将29M数据加载完成,这完全归功于
    //加载地址0x80001000处dcache和icache都已打开[luther.gliethttp]
    if ( !BP_ReadData( hPart,
                       (LPBYTE)(g_pTOC->id[g_dwTocEntry].dwLoadAddress),
                       SECTOR_TO_FILE_SIZE(g_pTOC->id[g_dwTocEntry].dwTtlSectors)) )
    {
        OALMSG(OAL_ERROR, (TEXT("ERROR: ReadOSImageFromBootMedia: Failed to read kernel region from partition./r/n")));
        return(FALSE);
    }

    if (!g_pTOC->chainInfo.dwLoadAddress)
    {
        chainaddr = g_pTOC->chainInfo.dwLoadAddress;
        flashaddr = g_pTOC->chainInfo.dwFlashAddress;
        for ( i = 0; i < (g_pTOC->chainInfo.dwLength); i++ )
        {
            OALMSG(TRUE, (TEXT("chainaddr=0x%x, flashaddr=0x%x/r/n"), chainaddr, flashaddr+i));

            if ( !FMD_ReadSector(flashaddr+i, (PUCHAR)(chainaddr), &si, 1) ) {
                OALMSG(OAL_ERROR, (TEXT("TOC_Write ERROR: Unable to read/verify TOC/r/n")));
                return FALSE;
            }
            chainaddr += 512;
        }
    }
    OALMSG(OAL_FUNC, (TEXT("_ReadOSImageFromBootMedia/r/n")));
    return(TRUE);
}

HANDLE BP_OpenPartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags)
{
        DWORD dwPartIndex;
        BOOL fExists;

        ASSERT (g_pbMBRSector);
        
        if (!IsValidMBR()) {//找到第一个非坏块,同时非reserved的块,同时MBR的各个标志位信息都正确,就是所谓的MBR起始块[luther.gliethttp]
            DWORD dwFlags = 0;

            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;
            }
            BP_LowLevelFormat (0, g_FlashInfo.dwNumBlocks, dwFlags);//如果没有找到,那么进行低格[luther.gliethttp]
            dwPartIndex = 0;
            fExists = FALSE;
        }
        else {
            fExists = GetPartitionTableIndex(dwPartType, fActive, &dwPartIndex);//获取dwPartType的主分区号,如果dwPartType已经存在的话[luther.gliethttp]
        }

        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;
            }            
            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))//如果已经没有空的主分区,即4个主分区全部占满,那么false.
                return INVALID_HANDLE_VALUE;

            // Create new partition
            return CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);//否则在该空闲主分区建立本image分区信息[luther.gliethttp]
        }

        return INVALID_HANDLE_VALUE;
        
}

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

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) {//由本函数自由选定一个空闲扇区[luther.gliethttp]
        
        dwStartSector = FindFreeSector();//找到从g_dwMBRSectorNum开始的第一个没有被任何主分区管理的空闲扇区,该扇区之后的所有扇区都可以被该新主分区管理,因为到目前为止还没有任何主分区管理他们[luther.gliethttp]
        if (dwStartSector == INVALID_ADDR) {
            RETAILMSG(1, (TEXT("CreatePartition: can't find free sector./r/n")));
            return INVALID_HANDLE_VALUE;
        }

        // Start partitions on the next block if they are currently on the wrong block type.
        if (dwStartSector % g_FlashInfo.wSectorsPerBlock) {//如果该sector不是block的第一扇区,那么将使用下一个block第一扇区作为,
            DWORD dwBlock = dwStartSector / g_FlashInfo.wSectorsPerBlock;
            if (IS_PART_READONLY(dwBootInd) != IS_BLOCK_READONLY(dwBlock)) {
                dwStartSector = (dwBlock+1) * g_FlashInfo.wSectorsPerBlock;//下一个block为分区表管理的数据区首地址[luther.gliethttp]
            }
        }
    }

    if (IS_PART_READONLY(dwBootInd)) {
/*对于
WriteOSImageToBootMedia
==>BP_OpenPartition( NEXT_FREE_LOC,
                                USE_REMAINING_SPACE,
                                PART_DOS32,//非READONLY分区
                                TRUE,
                                PART_OPEN_ALWAYS);
不会执行到这里
*/

        // Allow read-only partitions to go to the end of disk, if requested.
        if (dwNumSectors == USE_REMAINING_SPACE) {

            DWORD dwLastLogSector = LastLogSector();//表示使用
            if (dwLastLogSector == INVALID_ADDR)
                return INVALID_HANDLE_VALUE;

            dwNumSectors = dwLastLogSector - dwStartSector + 1;//表示使用dwStartSector开始的所有剩余flash扇区空间[luther.gliethttp]
        }
    }
    else {

        DWORD dwLastLogSector = LastLogSector();//返回flash磁盘可用的结尾扇区号
        if (dwLastLogSector == INVALID_ADDR)
            return INVALID_HANDLE_VALUE;
//define SECTOR_WRITE_COMPLETED 0x0004  // Indicates data is valid for the FAL
//#define MINIMUM_FLASH_BLOCKS_TO_RESERVE                2
//#define PERCENTAGE_OF_MEDIA_TO_RESERVE                400        // 0.25% of the media {NOTE: 100% / 0.25% == 400}   //留有25%的free空间
        // 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) {//保证最少1/4空闲空间剩余
            dwReservedBlocks = MINIMUM_FLASH_BLOCKS_TO_RESERVE;
        }
        
        DWORD dwNumMaxSectors = dwLastLogSector - dwStartSector + 1 - dwReservedBlocks * g_FlashInfo.wSectorsPerBlock;//计算该分区所能支配的最大扇区数目[luther.gliethttp]

        // If dwNumSectors was provided, validate it isn't past the max.
        // If dwNumSectors is USE_REMAINING_SPACE, fill disk with max sectors.
        if ((dwNumSectors == USE_REMAINING_SPACE)  || (dwNumMaxSectors <  dwNumSectors)) {
            RETAILMSG(1, (TEXT("CreatePartition: Num sectors set to 0x%x to allow for compaction blocks./r/n"), dwNumMaxSectors));
            dwNumSectors = dwNumMaxSectors ;//将所有的可用扇区作为该主分区管理flash扇区[luther.gliethttp]
        }
    }
    
    if (!AreSectorsFree (dwStartSector, dwNumSectors)){//再次确认dwStartSector之后的dwNumSectors扇区确实没有被任何主分区管理[luther.gliethttp]
        RETAILMSG (1, (TEXT("CreatePartition: sectors [0x%x, 0x%x] requested are out of range or taken by another partition/r/n"), dwStartSector, dwNumSectors));
        return INVALID_HANDLE_VALUE;
    }
//至此dwStartSector之后的dwNumSectors个扇区可以由该主分区管理[luther.gliethttp]

    RETAILMSG(1, (TEXT("CreatePartition: Start = 0x%x, Num = 0x%x./r/n"), dwStartSector, dwNumSectors));
    
    AddPartitionTableEntry (dwPartIndex, dwStartSector, dwNumSectors, (BYTE)dwPartType, (BYTE)dwBootInd);//将该分区信息添加到该主分区表[luther.gliethttp]

    if (IS_PART_READONLY(dwBootInd)) {
        if (!WriteLogicalNumbers (dwStartSector, dwNumSectors, TRUE)) {
            RETAILMSG(1, (TEXT("CreatePartition: can't mark sector info./r/n")));
            return INVALID_HANDLE_VALUE;
        }
    }

    if (!WriteMBR()) //ok,主分区已经在BinFS的缓冲区设置完毕了,现在将BinFS缓冲区中的数据回写到flash.[luther.gliethttp]
        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];            
}

static DWORD FindFreeSector()
{
    DWORD dwFreeSector = 1;//表示从该扇区之后的所有扇区都还没有一个主分区来管理他们,所以可以有效使用
    PPARTENTRY pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET);

    for (int i = 0; i < NUM_PARTS; i++) {
        if (!IsValidPart (pPartEntry))
            break;
        if ((pPartEntry->Part_StartSector + pPartEntry->Part_TotalSectors) > dwFreeSector)
            dwFreeSector = pPartEntry->Part_StartSector + pPartEntry->Part_TotalSectors;//这里明显是为了找到所有登记了的主分区,他们最大管理的扇区号,
            //(就像我们对pc进行分区一样,我们可以任意从分区表中删除一个fat32分区,然后该分区表对应的start_sector - end_sector就空闲出来了,当然这段空闲出来的分区,可以供
            //另外一次操作重新建立成ntfs分区,就是说dwFreeSectorb之后的所有扇区都是没有人管理的,即没有主分区来管理的,所以可以由新创建的主分区表项管理该dwFreeSector以后的
            //所有分区)[luther.gliethttp]
        RETAILMSG(1, (TEXT("FindFreeSector: FreeSector is: 0x%x after processing part 0x%x./r/n"), dwFreeSector, pPartEntry->Part_FileSystem));
        pPartEntry++;
    }

    DWORD dwLastLogSector = LastLogSector();//找到最靠后的那个空闲block块,然后返回该块的第一个扇区[luther.gliethttp]
    if (dwLastLogSector == INVALID_ADDR || dwFreeSector >= dwLastLogSector)//所以dwFreeSector不应该超过最大sector地址[luther.gliethttp]
        dwFreeSector = INVALID_ADDR;

    return dwFreeSector;
}

static DWORD LastLogSector()
{
    if (g_dwLastLogSector) {//在BP_Init中g_dwLastLogSector = 0;
       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++;//不可用块计数(坏块或者RESERVED块)
    }
    //找到最靠后的那个空闲block块,然后返回该块的第一个扇区[luther.gliethttp]
    //从该语句算法来看,所有UnusableBlocks不可用块都会放到整个flash的结尾,当然也可能只是统计一下整个flash可用sectors有多少[lutehr.gliethttp]
    g_dwLastLogSector = (g_FlashInfo.dwNumBlocks - dwUnusableBlocks) * g_FlashInfo.wSectorsPerBlock - 1;

    RETAILMSG(1, (TEXT("LastLogSector: Last log sector is: 0x%x./r/n"), g_dwLastLogSector));
    
    return g_dwLastLogSector;
}

static BOOL AreSectorsFree (DWORD dwStartSector, DWORD dwNumSectors)
{
    PPARTENTRY pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET);//4个主分区表的起始地址
    DWORD dwEndSector = dwStartSector + dwNumSectors - 1;//结尾扇区
    DWORD dwEndReservedSector;

    DWORD dwLastLogSector = LastLogSector();//返回所能管理的最后一个扇区号
    if ((dwLastLogSector == INVALID_ADDR) || (dwNumSectors > dwLastLogSector+1) || (dwEndSector > dwLastLogSector) ||
        (dwNumSectors == 0) || (dwStartSector > dwEndSector))
        return FALSE;
    
    for (int i = 0; i < NUM_PARTS; i++) {
        if (!IsValidPart (pPartEntry))
            break;        
        dwEndReservedSector = pPartEntry->Part_StartSector + pPartEntry->Part_TotalSectors - 1;
//检查dwStartSector之后的dwNumSectors个扇区是否被现有有效主分区所管理,
//我们当然期望没有被管理,这样我们才能成功创建我们需要的新主分区[luther.gliethttp]
        if (!(dwStartSector > dwEndReservedSector || dwEndSector < pPartEntry->Part_StartSector))
            return FALSE;

        pPartEntry++;
    }
    return TRUE;
}

//添加主分区信息
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));//将信息拷贝到BinFS的MBR临时缓冲区下的相应主分区空间[luther.gliethttp]
}

static Addr LBAtoCHS(FlashInfo *pFlashInfo, Addr lba)
{
    if(lba.type == CHS)
        return 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);

    return chs;
}

//从主分区由BP_SetDataPointer设置的逻辑地址开始读取dwLength长度数据到pbBuffer缓冲区[luther.gliethttp]
BOOL BP_ReadData(HANDLE hPartition, LPBYTE pbBuffer, DWORD dwLength)
{
    if (hPartition == INVALID_HANDLE_VALUE)
        return FALSE;
    
    DWORD dwNumSects, dwBlockAddress;
    static LPBYTE pbSector = g_pbBlock;
    PPARTSTATE pPartState = (PPARTSTATE) hPartition;
    DWORD dwNextPtrValue = pPartState->dwDataPointer + dwLength;

    if (!pbBuffer || !pbSector || dwLength == 0)
        return(FALSE);

    RETAILMSG (1, (TEXT("ReadData: Start = 0x%x, Length = 0x%x./r/n"), pPartState->dwDataPointer, dwLength));

    // Check to make sure buffer size is within limits of partition
    if (((dwNextPtrValue - 1) / g_FlashInfo.wDataBytesPerSector) >= pPartState->pPartEntry->Part_TotalSectors) {
        RETAILMSG (1, (TEXT("ReadData: trying to read past end of partition./r/n")));
        return FALSE;
    }

    // Get the starting physical sector
    DWORD dwSectorAddr = Log2Phys (pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector + pPartState->pPartEntry->Part_StartSector);

    // If current pointer is not on a sector boundary, copy bytes up to the first sector boundary
    DWORD dwOffsetSector = pPartState->dwDataPointer % g_FlashInfo.wDataBytesPerSector;
    if (dwOffsetSector)
    {
        if (!FMD_ReadSector(dwSectorAddr, pbSector, NULL, 1))
        {
            RETAILMSG (1, (TEXT("ReadData: failed to read sector (0x%x)./r/n"), dwSectorAddr));
            return(FALSE);
        }
        
        DWORD dwNumBytesRead = g_FlashInfo.wDataBytesPerSector - dwOffsetSector;
        if (dwNumBytesRead > dwLength)
            dwNumBytesRead = dwLength;
        
        memcpy(pbBuffer, pbSector + dwOffsetSector, dwNumBytesRead);   
        dwLength -= dwNumBytesRead;
        pbBuffer += dwNumBytesRead;
        dwSectorAddr++;
    }

    // Compute sector length.
    dwNumSects = (dwLength / g_FlashInfo.wDataBytesPerSector);

    // NAND FMD only supports single-sector reads at the moment.
    while (dwNumSects--)
    {
        dwBlockAddress = (dwSectorAddr / g_FlashInfo.wSectorsPerBlock);

        // If the block is marked bad, skip to next block.  Note that the assumption in our error checking
        // is that any truely bad block will be marked either by the factory during production or will be marked
        // during the erase and write verification phases.  If anything other than a bad block fails ECC correction
        // in this routine, it's fatal.
        if (IS_BLOCK_UNUSABLE(dwBlockAddress))
        {
            dwSectorAddr += g_FlashInfo.wSectorsPerBlock;
            ++dwNumSects;        // Compensate for fact that we didn't write any sector data.
            continue;
        }

        // Read the sector - if this fails ECC correction, we fail the whole read operation.
        // Note - only single sector reads supported at the moment.
        if (!FMD_ReadSector(dwSectorAddr, pbBuffer, NULL, 1))
        {
            RETAILMSG (1, (TEXT("ReadData: failed to read sector (0x%x)./r/n"), dwSectorAddr));
            return(FALSE);
        }

        ++dwSectorAddr;
        pbBuffer += g_FlashInfo.wDataBytesPerSector;
    }

    DWORD dwNumExtraBytes = (dwLength % g_FlashInfo.wDataBytesPerSector);
    if (dwNumExtraBytes)
    {
        // Skip bad blocks
        while (IS_BLOCK_UNUSABLE(dwSectorAddr / g_FlashInfo.wSectorsPerBlock))
        {
            dwSectorAddr += g_FlashInfo.wSectorsPerBlock;
            if ((dwSectorAddr / g_FlashInfo.wSectorsPerBlock) >= g_FlashInfo.dwNumBlocks)
            {
                // This should never happen since partition has already been created
                RETAILMSG (1, (TEXT("ReadData: corrupt partition.  Reformat flash./r/n")));                
                return FALSE;
            }
        }
        
        if (!FMD_ReadSector(dwSectorAddr, pbSector, NULL, 1))
        {
            RETAILMSG (1, (TEXT("ReadData: failed to read sector (0x%x)./r/n"), dwSectorAddr));
            return(FALSE);
        }
        memcpy(pbBuffer, pbSector, dwNumExtraBytes);
    }

    pPartState->dwDataPointer = dwNextPtrValue;
    return(TRUE);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值