//
// 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.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
main.c
Abstract:
Ethernet boot loader main module. This file contains the C main
for the boot loader. NOTE: The firmware "entry" point (the real
entry point is _EntryPoint in init assembler file.
The Windows CE boot loader is the code that is executed on a Windows CE
development system at power-on reset and loads the Windows CE
operating system. The boot loader also provides code that monitors
the behavior of a Windows CE platform between the time the boot loader
starts running and the time the full operating system debugger is
available. Windows CE OEMs are supplied with sample boot loader code
that runs on a particular development platform and CPU.
Functions:
Notes:
--*/
#include <windows.h>
#include <pcireg.h>
#include <ethdbg.h>
#include <drv_glob.h>
#include <nkintr.h>
#include <pehdr.h>
#include <romldr.h>
#include <blcommon.h>
#include <bootpart.h>
#include <kitlprot.h>
#include "s2410.h"
#include "loader.h"
#include "fmd.h"
#include "cfnand.h"
#include "warning.h"
PDRIVER_GLOBALS pDriverGlobals = ((PDRIVER_GLOBALS) DRIVER_GLOBALS_PHYSICAL_MEMORY_START);
// Some global definitions
#ifdef SIMULATOR
void CleanExit(DWORD dwExitCode);
#define SPIN_FOREVER CleanExit(41);
#else
#define SPIN_FOREVER {while(TRUE);}
#endif
//
// Global variables
//
static BOOLEAN g_bDownloadImage = TRUE;
BOOLEAN g_bWaitForConnect;
DWORD g_dwImageStartBlock;
DWORD g_ImageType;
DWORD g_dwMinImageStart;
MultiBINInfo g_BINRegionInfo;
BOOL g_bBootMediaExist = FALSE;
#pragma pack(1)
// N.B: only uses 1 sector for now.
UCHAR g_TOC[SECTOR_SIZE];
#pragma pack()
const PTOC g_pTOC = (PTOC)&g_TOC;
PBOOT_CFG g_pBootCfg;
DWORD g_dwTocEntry;
#ifdef DEBUG
DWORD EdbgDebugZone = 0;//ZONE_WARNING|ZONE_INIT; //ZONE_DHCP;
#endif
// External functions
extern void InitClock();
extern DWORD OEMAddressTable[];
void Launch();
void BootloaderMain (void);
BOOL InitEthDevice(PBOOT_CFG pBootCfg);
static void SetDelay();
static void SetCS8900MACAddress();
// Function prototypes
static BOOL GetUserIPAddr (EDBG_ADDR *pMyAddr, LPDWORD pdwSubnetMask);
static BOOL SetUDID ();
#define LAST_LAUNCH_ADDR_VALID 0xBADBEEF6
// Local util function
//
DWORD
ToPhysicalAddr(DWORD add)
{
DWORD padd = add;
DWORD * pt = OEMAddressTable;
DWORD vir_start;
DWORD vir_end;
DWORD phy_start;
DWORD sz;
EdbgOutputDebugString("+ToPhysicalAddr:0x%x\r\n", add);
do
{
vir_start = *pt++;
phy_start = *pt++;
sz = *pt++;
if (vir_start == 0 && phy_start == 0 && sz == 0) break;
vir_end = vir_start + sz * (1024 * 1024);
if (add >= vir_start && add < vir_end)
{
padd = add - vir_start + phy_start;
break;
}
} while (1);
EdbgOutputDebugString("-ToPhysicalAddr:0x%x\r\n", padd);
return padd;
}
// util function that should really be in blcommon
//
static void
itoa10(
int n,
char s[]
)
{
int i = 0;
// Get absolute value of number
unsigned int val = (unsigned int)((n < 0) ? -n : n);
// Extract digits in reverse order
do {
s[i++] = (val % 10) + '0';
} while (val /= 10);
// Add sign if number negative
if (n < 0) s[i++] = '-';
s[i--] = '\0';
// Reverse string
for (n = 0; n < i; n++, i--) {
char swap = s[n];
s[n] = s[i];
s[i] = swap;
}
}
static void
CreateDeviceName(
EDBG_ADDR *pMyAddr,
char *szBuf
)
{
strcpy(szBuf,PLATFORM_STRING);
szBuf += strlen(szBuf);
itoa10(((pMyAddr->wMAC[2]>>8) | ((pMyAddr->wMAC[2] & 0x00ff) << 8)), szBuf);
}
#ifdef TODO
// This routine programs the serial EEPROM and sets the
// Ethernet Address to 00 50 F2 08 NN NN (N=Debug board number).
static void SetSerialNumber(USHORT dbgBoardSerialNumber) {
USHORT i;
EdbgOutputDebugString("SetSerialNumber: %u \r\n", dbgBoardSerialNumber);
if ((dbgBoardSerialNumber <0) || (dbgBoardSerialNumber > 32000)) {
EdbgOutputDebugString("Error Serial Number between 0 and 32000\n");
}
for (i=0;i<16;i+=2) {
// Set all switch Areas to the same
SMCWriteEEPROM((UINT16)(0x0+i), 0xB0);
SMCWriteEEPROM((UINT16)(0x1+i), 0x1866);
}
for (i=16;i<0x20;i++) {
SMCWriteEEPROM(i,0x0);
}
// Avenger is 00-50-F2-03-XX-XX
// Trango is 00-50-F2-08-XX-XX
// Catfish is 00-50-F2-08-XX-XX ??
SMCWriteEEPROM(0x20, 0x5000); // Is 00-50-??-??-??-??
SMCWriteEEPROM(0x21, 0x08F2); // Is ??-??-F2-08-??-??
SMCWriteEEPROM(0x22, htons((UINT16)(dbgBoardSerialNumber)));
SMCWriteEEPROM(0x23, 0x389D);
SMCWriteEEPROM(0x24, 0x4595);
SMCWriteEEPROM(0x25, 0xFFFF);
SMCWriteEEPROM(0x26, 0x00FC);
SMCWriteEEPROM(0x27, 0x0000);
SMCWriteEEPROM(0x28, 0x5765);
SMCWriteEEPROM(0x29, 0x2776);
SMCWriteEEPROM(0x2A, 0x6520);
SMCWriteEEPROM(0x2B, 0x7374);
SMCWriteEEPROM(0x2C, 0x696C);
SMCWriteEEPROM(0x2D, 0x6C20);
SMCWriteEEPROM(0x2E, 0x676F);
SMCWriteEEPROM(0x2F, 0x7420);
}
#endif
//
// Functions called from blcommon
//
/*
@func BOOL | OEMVerifyMemory | Verify that the memory to be used by the downloaded BIN file is valid. This function also decides whether the image is the
bootloader or not based on its address (this information is used later when deciding how to store the image in flash).
@rdesc TRUE = Address specified is valid memory, FALSE = Address specified is *not* valid memory.
@comm
@xref
*/
BOOL OEMVerifyMemory(DWORD dwStartAddr, DWORD dwLength)
{
RETAILMSG(1, (TEXT("OEMVerifyMemory: StartAddr: 0x%x, Length:0x%x \r\n"), dwStartAddr, dwLength));
// Is the image being downloaded the bootloader?
if ((dwStartAddr >= EBOOT_STORE_ADDRESS) &&
((dwStartAddr + dwLength - 1) < (EBOOT_STORE_ADDRESS + EBOOT_STORE_MAX_LENGTH)))
{
RETAILMSG(1, (TEXT("Downloading Bootloader image\r\n")));
g_ImageType = IMAGE_TYPE_LOADER; // Bootloader image.
return TRUE;
}
// if it's MXIP don't test address to allow PPC images using funky addresses in their .BIN regions
else if ( g_BINRegionInfo.dwNumRegions > 1 )
{
RETAILMSG(1, (TEXT("Downloading %d regions of MXIP image\r\n"), g_BINRegionInfo.dwNumRegions));
// 1st region is RAMIMAGE, remaining are MXIP
g_ImageType = IMAGE_TYPE_RAMIMAGE | IMAGE_TYPE_BINFS | IMAGE_TYPE_MXIP;
return TRUE;
}
// Is it a ram image?
else if ((dwStartAddr >= ROM_RAMIMAGE_START) &&
((dwStartAddr + dwLength - 1) < (ROM_RAMIMAGE_START + ROM_RAMIMAGE_SIZE)))
{
RETAILMSG(1, (TEXT("Downloading RAM image\r\n")));
g_ImageType = IMAGE_TYPE_RAMIMAGE;
return TRUE;
}
// HACKHACK: get around MXIP images with funky addresses
g_ImageType = IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS