brdbootldr/ubootldr/main.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brdbootldr/ubootldr/main.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,449 @@
+// 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;
+	}
+