⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand.c

📁 Freescale ARM9系列CPU MX27的WINCE 5.0下的BSP
💻 C
📖 第 1 页 / 共 4 页
字号:
//
//  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 + -