brdbootldr/ubootldr/main.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 11 May 2010 17:28:22 +0300
branchRCL_3
changeset 26 c734af59ce98
parent 0 a41df078684a
permissions -rw-r--r--
Revision: 201019 Kit: 201019

// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// improvised boot loader mechanism
// 
//

/**
 @file
*/

#include <e32const.h>
#include <e32const_private.h>
#include <e32std.h>
#include <e32std_private.h>
#include <e32svr.h>
#include <e32cons.h>
#include <f32file.h>
#include <hal.h>
#include <u32hal.h>
#include "bootloader_variantconfig.h"
#include <nkern/nk_trace.h>
#include <e32twin.h>
#include <e32rom.h>

#include <hal.h>
#include <d32ethernet.h>

#define FILE_ID	0x594D555D
#include "bootldr.h"
#include "ubootldrldd.h"

#include <d32comm.h>

#ifdef _DEBUG_CORELDR_
#define WAIT_TO_REBOOT  10000000
#else
#define WAIT_TO_REBOOT    100000
#endif

#define addr_to_page(a) (a&~(0x1000-1))

_LIT(KPanicText,"UBOOTLDR");
_LIT(LDD_NAME, "Enet");
_LIT(PDD_NAME, "Ethernet");

// Memory
RUBootldrLdd Ldd;
RChunk TheRamChunk;		// This is the download area

/// Global number of seconds to delay before reboot

void GetChunk()
	{
	TInt PageSize;
	UserHal::PageSizeInBytes(PageSize);

	TInt r = User::LoadLogicalDevice(KBootldrLddName);

	r = Ldd.Open();
	if (r!=KErrNone)
			{
			PrintToScreen(_L("FAULT due to LDD open\r\n"));
			BOOT_FAULT();
			}

	TUint8* kernelAddress;
	r=Ldd.CreateChunk(KRamTargetSize,(TAny**)&kernelAddress);
	if (r!=KErrNone)
			{
			PrintToScreen(_L("FAULT due to chunk create\r\n"));
			BOOT_FAULT();
			}

	r = Ldd.CommitMemory(KRamTargetSize,addr_to_page(KRamTargetAddr));
	if (r!=KErrNone)
			{
			PrintToScreen(_L("FAULT due to commit\r\n"));
			BOOT_FAULT();
			}

	r = Ldd.GetChunkHandle(TheRamChunk);
	if (r!=KErrNone)
			{
			PrintToScreen(_L("FAULT due to handle\r\n"));
			BOOT_FAULT();
			}

	TUint8* Base = TheRamChunk.Base();
	ActualDestinationAddress = (TUint32*)Base;
	}

// method of getting the date string at build time
// Taken from e32test\device\t_usbco22.cpp
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WDATE__ WIDEN(__DATE__)


//////////////////////////////////////////////////////////////////////////////
//
// Application entry point
//
//////////////////////////////////////////////////////////////////////////////
LOCAL_C void RunAppL()
	{
	TInt r;

	// Get the memory download area mapped into a chunk
	GetChunk();

	// Initialise our graphical screen
	InitDisplay();

#ifdef __USE_VARIANT_INIT__
	// The variant initialisation function is likely to perform bootloader
	// configuration or print debug information.
	VariantInit();
#endif

#ifdef __USE_USBMS__
	// If the bootloader is in the USB Mass Storage mode (indicated by the Variant
	// initialisation routine) then call that method first; it will either read/boot
	// an image, start the USB Mass Storage boot application or return.
	if ((LoadDevice==ELoadUSBMS) || (LoadDevice==EBootUSBMS))
		TryUSBMS();
#endif

	// Start the menu UI thread, this will cause a console to overwrite the framebuffer
	StartMenu();
	ClearScreen();

	PrintToScreen(_L("Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).\r\n"));
	PrintToScreen(_L("BootLoader %d.%d\r\n"), BOOTLDR_VERSION_MAJOR, BOOTLDR_VERSION_MINOR);
	PrintToScreen(_L("Platform build %d\n\rBuilt: %s\r\n"), PLATFORM_BUILD, __WDATE__);

	// Load Ethernet driver:  it might need to load to set the MAC address in HAL
    TInt pddLoaded = KErrUnknown;
	TInt lddLoaded = KErrUnknown;
	TInt opened    = KErrUnknown;
	RBusDevEthernet card;

    pddLoaded = User::LoadPhysicalDevice(PDD_NAME);
	if (pddLoaded == KErrNone)
		{
		lddLoaded = User::LoadLogicalDevice(LDD_NAME);
		if (lddLoaded == KErrNone)
			{
			opened = card.Open(0);
			User::After(2000);
			}
		}

	TInt serialNum;
	r = HAL::Get(HAL::ESerialNumber, serialNum);

	if (r == KErrNone && serialNum != 0)
		{
		// we only show the serial number if it was available from HAL and set to something
		PrintToScreen(_L("MAC Address: 00-0a-%02x-%02x-%02x-%02x\r\n"),
			(serialNum & 0xFF000000) >> 24,
			(serialNum & 0x00FF0000) >> 16,
			(serialNum & 0x0000FF00) >>  8,
			(serialNum & 0x000000FF)
			);
		}


	// Free the Ethernet driver now we're done getting the MAC address
	if (opened == KErrNone)
		{
		card.Close();
		}
	if (lddLoaded == KErrNone)
		{
	    User::FreeLogicalDevice(LDD_NAME);
		}
	if (pddLoaded == KErrNone)
		{
	    User::FreePhysicalDevice(PDD_NAME);
		}

	if (LoadDevice == EBootEMMC)
		{
		if ( SearchDrivesRaw() )
			{
			DoDownload();
			}
		}
		
#ifdef __USE_LOCAL_DRIVES__
	// The next method to test is reading an image file from removable media
	if (SearchDrives())
		DoDownload();
#endif

	// The last method is to attempt to download an image over the serial port
	switch (SerialBaud)
		{
		case EBps115200:
			PrintToScreen(_L("Initiating YModem-G on port %d @ 115200 baud\r\n"), SerialDownloadPort);
			break;
		case EBps230400:
			PrintToScreen(_L("Initiating YModem-G on port %d @ 230400 baud\r\n"), SerialDownloadPort);
			break;
		default:
			PrintToScreen(_L("Initiating YModem-G download on port %d\r\n"), SerialDownloadPort);
			SerialBaud = EBps115200;
			break;
		}
	r=InitSerialDownload(SerialDownloadPort);
	if (r!=KErrNone)
		{
		RDebug::Print(_L("FAULT: YModem-G download returned %d\r\n"),r);
		BOOT_FAULT();
		}

	PrintToScreen(_L("Receiving %lS\r\nSize %d\r\n"),&FileName,FileSize);
	DoDownload();
}

TUint Check(const TUint32* aPtr, TInt aSize)
	{
	TUint sum=0;
	aSize/=4;
	while (aSize-->0)
		sum+=*aPtr++;
	return sum;
	}

TUint CheckSumRom()
	{
#if 0
	//
	// This code was obtained from t_romchk in the e32tests, it was useful for
	// checking that roms were not getting corrupted during the download
	// process.
	//
	// However, it is not a universal checksum and is not suitable for all
	// types of images it is therefore being disabled until we need it again.
	//

	PrintToScreen(_L("Checking ROM contents...\r\n"));

	const TRomHeader* romHdr = (const TRomHeader*)DestinationAddress();
	TInt size = romHdr->iUnpagedUncompressedSize;
	const TUint32* addr = (TUint32*)romHdr;
	PrintToScreen(_L("ROM at %x, size %x\r\n"),addr,size);

	TUint checkSum = Check(addr,size);

	// hack the checksum because ROMBUILD is broken
	checkSum -= (romHdr->iRomSize-size)/4; // adjust for missing 0xffffffff
	checkSum -= romHdr->iCompressionType;
	checkSum -= romHdr->iUnpagedCompressedSize;
	checkSum -= romHdr->iUnpagedUncompressedSize;

	TUint expectedChecksum = 0x12345678;
	if (checkSum != expectedChecksum)
		{
		PrintToScreen(_L("Fail: Checksum = %8x, expected %8x\r\n"),checkSum,expectedChecksum);
		RDebug::Print(_L("Fail: Checksum = %8x, expected %8x\r\n"),checkSum,expectedChecksum);
		BOOT_FAULT();
		}
	else
		{
		PrintToScreen(_L("Pass: Checksum = %8x, expected %8x\r\n"),checkSum,expectedChecksum);
		RDebug::Print(_L("Pass: Checksum = %8x, expected %8x\r\n"),checkSum,expectedChecksum);
		}
#endif
	return 0;
	}


GLDEF_C void DoDownload()
/*
 The DoDownload method is ultimatly called by all the download routines, it is
 responsible for unzipping images as well as stripping off EPOC headers and
 starting the flash writing methods.
 */
	{
	TInt r;

	// If the image is zipped start the unzip thread
	if (ImageZip)
		{
		// initialise unzip
		PrintToScreen(_L("Loading zip ..\r\n"));
		r=DoZipDownload(bootFile);
		if (r!=KErrNone)
			{
			PrintToScreen(_L("\r\nFAULT due to zip %d\r\n"), r);
			BOOT_FAULT();
			}
		PrintToScreen(_L("\r\nZip download complete.\r\n"));
		}
	else
		{
		LoadSize=FileSize;
				
		if( ImageDeflated )
    		{
    		PrintToScreen(_L("\r\n\r\nLoading deflated image...\r\n"));
    	    ImageHeaderPresent=EFalse;
    	    DoDeflateDownload();
    	    PrintToScreen(_L("Deflated image download complete.\r\n"));	  
    		}
		else
    		{
    		// If it isn't a zipped or deflated image then the filesize is the image size -
    		// check that it is valid for a Symbian image and determine whether to
    		// remove any header that may be present.
    		TInt size_mod_4k=FileSize & 0xfff;
    		if (size_mod_4k==0)
    			{
    			ImageHeaderPresent=EFalse;
    			PrintToScreen(_L("Image header not present.\r\n"));
    			}
    		else if (size_mod_4k==256)
    			{
    			ImageHeaderPresent=ETrue;
    			PrintToScreen(_L("Image header present.\r\n"));
    			}
    		else
    			{
    		    PrintToScreen(_L("\r\n\r\nInvalid size\r\n"));
    			BOOT_FAULT();	
    			}
    		ImageSize=ImageHeaderPresent ? LoadSize-256 : LoadSize;
    		TUint8* pD=(TUint8*)DestinationAddress();
    		TInt block_size;
    		if (FileSize==0)
    			block_size=0x1000;		// YModem download with unknown size
    		else
    			block_size=Max(0x1000,FileSize>>8);
    		block_size=(block_size+0xfff)&~0xfff;
    		if (FileSize>0)
    			InitProgressBar(0,(TUint)FileSize,_L("LOAD"));
    		r=KErrNone;

// If target location is flash start the flasher thread
#ifdef __SUPPORT_FLASH_REPRO__
    		if (LoadToFlash)
    			{
    			r=InitFlashWrite();
    			if (r!=KErrNone)
    				{
    				PrintToScreen(_L("FAULT due to InitFlashWrite return %d\r\n"), r);
    				BOOT_FAULT();
    				}
    			}
#endif

    		while (r==KErrNone)
    			{
    			TInt len=block_size;
    			r=ReadInputData(pD,len);

    			if (r!=KErrNone && r!=KErrEof)
    				break;
    			pD+=len;
    			ImageReadProgress+=len;
    			if (FileSize>0)
    				{
    				UpdateProgressBar(0,(TUint)ImageReadProgress);
				}
#ifdef __SUPPORT_FLASH_REPRO__
    			if (LoadToFlash)
    				NotifyDataAvailable(ImageReadProgress);
#endif
    			}

    		if (r!=KErrEof)	
    			{
    			PrintToScreen(_L("FAULT due to EOF. %d bytes read.\r\n"), ImageReadProgress);
    			BOOT_FAULT();
    			}
    		else
    			PrintToScreen(_L("Loaded %d bytes.\r\n"), ImageReadProgress);

    		if (ImageReadProgress < LoadSize)
    			ImageSize=ImageHeaderPresent ? ImageReadProgress-256 : ImageReadProgress;
#ifdef __SUPPORT_FLASH_REPRO__
    		if (LoadToFlash)
    			NotifyDownloadComplete();
#endif
    		}

		}
	if (CloseInputFunction)
		CloseInput();

	if (LoadToFlash)
		{
		// In the load to flash scenario it will boot the image.
		while(1)
			User::After(10000000);
		}

	// Booting from Ram - remove the header
	if (ImageHeaderPresent)
		{
		TUint8* pI=(TUint8*)DestinationAddress();
		Mem::Move(pI,pI+256,ImageSize);
		}

	CheckSumRom();

	PrintToScreen(_L("Booting Image...\r\n"));
	// Restart board with "boot image + located in ram"

	User::After(WAIT_TO_REBOOT);
		

	HAL::Set(HAL::EDisplayState, 0);
	Restart(KtRestartReasonBootRestart | KtRestartReasonRAMImage);

	//  *** NOTREACHED ***
	}

GLDEF_C TInt E32Main()
	{
	CTrapCleanup* cleanup=CTrapCleanup::New();

	// Make bootloader panics fault the system. This means that this process
	// will NEVER END
	User::SetCritical(User::ESystemPermanent);

	TRAPD(error,RunAppL());
	__ASSERT_ALWAYS(!error, User::Panic(KPanicText, error));
	
	delete cleanup;

	PrintToScreen(_L("Boot loader ended abnormally")); 

	Ldd.Close();
	return 0;
	}