📄 fmd.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.
//
#include <am29lv800.h>
#include <bsp.h>
#include "fmd.hxx"
#ifdef DEBUG
#undef ZONE_INIT
#undef ZONE_ERROR
#define ZONE_INIT DEBUGZONE(14)
#define ZONE_ERROR DEBUGZONE(15)
#endif // DEBUG
#ifdef UNDER_BOOTLOADER
// Define a fake LocalFree so we can build. No one should be calling this.
HLOCAL LocalFree(HLOCAL hMem) {
ASSERT(FALSE);
return 0;
}
#else
#include <creg.hxx>
#include <ddkreg.h>
#endif
// Assume there will be no more than 16 reserved regions
#define MAX_RESERVES 16
// Assume there will be no more than 16 regions
#define MAX_REGIONS 16
#define DEFAULT_COMPACTION_BLOCKS 4
class CNorFmd : public CFmd {
public:
CNorFmd() : CFmd() {
m_dwBaseAddr = 0;
m_dwLength = 0;
m_cbSector = 0;
m_cbBlock = 0;
m_cBlocks = 0;
m_cRegions = 0;
m_cReserved = 0;
m_fXIPEntire = FALSE;
m_fUpdateMode = FALSE;
#ifndef UNDER_BOOTLOADER
m_pReservedTable = NULL;
m_pRegionTable = NULL;
m_pStartSectorTable = NULL;
#endif
}
virtual ~CNorFmd() {}
virtual PVOID Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut) = 0;
virtual BOOL Deinit(PVOID pv) {
ASSERT(pv == VALID_FMD_HANDLE);
#ifndef UNDER_BOOTLOADER
if (m_pReservedTable) LocalFree(m_pReservedTable);
if (m_pRegionTable) LocalFree(m_pRegionTable);
if (m_pStartSectorTable) LocalFree(m_pStartSectorTable);
#endif
return TRUE;
}
virtual BOOL GetInfo(PFlashInfo pFlashInfo) {
pFlashInfo->flashType = NOR;
pFlashInfo->dwNumBlocks = m_cBlocks;
pFlashInfo->dwBytesPerBlock = m_cbBlock;
pFlashInfo->wSectorsPerBlock = (WORD) m_pRegionTable[0].dwSectorsPerBlock;
pFlashInfo->wDataBytesPerSector = (WORD) m_cbSector;
return TRUE;
}
virtual BOOL GetInfoEx(PFlashInfoEx pFlashInfo, PDWORD pdwNumRegions) {
if (!pdwNumRegions) {
return FALSE;
}
if (!pFlashInfo) {
// Return required buffer size to caller
*pdwNumRegions = m_cRegions;
return TRUE;
}
if (*pdwNumRegions < m_cRegions) {
*pdwNumRegions = m_cRegions;
DEBUGMSG(ZONE_ERROR, (TEXT("FMD_GetInfoEx: Insufficient buffer for number of regions")));
return FALSE;
}
PREFAST_SUPPRESS(386, "Already adjusted size above.");
memcpy (pFlashInfo->region, m_pRegionTable, m_cRegions * sizeof(FlashRegion));
*pdwNumRegions = m_cRegions;
pFlashInfo->cbSize = sizeof(FlashInfoEx);
pFlashInfo->flashType = NOR;
pFlashInfo->dwNumBlocks = m_cBlocks;
pFlashInfo->dwDataBytesPerSector = m_cbSector;
pFlashInfo->dwNumRegions = m_cRegions;
return TRUE;
}
virtual VOID GetPhysSectorAddr(DWORD dwSector, PSECTOR_ADDR pStartSectorAddr) {
GetPhysicalSectorAddress(dwSector, pStartSectorAddr, NULL);
}
virtual DWORD GetBlockStatus(BLOCK_ID blockID)
{
// Look to see if the block is reserved
if (IsReservedTableBlock(blockID))
return BLOCK_STATUS_RESERVED;
DWORD dwRegion = GetRegion(blockID);
if (dwRegion == INVALID_BLOCK_ID)
return BLOCK_STATUS_UNKNOWN;
// If the block is in the XIP, return XIP status if we are in update mode,
// otherwise in regular mode, return read-only.
if (m_pRegionTable[dwRegion].regionType == XIP)
return m_fUpdateMode ? BLOCK_STATUS_XIP : BLOCK_STATUS_READONLY;
// If the block is in the READONLY_FILESYS, return READONLY status if
// we are in not in update mode, otherwise in regular mode, return normal.
if (m_pRegionTable[dwRegion].regionType == READONLY_FILESYS)
//return g_bUpdateMode ? 0 : BLOCK_STATUS_READONLY;
return 0;
SECTOR_ADDR Sector = GetStartSectorInBlock(blockID);
if (Sector == INVALID_SECTOR_ADDR)
return BLOCK_STATUS_UNKNOWN;
SectorInfo SI;
DWORD dwResult = 0;
if (!ReadSector(Sector, NULL, &SI, 1))
return BLOCK_STATUS_UNKNOWN;
//if (!(SI.bOEMReserved & OEM_BLOCK_READONLY))
//dwResult |= BLOCK_STATUS_READONLY;
if (!(SI.bOEMReserved & OEM_BLOCK_RESERVED))
dwResult |= BLOCK_STATUS_RESERVED;
DEBUGMSG(ZONE_INIT, (TEXT("FMD_GetBlockStatus(0x%x)=0x%x\r\n"), blockID, dwResult));
return dwResult;
}
virtual DWORD SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus) {
DEBUGMSG(ZONE_INIT, (TEXT("FMD_SetBlockStatus(0x%x, 0x%x)\r\n"), blockID, dwStatus));
// Don't allow setting block status for reserved or XIP blocks.
if (IsReservedTableBlock(blockID))
return FALSE;
DWORD dwRegion = GetRegion(blockID);
if (dwRegion == INVALID_BLOCK_ID)
return FALSE;
if (m_pRegionTable[dwRegion].regionType == XIP)
return FALSE;
if (dwStatus & (BLOCK_STATUS_READONLY | BLOCK_STATUS_RESERVED)) {
SECTOR_ADDR Sector = GetStartSectorInBlock(blockID);
if (Sector == INVALID_SECTOR_ADDR)
return FALSE;
SectorInfo SI;
if (!ReadSector(Sector, NULL, &SI, 1)) {
return FALSE;
}
if (dwStatus & BLOCK_STATUS_READONLY) {
SI.bOEMReserved &= ~OEM_BLOCK_READONLY;
}
if (dwStatus & BLOCK_STATUS_RESERVED) {
SI.bOEMReserved &= ~OEM_BLOCK_RESERVED;
}
if (!WriteSector (Sector, NULL, &SI, 1)) {
return FALSE;
}
}
return TRUE;
}
virtual BOOL EraseBlock(BLOCK_ID blockID) = 0;
virtual BOOL ReadSector (SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
DEBUGMSG(ZONE_INIT, (TEXT("FMD_ReadSector(0x%x, 0x%x, 0x%x, 0x%x)\r\n"), startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors));
//----- 1. Check the input parameters -----
// NOTE: The FAL insures that the starting sector address is in the allowable range.
if((dwNumSectors == 0) || ((pSectorBuff == NULL) && (pSectorInfoBuff == NULL)))
{
return(FALSE);
}
//----- 2. Process the read request(s)... -----
for(DWORD i = startSectorAddr ; i < (startSectorAddr + dwNumSectors) ; i++)
{
//----- Compute the physical address for the requested -----
volatile SECTOR_ADDR physicalSectorAddr;
volatile SECTOR_ADDR physicalSectorInfoAddr;
GetPhysicalSectorAddress(i, (PSECTOR_ADDR)&physicalSectorAddr, (PSECTOR_ADDR)&physicalSectorInfoAddr);
//----- Read the necessary sector data -----
if(pSectorBuff)
{
memcpy(pSectorBuff, (UCHAR*)physicalSectorAddr, m_cbSector);
pSectorBuff += m_cbSector;
}
//----- Read the necessary SectorInfo data (metadata) -----
if(pSectorInfoBuff)
{
if (m_fXIPEntire)
{
// For XIP, fill the SectorInfo with 1:1 log/phys mapping and read-only status
memset (pSectorInfoBuff, 0xff, sizeof(SectorInfo));
pSectorInfoBuff->dwReserved1 = startSectorAddr;
}
else
{
// For non-XIP, The metadata bytes are physicalSectorInfoAddr read directly into the SectorInfo structure...
if (physicalSectorInfoAddr)
memcpy(pSectorInfoBuff, (CONST PVOID)physicalSectorInfoAddr, sizeof(SectorInfo));
}
pSectorInfoBuff++;
}
}
return(TRUE);
}
virtual BOOL WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors) = 0;
virtual BOOL OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize, PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned);
protected:
BOOL IsReservedTableBlock (BLOCK_ID dwBlock)
{
for (DWORD i = 0; i < m_cReserved; i++)
{
if (dwBlock >= m_pReservedTable[i].dwStartBlock &&
dwBlock <= (m_pReservedTable[i].dwStartBlock + m_pReservedTable[i].dwNumBlocks - 1))
{
return TRUE;
}
}
return FALSE;
}
DWORD GetRegion (DWORD dwBlock)
{
for (DWORD i = 0; i < m_cRegions; i++)
{
if (dwBlock >= m_pRegionTable[i].dwStartPhysBlock &&
dwBlock < (m_pRegionTable[i].dwStartPhysBlock + m_pRegionTable[i].dwNumPhysBlocks))
{
return i;
}
}
DEBUGMSG(ZONE_ERROR, (TEXT("GetRegion: Could not find region for block 0x%x.\r\n"), dwBlock));
ASSERT(0);
return INVALID_BLOCK_ID;
}
SECTOR_ADDR GetStartSectorInBlock (DWORD dwBlock)
{
DWORD i = GetRegion(dwBlock);
if (i == INVALID_BLOCK_ID)
return INVALID_SECTOR_ADDR;
// The starting sector in the block is the starting physical sector
// of the region plus the block offset into the region times
// the sectors per block
return m_pStartSectorTable[i] + (dwBlock - m_pRegionTable[i].dwStartPhysBlock) *
m_pRegionTable[i].dwSectorsPerBlock;
}
virtual VOID GetPhysicalSectorAddress(DWORD dwSector, PSECTOR_ADDR pStartSectorAddr, PSECTOR_ADDR pStartSectorInfoAddr) {
for (DWORD i = 0; i < m_cRegions; i++)
{
// Determine the region this physical sector resides in
if (dwSector >= m_pStartSectorTable[i] &&
((i == m_cRegions - 1) || (dwSector < m_pStartSectorTable[i+1])))
{
DWORD dwSectorOffsetInRegion = dwSector - m_pStartSectorTable[i];
DWORD dwBlockID = dwSectorOffsetInRegion / m_pRegionTable[i].dwSectorsPerBlock + m_pRegionTable[i].dwStartPhysBlock;
DWORD dwSectorOffsetInBlock = dwSectorOffsetInRegion % m_pRegionTable[i].dwSectorsPerBlock;
// Determine physical address of the block
SECTOR_ADDR BlockAddr = m_dwBaseAddr + (dwBlockID * m_cbBlock);
// Determine the physical address of the sector
*pStartSectorAddr = BlockAddr + (dwSectorOffsetInBlock * m_cbSector);
// If this is a region with SectorInfo, return the address of the start of sector info, which
// is located immediatly after the sector data for all the sectors in the block.
if (pStartSectorInfoAddr && m_pRegionTable[i].regionType != XIP) {
*pStartSectorInfoAddr = BlockAddr + (m_pRegionTable[i].dwSectorsPerBlock * m_cbSector) + (dwSectorOffsetInBlock * sizeof(SectorInfo));
}
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -