// If there isn't a SmartMedia card in the system, it'll be kind of hard to write an image to it...
//
if (!g_bSmartMediaExist)
{
EdbgOutputDebugString("WARNING: Smart Media device doesn't exist - unable to store image.\r\n");
return(FALSE);
}
// Format the SmartMedia card prior to writing.
//
EdbgOutputDebugString("INFO: Formatting SmartMedia (please wait)...\r\n");
if (!FormatSmartMedia())
{
EdbgOutputDebugString("ERROR: Failed to format SmartMedia.\r\n");
return(FALSE);
}
EdbgOutputDebugString("INFO: Writing download image to SmartMedia (please wait)...\r\n");
// Get NAND flash info.
//
if (!FMD_GetInfo(&FlashInfo))
{
EdbgOutputDebugString("ERROR: Unable to get SmartMedia flash information.\r\n");
return(FALSE);
}
uSectorSize = FlashInfo.wDataBytesPerSector;
ulBlockSize = FlashInfo.dwBytesPerBlock;
ulSectorsPerBlock = (ulBlockSize / uSectorSize);
// Write the image to NAND flash (starting at sector 0, skipping bad blocks).
//
// NOTE: we're going to assume that the image being written to SmartMedia has been generated
// by the disk image utility. As such, the first two flash blocks are reserved for the Steppingstone
// loader and the IPL. We'll mark these sectors reserved and start the logical sector numbering at
// 0 on the following sector. This shouldn't affect our ability to store/load a single NK solution
// since the logical sector numbering and the reserved status won't matter to the ReadImageFromSmartMedia
// routine (below).
//
ulImageLengthSectors = (dwImageLength / (uSectorSize + sizeof(SectorInfo)));
for (ulLogicalSector = 0, ulBadBlocks = 0, MACCount = 0; ulLogicalSector < ulImageLengthSectors ; ulLogicalSector++)
{
// Compute the physical sector address (equal to logical sector address plus compensation for any bad blocks).
UINT32 ulPhysicalSector = ((ulBadBlocks * ulSectorsPerBlock) + ulLogicalSector);
UINT32 ulBlockNumber = (ulPhysicalSector / ulSectorsPerBlock);
// If we're writing the first sector of a new block and the block is marked bad, skip the whole block.
while (!(ulPhysicalSector % ulSectorsPerBlock) && (FMD_GetBlockStatus(ulBlockNumber) == BLOCK_STATUS_BAD))
{
ulBadBlocks++;
// Recompute the sector and block numbers based on bad blocks.
ulPhysicalSector += ulSectorsPerBlock;
ulBlockNumber++;
}
// Have we walked off the end of flash?
if (ulPhysicalSector > (FlashInfo.dwNumBlocks * ulSectorsPerBlock))
{
EdbgOutputDebugString("ERROR: SmartMedia sector write would be out of bounds (physical sector = 0x%x max sector = 0x%x).\r\n", ulPhysicalSector, (FlashInfo.dwNumBlocks * ulSectorsPerBlock));
return(FALSE);
}
// update the buffer to the current sector
pBuffer = (BYTE *)(dwImageStart + (ulLogicalSector * (uSectorSize + sizeof(SectorInfo))));
// sector info immediately follows the current sector
pSectInfo = (SectorInfo *) (pBuffer + uSectorSize);
// For NAND-only boots, the NOR flash at nGCS0 isn't available for retrieving the CS8900A MAC
// address (nor is there a EEPROM connected to the CS8900A where we could store this address).
// We'll use the logical sector field for the first couple reserved block sectors to store
// the address.
//
if ((MACCount < 3) && !(pSectInfo->bOEMReserved & OEM_BLOCK_RESERVED))
{
pSectInfo->dwReserved1 = pBootCfg->CS8900MAC[MACCount++];
}
// Write the sector to flash...
//
if (!FMD_WriteSector(ulPhysicalSector, pBuffer, pSectInfo, 1))
{
EdbgOutputDebugString("ERROR: Failed to write to SmartMedia (sector number 0x%x).\r\n", ulPhysicalSector);
return(FALSE);
}
}
EdbgOutputDebugString("INFO: Writing image to SmartMedia completed successfully.\r\n");
return(TRUE);
// 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) && !pChainInfo ; nCount++)
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");
// 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.dwRegionStart == (DWORD)((pChainInfo + nCount)->pvAddr) ) {
dwMaxRegionLength = (pChainInfo + nCount)->dwMaxLength;
EdbgOutputDebugString("dwMaxRegionLength[%u]: 0x%x \r\n", i, dwMaxRegionLength);
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( NEXT_FREE_LOC,
FILE_TO_SECTOR_SIZE(dwBINFSPartLength) + 1, // sizeof image + MBR sector
PART_BINFS,
TRUE,
PART_OPEN_ALWAYS);
*/
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 )
{
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);
// 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);
}
// 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) )
{
g_pTOC->id[g_dwTocEntry].dwStoreOffset = dwStoreOffset;
g_pTOC->id[g_dwTocEntry].dwJumpAddress = 0; // Filled upon return to OEMLaunch