📄 fmd.cpp
字号:
Returns: None.
------------------------------------------------------------------------------*/
VOID FMD_PowerUp(VOID)
{
return;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_PowerDown()
Description: Suspends power to the Flash memory device (if applicable).
Returns: None.
------------------------------------------------------------------------------*/
VOID FMD_PowerDown(VOID)
{
return;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_OEMIoControl()
Description: Implements user-defined (a.k.a. application specific) commands
for the Flash memory device
Returns: None.
------------------------------------------------------------------------------*/
BOOL FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize,
PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
{
switch(dwIoControlCode)
{
case IOCTL_FMD_GET_INTERFACE:
{
if (!pOutBuf || nOutBufSize < sizeof(FMDInterface))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE bad parameter(s).\r\n")));
return(FALSE);
}
PFMDInterface pInterface = (PFMDInterface)pOutBuf;
pInterface->cbSize = sizeof(FMDInterface);
pInterface->pInit = FMD_Init;
pInterface->pDeInit = FMD_Deinit;
pInterface->pGetInfo = FMD_GetInfo;
pInterface->pGetBlockStatus = FMD_GetBlockStatus;
pInterface->pSetBlockStatus = FMD_SetBlockStatus;
pInterface->pReadSector = FMD_ReadSector;
pInterface->pWriteSector = FMD_WriteSector;
pInterface->pEraseBlock = FMD_EraseBlock;
pInterface->pPowerUp = FMD_PowerUp;
pInterface->pPowerDown = FMD_PowerDown;
pInterface->pGetPhysSectorAddr = FMD_GetPhysSectorAddr;
break;
}
case IOCTL_FMD_SET_XIPMODE:
// Select between XIP mode or non-XIP mode. The difference from the FMD's standpoint is whether or not
// sector information is stored along with each sector. This should be called before FMD_Init.
if (!pInBuf || nInBufSize < sizeof(BOOLEAN))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_SET_XIPMODE bad parameter(s).\r\n")));
return(FALSE);
}
g_bXIPEntire = *(PBOOLEAN)pInBuf;
break;
case IOCTL_FMD_GET_XIPMODE:
if (!pOutBuf || nOutBufSize < sizeof(BOOLEAN))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_XIPMODE bad parameter(s).\r\n")));
return(FALSE);
}
*(PBOOLEAN)pOutBuf = g_bXIPEntire;
break;
case IOCTL_FMD_LOCK_BLOCKS:
// Lock one of more blocks in a specified range.
if (!pInBuf || nInBufSize < sizeof(BlockLockInfo))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_LOCK_BLOCKS bad parameter(s).\r\n")));
return(FALSE);
}
if (!SetBlockLock(((PBlockLockInfo)pInBuf)->StartBlock, ((PBlockLockInfo)pInBuf)->NumBlocks, TRUE))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_LOCK_BLOCKS failed to lock blocks (start=0x%x, number=0x%x).\r\n"), ((PBlockLockInfo)pInBuf)->StartBlock, ((PBlockLockInfo)pInBuf)->NumBlocks));
return(FALSE);
}
break;
case IOCTL_FMD_UNLOCK_BLOCKS:
// Unlock one of more blocks in a specified range.
if (!pInBuf || nInBufSize < sizeof(BlockLockInfo))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_UNLOCK_BLOCKS bad parameter(s).\r\n")));
return(FALSE);
}
if (!SetBlockLock(((PBlockLockInfo)pInBuf)->StartBlock, ((PBlockLockInfo)pInBuf)->NumBlocks, FALSE))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_UNLOCK_BLOCKS failed to unlock blocks (start=0x%x, number=0x%x).\r\n"), ((PBlockLockInfo)pInBuf)->StartBlock, ((PBlockLockInfo)pInBuf)->NumBlocks));
return(FALSE);
}
break;
default:
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: unrecognized IOCTL (0x%x).\r\n"), dwIoControlCode));
return(FALSE);
}
return(TRUE);
}
VOID DefineLayout()
{
if (!g_FMDInfo.SectorSize)
g_FMDInfo.SectorSize = SECTOR_SIZE;
if (!g_bXIPEntire) // Not XIP mode.
{
g_FMDInfo.SectorsPerBlock = g_FMDInfo.BlockSize / (g_FMDInfo.SectorSize + sizeof(SectorInfo));
g_FMDInfo.SectorInfoOffset = g_FMDInfo.SectorsPerBlock * g_FMDInfo.SectorSize;
// Assert there is enough room for a signiture gc_dwFlashSignature at the end
// of the block. If not, the signiture should be modified by the OEM
ASSERT (g_FMDInfo.BlockSize % (g_FMDInfo.SectorSize + sizeof(SectorInfo)) >= BLOCK_SIG_BYTES);
}
else // XIP mode.
{
g_FMDInfo.SectorsPerBlock = g_FMDInfo.BlockSize / g_FMDInfo.SectorSize;
g_FMDInfo.SectorInfoOffset = 0;
}
}
BOOLEAN InitializeFlash(volatile ULONG* pBaseAddress, ULONG FlashLength)
{
UCHAR nCount = 0;
ASSERT(pBaseAddress);
ASSERT(FlashLength);
if (!pBaseAddress || !FlashLength)
return(FALSE);
if (!g_dwWriteBufferSize || !g_FMDInfo.BlockSize)
{
// Assume the flash part is an Intel Strataflash - first check the manufacturer code.
//
//dcv g_bPairedFlash = TRUE; // Assume flash is paired.
WRITE_COMMAND(pBaseAddress, READ_IDENT_CMD);
if (!CHECK_STATUS_INDEXED(pBaseAddress, QS_MFGCODE_OFFSET, MFGCODE_INTEL))
{
g_bPairedFlash = FALSE; // Maybe it's not paired?
WRITE_COMMAND(pBaseAddress, READ_IDENT_CMD);
if (!CHECK_STATUS_INDEXED(pBaseAddress, QS_MFGCODE_OFFSET, MFGCODE_INTEL))
{
// This isn't an Intel flash part.
DEBUGMSG(1, (TEXT("ERROR: InitializeFlash: invalid manufacturing code.\r\n")));
return(FALSE);
}
}
// Look for a Common Flash Interface (CFI).
//
WRITE_COMMAND(pBaseAddress, READ_QUERY_CMD);
if (!CHECK_STATUS_INDEXED(pBaseAddress, QS_IDSTRING_OFFSET, IDSTRING_Q) ||
!CHECK_STATUS_INDEXED(pBaseAddress, QS_IDSTRING_OFFSET + 1, IDSTRING_R) ||
!CHECK_STATUS_INDEXED(pBaseAddress, QS_IDSTRING_OFFSET + 2, IDSTRING_Y))
{
// This flash doesn't support CFI, so it's not a Strataflash.
DEBUGMSG(1, (TEXT("ERROR: InitializeFlash: didn't find StrataFlash CFI.\r\n")));
return(FALSE);
}
// We're pretty sure this is an Intel Strataflash part at this point - use the CFI to
// collect information on it (we're still in query mode). Also, we'll assume that both
// high and low word flash parts are the same from here on out (if paired).
//
for (nCount = 0 ; nCount < sizeof(FLASH_SYSINTERFACE_INFO) ; nCount++)
{
*((PUCHAR)&g_FMDInfo.SysInt + nCount) = (UCHAR)(READ_FLASH_INDEXED(pBaseAddress, QS_SYSINTF_OFFSET + nCount) & 0xFF);
}
for (nCount = 0 ; nCount < sizeof(FLASH_GEOMETRY_INFO) ; nCount++)
{
*((PUCHAR)&g_FMDInfo.Geometry + nCount) = (UCHAR)(READ_FLASH_INDEXED(pBaseAddress, QS_DEVGEOM_OFFSET + nCount) & 0xFF);
}
// The block erase code assumes a single block per erase region - check for that here...
//
if (g_FMDInfo.Geometry.NumEraseBlocks != 1)
{
DEBUGMSG(1, (TEXT("ERROR: InitializeFlash: more than one block per erase region (%d).\r\n"), g_FMDInfo.Geometry.NumEraseBlocks));
return(FALSE);
}
// Compute block size and the total number of blocks here. Since we know an erase region contains
// only one block, the erase region size is equal to the block size.
// Note that the flash block size is 128KB, if paired, we have two of the 16-bit parts and the block size is effectively 256KB.
g_FMDInfo.BlockSize = (g_FMDInfo.Geometry.EraseRegionSize * REGION_SIZE_MULT);
if (g_bPairedFlash)
{
g_FMDInfo.BlockSize *= 2;
}
g_dwWriteBufferSize = g_bPairedFlash ? (1 << g_FMDInfo.Geometry.WriteBuffSize) * 2 : (1 << g_FMDInfo.Geometry.WriteBuffSize);
// Put the Flash into a known state (READ_ARRAY mode with WRITE-ENABLE disabled).
//
WRITE_COMMAND(pBaseAddress, READ_ARRAY_CMD);
}
// In order for all the math to work out later, we require that the flash base address be block-aligned and that the flash length be
// an integral number of blocks.
if (!IS_BLOCK_ALIGNED(pBaseAddress) || !IS_BLOCK_ALIGNED(FlashLength))
{
DEBUGMSG(1, (TEXT("ERROR: InitializeFlash: base address and length must be block-aligned (Base=0x%x, Length=0x%x).\r\n"), (ULONG)pBaseAddress, FlashLength));
return(FALSE);
}
g_FMDInfo.BaseAddress = (ULONG)pBaseAddress;
g_FMDInfo.FlashLength = (ULONG)FlashLength;
// Note that we need to adjust the total available blocks if the caller specified a non-zero flash offset value.
g_FMDInfo.TotalFlashBlocks = (FlashLength / g_FMDInfo.BlockSize);
DefineLayout();
return TRUE;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: CheckStatus()
Description: Checks status of the operation.
Parameters: ulBlockAddress - The block address to write status command to
fLockCmd - TRUE if this is a Set/Clear Lock-Bit command.
Returns: None.
------------------------------------------------------------------------------*/
BOOL CheckStatus(ULONG ulBlockAddress, BOOL fLockCmd)
{
ULONG ulStatus;
ULONG ulCount = 0;
while (!CHECK_STATUS(ulBlockAddress, STATUS_READY_MASK))
{
if ( ulCount++ == CHECK_STATUS_TIMEOUT )
{
DEBUGMSG(1, (TEXT("STRATA Error: Timed out checking status\r\n")));
break;
}
}
ulStatus = READ_FLASH(ulBlockAddress);
if (ulStatus == (ULONG)CREATE_MASK(STATUS_READY_MASK))
{
// Success
return TRUE;
}
//
// Print appropriate error...
//
DWORD dwBlock = (ulBlockAddress - g_FMDInfo.BaseAddress) / g_FMDInfo.BlockSize;
if ((ulStatus & STATUS_ERROR_VOLTAGE) == STATUS_ERROR_VOLTAGE)
DEBUGMSG(1, (TEXT("STRATA Error: Voltage Range Error ... Lower flash.\r\n")));
else if ((ulStatus & STATUS_ERROR_COMMAND) == STATUS_ERROR_COMMAND)
DEBUGMSG(1, (TEXT("STRATA Error: Command Sequence Error ... Lower flash.\r\n")));
else if ((ulStatus & STATUS_ERROR_LOCKED) == STATUS_ERROR_LOCKED)
DEBUGMSG(1, (TEXT("STRATA Error: Block %d locked ... Lower flash.\r\n"), dwBlock));
else if ((ulStatus & STATUS_ERROR_SR5) == STATUS_ERROR_SR5)
{
if (fLockCmd)
DEBUGMSG(1, (TEXT("STRATA Error: Clear Lock Bits Error for Block %d ... Lower flash.\r\n"), dwBlock));
else
DEBUGMSG(1, (TEXT("STRATA Error: Erase Error for Block %d ... Lower flash.\r\n"), dwBlock));
}
else if ((ulStatus & STATUS_ERROR_SR4) == STATUS_ERROR_SR4)
{
if (fLockCmd)
DEBUGMSG(1, (TEXT("STRATA Error: Set Lock Bits Error for Block %d ... Lower flash.\r\n"), dwBlock));
else
DEBUGMSG(1, (TEXT("STRATA Error: Programming Error for Block %d ... Lower flash.\r\n"), dwBlock));
}
if (g_bPairedFlash)
{
if ((ulStatus & UPPER(STATUS_ERROR_VOLTAGE)) == UPPER(STATUS_ERROR_VOLTAGE))
DEBUGMSG(1, (TEXT("STRATA Error: Voltage Range Error ... Upper flash.\r\n")));
else if ((ulStatus & UPPER(STATUS_ERROR_COMMAND)) == UPPER(STATUS_ERROR_COMMAND))
DEBUGMSG(1, (TEXT("STRATA Error: Command Sequence Error ... Upper flash.\r\n")));
else if ((ulStatus & UPPER(STATUS_ERROR_LOCKED)) == UPPER(STATUS_ERROR_LOCKED))
DEBUGMSG(1, (TEXT("STRATA Error: Block %d locked ... Upper flash.\r\n"), dwBlock));
else if ((ulStatus & UPPER(STATUS_ERROR_SR5)) == UPPER(STATUS_ERROR_SR5))
{
if (fLockCmd)
DEBUGMSG(1, (TEXT("STRATA Error: Clear Lock Bits Error for Block %d ... Upper flash.\r\n"), dwBlock));
else
DEBUGMSG(1, (TEXT("STRATA Error: Erase Error for Block %d ... Upper flash.\r\n"), dwBlock));
}
else if ((ulStatus & UPPER(STATUS_ERROR_SR4)) == UPPER(STATUS_ERROR_SR4))
{
if (fLockCmd)
DEBUGMSG(1, (TEXT("STRATA Error: Set Lock Bits Error for Block %d ... Upper flash.\r\n"), dwBlock));
else
DEBUGMSG(1, (TEXT("STRATA Error: Programming Error for Block %d ... Upper flash.\r\n"), dwBlock));
}
}
// Clear the status register
WRITE_COMMAND(ulBlockAddress, CLEAR_STATUS_CMD);
return FALSE;
}
BOOL SignBlock(volatile ULONG ulBlockAddress, PUCHAR pusSignature)
{
if (g_bXIPEntire)
return TRUE;
SECTOR_ADDR ulSignatureStart = BLOCK_SIG_LOC(ulBlockAddress, g_FMDInfo.BlockSize);
DWORD dwBytesWritten = 0;
dwBytesWritten = DoBufferedWrite(ulBlockAddress, ulSignatureStart, pusSignature, BLOCK_SIG_BYTES);
return (dwBytesWritten == BLOCK_SIG_BYTES);
}
BOOL VerifySignatures()
{
if (g_bXIPEntire)
return TRUE;
int iRetVal;
ULONG ulBlockStart = g_FMDInfo.BaseAddress;
for (UINT i = 0; i < g_FMDInfo.TotalFlashBlocks; i++)
{
// compare the signatures
iRetVal = memcmp((void *) BLOCK_SIG_LOC(ulBlockStart, g_FMDInfo.BlockSize),
(void *) gc_dwBlockSig,
BLOCK_SIG_BYTES);
if (iRetVal != 0)
{
DEBUGMSG(1, (TEXT("VerifySignatures: invalid block detected, calling FMD_EraseBlock\r\n")));
if (!FMD_EraseBlock(i))
{
DEBUGMSG(1, (TEXT("VerifySignatures: error in FMD_EraseBlock, bailing\r\n")));
return FALSE;
}
}
// increment to the next block
ulBlockStart += g_FMDInfo.BlockSize;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -