📄 nand.c
字号:
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on
// your install media.
//
//-----------------------------------------------------------------------------
//
// Copyright (C) 2004, Motorola Inc. All Rights Reserved
//
//------------------------------------------------------------------------------
// Copyright (C) 2006, Freescale Semiconductor, Inc. All Rights Reserved.
// THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
// AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//------------------------------------------------------------------------------
// File: nand.c
//
// EBOOT Nand flash routines
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// INCLUDE FILES
//-----------------------------------------------------------------------------
#include <windows.h>
#include <blcommon.h>
#include <bootpart.h>
#include <fmd.h>
#include "bsp.h"
#include "loader.h"
#include "nand.h"
//-----------------------------------------------------------------------------
// GLOBAL DEFINITIONS
//-----------------------------------------------------------------------------
#if DEBUG
#define LE32(x32) \
(((x32 & 0x000000FF) << 24) | \
((x32 & 0x0000FF00) << 8) | \
((x32 & 0x00FF0000) >> 8) | \
((x32 & 0xFF000000) >> 24))
#endif
// Only enable this for testing
#define IGNORE_OEM_RESERVED_BAD_BLOCKS 0
//-----------------------------------------------------------------------------
// GLOBAL OR STATIC VARIABLES
//-----------------------------------------------------------------------------
static BOOL g_fNandExists;
static BOOL g_fBlock0Erased;
static FlashInfo g_FlashInfo;
static DWORD g_FlashWidth;
static DWORD g_FlashClock;
//-----------------------------------------------------------------------------
// STATIC FUNCTION PROTOTYPES
//-----------------------------------------------------------------------------
static PVOID GetKernelExtPointer(DWORD dwRegionStart, DWORD dwRegionLength);
static PVOID GetNandLoaderFilePointer(DWORD dwRegionStart, DWORD dwRegionLength);
static DWORD FindFirstGoodBlock(DWORD dwStartBlock);
static BOOL WriteOSRegionsToNand(BOOT_CFG *pBootCfg);
static BOOL WriteEBootRegionToNand(BOOT_CFG *pBootCfg);
static BOOL WriteNandLoaderRegionToNand(BOOT_CFG *pBootCfg);
#ifdef DEBUG
static DWORD GetBlockNumberInput(void);
static void DisplayMem(UINT32 start, UINT32 size, UINT32 displaySize);
#endif
//-----------------------------------------------------------------------------
// EXPORTED FUNCTIONS
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// FUNCTION: InitPartitionMgr
//
// DESCRIPTION: Initialises the Boot partition manager for
// Nand flash interface.
//
// PARAMETERS: None
//
// RETURNS: TRUE for success. FALSE for failure.
//
//-----------------------------------------------------------------------------
BOOL InitPartitionMgr(void)
{
DWORD dwBlock;
DWORD dwReservedBlocks;
DWORD dwBlockStatus;
OALMSG(OAL_FUNC, (TEXT("InitPartitionMgr+\r\n")));
g_fNandExists = FALSE;
g_fBlock0Erased = FALSE;
// Initialize the FMD flash interface and get flash information.
if(!BP_Init((LPBYTE)EBOOT_NANDCACHE_START, EBOOT_NANDCACHE_SIZE, NULL, NULL, NULL))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: BP_Init failed. Check if NAND is present.\r\n")));
return FALSE;
}
// Get NAND flash info
if(!FMD_GetInfo(&g_FlashInfo))
{
EdbgOutputDebugString("ERROR: Unable to get flash info.\r\n");
return FALSE;
}
//if(!FMD_GetAddInfo(&g_FlashWidth, &g_FlashClock))
//{
// EdbgOutputDebugString("ERROR: Unable to get additional flash info.\r\n");
// return FALSE;
//}
g_FlashWidth = 8;
OALMSG(OAL_FUNC, (TEXT("flash type: %s\r\n"), g_FlashInfo.flashType == NAND? L"NAND":L"NOR"));
OALMSG(OAL_FUNC, (TEXT("dwNumBlocks: %d\r\n"), g_FlashInfo.dwNumBlocks));
OALMSG(OAL_FUNC, (TEXT("wSectorsPerBlock: %d\r\n"), g_FlashInfo.wSectorsPerBlock));
OALMSG(OAL_FUNC, (TEXT("wDataBytesPerSector: %d\r\n"), g_FlashInfo.wDataBytesPerSector));
OALMSG(OAL_FUNC, (TEXT("dwBytesPerBlock: 0x%x\r\n"), g_FlashInfo.dwBytesPerBlock));
OALMSG(OAL_FUNC, (TEXT("width: %d\r\n"), g_FlashWidth));
//OALMSG(OAL_FUNC, (TEXT("clock: %d\r\n"), g_FlashClock));
// Sanity check for first good block after block 0.
OALMSG(OAL_FUNC, (TEXT("start block: %d\r\n"), FindFirstGoodBlock(1)));
// Check that NANDLoader and EBOOT blocks are marked as readonly and
// oem reserved.
for(dwBlock = 0, dwReservedBlocks = 0;
dwReservedBlocks < NAND_IMAGE_NUM_BLOCK(NAND_EBOOT_IMAGE_SIZE, g_FlashInfo.dwBytesPerBlock) + 1;
dwBlock++)
{
dwBlockStatus = FMD_GetBlockStatus(dwBlock);
if((dwBlockStatus & BLOCK_STATUS_UNKNOWN))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: Checking OEM reserved block %d status failed.\r\n"), dwBlock));
return FALSE;
}
if(dwBlockStatus & BLOCK_STATUS_BAD)
{
OALMSG(OAL_INFO, (TEXT("OEM reserved block %d status Bad.\r\n"), dwBlock));
continue;
}
// Set blocks as OEM_RESERVED and READONLY
if((dwBlockStatus & (BLOCK_STATUS_READONLY | BLOCK_STATUS_RESERVED)) !=
(BLOCK_STATUS_READONLY | BLOCK_STATUS_RESERVED))
{
OALMSG(OAL_INFO, (TEXT("INFO: Setting block %d status as OEM reserved/read only.\r\n"), dwBlock));
if(FMD_SetBlockStatus(dwBlock, (BLOCK_STATUS_READONLY | BLOCK_STATUS_RESERVED)) != TRUE)
{
OALMSG(OAL_ERROR, (TEXT("ERROR: Setting OEM reserved block %d status failed.\r\n"), dwBlock));
return FALSE;
}
else
dwReservedBlocks++;
}
else
dwReservedBlocks++;
}
OALMSG(OAL_FUNC, (TEXT("last oem block: %d\r\n"), dwBlock - 1));
g_fNandExists = TRUE;
OALMSG(OAL_FUNC, (TEXT("InitPartitionMgr-: Nand %c\r\n"),
g_fNandExists? 'T':'F'));
return TRUE;
}
//-----------------------------------------------------------------------------
//
// FUNCTION: DeinitPartitionMgr
//
// DESCRIPTION: Deinitializes Nand flash interface.
//
// PARAMETERS: None
//
// RETURNS: None
//
//-----------------------------------------------------------------------------
void DeinitPartitionMgr(void)
{
// Deinitialize the NFC hardware
FMD_Deinit("FMOK");
}
//-----------------------------------------------------------------------------
//
// FUNCTION: WriteRegionsToNand
//
// DESCRIPTION: Writes bin regions to NAND.
//
// PARAMETERS:
// pBootCfg - Ptr to EBOOT configuration structure
//
// RETURNS: TRUE for success. FALSE for failure.
//
//-----------------------------------------------------------------------------
BOOL WriteRegionsToNand(BOOT_CFG *pBootCfg)
{
extern MultiBINInfo g_BINRegionInfo;
DWORD dwImageStart = 0;
BOOL result;
DWORD dwCurMSec;
CHAR selection;
OALMSG(OAL_INFO, (TEXT("WriteRegionsToNand+\r\n")));
if(!pBootCfg)
{
OALMSG(OAL_ERROR, (TEXT("WriteRegionsToNand: Invalid input Parameter!\r\n")));
return FALSE;
}
if(g_fNandExists != TRUE)
{
EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to write image.\r\n");
return FALSE;
}
/*
* I don't like this at all. It'll be nicer to be able to identify
* bins via the .exe names in pTOC. Unfortunately WinCE tools are all
* keyed off to work with the magic "nk.exe". Too bad,
* we sort by launch/download address (offset from start of flash
* cache area.)
*
* Note: These addresses will change if the respective .bib files
* RAMIMAGE and ROMOFFSET entries change.
*
* This is how it goes:
* 0x00000000 - NK ram OS image
* 0x00040000/0x00044000 - EBoot ram OS image
*/
dwImageStart = pBootCfg->LaunchAddress - 0x1000;
if(dwImageStart == EBOOT_RAM_IMAGE_START)
{
BOOL err = FALSE;
OALMSG(OAL_INFO, (TEXT("WriteRegionsToNand: writing EBoot region!\r\n")));
EdbgOutputDebugString("Press 'N' within 3 seconds to update NANDLoader image.\r\n");
dwCurMSec = OEMEthGetSecs();
while(OEMEthGetSecs() < (dwCurMSec + 3))
{
selection = OEMReadDebugByte();
if((selection == 'n' || selection == 'N'))
{
OALMSG(OAL_INFO, (TEXT("WriteRegionsToNand: writing NandLoader!\r\n")));
result = WriteNandLoaderRegionToNand(pBootCfg);
if(result == FALSE)
{
EdbgOutputDebugString("ERROR: Write NandLoader failed.\r\n");
err = TRUE;
}
break;
}
}
EdbgOutputDebugString("Press 'E' within 3 seconds to update NAND EBOOT image.\r\n");
dwCurMSec = OEMEthGetSecs();
while(OEMEthGetSecs() < (dwCurMSec + 3))
{
selection = OEMReadDebugByte();
if((selection == 'e' || selection == 'E'))
{
OALMSG(OAL_INFO, (TEXT("WriteRegionsToNand: writing EBOOT!\r\n")));
result = WriteEBootRegionToNand(pBootCfg);
if(result == FALSE)
{
EdbgOutputDebugString("ERROR: Write EBOOT failed.\r\n");
err = TRUE;
}
break;
}
}
if(err == TRUE)
result = FALSE;
}
else if(dwImageStart == OS_RAM_IMAGE_START)
{
OALMSG(OAL_INFO, (TEXT("WriteRegionsToNand: writing OS region!\r\n")));
result = WriteOSRegionsToNand(pBootCfg);
}
else
{
OALMSG(OAL_INFO, (TEXT("WriteRegionsToNand: dwImageStart: %X\r\n"), dwImageStart));
OALMSG(OAL_INFO, (TEXT("WriteRegionsToNand: OS_RAM_IMAGE_START: %X\r\n"), OS_RAM_IMAGE_START));
OALMSG(OAL_INFO, (TEXT("WriteRegionsToNand: EBOOT_RAM_IMAGE_START: %X\r\n"), EBOOT_RAM_IMAGE_START));
result = FALSE;
}
return result;
}
//-----------------------------------------------------------------------------
//
// FUNCTION: ReadKernelRegionFromNand
//
// DESCRIPTION: Reads kernel region from NAND to RAM.
//
// PARAMETERS:
// pBootCfg - Ptr to EBOOT configuration structure
//
// RETURNS: TRUE for success. FALSE for failure.
//
//-----------------------------------------------------------------------------
BOOL ReadKernelRegionFromNand(BOOT_CFG *pBootCfg)
{
HANDLE hPart;
EBOOT_NANDCFG nandParams;
OALMSG(OAL_INFO, (TEXT("ReadKernelRegionFromNand+\r\n")));
if(!pBootCfg)
{
OALMSG(1, (TEXT("ReadRegionsFromNand: Invalid input Parameter!\r\n")));
return FALSE;
}
if(g_fNandExists != TRUE)
{
EdbgOutputDebugString("WARNING: NAND device doesn't exist - unable to retrieve image.\r\n");
return FALSE;
}
// Try to read BOOTSECTION partition from NAND
hPart = BP_OpenPartition(NEXT_FREE_LOC, USE_REMAINING_SPACE,
PART_BOOTSECTION, FALSE, PART_OPEN_EXISTING);
if(hPart == INVALID_HANDLE_VALUE)
{
EdbgOutputDebugString("ERROR: cannot find BOOTSECTION partition!\r\n");
return FALSE;
}
// Read kernel region info from parameters
if(BP_ReadData(hPart, (LPBYTE)&nandParams, sizeof(EBOOT_NANDCFG)))
{
if(nandParams.ConfigMagicNumber != EbootCFGMagicNumber)
{
EdbgOutputDebugString("ERROR: invalid BOOTSECTION data!\r\n");
return FALSE;
}
}
else
{
EdbgOutputDebugString("ERROR: failed to read BOOTSECTION data!\r\n");
return FALSE;
}
EdbgOutputDebugString("Opening BINFS partition\r\n");
// Open BINFS partition.
hPart = BP_OpenPartition(NEXT_FREE_LOC, USE_REMAINING_SPACE,
PART_BINFS, TRUE, PART_OPEN_EXISTING);
if(hPart == INVALID_HANDLE_VALUE)
{
EdbgOutputDebugString("ERROR: failed to open BINFS partition!\r\n");
return FALSE;
}
EdbgOutputDebugString("Reading kernel region to RAM:\r\n");
// Set the offset into the BINFS partition and read the image.
if(!BP_SetDataPointer(hPart, nandParams.dwImageOffset))
{
EdbgOutputDebugString("ERROR: failed to set data pointer in BINFS partition (address=0x%x).\r\n", nandParams.dwImageOffset);
return FALSE;
}
if(!BP_ReadData(hPart, (LPBYTE)nandParams.dwRegionStart, nandParams.dwRegionLength))
{
EdbgOutputDebugString("ERROR: failed to read BINFS data (start=0x%x, length=0x%x).\r\n",
nandParams.dwRegionStart, nandParams.dwRegionLength);
return FALSE;
}
// Read chain info to ram if required
if(nandParams.dwChainLength != 0)
{
EdbgOutputDebugString("Reading Chain info to RAM:\r\n");
if(!BP_SetDataPointer(hPart, nandParams.dwChainOffset))
{
EdbgOutputDebugString("ERROR: failed to set data pointer in BINFS partition (address=0x%x).\r\n", nandParams.dwChainOffset);
return FALSE;
}
if(!BP_ReadData(hPart, (LPBYTE)nandParams.dwChainStart, nandParams.dwChainLength))
{
EdbgOutputDebugString("ERROR: failed to read BINFS data (start=0x%x, length=0x%x).\r\n",
nandParams.dwChainStart, nandParams.dwChainLength);
return FALSE;
}
}
// Update launch address
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -