WriteRegionsToBootMedia ( )的详细分析
这个函数的原型如下:
BOOL WriteRegionsToBootMedia(DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr)
{
BYTE nCount;
DWORD dwNumExts;
PXIPCHAIN_SUMMARY pChainInfo = NULL;
EXTENSION *pExt = NULL;
DWORD dwBINFSPartLength = 0;
HANDLE hPart, hPartEx;
DWORD dwStoreOffset;
DWORD dwMaxRegionLength[BL_MAX_BIN_REGIONS] = {0};
DWORD dwChainStart, dwChainLength;
// Initialize the variables
dwChainStart = dwChainLength = 0;
EdbgOutputDebugString("+WriteRegionsToBootMedia: ImageStart: 0x%x, ImageLength: 0x%x, LaunchAddr:0x%x/r/n",
dwImageStart, dwImageLength, dwLaunchAddr);
if ( !g_bBootMediaExist ) {
EdbgOutputDebugString("ERROR: WriteRegionsToBootMedia: device doesn't exist./r/n");
return(FALSE);
}
if ( !VALID_TOC(g_pTOC) ) {
EdbgOutputDebugString("WARN: WriteRegionsToBootMedia: INVALID_TOC/r/n");
if ( !TOC_Init(g_dwTocEntry, g_ImageType, dwImageStart, dwImageLength, dwLaunchAddr) ) {
EdbgOutputDebugString("ERROR: INVALID_TOC/r/n");
return(FALSE);
}//如果没有读到TOC在这里初始化TOC并且将相关信息写入
}
if ( !(IMAGE_TYPE_BINFS & g_pTOC->id[g_dwTocEntry].dwImageType) ) {
EdbgOutputDebugString("ERROR: WriteRegionsToBootMedia: INVALID_IMAGE_TYPE: 0x%x/r/n",
g_pTOC->id[g_dwTocEntry].dwImageType);
return(FALSE);
}//确认这里是BINFS
// Look in the kernel region's extension area for a multi-BIN extension descriptor.
// This region, if found, details the number, start, and size of each BIN region.
for (nCount = 0, dwNumExts = 0 ; (nCount < g_BINRegionInfo.dwNumRegions); nCount++)
{
// Does this region contain nk.exe and an extension pointer?
pExt = (EXTENSION *)GetKernelExtPointer(g_BINRegionInfo.Region[nCount].dwRegionStart,
g_BINRegionInfo.Region[nCount].dwRegionLength );
if ( pExt != NULL)
{
// If there is an extension pointer region, walk it until the end.
while (pExt)
{
DWORD dwBaseAddr = g_BINRegionInfo.Region[nCount].dwRegionStart;
pExt = (EXTENSION *)OEMMapMemAddr(dwBaseAddr, (DWORD)pExt);
EdbgOutputDebugString("INFO: OEMLaunch: Found chain extenstion: '%s' @ 0x%x/r/n", pExt->name, dwBaseAddr);
if ((pExt->type == 0) && !strcmp(pExt->name, "chain information"))
{
pChainInfo = (PXIPCHAIN_SUMMARY) OEMMapMemAddr(dwBaseAddr, (DWORD)pExt->pdata);
dwNumExts = (pExt->length / sizeof(XIPCHAIN_SUMMARY));
EdbgOutputDebugString("INFO: OEMLaunch: Found 'chain information' (pChainInfo=0x%x Extensions=0x%x)./r/n", (DWORD)pChainInfo, dwNumExts);
break;
}
pExt = (EXTENSION *)pExt->pNextExt;
}
}
else {
// Search for Chain region. Chain region doesn't have the ROMSIGNATURE set
DWORD dwRegionStart = g_BINRegionInfo.Region[nCount].dwRegionStart;
DWORD dwSig = *(LPDWORD) OEMMapMemAddr(dwRegionStart, dwRegionStart + ROM_SIGNATURE_OFFSET);
//确定镜像的开始地址和签名
if ( dwSig != ROM_SIGNATURE) {
// It is the chain
dwChainStart = dwRegionStart;
dwChainLength = g_BINRegionInfo.Region[nCount].dwRegionLength;
EdbgOutputDebugString("Found the Chain region: StartAddress: 0x%X; Length: 0x%X/n", dwChainStart, dwChainLength);
}
}
}
// Determine how big the Total BINFS partition needs to be to store all of this.
if (pChainInfo && dwNumExts == g_BINRegionInfo.dwNumRegions) // We're downloading all the regions in a multi-region image...
{
DWORD i;
EdbgOutputDebugString("Writing multi-regions/r/n");
for (nCount = 0, dwBINFSPartLength = 0 ; nCount < dwNumExts ; nCount++)
{
dwBINFSPartLength += (pChainInfo + nCount)->dwMaxLength;
EdbgOutputDebugString("BINFSPartMaxLength[%u]: 0x%x, TtlBINFSPartLength: 0x%x /r/n",
nCount, (pChainInfo + nCount)->dwMaxLength, dwBINFSPartLength);
// MultiBINInfo does not store each Regions MAX length, and pChainInfo is not in any particular order.
// So, walk our MultiBINInfo matching up pChainInfo to find each regions MAX Length
for (i = 0; i < dwNumExts; i++) {
if ( g_BINRegionInfo.Region[i].dwRegionStart == (DWORD)((pChainInfo + nCount)->pvAddr) ) {
dwMaxRegionLength[i] = (pChainInfo + nCount)->dwMaxLength;
EdbgOutputDebugString("dwMaxRegionLength[%u]: 0x%x /r/n", i, dwMaxRegionLength[i]);
break;
}
}
}
}
else // A single BIN file or potentially a multi-region update (but the partition's already been created in this latter case).
{
dwBINFSPartLength = g_BINRegionInfo.Region[0].dwRegionLength;
EdbgOutputDebugString("Writing single region/multi-region update, dwBINFSPartLength: %u /r/n", dwBINFSPartLength);
}//在这里确认了实际代码的大小
// Open/Create the BINFS partition where images are stored. This partition starts immediately after the MBR on the Boot Media and its length is
// determined by the maximum image size (or sum of all maximum sizes in a multi-region design).
// Parameters are LOGICAL sectors.
hPart = BP_OpenPartition( PAGES_PER_BLOCK, //logic 0 is 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 )
{
EdbgOutputDebugString("ERROR: WriteRegionsToBootMedia: Failed to open/create BINFS partition./r/n");
return(FALSE);
}
// Are there multiple BIN files in RAM (we may just be updating one in a multi-BIN solution)?
for (nCount = 0, dwStoreOffset = 0; nCount < g_BINRegionInfo.dwNumRegions ; nCount++)
{
DWORD dwRegionStart= (DWORD)OEMMapMemAddr(0, g_BINRegionInfo.Region[nCount].dwRegionStart);
DWORD dwRegionLength = g_BINRegionInfo.Region[nCount].dwRegionLength;
// Media byte offset where image region is stored.
dwStoreOffset += nCount ? dwMaxRegionLength[nCount-1] : 0;
//计算偏移
// Set the file pointer (byte indexing) to the correct offset for this particular region.
if ( !BP_SetDataPointer(hPart, dwStoreOffset) )
{
EdbgOutputDebugString("ERROR: StoreImageToBootMedia: Failed to set data pointer in BINFS partition (offset=0x%x)./r/n", dwStoreOffset);
return(FALSE);
}//设置补偿
// Write the region to the BINFS partition.
if ( !BP_WriteData(hPart, (LPBYTE)dwRegionStart, dwRegionLength) )
{
EdbgOutputDebugString("ERROR: StoreImageToBootMedia: Failed to write region to BINFS partition (start=0x%x, length=0x%x)./r/n", dwRegionStart, dwRegionLength);
return(FALSE);
}//将镜像文件写入FLASH
// update our TOC?
if ((g_pTOC->id[g_dwTocEntry].dwLoadAddress == g_BINRegionInfo.Region[nCount].dwRegionStart) &&
g_pTOC->id[g_dwTocEntry].dwTtlSectors == FILE_TO_SECTOR_SIZE(dwRegionLength) )
{//这个条件在打算写入FLASH前给定的
g_pTOC->id[g_dwTocEntry].dwStoreOffset = dwStoreOffset;
g_pTOC->id[g_dwTocEntry].dwJumpAddress = 0; // Filled upon return to OEMLaunch
//这个跳转地址在之后写入TOC的时候还会更新,这样做是为了这个函数调用的通用性
g_pTOC->id[g_dwTocEntry].dwImageType = g_ImageType;
g_pTOC->id[g_dwTocEntry].sgList[0].dwSector = FILE_TO_SECTOR_SIZE(g_dwLastWrittenLoc);
g_pTOC->id[g_dwTocEntry].sgList[0].dwLength = g_pTOC->id[g_dwTocEntry].dwTtlSectors;
// copy Kernel Region to SDRAM for jump
memcpy((void*)g_pTOC->id[g_dwTocEntry].dwLoadAddress, (void*)dwRegionStart, dwRegionLength);//拷贝镜像到下载地址
EdbgOutputDebugString("Updateded TOC!/r/n");
}
else if( (dwChainStart == g_BINRegionInfo.Region[nCount].dwRegionStart) &&
(dwChainLength == g_BINRegionInfo.Region[nCount].dwRegionLength))
{
// Update our TOC for Chain region
g_pTOC->chainInfo.dwLoadAddress = dwChainStart;
g_pTOC->chainInfo.dwFlashAddress = FILE_TO_SECTOR_SIZE(g_dwLastWrittenLoc);
g_pTOC->chainInfo.dwLength = FILE_TO_SECTOR_SIZE(dwMaxRegionLength[nCount]);
EdbgOutputDebugString("Written Chain Region to the Flash/n");
EdbgOutputDebugString("LoadAddress = 0x%X; FlashAddress = 0x%X; Length = 0x%X/n",
g_pTOC->chainInfo.dwLoadAddress,
g_pTOC->chainInfo.dwFlashAddress,
g_pTOC->chainInfo.dwLength);
// Now copy it to the SDRAM
memcpy((void *)g_pTOC->chainInfo.dwLoadAddress, (void *)dwRegionStart, dwRegionLength);
// memcpy((void *)0x8c050000, (void *)dwRegionStart, dwRegionLength);
}
}
// create extended partition in whatever is left
//
hPartEx = BP_OpenPartition( NEXT_FREE_LOC,
USE_REMAINING_SPACE,
PART_DOS32,
TRUE,
PART_OPEN_ALWAYS);
if (hPartEx == INVALID_HANDLE_VALUE )
{
EdbgOutputDebugString("*** WARN: StoreImageToBootMedia: Failed to open/create Extended partition ***/r/n");
}
//创建剩下的FLASH为FAT格式
EdbgOutputDebugString("-WriteRegionsToBootMedia/r/n");
return(TRUE);
}
之后就是再提一下BP_WriteData()函数,它与BP_ReadData()类似,主要是对如果不对齐block的情况进行处理。我将主要代码搬过来看看就可以了:
DWORD dwBlock = Log2Phys (pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector + pPartState->pPartEntry->Part_StartSector) / g_FlashInfo.wSectorsPerBlock;//块地址
DWORD dwOffsetBlock = (pPartState->dwDataPointer + pPartState->pPartEntry->Part_StartSector * g_FlashInfo.wDataBytesPerSector) % g_dwDataBytesPerBlock;//块偏移
// Update the global indicating last written physical address. Global variable is used by the caller.
g_dwLastWrittenLoc = dwBlock * g_dwDataBytesPerBlock + dwOffsetBlock;
// If current pointer is not on a block boundary, copy bytes up to the first block boundary
if (dwOffsetBlock)
{
if (!ReadBlock(dwBlock, g_pbBlock, g_pSectorInfoBuf)) {
RETAILMSG (1, (TEXT("WriteData: failed to read block (0x%x)./r/n"), dwBlock));
return(FALSE);
}
DWORD dwNumBytesWrite = g_dwDataBytesPerBlock - dwOffsetBlock;
if (dwNumBytesWrite > dwLength)
dwNumBytesWrite = dwLength;
memcpy(g_pbBlock + dwOffsetBlock, pbBuffer, dwNumBytesWrite);
if (!FMD_EraseBlock(dwBlock)) {
RETAILMSG (1, (TEXT("WriteData: failed to erase block (0x%x)./r/n"), dwBlock));
return FALSE;
}
if (!WriteBlock(dwBlock, g_pbBlock, g_pSectorInfoBuf)) {
RETAILMSG (1, (TEXT("WriteData: failed to write block (0x%x)./r/n"), dwBlock));
return(FALSE);
}
dwLength -= dwNumBytesWrite;
pbBuffer += dwNumBytesWrite;
dwBlock++;
}
//这块对镜像写入的前端处理
// Compute number of blocks.
dwNumBlocks = (dwLength / g_dwDataBytesPerBlock);
while (dwNumBlocks--)
{
// 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(dwBlock))
{
++dwBlock;
++dwNumBlocks; // Compensate for fact that we didn't write any blocks.
continue;
}
if (!ReadBlock(dwBlock, NULL, g_pSectorInfoBuf)) {
RETAILMSG (1, (TEXT("WriteData: failed to read block (0x%x)./r/n"), dwBlock));
return(FALSE);
}
if (!FMD_EraseBlock(dwBlock)) {
RETAILMSG (1, (TEXT("WriteData: failed to erase block (0x%x)./r/n"), dwBlock));
return FALSE;
}
if (!WriteBlock(dwBlock, pbBuffer, g_pSectorInfoBuf)) {
RETAILMSG (1, (TEXT("WriteData: failed to write block (0x%x)./r/n"), dwBlock));
return(FALSE);
}
++dwBlock;
pbBuffer += g_dwDataBytesPerBlock;
}
//处理成块的镜像文件
DWORD dwNumExtraBytes = (dwLength % g_dwDataBytesPerBlock);
if (dwNumExtraBytes)
{
// Skip bad blocks
while (IS_BLOCK_UNUSABLE(dwBlock))
{
dwBlock++;
if (dwBlock >= g_FlashInfo.dwNumBlocks)
{
// This should never happen since partition has already been created
RETAILMSG (1, (TEXT("WriteData: corrupt partition. Reformat flash./r/n")));
return FALSE;
}
}
if (!ReadBlock(dwBlock, g_pbBlock, g_pSectorInfoBuf)) {
RETAILMSG (1, (TEXT("WriteData: failed to read block (0x%x)./r/n"), dwBlock));
return(FALSE);
}
memcpy(g_pbBlock, pbBuffer, dwNumExtraBytes);
if (!FMD_EraseBlock(dwBlock)) {
RETAILMSG (1, (TEXT("WriteData: failed to erase block (0x%x)./r/n"), dwBlock));
return FALSE;
}
if (!WriteBlock(dwBlock, g_pbBlock, g_pSectorInfoBuf)) {
RETAILMSG (1, (TEXT("WriteData: failed to write block (0x%x)./r/n"), dwBlock));
return(FALSE);
}
}
//镜像后端处理
pPartState->dwDataPointer = dwNextPtrValue;
return(TRUE);
到这基本的磁盘方面的东西就介绍完了,最后就提一下MBR实际是在低格的时候创建的,而且其block位置也在低格的时候确定,而与分区的地址没有关系。所以分区的地址应该是镜像文件的开始地址,而在读取镜像文件的时候MBR也是通过搜索找到的,而与镜像地址没关系。从这里你也可以发现实际MBR的BLOCK地址前不能有完好并且未使用的block,不然这个块会被处理为MBR的。这个大家注意一下就好了。(EBOOT分析结束)如果有不清楚的可以联系我:mail : gsujianwen@163.com