fmd.c

来自「Windows CE 6.0 BSP for VOIP sample phone」· C语言 代码 · 共 850 行 · 第 1/2 页

C
850
字号
//
// 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.
//
//------------------------------------------------------------------------------
//
//  This file implements FMD for NOR flash memory. It uses abstract NOR_xxxx
//  functions.
//
//  This is read-only version intended to be used as part of IPL.
//
#include <windows.h>
#include <oal.h>
#include <fmd.h>
#include <fls.h>

//------------------------------------------------------------------------------
//
//     The FAL expects the Flash media to be broken up into Flash blocks
//     which are then subdivided into physical sectors.  Some types of
//     Flash memory (i.e. NAND Flash) already have this layout.  NOR Flash,
//     on the other hand, DOES NOT breakup each Flash block into physical
//     sectors.  Instead, each byte is individually addressable (like RAM).
//     Despite this characteristic, NOR Flash can still logically be broken
//     up into discrete sectors as follows:
//
//                             NOR Flash
//
//                          Sector Data     SectorInfo
//                  ---------------------------------
//                  |Sector(0)              |       |
//                  |Sector(1)              |       |
//                  |Sector(2)              |       |       Block 0
//                  |...                    |       |
//                  |Sector(k)              |       |
//                  |                       XXXXXXXXX
//                   -------------------------------
//                  |Sector(k+1)            |       |
//                  |Sector(k+2)            |       |
//                  |Sector(k+3)            |       |       Block 1
//                  |...                    |       |
//                  |Sector(2k)             |       |
//                  |                       XXXXXXXXX
//                   -------------------------------
//                  |                       |       |
//                  |                       |       |
//                  |                       |       |       Block 2
//                  |                       |       |
//                  |                       |       |
//                  |                       XXXXXXXXX
//                   -------------------------------        ...
//                  |                       |       |
//                  |                       |       |
//                  |                       |       |       Block N
//                  |                       |       |
//                  |                       |       |
//                  |                       XXXXXXXXX
//                  ---------------------------------
//
//     That is, each NOR Flash block is logically subdivided into a "page",
//     where each page contains space for sector data and SectorInfo metadata.
//     Most often, Flash blocks are a power of 2 in size but the size
//     of a page is not a power of 2 (i.e. 512 + 8 = 520 bytes).
//     Thus, each Flash block DOES NOT evenly divide into an integral number
//     of pages and some bytes in a block are left unused.  These unused
//     bytes are denoted above by XXXXX's.
//
//     To help clarify how this process works, consider the following
//     example: suppose you have a NOR Flash memory device that contains
//     256 Flash blocks each 256K in size. From these size characteristics,
//     we find:
//
//         (256K / (512+8)) ==> 504 sectors + 64 unused bytes
//
//     Therefore, each Flash block can map 504 sectors (including SectorInfo
//     metadata) and leave 64 unused bytes per block.  Notice that 8 bytes
//     is used for the SectorInfo metadata although the SectorInfo structure
//     is currently only 6 bytes.  The reason for this is to make sure that
//     all sector addresses are DWORD aligned (i.e. 520 divides by 4 evenly
//     while 518 doesn't divide by 4 evenly).  Furthemore, we see that
//     this NOR Flash memory can map (504*256)==>129,024 physical sectors.
//
//     -------
//
//     Two other points are worth mentioning:
//
//     1) NOR Flash memory is guaranteed by manufacturing to ship
//        with no bad Flash blocks.
//     2) NOR Flash memory doesn't suffer from electrical leakage
//        currents (like NAND Flash) and it does not require error-correction
//        codes (ECC) to insure data integrity.
//
//------------------------------------------------------------------------------

#ifndef dimof
#define dimof(x)    (sizeof(x)/sizeof(x[0]))
#endif

//------------------------------------------------------------------------------

typedef struct {

    DWORD memBase;
    DWORD memLen;
    DWORD sectorSize;
    DWORD blockSize;

    UCHAR *pBase;
    ULONG blocks;

    ULONG reservedRegions;
    ReservedEntry reservedRegion[16];
    ULONG regions;
    FlashRegion region[16];
    ULONG firstSector[17];

} FmdInfo_t;

//------------------------------------------------------------------------------

static FmdInfo_t s_fmd;

//------------------------------------------------------------------------------

static DWORD s_blockSign[] =
    { 0xC1552106, 0xDF9C29D5, 0xBAB8EAB8, 0x82D3F9F3,
      0x3B438A47, 0xA9D92AE6, 0x09396731, 0x12BF6753 };

//------------------------------------------------------------------------------

static DWORD
FindBlockSize(
    VOID *pBase,
    ULONG size
    )
{
    OAL_FLASH_INFO flashInfo;
    ULONG blockSize = 0;
    ULONG region;
    ULONG flashSize;

    while (size > 0)
        {
        if (!OALFlashInfo(pBase, &flashInfo))
            {
            blockSize = 0;
            goto cleanUp;
            }
        for (region = 0; region < flashInfo.regions; region++)
            {
            if (flashInfo.aBlockSize[region] > blockSize)
                {
                    if ( (blockSize > 0) &&
                        ((flashInfo.aBlockSize[region] % blockSize) != 0) )
                        {
                        blockSize = 0;
                        goto cleanUp;
                        }
                    blockSize = flashInfo.aBlockSize[region];
                }
            else if (blockSize > 0)
                {
                if ((blockSize % flashInfo.aBlockSize[region]) != 0)
                    {
                    blockSize = 0;
                    goto cleanUp;
                    }
                }
            }
        flashSize = flashInfo.size * flashInfo.parallel;
        pBase = (UCHAR*)pBase + flashSize;
        if (flashSize > size) break;
        size -= flashSize;
        }

cleanUp:
    return blockSize;
}

//------------------------------------------------------------------------------

static BOOL
VerifyBlockSignature(
    BLOCK_ID block
    )
{
    int rc;
    UCHAR *pBlock;

    // There is no block signature on reserved blocks
    if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_RESERVED) != 0)
        {
        rc = 0;
        goto cleanUp;
        }

    // Get block end address
    pBlock = s_fmd.pBase + (block + 1) * s_fmd.blockSize;

    // Compare signature
    rc = memcmp(pBlock - sizeof(s_blockSign), s_blockSign, sizeof(s_blockSign));

cleanUp:
    return (rc == 0);
}

//------------------------------------------------------------------------------

static BOOL
BuildLayoutInfo(
    UCHAR *pLayoutSector
    )
{
    BOOL rc = FALSE;
    FlashLayoutSector *pSector = (FlashLayoutSector*)pLayoutSector;
    UCHAR *pInfo = (UCHAR*)&pSector[1];
    FlashRegion *pRegion;
    ULONG sector;
    ULONG region;

    s_fmd.reservedRegions = pSector->cbReservedEntries/sizeof(ReservedEntry);
    if (s_fmd.reservedRegions > dimof(s_fmd.reservedRegion))
        {
        OALMSG(OAL_ERROR, (L"ERROR: FMD_Init!BuildLayoutInfo: "
            L"To many reserved regions (%d)\r\n", s_fmd.reservedRegions
            ));
        goto cleanUp;
        }
    if (s_fmd.reservedRegions > 0)
        {
        memcpy(
            s_fmd.reservedRegion, pInfo,
            s_fmd.reservedRegions * sizeof(ReservedEntry)
            );
        }

    s_fmd.regions = pSector->cbRegionEntries/sizeof(FlashRegion);
    if (s_fmd.regions > dimof(s_fmd.region))
        {
        OALMSG(OAL_ERROR, (L"ERROR: FMD_Init!BuildLayoutInfo: "
            L"To many regions (%d)\r\n", s_fmd.regions
            ));
        goto cleanUp;
        }

    if (s_fmd.regions > 0)
       {
        memcpy(
            s_fmd.region, pInfo + pSector->cbReservedEntries,
            s_fmd.regions * sizeof(FlashRegion)
            );
        }

    // Build region first sector table
    if ((s_fmd.regions + 1) > dimof(s_fmd.firstSector))
        {
        OALMSG(OAL_ERROR, (L"ERROR: FMD_Init!BuildLayoutInfo: "
            L"To many regions (%d)\r\n", s_fmd.regions
            ));
        goto cleanUp;
        }
    
    pRegion = &s_fmd.region[0];
    sector = pRegion->dwStartPhysBlock * pRegion->dwSectorsPerBlock;
    for (region = 0; region < s_fmd.regions; region++)
        {
        s_fmd.firstSector[region] = sector;
        sector += pRegion->dwNumPhysBlocks * pRegion->dwSectorsPerBlock;
        pRegion++;
        }
    s_fmd.firstSector[region] = sector;

    // Verify block signatures
    pRegion = &s_fmd.region[0];
    for (region = 0; region < s_fmd.regions; region++, pRegion++)
        {
        ULONG block, count;

        if (pRegion->regionType == XIP) continue;

        block = pRegion->dwStartPhysBlock;
        count = pRegion->dwNumPhysBlocks;
        while (count-- > 0)
            {
            if (!VerifyBlockSignature(block))
                {
                OALMSG(OAL_ERROR, (L"ERROR: FMD_Init!BuildLayoutInfo: "
                    L"Failed verify block signature (block %d)\r\n", block
                    ));
                //goto cleanUp;
                }
            block++;
            }
        }

    rc = TRUE;

cleanUp:
    return rc;
}

//------------------------------------------------------------------------------

static VOID GetSectorAddresses(
    SECTOR_ADDR sector, VOID **ppSector, VOID **ppSectorInfo
    )
{
    UCHAR *pSector = NULL;
    UCHAR *pInfo = NULL;
    UCHAR *pBlock;
    ULONG region;
    FlashRegion *pRegion;
    ULONG sectorInRegion;
    ULONG sectorInBlock;
    ULONG block;


    for (region = 0; region < s_fmd.regions; region++)
        {
        // Try next region in sector isn't in range
        if ( (sector < s_fmd.firstSector[region]) ||
             (sector >= s_fmd.firstSector[region + 1]) )
            {
            continue;
            }
        pRegion = &s_fmd.region[region];

        // Calculate block, sector position in region and inblock
        sectorInRegion = sector - s_fmd.firstSector[region];
        block = sectorInRegion / pRegion->dwSectorsPerBlock;
        block += pRegion->dwStartPhysBlock;
        sectorInBlock = sectorInRegion % pRegion->dwSectorsPerBlock;
        // Block address
        pBlock = s_fmd.pBase + block * s_fmd.blockSize;
        // Sector address
        pSector = pBlock + sectorInBlock * s_fmd.sectorSize;
        // 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 (pRegion->regionType != XIP)
            {
            pInfo = pBlock + pRegion->dwSectorsPerBlock * s_fmd.sectorSize;
            pInfo += sectorInBlock * sizeof(SectorInfo);
            }
        break;
        }

    *ppSector = pSector;
    *ppSectorInfo = pInfo;
}

//------------------------------------------------------------------------------

VOID*
FMD_Init(
    LPCTSTR activePath,
    PCI_REG_INFO *pRegIn,
    PCI_REG_INFO *pRegOut
    )
{
    HANDLE hFMD = NULL;
    UCHAR *pLayoutSector;
    UCHAR *pAddress;
    ULONG sectors;


    memset(&s_fmd, 0, sizeof(s_fmd));

    // This must not be NULL
    if (pRegIn == NULL) goto cleanUp;
    
    // Map NAND registers
    s_fmd.memBase = pRegIn->MemBase.Reg[0];
    s_fmd.memLen = pRegIn->MemLen.Reg[0];

    // Map base address    
    s_fmd.pBase = OALPAtoUA(s_fmd.memBase);

    // Find block size
    s_fmd.blockSize = FindBlockSize(s_fmd.pBase, s_fmd.memLen);

    // Calculate number of blocks on device
    s_fmd.blocks = s_fmd.memLen / s_fmd.blockSize;

    //----------------------------------------------------------------------
    //  Get volume/device layout
    //----------------------------------------------------------------------

    s_fmd.reservedRegions = 0;
    s_fmd.regions = 0;
    pLayoutSector = NULL;

    // Set sector size to 512 bytes, we can modify it later
    s_fmd.sectorSize = 512;

    // Now we have to try find boot sector & flash partition table
    pAddress = s_fmd.pBase;
    sectors = s_fmd.memLen / s_fmd.sectorSize;

    while (sectors-- > 0)
        {
        UINT32 sectorSize;
        
        // Check for boot sector
        if (!IS_VALID_BOOTSEC(pAddress))
            {
            // Move to next sector
            pAddress += s_fmd.sectorSize;
            continue;
            }

        // Look for flash layout
        sectorSize = 512;
        while (sectorSize <= s_fmd.blockSize)
            {
            if (IS_VALID_FLS(pAddress + sectorSize))
                {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?