//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// 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.
//

extern "C"
{
#include <windows.h>
#include <bsp.h>
#include "loader.h"
#include <fmd.h>
#include <clkinfo.h>
#ifdef SDMMC_BOOT
#include <register_map.h>
#include <hsmmcdrv.h>

#endif
DWORD g_TOC_BLOCK;
DWORD g_TOC_SECTOR;

extern DWORD        g_ImageType;
#ifdef SDMMC_BOOT
extern UCHAR        g_TOC[TOC_SECTOR_SIZE];
extern ADDRESSINFOSECTOR g_AddressInfoSector;
extern MultiBINInfo g_BINRegionInfo;
#else
extern UCHAR        g_TOC[NAND_SECTOR_SIZE];
extern DWORD _NUM_OF_BLOCKS;
extern DWORD _BYTES_PER_BLOCK;
extern WORD _SECTORS_PER_BLOCK;
extern WORD _BYTES_PER_SECTOR;
extern MultiBINInfo g_BINRegionInfo;//lqm added.

#endif
extern const PTOC   g_pTOC;
extern DWORD        g_dwTocEntry;
extern PBOOT_CFG    g_pBootCfg;
extern BOOL         g_bBootMediaExist;
extern SYSTEM_CLOCK g_SysClockTable[SYS_CLK_DEF_MAX];

extern int DWORDToBytes(UCHAR *szData, const DWORD dwData);
extern UINT32 USBWriteString(UINT8 * pbData, UINT32 cbData);

extern PDownloadManifest g_pDownloadManifest;



}

extern DWORD 		g_dwLastWrittenLoc;                     //  Defined in bootpart.lib
extern PSectorInfo 	g_pSectorInfoBuf;
extern FlashInfo 	g_FlashInfo;




PXIPCHAIN_SUMMARY g_pXIPChainSummary = NULL;
EXTENSION *g_pExt = NULL;
HANDLE g_hPartBINFS = INVALID_HANDLE_VALUE;





#define SECTOR_WRITE_COMPLETED 0x4

// you must match these defines with <NAND ...> values in memory.cfg.xml file
#define EBOOT_WRITE_NAND_SECTORSIZE     (g_FlashInfo.wDataBytesPerSector)

#define EBOOT_WRITE_NAND_UNITSIZE        (0x20000)

#define EBOOT_WRITE_NAND_SECTOR_PER_UNIT (EBOOT_WRITE_NAND_UNITSIZE/EBOOT_WRITE_NAND_SECTORSIZE)

#ifdef SDMMC_BOOT
extern HANDLE BP_OpenStoragePartition(DWORD dwStartSector,DWORD dwNumSectors,DWORD dwPartType,BOOL fActive,DWORD dwCreationFlags);
extern BOOL BP_Storage_Init(LPBYTE pMemory,DWORD dwSize,LPCTSTR lpActiveReg,PPCI_REG_INFO pRegIn,PPCI_REG_INFO pRegOut);
#endif
// Define a dummy SetKMode function to satisfy the NAND FMD.
//
DWORD SetKMode (DWORD fMode)
{
    return(1);
}

void BootConfigPrint(void)
{
    EdbgOutputDebugString( "BootCfg { \r\n");
    EdbgOutputDebugString( "  ConfigFlags: 0x%x\r\n", g_pBootCfg->ConfigFlags);
    EdbgOutputDebugString( "  BootDelay: 0x%x\r\n", g_pBootCfg->BootDelay);
    EdbgOutputDebugString( "  IP: %s\r\n", inet_ntoa(g_pBootCfg->EdbgAddr.dwIP));
    EdbgOutputDebugString( "  MAC Address: %B:%B:%B:%B:%B:%B\r\n",
                           g_pBootCfg->EdbgAddr.wMAC[0] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[0] >> 8,
                           g_pBootCfg->EdbgAddr.wMAC[1] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[1] >> 8,
                           g_pBootCfg->EdbgAddr.wMAC[2] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[2] >> 8);
    EdbgOutputDebugString( "  Port: %s\r\n", inet_ntoa(g_pBootCfg->EdbgAddr.wPort));

    EdbgOutputDebugString( "  SubnetMask: %s\r\n", inet_ntoa(g_pBootCfg->SubnetMask));
    EdbgOutputDebugString( "}\r\n");
}


// Set default boot configuration values
static void BootConfigInit(DWORD dwIndex)
{
    UINT32 i;

    EdbgOutputDebugString("+BootConfigInit\r\n");

    g_pBootCfg = &g_pTOC->BootCfg;

    memset(g_pBootCfg, 0, sizeof(BOOT_CFG));

    g_pBootCfg->ConfigMagicNumber = EBOOT_CFG_MAGIC_NUMBER;
    g_pBootCfg->ConfigFlags  = BOOT_TYPE_MULTISTAGE | CONFIG_FLAGS_DEBUGGER;
    g_pBootCfg->BootDelay    = CONFIG_BOOTDELAY_DEFAULT;
    g_pBootCfg->SubnetMask = inet_addr("255.255.255.0");

    g_pBootCfg->bCleanBoot = FALSE;
	g_pBootCfg->fUpdateMode = FALSE;
	g_pBootCfg->bKITLBoot= FALSE;
//	g_pBootCfg->bUSBDLMode = TRUE;
	g_pBootCfg->KITLType= OAL_KITL_TYPE_NONE;
	
    g_pBootCfg->bUARTPathPDA = TRUE;
	g_pBootCfg->bNoSerialMSG = FALSE;
	g_pBootCfg->bUseOALLOG = TRUE;
	g_pBootCfg->bUseDRVMSG = TRUE;
	g_pBootCfg->dwLogMask = OALMASK(OAL_LOG_ERROR) | OALMASK(OAL_LOG_WARN) |OALMASK(OAL_INFO);

	for (i = 0; i < DRVLOG_PART_NUM; i++)
	{
		g_pBootCfg->dwDrvMsgMask[i] = INITIAL_LOGMASK_VAL;
	}
	
	memcpy(&g_pBootCfg->Clock_Info, &g_SysClockTable[SYS_CLK_DEF1], sizeof(g_pBootCfg->Clock_Info));
	
    EdbgOutputDebugString("-BootConfigInit\r\n");
    return;
}

void ID_Print(DWORD i) {
    DWORD j;
    EdbgOutputDebugString("ID[%u] {\r\n", i);
    EdbgOutputDebugString("  dwVersion: 0x%x\r\n",  g_pTOC->id[i].dwVersion);
    EdbgOutputDebugString("  dwSignature: 0x%x\r\n", g_pTOC->id[i].dwSignature);
    EdbgOutputDebugString("  String: '%s'\r\n", g_pTOC->id[i].ucString);
    EdbgOutputDebugString("  dwImageType: 0x%x\r\n", g_pTOC->id[i].dwImageType);
    EdbgOutputDebugString("  dwTtlSectors: 0x%x\r\n", g_pTOC->id[i].dwTtlSectors);
    EdbgOutputDebugString("  dwLoadAddress: 0x%x\r\n", g_pTOC->id[i].dwLoadAddress);
    EdbgOutputDebugString("  dwJumpAddress: 0x%x\r\n", g_pTOC->id[i].dwJumpAddress);
    EdbgOutputDebugString("  dwStoreOffset: 0x%x\r\n", g_pTOC->id[i].dwStoreOffset);
    for (j = 0; j < MAX_SG_SECTORS; j++) {
        if ( !g_pTOC->id[i].sgList[j].dwLength )
            break;
        EdbgOutputDebugString("  sgList[%u].dwSector: 0x%x\r\n", j, g_pTOC->id[i].sgList[j].dwSector);
        EdbgOutputDebugString("  sgList[%u].dwLength: 0x%x\r\n", j, g_pTOC->id[i].sgList[j].dwLength);
    }

    EdbgOutputDebugString("}\r\n");
}

void TOC_Print(void)
{
    int i;

    EdbgOutputDebugString("TOC {\r\n");
    EdbgOutputDebugString("dwSignature: 0x%x\r\n", g_pTOC->dwSignature);


    EdbgOutputDebugString("BootCfg\r\n");
    EdbgOutputDebugString("{\r\n");
    EdbgOutputDebugString("  ConfigFlags: 0x%x\r\n", g_pBootCfg->ConfigFlags);
    EdbgOutputDebugString("  dwBootDelay: 0x%x\r\n", g_pBootCfg->BootDelay);
    EdbgOutputDebugString("  IP: %s\r\n", inet_ntoa(g_pBootCfg->EdbgAddr.dwIP));
    EdbgOutputDebugString("  MAC Address: %B:%B:%B:%B:%B:%B\r\n",
                           g_pBootCfg->EdbgAddr.wMAC[0] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[0] >> 8,
                           g_pBootCfg->EdbgAddr.wMAC[1] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[1] >> 8,
                           g_pBootCfg->EdbgAddr.wMAC[2] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[2] >> 8);
    EdbgOutputDebugString("  Port: %s\r\n", inet_ntoa(g_pBootCfg->EdbgAddr.wPort));

    EdbgOutputDebugString("  SubnetMask: %s\r\n", inet_ntoa(g_pBootCfg->SubnetMask));
    EdbgOutputDebugString("}\r\n");


    for(i = 0;i < MAX_TOC_DESCRIPTORS;i++)
    {
        RETAILMSG(1, (TEXT("ID[%u]\r\n"), i));
        RETAILMSG(1, (TEXT("{\r\n")));
        RETAILMSG(1, (TEXT("  dwVersion: 0x%X\r\n"),    g_pTOC->id[i].dwVersion));
        RETAILMSG(1, (TEXT("  dwSignature: 0x%X\r\n"), g_pTOC->id[i].dwSignature));
        RETAILMSG(1, (TEXT("  String: %S\r\n"), g_pTOC->id[i].ucString));
        RETAILMSG(1, (TEXT("  dwImageType: 0x%X\r\n"), g_pTOC->id[i].dwImageType));
        RETAILMSG(1, (TEXT("  dwTtlSectors: 0x%X\r\n"), g_pTOC->id[i].dwTtlSectors));
        RETAILMSG(1, (TEXT("  dwLoadAddress: 0x%X\r\n"), g_pTOC->id[i].dwLoadAddress));
        RETAILMSG(1, (TEXT("  dwJumpAddress: 0x%X\r\n"), g_pTOC->id[i].dwJumpAddress));
        RETAILMSG(1, (TEXT("  dwStoreOffset: 0x%X\r\n"), g_pTOC->id[i].dwStoreOffset));
        RETAILMSG(1, (TEXT("}\r\n")));
    }    
}


// init the TOC to defaults
BOOL TOC_Init(void)
{
    DWORD dwSig = 0;

    memset(g_pTOC, 0, sizeof(g_TOC));

    // init boof cfg
    g_pBootCfg = &g_pTOC->BootCfg;

    memset(g_pBootCfg, 0, sizeof(BOOT_CFG));

	BootConfigInit(0);
    
    // init TOC...
    //
    g_pTOC->dwSignature = TOC_SIGNATURE;

    //  init TOC entry for Eboot
    //  Those are hard coded numbers from boot.bib
    g_pTOC->id[TOC_ENTRY_EBOOT].dwVersion     = (EBOOT_VERSION_MAJOR << 16) | EBOOT_VERSION_MINOR;
    g_pTOC->id[TOC_ENTRY_EBOOT].dwSignature   = IMAGE_EBOOT_SIG;
    g_pTOC->id[TOC_ENTRY_EBOOT].dwImageType   = IMAGE_TYPE_EBOOT;
    g_pTOC->id[TOC_ENTRY_EBOOT].dwLoadAddress = EBOOT_RAM_IMAGE_BASE;
    g_pTOC->id[TOC_ENTRY_EBOOT].dwJumpAddress = EBOOT_RAM_IMAGE_BASE;
    g_pTOC->id[TOC_ENTRY_EBOOT].dwStoreOffset = EBOOT_BLOCK;
    g_pTOC->id[TOC_ENTRY_EBOOT].dwTtlSectors  = FILE_TO_SECTOR_SIZE(IMAGE_EBOOT_SIZE);
    strcpy((char *)(g_pTOC->id[TOC_ENTRY_EBOOT].ucString), "eboot.bin");

    TOC_Print(); //lqm masked.

	return TRUE;
}

//
// Retrieve TOC from Nand.
//
static void LoopForDelay(UINT32 count) 
{ 
	volatile UINT32 j; 
	for(j = 0; j < count; j++)  ; 
}

volatile SDMMC_REG *g_vpHSMMCReg;	
BOOL TOC_Read(void)
{
    SectorInfo si;
    UINT32    i,j;
#ifdef SDMMC_BOOT    
    UINT32    dwTimeout;
    UINT32 *BufferToFuse = (UINT32 *)g_pTOC;
    UINT32 dwCountBlock=0;

	//modifed by terry 2012.6.15
#ifdef	SD_CHANNEL0
	g_vpHSMMCReg = (volatile SDMMC_REG *)OALPAtoVA(BASE_REG_PA_SDMMC0 , FALSE);
#else
	g_vpHSMMCReg = (volatile SDMMC_REG *)OALPAtoVA(BASE_REG_PA_SDMMC2 , FALSE);
#endif



#endif
    EdbgOutputDebugString("TOC_Read: %d \r\n", TOC_BLOCK);
	
    if ( !g_bBootMediaExist ) {
        EdbgOutputDebugString("TOC_Read ERROR: no boot media\r\n");
	    return FALSE;
	}

#ifdef SDMMC_BOOT
    RETAILMSG(1,(TEXT("### HSMMC::READTOC MMC from 0x%x to 0x%x 0x%x\n"),TOCSTARTSECTOR,SECTOROFTOC,BufferToFuse));    
    
    if (!SDHC_CLK_ON_OFF(1))
    {
        RETAILMSG(1,(TEXT("[ERROR] Not on/ff clock in TOC_Read()\r\n")));
        goto TOC_READ_FAIL;
    }
    
    dwTimeout = 0;
    while (!SDHC_CHECK_TRASN_STATE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERROR] SD/MMC card state is not TRANS in TOC_READ()\r\n")));
            goto TOC_READ_FAIL;
        }
        LoopForDelay(500000);
    }
    SDHC_SET_BLOCK_SIZE(7, 512); // Maximum DMA Buffer Size, Block Size
    SDHC_SET_BLOCK_COUNT(SECTOROFTOC); // Block Numbers to Write

    if (g_dwMMCSpec42 || g_dwIsSDHC)
        SDHC_SET_ARG(TOCSTARTSECTOR); // Card setctor Address to Write 
    else
        SDHC_SET_ARG(TOCSTARTSECTOR*512); // Card byte Address to Write


    SDHC_SET_TRANS_MODE(1, 1, 1, 1, 0);    

    dwTimeout = 0;
    while (!SDHC_WAIT_CMDLINE_READY())
    {  
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {        
            RETAILMSG(1,(TEXT("[ERROR] Not clear Cmd line in SDHC_READ().\r\n")));     
            goto TOC_READ_FAIL;
        }
    }     

    dwTimeout = 0;
    while (!SDHC_WAIT_DATALINE_READY())
    {   
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {        
            RETAILMSG(1,(TEXT("[ERROR] Not clear Data line in SDHC_READ().\r\n")));     
            goto TOC_READ_FAIL;
        }
    } 
    
    SDHC_SET_CMD(18, 0);
    dwTimeout = 0;
    while (!SDHC_WAIT_CMD_COMPLETE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERROR] No CMD Complete signal in TOC_READ()\r\n")));
            goto TOC_READ_FAIL;
        }
    }

    dwTimeout = 0;    
    while (!SDHC_CLEAR_CMD_COMPLETE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERROR] Not CMD Complete signal bit in TOC_READ()\r\n")));
            goto TOC_READ_FAIL;
        }        
    }

    for(j=0; j<SECTOROFTOC; j++)
    {
        dwTimeout = 0;
        while (!SDHC_WAIT_READ_READY())
        {
            if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
            {
                RETAILMSG(1,(TEXT("[ERROR] Not buffer ready in TOC_READ()\r\n")));
                goto TOC_READ_FAIL;
            }        
        }
        
        dwTimeout = 0;
        while (!SDHC_CLEAR_READ_READY())
        {
            if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
            {
                RETAILMSG(1,(TEXT("[ERROR] Not clear buffer ready bit in TOC_READ()\r\n")));
                goto TOC_READ_FAIL;
            }        
        }

        for(i=0; i<SECTOR_SIZE/4; i++)
        {
            *BufferToFuse++ = g_vpHSMMCReg->BDATA;
            dwCountBlock++;
        }
    }
    
    dwTimeout = 0;
    while(!SDHC_WAIT_TRANS_COMPLETE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERROR] Not clear buffer ready bit in TOC_READ()\r\n")));
            goto TOC_READ_FAIL;
        }        
    }
    
    dwTimeout = 0;    
    while(!SDHC_CLEAR_TRANS_COMPLETE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERROR] Not clear buffer ready bit in TOC_READ()\r\n")));
            goto TOC_READ_FAIL;
        }        
    }

        
#else
    if ( !FMD_ReadSector(TOC_SECTOR, (PUCHAR)g_pTOC, &si, 1) ) {
        EdbgOutputDebugString("TOC_Read ERROR: Unable to read TOC\r\n");
	    return FALSE;
	}
#endif
    // is it a valid TOC?
    if ( !VALID_TOC(g_pTOC) ) {
        EdbgOutputDebugString("TOC_Read ERROR: INVALID_TOC Signature: 0x%x\r\n", g_pTOC->dwSignature);
        return FALSE;
    }

    // is it an OEM block?
//    if ( (si.bBadBlock != BADBLOCKMARK) || (si.bOEMReserved & (OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY)) ) {
    if (si.bOEMReserved & (OEM_BLOCK_RESERVED)) {
        EdbgOutputDebugString("TOC_Read ERROR: SectorInfo verify failed: %x %x %x %x\r\n",
            si.dwReserved1, si.bOEMReserved, si.bBadBlock, si.wReserved2);
		return FALSE;
    }

    // invalidate TOC if Eboot version has been updated
    if (g_pTOC->id[0].dwVersion != ((EBOOT_VERSION_MAJOR << 16) | EBOOT_VERSION_MINOR))
	{
        EdbgOutputDebugString("TOC_Read WARN: Eboot version mismatch: TOC->dwVersion: 0x%x , Expected: 0x%x\r\n",
            g_pTOC->id[0].dwVersion, ((EBOOT_VERSION_MAJOR << 16) | EBOOT_VERSION_MINOR));
        EdbgOutputDebugString("Invalidating TOC for re-initializing.\r\n");
		return FALSE;
    }

    // update our boot config
    g_pBootCfg = &g_pTOC->BootCfg;
	
    // cache image type
    g_ImageType = g_pTOC->id[g_dwTocEntry].dwImageType;
	OALMSG(TRUE, (TEXT(" [SUN] g_ImageType: 0x%x \r\n"), g_ImageType));
	
    // Update BSP_ARGS from TOC stored in storage.
    // Setup stored OAL Log Mask stored in eboot configuration
	g_pBSPArgs->dwOALLogMask = g_pBootCfg->dwLogMask;
	g_pBSPArgs->bUseDRVMSG = g_pBootCfg->bUseDRVMSG;

	g_pBSPArgs->bKITLBoot		= g_pBootCfg->bKITLBoot;
	g_pBSPArgs->KITLType = g_pBootCfg->KITLType;
	g_pBSPArgs->bCleanBoot		= g_pBootCfg->bCleanBoot;
	g_pBSPArgs->fUpdateMode		= g_pBootCfg->fUpdateMode;
	g_pBSPArgs->bNoSerialMSG	= g_pBootCfg->bNoSerialMSG;
    
	OALLogSetZones(g_pBSPArgs->dwOALLogMask);

	for (i = 0; i<DRVLOG_PART_NUM; i++) {
		g_pBSPArgs->dwDrvMsgMask[i] = g_pBootCfg->dwDrvMsgMask[i];
	} 

#ifdef SDMMC_BOOT
      if (!SDHC_CLK_ON_OFF(0))
	{
		RETAILMSG(1,(TEXT("[ERR] Not on/ff clock in TOC_Read() 2\r\n")));
		goto TOC_READ_FAIL;
	}

#endif
	TOC_Print();
	
    OALMSG(OAL_FUNC, (TEXT(" - TOC_Read \r\n")));   
    return TRUE;


#ifdef SDMMC_BOOT
TOC_READ_FAIL:
	
    if (!SDHC_CLK_ON_OFF(0))
	{
		RETAILMSG(1,(TEXT("[ERR] Not on/ff clock in TOC_Read() 2\r\n")));
	} 	
	return FALSE;    
#endif

}


BOOL TOC_Write(void)
{
    SectorInfo si, si2;
#ifdef SDMMC_BOOT
    UINT32 i,j,dwTimeout;
    UINT32 *BufferToFuse = (UINT32 *)g_pTOC;
    UINT32 dwCountBlock=0;
    UCHAR ucTOC[TOC_SECTOR_SIZE];

	//modifed by terry 2012.6.15
#ifdef	SD_CHANNEL0
		 g_vpHSMMCReg = (volatile SDMMC_REG *)OALPAtoVA(BASE_REG_PA_SDMMC0 , FALSE);
#else
		 g_vpHSMMCReg = (volatile SDMMC_REG *)OALPAtoVA(BASE_REG_PA_SDMMC2 , FALSE);
#endif

#else
	static UCHAR toc[NAND_SECTOR_SIZE];
#endif    
    OALMSG(OAL_FUNC, (TEXT("+ TOC_Write\r\n")));

    if ( !g_bBootMediaExist ) {
		OALMSG(OAL_ERROR, (TEXT("TOC_Write WARN: no boot media\r\n")));
        return FALSE;
    }

#ifdef SDMMC_BOOT
    if (!SDHC_CLK_ON_OFF(1))
    {
        RETAILMSG(1,(TEXT("[ERR] Not on/ff clock in TOC_Write()\r\n")));
        goto TOC_WRITE_FAIL;
    }
#endif
    // is it a valid TOC?
    if ( !VALID_TOC(g_pTOC) ) {
		OALMSG(OAL_ERROR, (TEXT("TOC_Write ERROR: INVALID_TOC Signature: 0x%x\r\n"), g_pTOC->dwSignature));
        return FALSE;
    }

    // is it a valid image descriptor?
    if ( !VALID_IMAGE_DESCRIPTOR(&g_pTOC->id[g_dwTocEntry]) ) {
		OALMSG(OAL_ERROR, (TEXT("TOC_Write ERROR: INVALID_IMAGE[%u] Signature: 0x%x\r\n"), 
			g_dwTocEntry, g_pTOC->id[g_dwTocEntry].dwSignature));
        return FALSE;
    }
#ifdef SDMMC_BOOT


    dwTimeout = 0;    
    while (!SDHC_CHECK_TRASN_STATE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERR] SD/MMC card state is not TRANS in TOC_Write()\r\n")));
            goto TOC_WRITE_FAIL;
        }
        LoopForDelay(500000);
    }   

    SDHC_SET_BLOCK_SIZE(7, 512); // Maximum DMA Buffer Size, Block Size
    SDHC_SET_BLOCK_COUNT(SECTOROFTOC); // Block Numbers to Write

    if (g_dwMMCSpec42 || g_dwIsSDHC)
        SDHC_SET_ARG(TOCSTARTSECTOR); // Card Address to Write
    else
        SDHC_SET_ARG(TOCSTARTSECTOR*512); // Card Address to Write

    SDHC_SET_TRANS_MODE(1, 0, 1, 1, 0);


    dwTimeout = 0;
    while (!SDHC_WAIT_CMDLINE_READY())
    {  
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {        
            RETAILMSG(1,(TEXT("[ERR] Not clear Cmd line in SDHC_READ().\r\n")));     
            goto TOC_WRITE_FAIL;
        }
    }     

    dwTimeout = 0;
    while (!SDHC_WAIT_DATALINE_READY())
    {   
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {        
            RETAILMSG(1,(TEXT("[ERR] Not clear Data line in SDHC_READ().\r\n")));     
            goto TOC_WRITE_FAIL;
        }
    } 
    
    SDHC_SET_CMD(25, 0); 
    
    dwTimeout = 0;
    while (!SDHC_WAIT_CMD_COMPLETE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERR] No CMD Complete signal in TOC_Write()\r\n")));
            goto TOC_WRITE_FAIL;
        }
    }
    dwTimeout = 0;    
    while (!SDHC_CLEAR_CMD_COMPLETE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERR] Not CMD Complete signal bit in TOC_Write()\r\n")));
            goto TOC_WRITE_FAIL;
        }        
    }  

    for(j=0; j<SECTOROFTOC; j++)
    {
        dwTimeout = 0;
        while (!SDHC_WAIT_WRITE_READY())
        {
            if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
            {
                RETAILMSG(1,(TEXT("[ERR] No buffer ready signal in TOC_Write()\r\n")));
                goto TOC_WRITE_FAIL;
            }        
        }
        dwTimeout = 0;
        while (!SDHC_CLEAR_WRITE_READY())
        {
            if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
            {
                RETAILMSG(1,(TEXT("[ERR] Not clear buffer ready signal in TOC_Write()\r\n")));
                goto TOC_WRITE_FAIL;
            }        
        }

        for(i=0; i<SECTOR_SIZE/4; i++)//512 byte should be writed.
        {
            g_vpHSMMCReg->BDATA = *(UINT32 *)BufferToFuse++;    
            dwCountBlock++;                        
        }
    }

    dwTimeout = 0;
    while(!SDHC_WAIT_TRANS_COMPLETE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERR] No trasn complete signal in TOC_Write()\r\n")));
            goto TOC_WRITE_FAIL;
        }        
    }
    
    dwTimeout = 0;    
    while(!SDHC_CLEAR_TRANS_COMPLETE())
    {
        if ( dwTimeout++ > LOOP_FOR_TIMEOUT )
        {
            RETAILMSG(1,(TEXT("[ERR] Not clear trasn complete signal in TOC_WRITE()\r\n")));
            goto TOC_WRITE_FAIL;
        }        
    }

    // setup our metadata so filesys won't stomp us
    // write the sector & metadata

    memcpy ( &ucTOC , &g_TOC , TOC_SECTOR_SIZE );
    TOC_Read();

    if ( 0 != memcmp(&g_TOC, &ucTOC, TOC_SECTOR_SIZE) ) {
        EdbgOutputDebugString("TOC_Write ERROR: TOC verify failed\r\n");
        return FALSE;
    }


    if (!SDHC_CLK_ON_OFF(0))
    {
        RETAILMSG(1,(TEXT("[ERR] Not on/ff clock in TOC_Write() 2\r\n")));
        goto TOC_WRITE_FAIL;
    }   
    return TRUE;

TOC_WRITE_FAIL:

    if (!SDHC_CLK_ON_OFF(0))
    {
        RETAILMSG(1,(TEXT("[:ERR] Not on/ff clock in TOC_Write() 3\r\n")));
    }    
    return FALSE;
#else
    // in order to write a sector we must erase the entire block first
	// !! BUGBUG: must cache the TOC first so we don't trash other image descriptors !!
    if ( !FMD_EraseBlock(TOC_BLOCK) ) {
		OALMSG(OAL_ERROR, (TEXT("TOC_Write ERROR: EraseBlock[%d] \r\n"), g_TOC_BLOCK));
        return FALSE;
    }

    // setup our metadata so filesys won't stomp us
    si.dwReserved1 = 0xffffffff;
    si.bOEMReserved = ~(OEM_BLOCK_RESERVED);   // NAND cannot set bit 0->1
    si.bBadBlock = 0xff;
    si.wReserved2 = 0xffff;

    // write the sector & metadata
    if ( !FMD_WriteSector(TOC_SECTOR, (PUCHAR)&g_TOC, &si, 1) ) {
        OALMSG(OAL_ERROR, (TEXT("TOC_Write ERROR: Unable to save TOC\r\n")));
        return FALSE;
    }

    // read it back & verify both data & metadata
    if ( !FMD_ReadSector(TOC_SECTOR, (PUCHAR)&toc, &si2, 1) ) {
		OALMSG(OAL_ERROR, (TEXT("TOC_Write ERROR: Unable to read/verify TOC\r\n")));
        return FALSE;
    }

    if ( 0 != memcmp(&g_TOC, &toc, NAND_SECTOR_SIZE) ) {
        OALMSG(OAL_ERROR, (TEXT("TOC_Write ERROR: TOC verify failed\r\n")));
        return FALSE;
    }

    if ( 0 != memcmp(&si, &si2, sizeof(si)) ) {
        EdbgOutputDebugString("TOC_Write ERROR: SectorInfo verify failed: %x %x %x %x\r\n",
            si.dwReserved1, si.bOEMReserved, si.bBadBlock, si.wReserved2);
        return FALSE;
    }
#endif
    OALMSG(OAL_FUNC, (TEXT("- TOC_Write\r\n")));
    return TRUE;
}

/*
    @func   void | DumpXIPChainSummary | Dump XIPCHAIN_SUMMARY structure
    @rdesc  none
    @comm
    @xref
*/
void DumpXIPChainSummary(PXIPCHAIN_SUMMARY pChainInfo)
{
    EdbgOutputDebugString("[Dump XIP Chain Summary]\r\n");
    EdbgOutputDebugString(" - pvAddr: 0x%x\r\n", pChainInfo->pvAddr);
    EdbgOutputDebugString(" - dwMaxLength : %d\r\n", pChainInfo->dwMaxLength);
    EdbgOutputDebugString(" - usOrder : 0x%x\r\n", pChainInfo->usOrder);
    EdbgOutputDebugString(" - usFlags : 0x%x\r\n", pChainInfo->usFlags);
    EdbgOutputDebugString(" - reserved : 0x%x\r\n", pChainInfo->reserved);
}



static BOOL IsValidMBR() 
{
    BLOCK_ID  curBlock;
	
	DWORD dwMBRSectorNum;
    BYTE pbMBRSector[2048];
#ifdef SDMMC_BOOT

    RETAILMSG(1, (TEXT("[BP:INF] IsValidMBR: MBR sector = 0x%x\r\n"), MBRSTARTSECTOR));

	SDHC_READ(MBRSTARTSECTOR, SECTOROFMBR, (UINT32)pbMBRSector);

    RETAILMSG(1, (TEXT("KSH IsValidMBR 0x%x,0x%x,0x%x,\r\n"),pbMBRSector[0],pbMBRSector[1],pbMBRSector[2] ));
    return ((pbMBRSector[0] == 0xE9) &&
         (pbMBRSector[1] == 0xfd) &&
         (pbMBRSector[2] == 0xff) &&
         (pbMBRSector[SECTOR_SIZE-2] == 0x55) &&
         (pbMBRSector[SECTOR_SIZE-1] == 0xAA));
#else         
    
    for (curBlock = 0; curBlock < g_FlashInfo.dwNumBlocks; curBlock ++)
    {

		if((FMD_GetBlockStatus(curBlock) & (BLOCK_STATUS_BAD | BLOCK_STATUS_RESERVED)))
		{
            // skip bad or reserved block
            continue;		
        }
    
        // calculate the first sector of the block
        dwMBRSectorNum = curBlock * g_FlashInfo.wSectorsPerBlock;

        if (!FMD_ReadSector (dwMBRSectorNum, pbMBRSector, NULL, 1)) {
            // failed to read the sector, something is wrong
            return FALSE;
        }
        
        // check for MBR signature
        if ((pbMBRSector[0] == 0xE9) &&
            (pbMBRSector[1] == 0xfd) &&
            (pbMBRSector[2] == 0xff) &&
            (pbMBRSector[512-2] == 0x55) &&
            (pbMBRSector[512-1] == 0xAA)) {
        
            // found a valid MBR
            RETAILMSG (1, (TEXT("IsValidMBR: MBR sector = 0x%x (valid MBR)\r\n"), dwMBRSectorNum));            
            return TRUE;
        }
    }

    return FALSE;
    #endif
}


BOOL LoadNK()
{
    HANDLE hPart;
    
    OALMSG(OAL_FUNC, (TEXT("+LoadNK\r\n")));
    
    if(VALID_TOC(g_pTOC) != TRUE)
    {
        OALMSG(1, (TEXT("LoadNK : TOC is invalid. NK can't be loaded.\r\n")));
        return FALSE;
    }
    
    if(g_pTOC->id[TOC_ENTRY_NK].dwSignature != IMAGE_SXIP_SIG &&
        g_pTOC->id[TOC_ENTRY_NK].dwSignature != IMAGE_MXIP_SIG)
    {
        OALMSG(1, (TEXT("LoadNK : The image descriptor is invalid. NK can't be loaded.  Image signature = 0x%X\r\n"),
            g_pTOC->id[TOC_ENTRY_NK].dwSignature));

        return FALSE;
    }

    
    if( (OEMVerifyMemory(g_pTOC->id[TOC_ENTRY_NK].dwLoadAddress, sizeof(DWORD)) != TRUE) ||
        (OEMVerifyMemory(g_pTOC->id[TOC_ENTRY_NK].dwJumpAddress, sizeof(DWORD)) != TRUE) ||
        g_pTOC->id[TOC_ENTRY_NK].dwTtlSectors == 0 )
    {
        OALMSG(1, (TEXT("<ERROR> Invalid address or length. NK can't be loaded.\r\n")));
        OALMSG(1, (TEXT("<ERROR> LoadAddress = 0x%X, JumpAddress = 0x%X, # of sectors = 0x%X\r\n"),
            g_pTOC->id[TOC_ENTRY_NK].dwLoadAddress, g_pTOC->id[TOC_ENTRY_NK].dwJumpAddress, g_pTOC->id[TOC_ENTRY_NK].dwTtlSectors));
        return FALSE;
    }
    
    // Open the BINFS partition
    hPart = BP_OpenPartition(   
                                NEXT_FREE_LOC,
                                USE_REMAINING_SPACE,
                                PART_BINFS,
                                TRUE,
                                PART_OPEN_EXISTING
                            );
    
    if(hPart == INVALID_HANDLE_VALUE)
    {
        OALMSG(1, (TEXT("LoadNK : Failed to open existing partition.\r\n")));
        return FALSE;
    }
    
    // Set the partition file pointer to the correct offset for the kernel region.
    //
    if ( !BP_SetDataPointer(hPart, g_pTOC->id[TOC_ENTRY_NK].dwStoreOffset) )
    {
        OALMSG(1, (TEXT("<ERROR> Failed to set data pointer in partition (offset=0x%x).\r\n"),
            g_pTOC->id[TOC_ENTRY_NK].dwStoreOffset));
        return FALSE;
    }
    
    // Read the kernel region from the Boot Media into RAM.
    //
    if ( !BP_ReadData( hPart,
                       (LPBYTE)(g_pTOC->id[TOC_ENTRY_NK].dwLoadAddress),
                       SECTOR_TO_FILE_SIZE(g_pTOC->id[TOC_ENTRY_NK].dwTtlSectors)) )
    {
        OALMSG(1, (TEXT("Failed to read kernel region from partition.\r\n")));
        return FALSE;
    }

    OALMSG(OAL_INFO, (TEXT("NK was loaded successfully.\r\n")));
    
    return TRUE;
}

#ifdef SDMMC_BOOT
#define BUF_TEMP_SIZE 0x40000
extern BYTE g_BufTemp[BUF_TEMP_SIZE];
#endif

BOOL WriteFlashNK(DWORD dwStartAddr, DWORD dwLength)
{
    BYTE *pbBuffer;
    BOOL bReturn = TRUE;

    PXIPCHAIN_SUMMARY pXIPChainSummary = NULL;
    
    DWORD dwBINFSPartLength = 0;
    HANDLE hPartEx;
    DWORD dwStoreOffset = 0;
    DWORD dwMaxRegionLength[BL_MAX_BIN_REGIONS] = {0};
    DWORD dwChainStart, dwChainLength;
    
    
    DWORD dwStartAddrOrg;
    DWORD dwROMOffsetMSB;
    DWORD dwROMOffset;
    
    DWORD dwNumOfRegions;
    DWORD dwRegionIndex;
    
    BOOL bKernelImage;
   
    DWORD i;

	UCHAR ackdata[4] = {'O', 'K', 'U', 'P'};
	//UCHAR sizedata[4];

    
    //  Initialize the variables
    dwChainStart = dwChainLength = 0;
    
    
    if(!g_bBootMediaExist)
    {
        OALMSG(1, (TEXT("ERROR, No device exists.\r\n")));
        return(FALSE);
    }
    
    
    if(!VALID_TOC(g_pTOC))
    {
        OALMSG(OAL_WARN, (TEXT("WARNING, Invalid TOC\r\n")));
        OALMSG(OAL_WARN, (TEXT("Initialize TOC..\r\n")));

        if ( !TOC_Init() ) 
        {
            OALMSG(OAL_ERROR, (TEXT("ERROR: INVALID_TOC\r\n")));
            return(FALSE);
        }
    }


	OALMSG(1, (TEXT("[WriteFlashNK]:+++ dwStartAddr[0x%x] dwLength[0x%x] \r\n"),dwStartAddr,dwLength));
	


    pbBuffer = OEMMapMemAddr(dwStartAddr, dwStartAddr);

    // Original start address where the image is loaded (DRAM)
    dwStartAddrOrg = *(DWORD *)(OEMMapMemAddr(dwStartAddr, dwStartAddr + ROM_TOC_POINTER_OFFSET))
                        - *(DWORD *)(OEMMapMemAddr(dwStartAddr, dwStartAddr + ROM_TOC_OFFSET_OFFSET));


	

    // ROMOFFSET = dwStartAddr - dwStartAddrOrg
    dwROMOffsetMSB = (dwStartAddr >> 28) + 0x10 - (dwStartAddrOrg >> 28);
    dwROMOffset = ((dwROMOffsetMSB << 28) + (dwStartAddr & 0x0FFFFFFF)) - (dwStartAddrOrg & 0x0FFFFFFF);

    OALMSG(1, (TEXT("[WriteFlashNK]: dwROMOffsetMSB[0x%x] dwROMOffset[0x%x] \r\n"),dwROMOffsetMSB,dwROMOffset));
    
    dwStoreOffset = 0;                  // Where the image is written, the offset from the start of a partition
    bKernelImage = FALSE;               // set to TRUE only if the image is a kernel image (mutiple-XIP or single-XIP)
    
    if(g_pExt == NULL)
    {
        g_pExt = (EXTENSION *)GetKernelExtPointer(dwStartAddr, dwLength);

        if(g_pExt == NULL)
        {
            // The image has no ROMHDR extension.
            // a single NK.bin
            bKernelImage = TRUE;
        }

        // Map the address to the flash cache buffer.           
        g_pExt = (EXTENSION *)OEMMapMemAddr(dwStartAddr, (DWORD)g_pExt);            
    }

    OALMSG(1, (TEXT("[WriteFlashNK]: g_pExt[0x%x] \r\n"),(DWORD)g_pExt));   

    
    if(g_pExt != NULL)
    {
        if(g_pXIPChainSummary == NULL)
        {
            while(g_pExt != NULL)
            {
                if(g_pExt->type == 0 && strcmp(g_pExt->name, "chain information") == 0)
                {
                    g_pXIPChainSummary = (PXIPCHAIN_SUMMARY)OEMMapMemAddr(dwStartAddr, (DWORD)(g_pExt->pdata));
                    break;                                              
                }
                else
                {
                    g_pExt = (EXTENSION *)OEMMapMemAddr(dwStartAddr, (DWORD)(g_pExt->pNextExt));
                }
            }
        }
    
        if(g_pXIPChainSummary == NULL)
        {
            // Could not find the chain summary
            
            // The image has no XIP chain summary
            // a single NK.bin
            bKernelImage = TRUE;
            dwStoreOffset = 0;
        }
    }


    if(g_pXIPChainSummary)
    {
    OALMSG(1, (TEXT("[WriteFlashNK]: multbin \r\n")));       
        
        // Calculating the store offset by referring XIPCHAIN_SUMMARY.
    
        dwNumOfRegions = g_pExt->length / sizeof(XIPCHAIN_SUMMARY);
        dwRegionIndex = 0;
    
        pXIPChainSummary = g_pXIPChainSummary;
    
        
        while(1)
        {
            if(dwRegionIndex >= dwNumOfRegions)
            {
                // All XIP regions were checked.
				// No ROMXIP_OK_TO_LOAD flag for this image, thus skip writing. (ex. chain.bin)
				return TRUE;
            }
        
            if(pXIPChainSummary->usFlags & ROMXIP_OK_TO_LOAD)
            {
                // The region pointed by XIP chain summary is required to be written to the flash memory
                
                if(dwStartAddrOrg == (DWORD)(pXIPChainSummary->pvAddr))
                {
                    // The store offset for current image to be written was calculated successfully.
                    break;
                }

                // Add maximum length of the region which is pointed by the XIP chain summary
                // to the store offset of current image.
                dwStoreOffset += pXIPChainSummary->dwMaxLength;
            }
            else
            {
                // This region pointed by the XIP chain summary may be the chain.bin.
                // We don't need to write the chain.bin to the flash memory because we use NANDIMAGE type of non-kernel regions.
                // The BINFS enables kernel to do demand paging with the NAND flash memory.
                // If a non-kernel region is a RAMIMAGE type of image, OEMRomChain should be provided to the kernel.
                // Ref) http://msdn.microsoft.com/en-us/library/aa917019.aspx
                //      http://msdn.microsoft.com/en-us/library/ms836792.aspx
            }

    
            pXIPChainSummary++;
            dwRegionIndex++;
        }

        if(dwStartAddrOrg <= (DWORD)g_pExt && (DWORD)g_pExt < dwStartAddrOrg + dwLength)
        {
            // This region has ROMHDR extensions in its body.
            
            // Multiple-XIP kernel region
            bKernelImage = TRUE;
        }
    }
    else
    {
    OALMSG(1, (TEXT("[WriteFlashNK]: single bin \r\n")));      
        // The image has no ROMHDR extension.
        // a single NK.bin
        dwStoreOffset = 0;
    }

        
    if(g_hPartBINFS == INVALID_HANDLE_VALUE)
    {
        // calculate maximum length of BINFS partition
        // == sum of maximum lengths of all XIP regions

        if(g_pExt != NULL)
        {
			OALMSG(1, (TEXT("[WriteFlashNK]: Multiple-XIP \r\n"))); 

            // Multiple-XIP
            dwNumOfRegions = g_pExt->length / sizeof(XIPCHAIN_SUMMARY);
            dwRegionIndex = 0;
            dwBINFSPartLength = 0;

            pXIPChainSummary = g_pXIPChainSummary;
    
            while(1)
            {
                if(dwRegionIndex >= dwNumOfRegions)
                {
                    // All XIP regions were checked.
                    // end of calculating the length of BINFS partition
                    break;
                }
            
                if(pXIPChainSummary->usFlags & ROMXIP_OK_TO_LOAD)
                {
                    // The region pointed by XIP chain summary is required to be written to the flash memory
                    dwBINFSPartLength += pXIPChainSummary->dwMaxLength;
                }
                else
                {
                    // This region pointed by the XIP chain summary may be the chain.bin.
                    // We don't need to write the chain.bin to the flash memory because we use NANDIMAGE type of non-kernel regions.
                    // The BINFS enables kernel to do demand paging with the NAND flash memory.
                    // If a non-kernel region is a RAMIMAGE type of image, OEMRomChain should be provided to the kernel.
                    // Ref) http://msdn.microsoft.com/en-us/library/aa917019.aspx
                    //      http://msdn.microsoft.com/en-us/library/ms836792.aspx
                }
    
                pXIPChainSummary++;
                dwRegionIndex++;
            }
        }
        else
        {
            // Single-XIP
            dwBINFSPartLength = dwLength;
        }

		OALMSG(OAL_DEBUG, (TEXT("dwBINFSPartLength : 0x%X\r\n"), dwBINFSPartLength));
		OALMSG(OAL_DEBUG, (TEXT("dwLength          : 0x%X\r\n"), dwLength));




		OALMSG(1, (TEXT("dwBINFSPartLength : 0x%X\r\n"), dwBINFSPartLength));
		OALMSG(1, (TEXT("dwLength          : 0x%X\r\n"), dwLength));
		


		
        // temp
        // xip.bin has larger length than sum of maxlengths of all XIP regions
        // in this case, we should open a partition with the size of xip.bin
        if(dwBINFSPartLength < dwLength)
        {
        	RETAILMSG(1, (TEXT("dwBINFSPartLength = dwLength = 0x%x\r\n"), dwLength));
            dwBINFSPartLength = dwLength;
        }


#ifndef SDMMC_BOOT
		// TODO : Format should be done when it is really required. Ex) partition resizing.
		// Reserve boot blocks
		for(int i = 0;i < IMAGE_START_BLOCK;i++)
		{
			if(!(FMD_GetBlockStatus(i) & BLOCK_STATUS_BAD))
			{		
				FMD_SetBlockStatus(i, BLOCK_STATUS_RESERVED);
			}
		}

		OALMSG(1, (TEXT("[WriteFlashNK]:-----------1----\r\n")));	
#else
				SDHC_INIT();
#endif    




		if(BP_LowLevelFormat(0, g_FlashInfo.dwNumBlocks, FORMAT_SKIP_RESERVED | FORMAT_SKIP_BLOCK_CHECK) != TRUE)
		{
			OALMSG(OAL_ERROR, (TEXT("ERROR: Low-level boot media format failed.\r\n")));
			return FALSE;
		}
		
#ifdef SDMMC_BOOT

        // Open a BINFS partition
    g_hPartBINFS = BP_OpenPartition(SECTOROFMBR,
                             ((dwBINFSPartLength)/SECTOR_SIZE)+1,
                             PART_BINFS,
                             TRUE,
                             PART_OPEN_ALWAYS);
#else
        // Open a BINFS partition
        g_hPartBINFS = BP_OpenPartition
                        (
                            NEXT_FREE_LOC,
                            SECTOR_TO_BLOCK_SIZE(FILE_TO_SECTOR_SIZE(dwBINFSPartLength)) * _SECTORS_PER_BLOCK,
                            PART_BINFS,
                            TRUE,
                            PART_OPEN_ALWAYS
                        );

	OALMSG(1, (TEXT("[WriteFlashNK]:-----------2----\r\n")));	

#endif

        if(g_hPartBINFS == INVALID_HANDLE_VALUE)
        {
            RETAILMSG(1, (TEXT("<ERROR> WriteFlashNK : BINFS partition open was failed.\r\n")));
            return FALSE;
        }
        else
        {
            // Partition open success
			PPARTENTRY ppartBINFS = BP_GetPartitionInfo(g_hPartBINFS);
			if(ppartBINFS != NULL)
			{
				OALMSG(OAL_DEBUG, (TEXT("----- BINFS Partition -----\r\n"), ppartBINFS->Part_BootInd));
				OALMSG(OAL_DEBUG, (TEXT("Part_BootInd      : 0x%X\r\n"), ppartBINFS->Part_BootInd));
				OALMSG(OAL_DEBUG, (TEXT("Part_FirstHead    : 0x%X\r\n"), ppartBINFS->Part_FirstHead));
				OALMSG(OAL_DEBUG, (TEXT("Part_FirstSector  : 0x%X\r\n"), ppartBINFS->Part_FirstSector));
				OALMSG(OAL_DEBUG, (TEXT("Part_FirstTrack   : 0x%X\r\n"), ppartBINFS->Part_FirstTrack));
				OALMSG(OAL_DEBUG, (TEXT("Part_FileSystem   : 0x%X\r\n"), ppartBINFS->Part_FileSystem));
				OALMSG(OAL_DEBUG, (TEXT("Part_LastHead     : 0x%X\r\n"), ppartBINFS->Part_LastHead));
				OALMSG(OAL_DEBUG, (TEXT("Part_LastSector   : 0x%X\r\n"), ppartBINFS->Part_LastSector));
				OALMSG(OAL_DEBUG, (TEXT("Part_LastTrack    : 0x%X\r\n"), ppartBINFS->Part_LastTrack));
				OALMSG(OAL_DEBUG, (TEXT("Part_StartSector  : 0x%X\r\n"), ppartBINFS->Part_StartSector));
				OALMSG(OAL_DEBUG, (TEXT("Part_TotalSectors : 0x%X\r\n"), ppartBINFS->Part_TotalSectors));
				OALMSG(OAL_DEBUG, (TEXT("---------------------------\r\n"), ppartBINFS->Part_BootInd));

				OALMSG(1, (TEXT("----- BINFS Partition -----\r\n"), ppartBINFS->Part_BootInd));
				OALMSG(1, (TEXT("Part_BootInd      : 0x%X\r\n"), ppartBINFS->Part_BootInd));
				OALMSG(1, (TEXT("Part_FirstHead    : 0x%X\r\n"), ppartBINFS->Part_FirstHead));
				OALMSG(1, (TEXT("Part_FirstSector  : 0x%X\r\n"), ppartBINFS->Part_FirstSector));
				OALMSG(1, (TEXT("Part_FirstTrack   : 0x%X\r\n"), ppartBINFS->Part_FirstTrack));
				OALMSG(1, (TEXT("Part_FileSystem   : 0x%X\r\n"), ppartBINFS->Part_FileSystem));
				OALMSG(1, (TEXT("Part_LastHead     : 0x%X\r\n"), ppartBINFS->Part_LastHead));
				OALMSG(1, (TEXT("Part_LastSector   : 0x%X\r\n"), ppartBINFS->Part_LastSector));
				OALMSG(1, (TEXT("Part_LastTrack    : 0x%X\r\n"), ppartBINFS->Part_LastTrack));
				OALMSG(1, (TEXT("Part_StartSector  : 0x%X\r\n"), ppartBINFS->Part_StartSector));
				OALMSG(1, (TEXT("Part_TotalSectors : 0x%X\r\n"), ppartBINFS->Part_TotalSectors));
				OALMSG(1, (TEXT("---------------------------\r\n"), ppartBINFS->Part_BootInd));				
			}
			else
			{
				OALMSG(TRUE, (TEXT("Failed to get a BINFS partition information\r\n")));
				return FALSE;
			}
#ifdef SDMMC_BOOT     

            hPartEx = BP_OpenPartition( SECTOROFMBR + (SECTOROFIMAGE-SECTOROFFATFS),
                                    SECTOROFFATFS,
                                    PART_DOS32,
                                    TRUE,
                                    PART_OPEN_ALWAYS);

            // After fusing done, Store area shuold be clean.
            memset(g_BufTemp,0x00,SECTOR_SIZE);
            SDHC_WRITE(0, 1, (UINT32)g_BufTemp);

            BP_Storage_Init(g_BufTemp,0x1000,0,0,0);

            BP_OpenStoragePartition(IMAGESTARTSECTOR+SECTOROFIMAGE+0x100,
                                    g_dwSectorCount-(IMAGESTARTSECTOR+SECTOROFIMAGE+0x200+SECTOROFBOOTIMAGE),
                                    PART_DOS32,
                                    TRUE,
                                    PART_OPEN_ALWAYS);


            RETAILMSG(1,(TEXT("###### FlashImage Start sector 0x%x lenght 0x%x\r\n"),IMAGESTARTSECTOR,SECTOROFIMAGE));


#if 1            // update sector information after fusing image.
            g_AddressInfoSector.dwFlashImageStartSector = IMAGESTARTSECTOR;
            g_AddressInfoSector.dwFlashImageTotalSector = SECTOROFIMAGE;

            SDHC_WRITE(AISSTARTSECTOR, SECTOROFAIS, (UINT32)(&g_AddressInfoSector));
#endif
          
#else
            // Open an extension partition
            hPartEx = BP_OpenPartition( NEXT_FREE_LOC,
                                USE_REMAINING_SPACE,
                                PART_DOS32,
                                TRUE,
                                PART_OPEN_ALWAYS);

OALMSG(1, (TEXT("[WriteFlashNK]:-----------3----\r\n")));	


#endif
            if (hPartEx == INVALID_HANDLE_VALUE )
            {
                RETAILMSG(1, (TEXT("<WARNING> WriteFlashNK : Failed to open/create an extended partition.\r\n")));
            }
            else
            {
	            // Partition open success
				PPARTENTRY ppartEx = BP_GetPartitionInfo(hPartEx);
				if(ppartEx != NULL)
				{
					OALMSG(OAL_DEBUG, (TEXT("--- Extention Partition ---\r\n"), ppartBINFS->Part_BootInd));
					OALMSG(OAL_DEBUG, (TEXT("Part_BootInd      : 0x%X\r\n"), ppartEx->Part_BootInd));
					OALMSG(OAL_DEBUG, (TEXT("Part_FirstHead    : 0x%X\r\n"), ppartEx->Part_FirstHead));
					OALMSG(OAL_DEBUG, (TEXT("Part_FirstSector  : 0x%X\r\n"), ppartEx->Part_FirstSector));
					OALMSG(OAL_DEBUG, (TEXT("Part_FirstTrack   : 0x%X\r\n"), ppartEx->Part_FirstTrack));
					OALMSG(OAL_DEBUG, (TEXT("Part_FileSystem   : 0x%X\r\n"), ppartEx->Part_FileSystem));
					OALMSG(OAL_DEBUG, (TEXT("Part_LastHead     : 0x%X\r\n"), ppartEx->Part_LastHead));
					OALMSG(OAL_DEBUG, (TEXT("Part_LastSector   : 0x%X\r\n"), ppartEx->Part_LastSector));
					OALMSG(OAL_DEBUG, (TEXT("Part_LastTrack    : 0x%X\r\n"), ppartEx->Part_LastTrack));
					OALMSG(OAL_DEBUG, (TEXT("Part_StartSector  : 0x%X\r\n"), ppartEx->Part_StartSector));
					OALMSG(OAL_DEBUG, (TEXT("Part_TotalSectors : 0x%X\r\n"), ppartEx->Part_TotalSectors));
					OALMSG(OAL_DEBUG, (TEXT("---------------------------\r\n"), ppartBINFS->Part_BootInd));

				OALMSG(1, (TEXT("--- Extention Partition ---\r\n"), ppartBINFS->Part_BootInd));
				OALMSG(1, (TEXT("Part_BootInd	   : 0x%X\r\n"), ppartEx->Part_BootInd));
				OALMSG(1, (TEXT("Part_FirstHead    : 0x%X\r\n"), ppartEx->Part_FirstHead));
				OALMSG(1, (TEXT("Part_FirstSector  : 0x%X\r\n"), ppartEx->Part_FirstSector));
				OALMSG(1, (TEXT("Part_FirstTrack   : 0x%X\r\n"), ppartEx->Part_FirstTrack));
				OALMSG(1, (TEXT("Part_FileSystem   : 0x%X\r\n"), ppartEx->Part_FileSystem));
				OALMSG(1, (TEXT("Part_LastHead	   : 0x%X\r\n"), ppartEx->Part_LastHead));
				OALMSG(1, (TEXT("Part_LastSector   : 0x%X\r\n"), ppartEx->Part_LastSector));
				OALMSG(1, (TEXT("Part_LastTrack    : 0x%X\r\n"), ppartEx->Part_LastTrack));
				OALMSG(1, (TEXT("Part_StartSector  : 0x%X\r\n"), ppartEx->Part_StartSector));
				OALMSG(1, (TEXT("Part_TotalSectors : 0x%X\r\n"), ppartEx->Part_TotalSectors));
				OALMSG(1, (TEXT("---------------------------\r\n"), ppartBINFS->Part_BootInd));

					
				}
				else
				{
					OALMSG(TRUE, (TEXT("Failed to get an extension partition information\r\n")));
				}
			}           
        }
    }

    		OALMSG(1, (TEXT("[WriteFlashNK]:-----------4----\r\n")));	
    if(BP_SetDataPointer(g_hPartBINFS, dwStoreOffset) != TRUE)
    {
        RETAILMSG(1, (TEXT("<ERROR> WriteFlashNK : BP_SetDataPointer(0x%X, 0x%X) was failed.\r\n"), g_hPartBINFS, dwStoreOffset));
        return FALSE;
    }
    else
    {
        RETAILMSG(1, (TEXT("<INFO> WriteFlashNK : dwStoreOffset = 0x%X\r\n"), dwStoreOffset));
    }


    RETAILMSG (1, (TEXT("++++++++++WriteData: Start = 0x%x, Length = 0x%x.\r\n"), dwStoreOffset, dwLength));
    if(BP_WriteData(g_hPartBINFS, pbBuffer, dwLength) != TRUE)
    {
        RETAILMSG(1, (TEXT("<ERROR> WriteFlashNK : BP_WriteData(0x%X, 0x%X, 0x%X) was failed.\r\n"), g_hPartBINFS, pbBuffer, dwLength));
        return FALSE;
    }
	
    RETAILMSG (1, (TEXT("----------WriteData:\r\n")));

    if(bKernelImage)
    {
        // Default name
        memcpy(g_pTOC->id[TOC_ENTRY_NK].ucString, "NK", 2);
        g_pTOC->id[TOC_ENTRY_NK].ucString[2] = '\0';
        
        // find download manifest information for the NK
        for(i = 0;i < g_pDownloadManifest->dwNumRegions;i++)
        {
            if(g_pDownloadManifest->Region[i].dwRegionStart == dwStartAddr &&
                g_pDownloadManifest->Region[i].dwRegionLength == dwLength)
            {
                if(g_pDownloadManifest->Region[i].szFileName[0] == 0)
                {
                    // If the DownloadManifest does not have a filename, use the default name
                }
                else
                {
                    memcpy(g_pTOC->id[TOC_ENTRY_NK].ucString, g_pDownloadManifest->Region[i].szFileName, MAX_PATH);
                }
                break;  
            }
        }
            
        g_pTOC->id[TOC_ENTRY_NK].dwVersion          = 0x00000001;
        g_pTOC->id[TOC_ENTRY_NK].dwSignature        = (g_pXIPChainSummary == NULL) ? IMAGE_SXIP_SIG : IMAGE_MXIP_SIG;
        g_pTOC->id[TOC_ENTRY_NK].dwImageType        = IMAGE_TYPE_NK;
        g_pTOC->id[TOC_ENTRY_NK].dwLoadAddress      = dwStartAddrOrg;
        g_pTOC->id[TOC_ENTRY_NK].dwJumpAddress      = dwStartAddrOrg;           // TODO
        g_pTOC->id[TOC_ENTRY_NK].dwStoreOffset      = dwStoreOffset;
        g_pTOC->id[TOC_ENTRY_NK].dwTtlSectors       = FILE_TO_SECTOR_SIZE(dwLength);


      TOC_Write();
        RETAILMSG(1, (TEXT("WriteFlashNK : Kernel 0x%X  0x%X  0x%X\r\n"), dwStoreOffset, dwLength, dwStartAddrOrg));
    }


    return TRUE;
}
 


#ifndef SDMMC_BOOT
BOOL ReadBlock(DWORD dwBlock, LPBYTE pbBlock, PSectorInfo pSectorInfoTable)
{
    for (int iSector = 0; iSector < g_FlashInfo.wSectorsPerBlock; iSector++) {
        if (!FMD_ReadSector(dwBlock * g_FlashInfo.wSectorsPerBlock + iSector, pbBlock, pSectorInfoTable, 1))
            return FALSE;
        if (pbBlock)
            pbBlock += g_FlashInfo.wDataBytesPerSector;
        if (pSectorInfoTable)
            pSectorInfoTable++;
    }
    return TRUE;
}

BOOL WriteBlock(DWORD dwBlock, LPBYTE pbBlock, PSectorInfo pSectorInfoTable)
{
	OALMSG(0, (TEXT("++ WriteBlock  %d \r\n"), dwBlock));


#if (S5PV210_EVT>0)
	if(dwBlock == 0)
	{
		UINT32 CheckSum = 0;
		UINT32 dataLength = IMAGE_NBL1_SIZE;
	   	UINT8  Buffer;

		for(int i = IMAGE_NBL1_HEADER_SIZE;i < dataLength;i++)       // except Header (4WORD)
		{
			Buffer=*(volatile UINT8 *)(pbBlock+i);
			CheckSum = CheckSum + Buffer;
		}

		*(volatile UINT32 *)(pbBlock + HEADER_CHECKSUM_OFFSET) = CheckSum;

		OALMSG(TRUE, (TEXT("Checksum = %x,  header = %x %x %x %x\r\n"),
			CheckSum, 
			*(DWORD *)(pbBlock), 
			*(DWORD *)(pbBlock + 4), 
			*(DWORD *)(pbBlock + 8), 
			*(DWORD *)(pbBlock + 12)));
	}
#else
	// No checksum
#endif
	
    for (int iSector = 0; iSector < g_FlashInfo.wSectorsPerBlock; iSector++) {

// For iROM - NAND booting 
        if((dwBlock==0) && (iSector<(IMAGE_STEPLOADER_SIZE/(SECTOR_SIZE*4))))
        {
			OALMSG(0, (TEXT("++ FMD_WriteSector_Stepldr : 0x%x \r\n"), pbBlock));
            if (!FMD_WriteSector_Stepldr(dwBlock * g_FlashInfo.wSectorsPerBlock + iSector, pbBlock, pSectorInfoTable, 1))
                return FALSE;
			OALMSG(0, (TEXT("-- FMD_WriteSector_Stepldr\r\n")));
        }
		else
		{
        	if(dwBlock==0)
			{
				OALMSG(0, (TEXT(" End of writing Stepldr : BREAK! \r\n")));
				break;
        	}
			OALMSG(0, (TEXT(" ++ FMD_WriteSector: %d block, %d sector,  \r\n"), dwBlock, iSector));
	        if (!FMD_WriteSector(dwBlock * g_FlashInfo.wSectorsPerBlock + iSector, pbBlock, pSectorInfoTable, 1))
	            return FALSE;
			OALMSG(0, (TEXT(" -- FMD_WriteSector\r\n")));
        }
        if (pbBlock)
            pbBlock += g_FlashInfo.wDataBytesPerSector;
        if (pSectorInfoTable)
            pSectorInfoTable++;
    }
	OALMSG(0, (TEXT("-- WriteBlock\r\n")));
    return TRUE;
}
#endif

BOOL WriteRawImageToBootMedia(DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr)
{
	DWORD dwBlock = 0, dwNumBlocks = 0;
	LPBYTE pbBuffer;
    SectorInfo si;
	int i;
	
	OALMSG(OAL_FUNC, (TEXT("+WriteRawImageToBootMedia\r\n")));

    if ( !g_bBootMediaExist ) 
    {
        OALMSG(OAL_ERROR, (TEXT("ERROR: WriteRawImageToBootMedia: device doesn't exist.\r\n")));
        return(FALSE);
    }
	
    if (g_ImageType == IMAGE_TYPE_EBOOT)
    {
        dwBlock = EBOOT_BLOCK;
        if ( !VALID_TOC(g_pTOC) ) 
        {
            OALMSG(OAL_WARN, (TEXT("WARN: WriteRawImageToBootMedia: INVALID_TOC\r\n")));

            if ( !TOC_Init() ) 
            {
                OALMSG(OAL_ERROR, (TEXT("ERROR: INVALID_TOC\r\n")));
                return(FALSE);
            }
        }
    }
    else if (g_ImageType == IMAGE_TYPE_STEPLDR)
    {
        dwBlock = NBOOT_BLOCK;
        dwImageStart += dwLaunchAddr;
        dwImageLength = IMAGE_STEPLOADER_SIZE; //step loader can support 8k bytes.
    }
#ifdef SDMMC_BOOT
    else if (g_ImageType == IMAGE_TYPE_BOOTIMAGE)
    {        
        OALMSG(TRUE, (TEXT("g_ImageType = IMAGE_TYPE_BOOTIMAGE \r\n")));        
    }

	
	//added by terry for logo.bin 2012.06.18
	else if (g_ImageType == IMAGE_TYPE_LOGO)
	{
		OALMSG(TRUE, (TEXT("g_ImageType = IMAGE_TYPE_LOGO \r\n")));
	}

	
    pbBuffer = OEMMapMemAddr(dwImageStart, dwImageStart);

#else
    else if (g_ImageType == IMAGE_TYPE_BOOTIMAGE)
    {		
    	OALMSG(TRUE, (TEXT("g_ImageType = IMAGE_TYPE_BOOTIMAGE \r\n")));
        dwBlock = NBOOT_BLOCK;
        dwImageStart += dwLaunchAddr;
        dwImageLength = (IMAGE_STEPLOADER_SIZE + EBOOT_RAM_IMAGE_SIZE); //step loader can support 8k bytes.
		
    }

//added by terry for logo.bin 2012.06.18
else if (g_ImageType == IMAGE_TYPE_LOGO)
{
	OALMSG(TRUE, (TEXT("g_ImageType = IMAGE_TYPE_LOGO \r\n")));
	dwBlock = LOGO_BLOCK;

}
    pbBuffer = OEMMapMemAddr(dwImageStart, dwImageStart);

	// Compute number of blocks.
    dwNumBlocks = (dwImageLength / (g_FlashInfo.wDataBytesPerSector*g_FlashInfo.wSectorsPerBlock)) + (dwImageLength%(g_FlashInfo.wDataBytesPerSector*g_FlashInfo.wSectorsPerBlock) ? 1: 0);
    OALMSG(TRUE, (TEXT("dwImageLength = 0x%x \r\n"), dwImageLength));
	OALMSG(TRUE, (TEXT("dwNumBlocks = 0x%x \r\n"), dwNumBlocks));



	
#endif

#ifdef SDMMC_BOOT

SDHC_INIT();

//added by terry for logo.bin 2012.06.18
if (g_ImageType == IMAGE_TYPE_LOGO)
{
    RETAILMSG(1,(TEXT("Fusing Loader from memory 0x%x start sector %d \r\n"),pbBuffer,LOGOSTARTSECTOR));
    SDHC_WRITE(LOGOSTARTSECTOR, SECTORFORLOGO, (UINT32)pbBuffer);

}
else
{




#if (S5PV210_EVT>0)
        UINT32 CheckSum = 0;
        UINT32 dataLength = IMAGE_NBL1_SIZE;
           UINT8  Buffer;

        for(int i = IMAGE_NBL1_HEADER_SIZE;i < dataLength;i++)       // except Header (4WORD)
        {
            Buffer=*(volatile UINT8 *)(pbBuffer+i);
            CheckSum = CheckSum + Buffer;
        }

        *(volatile UINT32 *)(pbBuffer + HEADER_CHECKSUM_OFFSET) = CheckSum;

        OALMSG(TRUE, (TEXT("Checksum = %x,  header = %x %x %x %x\r\n"),
            CheckSum, 
            *(DWORD *)(pbBuffer), 
            *(DWORD *)(pbBuffer + 4), 
            *(DWORD *)(pbBuffer + 8), 
            *(DWORD *)(pbBuffer + 12)));
#else



            UINT32 CheckSum = 0;
        UINT32 dataLength = IMAGE_NBL1_SIZE - 4;
        UINT8  Buffer;

        for(i=0;i<dataLength;i++)
        {
            Buffer=*(volatile UINT8 *)(pbBuffer+i);
            CheckSum = CheckSum + Buffer;
        }

        *(volatile UINT32 *)(pbBuffer+i) = CheckSum;

#endif

    RETAILMSG(1,(TEXT("Fusing Loader from memory 0x%x start sector %d 0x%x 0x%x\r\n"),pbBuffer,BOOTIMAGESTARTSECTOR,*((volatile UINT32 *)(pbBuffer+8)),CheckSum));
    SDHC_WRITE(BOOTIMAGESTARTSECTOR, SECTOROFBOOTIMAGE, (UINT32)pbBuffer);

        // update sector information after fusing bootimage.
        g_AddressInfoSector.dwSignature = 0x53c5d5d;
        g_AddressInfoSector.dwStepldrStartSector = STEPLDRSTARTSECTOR;
        g_AddressInfoSector.dwStepldrTotalSector = SECTOROFSTEPLDR;
        g_AddressInfoSector.dwEbootStartSector = EBOOTSTARTSECTOR;
        g_AddressInfoSector.dwEbootTotalSector = SECTOROFEBOOT;
        g_AddressInfoSector.dwIPLStartSector = IPLSTARTSECTOR;
        g_AddressInfoSector.dwIPLTotalSector = SECTOROFIPL;
        g_AddressInfoSector.dwBootimageStartSector = BOOTIMAGESTARTSECTOR;
        g_AddressInfoSector.dwBootImageTotalSector = SECTOROFBOOTIMAGE;

	// added by terry for logo.bin 2012.06.27
        g_AddressInfoSector.dwBootimageStartSector = LOGOSTARTSECTOR;
        g_AddressInfoSector.dwBootImageTotalSector = SECTORFORLOGO;



        SDHC_WRITE(AISSTARTSECTOR, SECTOROFAIS, (UINT32)(&g_AddressInfoSector));

}   
    if (g_ImageType == IMAGE_TYPE_BOOTIMAGE)
    {

        memcpy(g_pTOC->id[TOC_ENTRY_BOOTSCREEN].ucString, "BOOTIMAG", 9);
        g_pTOC->id[TOC_ENTRY_BOOTSCREEN].ucString[9] = '\0';
         g_pTOC->id[TOC_ENTRY_BOOTSCREEN].dwVersion           = 0x00000000;                   // TODO : version management 
        g_pTOC->id[TOC_ENTRY_BOOTSCREEN].dwSignature         = IMAGE_BOOTSCREEN_SIG;
        g_pTOC->id[TOC_ENTRY_BOOTSCREEN].dwImageType         = IMAGE_TYPE_BOOTIMAGE;
        g_pTOC->id[TOC_ENTRY_BOOTSCREEN].dwLoadAddress       = (DWORD)pbBuffer;
        g_pTOC->id[TOC_ENTRY_BOOTSCREEN].dwJumpAddress       = (DWORD)pbBuffer;
        g_pTOC->id[TOC_ENTRY_BOOTSCREEN].dwStoreOffset       = BOOTIMAGESTARTSECTOR;
        g_pTOC->id[TOC_ENTRY_BOOTSCREEN].dwTtlSectors        = SECTOROFBOOTIMAGE;        

    }

      TOC_Write();
      TOC_Print();
    OALMSG(OAL_FUNC, (TEXT("_WriteRawImageToBootMedia\r\n")));
    
#else
	while (dwNumBlocks--)
    {
        // If the block is marked bad, skip to next block.  Note that the assumption in our error checking
        // is that any truely bad block will be marked either by the factory during production or will be marked
        // during the erase and write verification phases.  If anything other than a bad block fails ECC correction
        // in this routine, it's fatal.

        OALMSG(OAL_FUNC, (TEXT("dwBlock(0x%x) X "), dwBlock));
        OALMSG(OAL_FUNC, (TEXT("g_FlashInfo.wSectorsPerBlock(0x%x)"), g_FlashInfo.wSectorsPerBlock));
        OALMSG(OAL_FUNC, (TEXT(" = 0x%x \r\n"), dwBlock*g_FlashInfo.wSectorsPerBlock));

        if(g_ImageType != IMAGE_TYPE_STEPLDR && g_ImageType != IMAGE_TYPE_EBOOT && g_ImageType != IMAGE_TYPE_BOOTIMAGE && (g_ImageType != IMAGE_TYPE_LOGO))

//        if(g_ImageType != IMAGE_TYPE_STEPLDR && g_ImageType != IMAGE_TYPE_EBOOT && g_ImageType != IMAGE_TYPE_BOOTIMAGE)
        {
            // This will skip BadBlock for OS Images
            if((FMD_GetBlockStatus(dwBlock) & (BLOCK_STATUS_BAD | BLOCK_STATUS_RESERVED)))
            {
                OALMSG(TRUE, (TEXT("FMD_GetBlockStatus Error \r\n")));
                ++dwBlock;
                ++dwNumBlocks;
                continue;
            }
            if (!FMD_ReadSector(dwBlock*g_FlashInfo.wSectorsPerBlock, NULL, &si, 1))
            {
                OALMSG(TRUE, (TEXT("%s: Failed to get block(0x%x)'s sector info.\r\n"), _T(__FUNCTION__), dwBlock));
                ++dwBlock;
                ++dwNumBlocks;
            }
        }
        else
        {
            OALMSG(OAL_FUNC, (TEXT("Ignore BadBlock Checking for Step loader and eboot\r\n")));

            if (!FMD_ReadSector(dwBlock*g_FlashInfo.wSectorsPerBlock, NULL, &si, 1))
            {
                OALMSG(TRUE, (TEXT("%s: Failed to get block(0x%x)'s sector info.\r\n"), _T(__FUNCTION__), dwBlock));
            }

        }

        if(dwBlock != NBOOT_BLOCK)
        {       
            // Stepldr & Eboot image in nand flash
            // block mark as BLOCK_STATUS_RESERVED & BLOCK_STATUS_READONLY & BLOCK_STATUS_BAD
            if ((si.bBadBlock == BADBLOCKMARK) && (si.bOEMReserved != 0xFC ))
            {
                ++dwBlock;
                ++dwNumBlocks;        // Compensate for fact that we didn't write any blocks.
                continue;
            }

            if (!ReadBlock(dwBlock, NULL, g_pSectorInfoBuf))
            {
                OALMSG(OAL_ERROR, (TEXT("WriteData: failed to read block (0x%x).\r\n"), dwBlock));
                return(FALSE);
            }
	    g_pSectorInfoBuf->bOEMReserved &= ~OEM_BLOCK_RESERVED;

        }
		if (!FMD_EraseBlock(dwBlock))
        {
			OALMSG(OAL_ERROR, (TEXT("WriteData: failed to erase block (0x%x).\r\n"), dwBlock));
            return FALSE;
        }

		 if (!WriteBlock(dwBlock, pbBuffer, g_pSectorInfoBuf))
        {
            OALMSG(OAL_ERROR, (TEXT("WriteData: failed to write block (0x%x).\r\n"), dwBlock));
            return(FALSE);
        }else
    	{
	        RETAILMSG(1,  (TEXT("WriteData: succes to write block (0x%x).\r\n"), dwBlock));
    	}

		
		if(dwBlock==0)
			pbBuffer += IMAGE_STEPLOADER_SIZE;
		else
			pbBuffer += g_FlashInfo.dwBytesPerBlock;

        ++dwBlock;

        OALMSG(0,  (TEXT("dwBytesPerBlock : %d\r\n"), g_FlashInfo.dwBytesPerBlock));
    }

    if (g_ImageType == IMAGE_TYPE_EBOOT)
    {
        // Default name
        memcpy(g_pTOC->id[TOC_ENTRY_EBOOT].ucString, "EBOOT", 5);
        g_pTOC->id[TOC_ENTRY_EBOOT].ucString[5] = '\0';
        
        // find download manifest information for the EBOOT
        // While a ".lst" file which contains the EBOOT is downloaded, a filename for EBOOT(ex, eboot.bin) is provided.
        for(i = 0;i < g_pDownloadManifest->dwNumRegions;i++)
        {
            if(g_pDownloadManifest->Region[i].dwRegionStart == dwImageStart &&
                g_pDownloadManifest->Region[i].dwRegionLength == dwImageLength)
            {
                if(g_pDownloadManifest->Region[i].szFileName[0] == 0)
                {
                    // If the DownloadManifest does not have a filename, use the default name
                }
                else
                {
                    memcpy(g_pTOC->id[TOC_ENTRY_EBOOT].ucString, g_pDownloadManifest->Region[i].szFileName, MAX_PATH);
                }
                break;  
            }
        }

        g_pTOC->id[TOC_ENTRY_EBOOT].dwVersion           = 0x00000001;                   // TODO : version management 
        g_pTOC->id[TOC_ENTRY_EBOOT].dwSignature         = IMAGE_EBOOT_SIG;
        g_pTOC->id[TOC_ENTRY_EBOOT].dwImageType         = IMAGE_TYPE_EBOOT;
        g_pTOC->id[TOC_ENTRY_EBOOT].dwLoadAddress       = dwImageStart;
        g_pTOC->id[TOC_ENTRY_EBOOT].dwJumpAddress       = dwImageStart;
        g_pTOC->id[TOC_ENTRY_EBOOT].dwStoreOffset       = EBOOT_BLOCK;
        g_pTOC->id[TOC_ENTRY_EBOOT].dwTtlSectors        = FILE_TO_SECTOR_SIZE(dwImageLength);
    }

    OALMSG(OAL_FUNC, (TEXT("_WriteRawImageToBootMedia\r\n")));
#endif
    return TRUE;
}

