brdbootldr/ubootldr/main.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 137 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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;
	}