sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // improvised boot loader mechanism sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: */ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "bootloader_variantconfig.h" sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: #include sl@0: sl@0: #define FILE_ID 0x594D555D sl@0: #include "bootldr.h" sl@0: #include "ubootldrldd.h" sl@0: sl@0: #include sl@0: sl@0: #ifdef _DEBUG_CORELDR_ sl@0: #define WAIT_TO_REBOOT 10000000 sl@0: #else sl@0: #define WAIT_TO_REBOOT 100000 sl@0: #endif sl@0: sl@0: #define addr_to_page(a) (a&~(0x1000-1)) sl@0: sl@0: _LIT(KPanicText,"UBOOTLDR"); sl@0: _LIT(LDD_NAME, "Enet"); sl@0: _LIT(PDD_NAME, "Ethernet"); sl@0: sl@0: // Memory sl@0: RUBootldrLdd Ldd; sl@0: RChunk TheRamChunk; // This is the download area sl@0: sl@0: /// Global number of seconds to delay before reboot sl@0: sl@0: void GetChunk() sl@0: { sl@0: TInt PageSize; sl@0: UserHal::PageSizeInBytes(PageSize); sl@0: sl@0: TInt r = User::LoadLogicalDevice(KBootldrLddName); sl@0: sl@0: r = Ldd.Open(); sl@0: if (r!=KErrNone) sl@0: { sl@0: PrintToScreen(_L("FAULT due to LDD open\r\n")); sl@0: BOOT_FAULT(); sl@0: } sl@0: sl@0: TUint8* kernelAddress; sl@0: r=Ldd.CreateChunk(KRamTargetSize,(TAny**)&kernelAddress); sl@0: if (r!=KErrNone) sl@0: { sl@0: PrintToScreen(_L("FAULT due to chunk create\r\n")); sl@0: BOOT_FAULT(); sl@0: } sl@0: sl@0: r = Ldd.CommitMemory(KRamTargetSize,addr_to_page(KRamTargetAddr)); sl@0: if (r!=KErrNone) sl@0: { sl@0: PrintToScreen(_L("FAULT due to commit\r\n")); sl@0: BOOT_FAULT(); sl@0: } sl@0: sl@0: r = Ldd.GetChunkHandle(TheRamChunk); sl@0: if (r!=KErrNone) sl@0: { sl@0: PrintToScreen(_L("FAULT due to handle\r\n")); sl@0: BOOT_FAULT(); sl@0: } sl@0: sl@0: TUint8* Base = TheRamChunk.Base(); sl@0: ActualDestinationAddress = (TUint32*)Base; sl@0: } sl@0: sl@0: // method of getting the date string at build time sl@0: // Taken from e32test\device\t_usbco22.cpp sl@0: #define WIDEN2(x) L ## x sl@0: #define WIDEN(x) WIDEN2(x) sl@0: #define __WDATE__ WIDEN(__DATE__) sl@0: sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // Application entry point sl@0: // sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: LOCAL_C void RunAppL() sl@0: { sl@0: TInt r; sl@0: sl@0: // Get the memory download area mapped into a chunk sl@0: GetChunk(); sl@0: sl@0: // Initialise our graphical screen sl@0: InitDisplay(); sl@0: sl@0: #ifdef __USE_VARIANT_INIT__ sl@0: // The variant initialisation function is likely to perform bootloader sl@0: // configuration or print debug information. sl@0: VariantInit(); sl@0: #endif sl@0: sl@0: #ifdef __USE_USBMS__ sl@0: // If the bootloader is in the USB Mass Storage mode (indicated by the Variant sl@0: // initialisation routine) then call that method first; it will either read/boot sl@0: // an image, start the USB Mass Storage boot application or return. sl@0: if ((LoadDevice==ELoadUSBMS) || (LoadDevice==EBootUSBMS)) sl@0: TryUSBMS(); sl@0: #endif sl@0: sl@0: // Start the menu UI thread, this will cause a console to overwrite the framebuffer sl@0: StartMenu(); sl@0: ClearScreen(); sl@0: sl@0: PrintToScreen(_L("Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).\r\n")); sl@0: PrintToScreen(_L("BootLoader %d.%d\r\n"), BOOTLDR_VERSION_MAJOR, BOOTLDR_VERSION_MINOR); sl@0: PrintToScreen(_L("Platform build %d\n\rBuilt: %s\r\n"), PLATFORM_BUILD, __WDATE__); sl@0: sl@0: // Load Ethernet driver: it might need to load to set the MAC address in HAL sl@0: TInt pddLoaded = KErrUnknown; sl@0: TInt lddLoaded = KErrUnknown; sl@0: TInt opened = KErrUnknown; sl@0: RBusDevEthernet card; sl@0: sl@0: pddLoaded = User::LoadPhysicalDevice(PDD_NAME); sl@0: if (pddLoaded == KErrNone) sl@0: { sl@0: lddLoaded = User::LoadLogicalDevice(LDD_NAME); sl@0: if (lddLoaded == KErrNone) sl@0: { sl@0: opened = card.Open(0); sl@0: User::After(2000); sl@0: } sl@0: } sl@0: sl@0: TInt serialNum; sl@0: r = HAL::Get(HAL::ESerialNumber, serialNum); sl@0: sl@0: if (r == KErrNone && serialNum != 0) sl@0: { sl@0: // we only show the serial number if it was available from HAL and set to something sl@0: PrintToScreen(_L("MAC Address: 00-0a-%02x-%02x-%02x-%02x\r\n"), sl@0: (serialNum & 0xFF000000) >> 24, sl@0: (serialNum & 0x00FF0000) >> 16, sl@0: (serialNum & 0x0000FF00) >> 8, sl@0: (serialNum & 0x000000FF) sl@0: ); sl@0: } sl@0: sl@0: sl@0: // Free the Ethernet driver now we're done getting the MAC address sl@0: if (opened == KErrNone) sl@0: { sl@0: card.Close(); sl@0: } sl@0: if (lddLoaded == KErrNone) sl@0: { sl@0: User::FreeLogicalDevice(LDD_NAME); sl@0: } sl@0: if (pddLoaded == KErrNone) sl@0: { sl@0: User::FreePhysicalDevice(PDD_NAME); sl@0: } sl@0: sl@0: if (LoadDevice == EBootEMMC) sl@0: { sl@0: if ( SearchDrivesRaw() ) sl@0: { sl@0: DoDownload(); sl@0: } sl@0: } sl@0: sl@0: #ifdef __USE_LOCAL_DRIVES__ sl@0: // The next method to test is reading an image file from removable media sl@0: if (SearchDrives()) sl@0: DoDownload(); sl@0: #endif sl@0: sl@0: // The last method is to attempt to download an image over the serial port sl@0: switch (SerialBaud) sl@0: { sl@0: case EBps115200: sl@0: PrintToScreen(_L("Initiating YModem-G on port %d @ 115200 baud\r\n"), SerialDownloadPort); sl@0: break; sl@0: case EBps230400: sl@0: PrintToScreen(_L("Initiating YModem-G on port %d @ 230400 baud\r\n"), SerialDownloadPort); sl@0: break; sl@0: default: sl@0: PrintToScreen(_L("Initiating YModem-G download on port %d\r\n"), SerialDownloadPort); sl@0: SerialBaud = EBps115200; sl@0: break; sl@0: } sl@0: r=InitSerialDownload(SerialDownloadPort); sl@0: if (r!=KErrNone) sl@0: { sl@0: RDebug::Print(_L("FAULT: YModem-G download returned %d\r\n"),r); sl@0: BOOT_FAULT(); sl@0: } sl@0: sl@0: PrintToScreen(_L("Receiving %lS\r\nSize %d\r\n"),&FileName,FileSize); sl@0: DoDownload(); sl@0: } sl@0: sl@0: TUint Check(const TUint32* aPtr, TInt aSize) sl@0: { sl@0: TUint sum=0; sl@0: aSize/=4; sl@0: while (aSize-->0) sl@0: sum+=*aPtr++; sl@0: return sum; sl@0: } sl@0: sl@0: TUint CheckSumRom() sl@0: { sl@0: #if 0 sl@0: // sl@0: // This code was obtained from t_romchk in the e32tests, it was useful for sl@0: // checking that roms were not getting corrupted during the download sl@0: // process. sl@0: // sl@0: // However, it is not a universal checksum and is not suitable for all sl@0: // types of images it is therefore being disabled until we need it again. sl@0: // sl@0: sl@0: PrintToScreen(_L("Checking ROM contents...\r\n")); sl@0: sl@0: const TRomHeader* romHdr = (const TRomHeader*)DestinationAddress(); sl@0: TInt size = romHdr->iUnpagedUncompressedSize; sl@0: const TUint32* addr = (TUint32*)romHdr; sl@0: PrintToScreen(_L("ROM at %x, size %x\r\n"),addr,size); sl@0: sl@0: TUint checkSum = Check(addr,size); sl@0: sl@0: // hack the checksum because ROMBUILD is broken sl@0: checkSum -= (romHdr->iRomSize-size)/4; // adjust for missing 0xffffffff sl@0: checkSum -= romHdr->iCompressionType; sl@0: checkSum -= romHdr->iUnpagedCompressedSize; sl@0: checkSum -= romHdr->iUnpagedUncompressedSize; sl@0: sl@0: TUint expectedChecksum = 0x12345678; sl@0: if (checkSum != expectedChecksum) sl@0: { sl@0: PrintToScreen(_L("Fail: Checksum = %8x, expected %8x\r\n"),checkSum,expectedChecksum); sl@0: RDebug::Print(_L("Fail: Checksum = %8x, expected %8x\r\n"),checkSum,expectedChecksum); sl@0: BOOT_FAULT(); sl@0: } sl@0: else sl@0: { sl@0: PrintToScreen(_L("Pass: Checksum = %8x, expected %8x\r\n"),checkSum,expectedChecksum); sl@0: RDebug::Print(_L("Pass: Checksum = %8x, expected %8x\r\n"),checkSum,expectedChecksum); sl@0: } sl@0: #endif sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: GLDEF_C void DoDownload() sl@0: /* sl@0: The DoDownload method is ultimatly called by all the download routines, it is sl@0: responsible for unzipping images as well as stripping off EPOC headers and sl@0: starting the flash writing methods. sl@0: */ sl@0: { sl@0: TInt r; sl@0: sl@0: // If the image is zipped start the unzip thread sl@0: if (ImageZip) sl@0: { sl@0: // initialise unzip sl@0: PrintToScreen(_L("Loading zip ..\r\n")); sl@0: r=DoZipDownload(bootFile); sl@0: if (r!=KErrNone) sl@0: { sl@0: PrintToScreen(_L("\r\nFAULT due to zip %d\r\n"), r); sl@0: BOOT_FAULT(); sl@0: } sl@0: PrintToScreen(_L("\r\nZip download complete.\r\n")); sl@0: } sl@0: else sl@0: { sl@0: LoadSize=FileSize; sl@0: sl@0: if( ImageDeflated ) sl@0: { sl@0: PrintToScreen(_L("\r\n\r\nLoading deflated image...\r\n")); sl@0: ImageHeaderPresent=EFalse; sl@0: DoDeflateDownload(); sl@0: PrintToScreen(_L("Deflated image download complete.\r\n")); sl@0: } sl@0: else sl@0: { sl@0: // If it isn't a zipped or deflated image then the filesize is the image size - sl@0: // check that it is valid for a Symbian image and determine whether to sl@0: // remove any header that may be present. sl@0: TInt size_mod_4k=FileSize & 0xfff; sl@0: if (size_mod_4k==0) sl@0: { sl@0: ImageHeaderPresent=EFalse; sl@0: PrintToScreen(_L("Image header not present.\r\n")); sl@0: } sl@0: else if (size_mod_4k==256) sl@0: { sl@0: ImageHeaderPresent=ETrue; sl@0: PrintToScreen(_L("Image header present.\r\n")); sl@0: } sl@0: else sl@0: { sl@0: PrintToScreen(_L("\r\n\r\nInvalid size\r\n")); sl@0: BOOT_FAULT(); sl@0: } sl@0: ImageSize=ImageHeaderPresent ? LoadSize-256 : LoadSize; sl@0: TUint8* pD=(TUint8*)DestinationAddress(); sl@0: TInt block_size; sl@0: if (FileSize==0) sl@0: block_size=0x1000; // YModem download with unknown size sl@0: else sl@0: block_size=Max(0x1000,FileSize>>8); sl@0: block_size=(block_size+0xfff)&~0xfff; sl@0: if (FileSize>0) sl@0: InitProgressBar(0,(TUint)FileSize,_L("LOAD")); sl@0: r=KErrNone; sl@0: sl@0: // If target location is flash start the flasher thread sl@0: #ifdef __SUPPORT_FLASH_REPRO__ sl@0: if (LoadToFlash) sl@0: { sl@0: r=InitFlashWrite(); sl@0: if (r!=KErrNone) sl@0: { sl@0: PrintToScreen(_L("FAULT due to InitFlashWrite return %d\r\n"), r); sl@0: BOOT_FAULT(); sl@0: } sl@0: } sl@0: #endif sl@0: sl@0: while (r==KErrNone) sl@0: { sl@0: TInt len=block_size; sl@0: r=ReadInputData(pD,len); sl@0: sl@0: if (r!=KErrNone && r!=KErrEof) sl@0: break; sl@0: pD+=len; sl@0: ImageReadProgress+=len; sl@0: if (FileSize>0) sl@0: { sl@0: UpdateProgressBar(0,(TUint)ImageReadProgress); sl@0: } sl@0: #ifdef __SUPPORT_FLASH_REPRO__ sl@0: if (LoadToFlash) sl@0: NotifyDataAvailable(ImageReadProgress); sl@0: #endif sl@0: } sl@0: sl@0: if (r!=KErrEof) sl@0: { sl@0: PrintToScreen(_L("FAULT due to EOF. %d bytes read.\r\n"), ImageReadProgress); sl@0: BOOT_FAULT(); sl@0: } sl@0: else sl@0: PrintToScreen(_L("Loaded %d bytes.\r\n"), ImageReadProgress); sl@0: sl@0: if (ImageReadProgress < LoadSize) sl@0: ImageSize=ImageHeaderPresent ? ImageReadProgress-256 : ImageReadProgress; sl@0: #ifdef __SUPPORT_FLASH_REPRO__ sl@0: if (LoadToFlash) sl@0: NotifyDownloadComplete(); sl@0: #endif sl@0: } sl@0: sl@0: } sl@0: if (CloseInputFunction) sl@0: CloseInput(); sl@0: sl@0: if (LoadToFlash) sl@0: { sl@0: // In the load to flash scenario it will boot the image. sl@0: while(1) sl@0: User::After(10000000); sl@0: } sl@0: sl@0: // Booting from Ram - remove the header sl@0: if (ImageHeaderPresent) sl@0: { sl@0: TUint8* pI=(TUint8*)DestinationAddress(); sl@0: Mem::Move(pI,pI+256,ImageSize); sl@0: } sl@0: sl@0: CheckSumRom(); sl@0: sl@0: PrintToScreen(_L("Booting Image...\r\n")); sl@0: // Restart board with "boot image + located in ram" sl@0: sl@0: User::After(WAIT_TO_REBOOT); sl@0: sl@0: sl@0: HAL::Set(HAL::EDisplayState, 0); sl@0: Restart(KtRestartReasonBootRestart | KtRestartReasonRAMImage); sl@0: sl@0: // *** NOTREACHED *** sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: CTrapCleanup* cleanup=CTrapCleanup::New(); sl@0: sl@0: // Make bootloader panics fault the system. This means that this process sl@0: // will NEVER END sl@0: User::SetCritical(User::ESystemPermanent); sl@0: sl@0: TRAPD(error,RunAppL()); sl@0: __ASSERT_ALWAYS(!error, User::Panic(KPanicText, error)); sl@0: sl@0: delete cleanup; sl@0: sl@0: PrintToScreen(_L("Boot loader ended abnormally")); sl@0: sl@0: Ldd.Close(); sl@0: return 0; sl@0: } sl@0: