📄 blcommon.c
字号:
HALT (BLERR_MAGIC);
return (FALSE);
}
// Continue with download of next file
// +1 to account for the manifest
g_downloadFilesRemaining = (BYTE)(g_DownloadManifest.dwNumRegions + 1);
continue;
#ifdef SECURE_BOOTLOADER
case BL_IMAGE_TYPE_BIN:
KITLOutputDebugString("\r\n**\r\n");
KITLOutputDebugString("** ERROR: This boot loader does not support unsigned .bin images.\r\n");
KITLOutputDebugString("** Image must be signed with a recognized private key.\r\n");
KITLOutputDebugString("**\r\n");
HALT (BLERR_SIGNATURE);
return (FALSE);
case BL_IMAGE_TYPE_SIGNED_BIN:
rval &= DownloadSignedBin( pdwImageStart, pdwImageLength, pdwLaunchAddr );
break;
case BL_IMAGE_TYPE_SIGNED_NB0:
rval &= DownloadSignedNB0( pdwImageStart, pdwImageLength, pdwLaunchAddr );
break;
#else // not SECURE_BOOTLOADER
case BL_IMAGE_TYPE_BIN:
rval &= DownloadBin( pdwImageStart, pdwImageLength, pdwLaunchAddr );
break;
case BL_IMAGE_TYPE_SIGNED_BIN:
KITLOutputDebugString("\r\n**\r\n");
KITLOutputDebugString("** ERROR: This boot loader does not support signed .bin images.\r\n");
KITLOutputDebugString("**\r\n");
HALT (BLERR_SIGNATURE);
return (FALSE);
case BL_IMAGE_TYPE_SIGNED_NB0:
KITLOutputDebugString("\r\n**\r\n");
KITLOutputDebugString("** ERROR: This boot loader does not support signed .nb0 images.\r\n");
KITLOutputDebugString("**\r\n");
HALT (BLERR_SIGNATURE);
return (FALSE);
#endif // SECURE_BOOTLOADER
case BL_IMAGE_TYPE_MULTIXIP:
KITLOutputDebugString("\r\n**\r\n");
KITLOutputDebugString("** ERROR: The X000FF packet is an old-style multi-bin download manifest and it's no longer supported.\r\n");
KITLOutputDebugString("** Please update your Platform Builder installation in you want to download multiple files.\r\n");
KITLOutputDebugString("**\r\n");
HALT (BLERR_MAGIC);
return (FALSE);
case BL_IMAGE_TYPE_UNKNOWN:
#ifdef SECURE_BOOTLOADER
KITLOutputDebugString("\r\n**\r\n");
KITLOutputDebugString("** ERROR: Unrecognized image type (possibly unsigned .nb0).\r\n");
KITLOutputDebugString("** This boot loader does not support unsigned images.\r\n");
KITLOutputDebugString("** Image must be signed with a recognized private key.\r\n");
KITLOutputDebugString("**\r\n");
HALT (BLERR_MAGIC);
return (FALSE);
#else
// Assume files without a "type" header (e.g. raw data) are unsigned .nb0
rval &= DownloadNB0( pdwImageStart, pdwImageLength, pdwLaunchAddr );
break;
#endif
default:
// should never get here
return (FALSE);
}
}
while (--g_downloadFilesRemaining);
ComputeChecksum();
rval &= WriteImageToFlash();
return rval;
}
#ifdef SECURE_BOOTLOADER
static BOOL InitSecureBootLoader()
{
// Initialize public keys for signature validation
g_keyData.rgpbPublicKeys = g_rgpbPublicKeys; // pointer to array of public keys
g_keyData.rgdwKeyLengths = g_rgdwKeyLengths; // pointer to array of public key lengths
g_keyData.wNumPublicKeys = g_wNumPublicKeys; // number of public keys in rgpbPublicKeys
g_keyData.wMinSearchIndex = 0; // starting array index of search
g_keyData.wMaxSearchIndex = g_wNumPublicKeys - 1; // ending array index of search
KITLOutputDebugString("Secure Boot Loader includes %d public keys\r\n",
g_keyData.wNumPublicKeys);
return TRUE;
}
#endif
#ifdef SECURE_BOOTLOADER
static BOOL DownloadSignedBin (LPDWORD pdwImageStart, LPDWORD pdwImageLength, LPDWORD pdwLaunchAddr)
{
RegionInfo *pCurDownloadFile;
BOOL fIsFlash = FALSE;
LPBYTE lpDest = NULL;
DWORD dwImageStart, dwImageLength;
DWORD dwSignedDataLength, dwSigLength;
BYTE bFlags;
DWORD dwRecNum = 0;
DWORD dwRecAddr, dwRecLen, dwRecChk;
DWORD dwPacketNum = 1;
DWORD dwChunksRemaining = 0;
DWORD dwChunkOffset = 0;
HRESULT hr;
PACKETDATA packetData;
g_bBINDownload = TRUE;
if (!OEMReadData (sizeof (DWORD), (LPBYTE) &dwImageStart) ||
!OEMReadData (sizeof (DWORD), (LPBYTE) &dwImageLength))
{
KITLOutputDebugString ("Unable to read image start/length\r\n");
HALT (BLERR_MAGIC);
return (FALSE);
}
// If Platform Builder didn't provide a manifest (i.e., we're
// only downloading a single .bin file), manufacture a manifest so we
// can notify the OEM.
//
if (!g_DownloadManifest.dwNumRegions)
{
g_DownloadManifest.dwNumRegions = 1;
g_DownloadManifest.Region[0].dwRegionStart = dwImageStart;
g_DownloadManifest.Region[0].dwRegionLength = dwImageLength;
}
// Provide the download manifest to the OEM.
//
if (!g_fOEMNotified && g_pOEMMultiBINNotify)
{
g_pOEMMultiBINNotify((PDownloadManifest)&g_DownloadManifest);
g_fOEMNotified = TRUE;
}
// Locate the current download manifest entry (current download file).
//
pCurDownloadFile = &g_DownloadManifest.Region[g_DownloadManifest.dwNumRegions - g_downloadFilesRemaining];
// give the OEM a chance to verify memory
if (g_pOEMVerifyMemory && !g_pOEMVerifyMemory (pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionLength))
{
KITLOutputDebugString ("!OEMVERIFYMEMORY: Invalid image\r\n");
HALT (BLERR_OEMVERIFY);
return (FALSE);
}
#ifdef DEBUG
// Clearing memory ensures no garbage between sparse .bin records, so that
// our post-download checksum will be accurate.
memset( (LPVOID) OEMMapMemAddr(pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionStart),
0, pCurDownloadFile->dwRegionLength );
#endif
// Check for flash image. Start erasing if it is.
// This is risky iff:
// We're downloading the bootloader
// OEM has implemented OEMStartEraseFlash()/OEMContinueEraseFlash()
// Download fails (e.g. image has been tampered with)
//
// In this scenario only, the device will be unbootable and require
// JTAG recovery.
//
// The OEM should implement the flash functions to skip erase if the image
// is a bootloader (i.e. defer erase until OEMFinishEraseFlash()).
// That prevents bricking the device.
//
// It's safe to erase flash and/or flush RAM to flash when download the OS.
// In fact this improves download speed, and lets you download images
// much larger than available RAM.
if ((fIsFlash = OEMIsFlashAddr (pCurDownloadFile->dwRegionStart))
&& !OEMStartEraseFlash (pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionLength))
{
KITLOutputDebugString ("Invalid flash address/length\r\n");
HALT (BLERR_FLASHADDR);
return (FALSE);
}
//------------------------------------------------------------------------
// Signed files are prefixed with a 16-byte random seed, which
// is included in the hash.
//------------------------------------------------------------------------
if (!OEMReadData (RANDOM_SEED_LENGTH, (LPBYTE) &packetData.bRandomSeed))
{
KITLOutputDebugString ("ERROR: Failed to read random seed at start of signed .bin file\r\n");
HALT (BLERR_MAGIC);
return (FALSE);
}
//------------------------------------------------------------------------
// Download signed packets (.bin records or record chunks)
//------------------------------------------------------------------------
while ( OEMReadData (sizeof (DWORD), (LPBYTE) &dwSignedDataLength) &&
OEMReadData (sizeof (DWORD), (LPBYTE) &dwSigLength) &&
OEMReadData (sizeof (BYTE), (LPBYTE) &bFlags) )
{
#ifdef DEBUG
KITLOutputDebugString("\r\n------------------------------------------------------------------------------\r\n");
KITLOutputDebugString(" <> Packet [ %d ] dwSignedDataLength = 0x%x, dwSigLen = 0x%x, bFlags = 0x%x\r\n",
dwPacketNum, dwSignedDataLength, dwSigLength, bFlags);
#endif
// Check if what we just read was a chunk header instead of a
// signed packet header.
//
// If a .bin record is larger than the <packet size> parameter to
// ImageHash.exe, it will be broken into multiple chunks.
//
// This theoretically allows download of .bin records that are larger
// than the bootloader's available RAM. However BLCommon doesn't
// implement that. The OEM can do it by creatively using
// OEMMapMemAddr() and OEMContinueEraseFlash() to periodically flush
// the RAM buffer to flash.
if (bFlags & SBL_FLAG_CHUNK_HEADER)
{
// It's a chunk header; we must reinterpret the data we just read:
//
// field 0: ignore (always zero for a chunk header)
// field 1: dwChunksRemaining (multiple chunks = one .bin record)
// field 2: bFlags (no change)
dwChunksRemaining = dwSigLength;
dwChunkOffset = 0;
#ifdef DEBUG
KITLOutputDebugString(" <> Record chunk (dwChunksRemaining = %d)\r\n", dwChunksRemaining);
#endif
// Read the signed packet header
if ( !(OEMReadData (sizeof (DWORD), (LPBYTE) &dwSignedDataLength) &&
OEMReadData (sizeof (DWORD), (LPBYTE) &dwSigLength) &&
OEMReadData (sizeof (BYTE), (LPBYTE) &bFlags)))
{
KITLOutputDebugString ("ERROR: Failed to read signed packet header %d, ABORT!\r\n", dwPacketNum);
HALT (BLERR_CORRUPTED_DATA);
return (FALSE);
}
#ifdef DEBUG
KITLOutputDebugString(" <> Packet [ %d ] dwSignedDataLength = 0x%x, dwSigLen = 0x%x, bFlags = 0x%x\r\n",
dwPacketNum, dwSignedDataLength, dwSigLength, bFlags);
#endif
}
// Read the .bin record header
if ( !(OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecAddr) &&
OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecLen) &&
OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecChk)) )
{
KITLOutputDebugString ("ERROR: Failed to read .bin record header %d, ABORT!\r\n", dwPacketNum);
HALT (BLERR_CORRUPTED_DATA);
return (FALSE);
}
#ifdef DEBUG
KITLOutputDebugString(" <> Record [ %d ] dwRecAddr = 0x%x, dwRecLen = 0x%x, dwRecChk = 0x%x\r\n",
dwRecNum, dwRecAddr, dwRecLen, dwRecChk);
#endif
if (bFlags & SBL_FLAG_END_FILE)
{
// last packet always has unused signature block, read it!
ASSERT(dwSignedDataLength == 0);
ASSERT(dwSigLength <= sizeof(g_rgpbSignature));
OEMReadData(dwSigLength, (LPBYTE) &g_rgpbSignature);
KITLOutputDebugString("Reached last record of signed .bin file\r\n");
break;
}
// map the record address (FLASH data is cached, for example)
// add offset if this is a record chunk
lpDest = OEMMapMemAddr (pCurDownloadFile->dwRegionStart, dwRecAddr + dwChunkOffset);
// read record (or record chunk)
if (!OEMReadData (dwSignedDataLength, lpDest))
{
KITLOutputDebugString ("ERROR: Data packet %d corrupted, ABORT!\r\n", dwPacketNum);
HALT (BLERR_CORRUPTED_DATA);
return (FALSE);
}
#ifdef DEBUG
else
{
KITLOutputDebugString ("Read 0x%x bytes into cache: 0x%x (final address: 0x%x)\r\n",
dwSignedDataLength,
lpDest,
dwRecAddr + dwChunkOffset);
DumpMem( lpDest, 64 );
}
#endif
// Check for last chunk in a fragmented .bin record
if (0 != dwChunksRemaining)
{
if (--dwChunksRemaining > 0)
{
dwChunkOffset += dwSignedDataLength;
}
else
{
dwChunkOffset = 0;
}
#ifdef DEBUG
KITLOutputDebugString("dwChunksRemaining = %d, offset = 0x%x\r\n",
dwChunksRemaining, dwChunkOffset);
#endif
}
if (0 == dwChunksRemaining)
{
LPBYTE cacheAddress = OEMMapMemAddr (pCurDownloadFile->dwRegionStart, dwRecAddr);
// The packet signature makes this redundant, but we check anyway.
if (!VerifyChecksum (dwRecLen, cacheAddress, dwRecChk))
{
HALT (BLERR_CHECKSUM);
return (FALSE);
}
dwRecNum++;
}
// Look for ROMHDR to compute ROM offset. NOTE: romimage guarantees that the record containing
// the TOC signature and pointer will always come before the record that contains the ROMHDR contents.
//
if (dwRecLen == sizeof(ROMHDR) && (*(LPDWORD) OEMMapMemAddr(pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE))
{
DWORD dwTempOffset = (dwRecAddr - *(LPDWORD)OEMMapMemAddr(pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionStart + ROM_SIGNATURE_OFFSET + sizeof(ULONG)));
ROMHDR *pROMHdr = (ROMHDR *)lpDest;
// Check to make sure this record really contains the ROMHDR.
//
if ((pROMHdr->physfirst == (pCurDownloadFile->dwRegionStart - dwTempOffset)) &&
(pROMHdr->physlast == (pCurDownloadFile->dwRegionStart - dwTempOffset + pCurDownloadFile->dwRegionLength)) &&
(DWORD)(HIWORD(pROMHdr->dllfirst << 16) <= pROMHdr->dlllast) &&
(DWORD)(LOWORD(pROMHdr->dllfirst << 16) <= pROMHdr->dlllast))
{
g_dwROMOffset = dwTempOffset;
KITLOutputDebugString("rom_offset=0x%x.\r\n", g_dwROMOffset);
}
}
// read packet signature
ASSERT(dwSigLength <= sizeof(g_rgpbSignature));
if (!OEMReadData (dwSigLength, (LPBYTE) &g_rgpbSignature))
{
KITLOutputDebugString ("ERROR: Failed to read signature for packet %d, ABORT!\r\n", dwPacketNum);
HALT (BLERR_SIGNATURE);
return (FALSE);
}
//------------------------------------------------------------------------
// Validate signature for this record or chunk
//------------------------------------------------------------------------
packetData.pbData = lpDest; // data to verify
packetData.dwDataLength = dwSignedDataLength; // length of data in bytes
packetData.pbSig = g_rgpbSignature; // signature to verify
packetData.dwSigLength = dwSigLength; // length of signature in bytes
packetData.dwRecAddress = dwRecAddr; // record address
packetData.dwRecLength = dwRecLen; // record length
packetData.dwRecCheck = dwRecChk; // record checksum
packetData.dwSequenceNumber = dwPacketNum; // packet sequence number
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -