📄 flsnand.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Module Name: FSLNAND.CPP
Abstract: FLASH Media Driver Interface Hook for Windows CE
Notes: The following module defines the FMD Hook interface
used to intercept and filter calls made by the FAL in
to the FMD. This layer handles "Flash Layout Sector"
(FLS) for Image Update builds. It manages flash regions
and reserve regions for NAND flash parts. Provides
GetInfoEx functionality. Supports IOCTLs for reading
and writing reserved regions. Supports IOCTL for writing
raw blocks.
Environment: This lib is likned as a "shim" layer between the FAL
and FMD libs.
-----------------------------------------------------------------------------*/
#include <fmd.h>
#include <fls.h>
// TODO: adjust MAX_PAGE_SIZE accordingly if the media sector size is larger than 2K
#define MAX_PAGE_SIZE 2048
static BYTE g_pFLSBuffer[MAX_PAGE_SIZE];
// Assume there will be no more than 16 reserved regions
#define MAX_RESERVES 16
static ReservedEntry g_pLogicalReservedTable[MAX_RESERVES];
static ReservedEntry g_pPhysReservedTable[MAX_RESERVES];
// Assume there will be no more than 16 regions
#define MAX_REGIONS 16
static FlashRegion g_pRegionTable[MAX_REGIONS];
static FlashInfo g_flashInfo;
static FMDInterface g_hookInterface;
static DWORD g_dwNumRegions;
static DWORD g_dwNumReserved;
// All reserve blocks are at the beginning of flash. This stores the
// starting non-reserved block, as specified in the FLS.
static DWORD g_dwStartNonResBlock;
#define DEFAULT_COMPACTION_BLOCKS 4
#define IsBlockBad(blockID) (BLOCK_STATUS_BAD & g_hookInterface.pGetBlockStatus(blockID))
// Helper funcitons
static inline BOOL LoadFLS();
static BOOL DefineLayout();
static BOOL DefineReserveRegions();
static BOOL ReadWriteReserved (PReservedReq pReq, BOOL fRead);
static BOOL RawWriteBlocks (PRawWriteBlocksReq pReq);
static BOOL WriteBlock (DWORD dwBlock, LPBYTE pBuffer);
// --------------------------------------------------------------------
// --------------------------------------------------------------------
PVOID FLSNAND_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
{
VOID *pFmdInstance;
// init the underlying FMD
pFmdInstance = g_hookInterface.pInit(lpActiveReg, pRegIn, pRegOut);
// attempt to determine flash layout
if (pFmdInstance && !LoadFLS())
{
RETAILMSG (1, (TEXT("FLSNAND_Init: failed to initialize\r\n")));
// failed determining flash layout
g_hookInterface.pDeInit(pFmdInstance);
pFmdInstance = NULL;
}
return pFmdInstance;
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
BOOL FLSNAND_GetInfoEx(PFlashInfoEx pFlashInfoEx, PDWORD pdwNumRegions)
{
if (!LoadFLS())
{
// failed loading the flash layout sector
return FALSE;
}
if (!pdwNumRegions)
{
return FALSE;
}
if (!pFlashInfoEx)
{
// Return required buffer size to caller
*pdwNumRegions = g_dwNumRegions;
return TRUE;
}
if (*pdwNumRegions < g_dwNumRegions)
{
*pdwNumRegions = g_dwNumRegions;
DEBUGMSG (1, (TEXT("FLSNAND_GetInfoEx: Insufficient buffer for number of regions\r\n")));
return FALSE;
}
memcpy (pFlashInfoEx->region, g_pRegionTable, g_dwNumRegions * sizeof(FlashRegion));
// print flash regions to debug output
RETAILMSG(1, (L"media contains %u flash regions:\r\n", g_dwNumRegions));
for (DWORD iRegion = 0; iRegion < g_dwNumRegions; iRegion++)
{
RETAILMSG(1, (L" Type=%d, StartP=0x%x, NumP=0x%x, NumL=0x%x, Sec/Blk=0x%x, B/Blk=0x%x, Compact=%d.\r\n",
g_pRegionTable[iRegion].regionType,
g_pRegionTable[iRegion].dwStartPhysBlock,
g_pRegionTable[iRegion].dwNumPhysBlocks,
g_pRegionTable[iRegion].dwNumLogicalBlocks,
g_pRegionTable[iRegion].dwSectorsPerBlock,
g_pRegionTable[iRegion].dwBytesPerBlock,
g_pRegionTable[iRegion].dwCompactBlocks));
}
// print reserve regions to debug output
RETAILMSG(1, (L"media contains %u reserved regions:\r\n", g_dwNumReserved));
for (DWORD iReserve = 0; iReserve < g_dwNumReserved; iReserve++)
{
RETAILMSG(1, (L" Name=%s, StartP=0x%x, NumP=0x%x, StartL=0x%x, NumL=0x%x\r\n",
g_pPhysReservedTable[iReserve].szName,
g_pPhysReservedTable[iReserve].dwStartBlock,
g_pPhysReservedTable[iReserve].dwNumBlocks,
g_pLogicalReservedTable[iReserve].dwStartBlock,
g_pLogicalReservedTable[iReserve].dwNumBlocks));
}
*pdwNumRegions = g_dwNumRegions;
pFlashInfoEx->cbSize = sizeof(FlashInfoEx);
pFlashInfoEx->flashType = NAND;
pFlashInfoEx->dwNumBlocks = g_flashInfo.dwNumBlocks;
pFlashInfoEx->dwDataBytesPerSector = g_flashInfo.wDataBytesPerSector;
pFlashInfoEx->dwNumRegions = g_dwNumRegions;
return(TRUE);
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
DWORD FLSNAND_GetBlockStatus(BLOCK_ID blockID)
{
if (!LoadFLS())
{
// failed loading the flash layout sector
return BLOCK_STATUS_UNKNOWN;
}
if (blockID < g_dwStartNonResBlock)
return BLOCK_STATUS_RESERVED;
return g_hookInterface.pGetBlockStatus(blockID);
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
BOOL FLSNAND_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize, PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
{
if (!LoadFLS())
{
// failed loading the flash layout sector
return FALSE;
}
switch(dwIoControlCode)
{
case IOCTL_FMD_READ_RESERVED:
// Read from a specified reserved region.
if (!pInBuf || nInBufSize < sizeof(ReservedReq))
{
DEBUGMSG(1, (TEXT("FLSNAND_OEMIoControl: IOCTL_FMD_READ_RESERVED bad parameter(s).\r\n")));
return(FALSE);
}
else
{
return ReadWriteReserved ((PReservedReq)pInBuf, TRUE);
}
break;
case IOCTL_FMD_WRITE_RESERVED:
// Write to a specified reserved region.
if (!pInBuf || nInBufSize < sizeof(ReservedReq))
{
DEBUGMSG(1, (TEXT("FLSNAND_OEMIoControl: IOCTL_FMD_READ_RESERVED bad parameter(s).\r\n")));
return(FALSE);
}
else
{
return ReadWriteReserved ((PReservedReq)pInBuf, FALSE);
}
break;
case IOCTL_FMD_GET_RESERVED_TABLE:
// Get the reserved table.
if (!pOutBuf)
{
// If no buffer is provided, return the required size.
if (pBytesReturned)
*pBytesReturned = g_dwNumReserved * sizeof(ReservedEntry);
return TRUE;
}
else
{
DWORD dwTableSize = g_dwNumReserved * sizeof(ReservedEntry);
if (nOutBufSize < dwTableSize)
{
if (pBytesReturned)
*pBytesReturned = 0;
return FALSE;
}
else
{
if (pBytesReturned)
*pBytesReturned = dwTableSize;
if (g_pLogicalReservedTable)
memcpy (pOutBuf, g_pLogicalReservedTable, dwTableSize);
return TRUE;
}
}
break;
case IOCTL_FMD_RAW_WRITE_BLOCKS:
if (!pInBuf || nInBufSize < sizeof(RawWriteBlocksReq))
{
DEBUGMSG(1, (TEXT("FLSNAND_OEMIoControl: IOCTL_FMD_RAW_WRITE_BLOCKS bad parameter(s).\r\n")));
return(FALSE);
}
else
{
return RawWriteBlocks ((PRawWriteBlocksReq)pInBuf);
}
break;
case IOCTL_FMD_GET_RAW_BLOCK_SIZE:
if (!pOutBuf || nOutBufSize < sizeof(DWORD))
{
DEBUGMSG(1, (TEXT("FLSNAND_OEMIoControl: IOCTL_FMD_GET_RAW_BLOCK_SIZE bad parameter(s).\r\n")));
return(FALSE);
}
else
{
*((PDWORD)pOutBuf) = g_flashInfo.wSectorsPerBlock * (g_flashInfo.wDataBytesPerSector + sizeof(SectorInfo));
if (pBytesReturned)
*pBytesReturned = sizeof(DWORD);
return TRUE;
}
break;
case IOCTL_FMD_GET_INFO:
if (!pOutBuf || nOutBufSize < sizeof(FMDInfo))
{
DEBUGMSG(1, (TEXT("FLSNAND_OEMIoControl: IOCTL_FMD_GET_INFO bad parameter(s).\r\n")));
return(FALSE);
}
else
{
PFMDInfo pInfo = (PFMDInfo)pOutBuf;
pInfo->flashType = NAND;
pInfo->dwBaseAddress = 0;
pInfo->dwNumRegions = g_dwNumRegions;
pInfo->dwNumReserved = g_dwNumReserved;
if (pBytesReturned)
*pBytesReturned = sizeof(FMDInfo);
return TRUE;
}
break;
default:
// pass to the FMD
return g_hookInterface.pOEMIoControl(dwIoControlCode, pInBuf, nInBufSize, pOutBuf, nOutBufSize, pBytesReturned);
}
return TRUE;
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
LPVOID FMDHOOK_HookInterface(PFMDInterface pInterface)
{
if (pInterface->cbSize != sizeof(FMDInterface)) {
// invalid FMDInterface structure
return NULL;
}
// save a copy of the hook structure so we can call underlying FMD functions
memcpy(&g_hookInterface, pInterface, sizeof(FMDInterface));
// hook only the functions that need to be intercepted
pInterface->pInit = FLSNAND_Init;
pInterface->pGetInfoEx = FLSNAND_GetInfoEx;
pInterface->pGetBlockStatus = FLSNAND_GetBlockStatus;
pInterface->pOEMIoControl = FLSNAND_OEMIoControl;
// status, read, write, and erase remain the same and will be handled by the FMD
return (LPVOID)&g_hookInterface;
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
void FMDHOOK_UnhookInterface(LPVOID pContext, FMDInterface *pInterface)
{
ASSERT(pContext == &g_hookInterface);
// restore the original FMD interface
memcpy(pInterface, &g_hookInterface, sizeof(FMDInterface));
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
static inline BOOL LoadFLS()
{
// only load the flash layout sector once
static BOOL fFLSLoaded = FALSE;
if (!fFLSLoaded) {
// parse the flash layout sector to define flash and reserve regions
fFLSLoaded = (g_hookInterface.pGetInfo(&g_flashInfo) &&
DefineLayout() &&
DefineReserveRegions());
RETAILMSG (!fFLSLoaded, (TEXT("FLSNAND LoadFLS: ERROR: unable to parse flash layout sector!\r\n")));
}
return fFLSLoaded;
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
static BOOL DefineLayout()
{
PFlashRegion pRegion = NULL;
if (g_flashInfo.wDataBytesPerSector > MAX_PAGE_SIZE) {
// the sector size is too large for the static buffer
// redefine MAX_PAGE_SIZE to be larger for this media
return FALSE;
}
// Find the MBR to determine if there is a flash layout sector
g_dwNumRegions = 0;
// Find the first usuable block
for (DWORD dwBlock = 0; dwBlock < g_flashInfo.dwNumBlocks; dwBlock++) {
if (g_hookInterface.pGetBlockStatus(dwBlock) & (BLOCK_STATUS_BAD | BLOCK_STATUS_RESERVED)) {
continue;
}
DWORD dwSector = dwBlock * g_flashInfo.wSectorsPerBlock;
if (!g_hookInterface.pReadSector (dwSector, g_pFLSBuffer, NULL, 1)) {
return FALSE;
}
// compare the signatures
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -