main.c
上传用户:qiulin1960
上传日期:2013-10-16
资源大小:2844k
文件大小:43k
源码类别:

Windows CE

开发平台:

Windows_Unix

  1. //
  2. // Copyright (c) Microsoft Corporation.  All rights reserved.
  3. //
  4. //
  5. // Use of this source code is subject to the terms of the Microsoft end-user
  6. // license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
  7. // If you did not accept the terms of the EULA, you are not authorized to use
  8. // this source code. For a copy of the EULA, please see the LICENSE.RTF on your
  9. // install media.
  10. //
  11. /*++
  12. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  13. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  14. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  15. PARTICULAR PURPOSE.
  16. Module Name:
  17.     main.c
  18. Abstract:
  19.     Ethernet boot loader main module. This file contains the C main
  20.     for the boot loader.    NOTE: The firmware "entry" point (the real
  21.     entry point is _EntryPoint in init assembler file.
  22.     The Windows CE boot loader is the code that is executed on a Windows CE
  23.     development system at power-on reset and loads the Windows CE
  24.     operating system. The boot loader also provides code that monitors
  25.     the behavior of a Windows CE platform between the time the boot loader
  26.     starts running and the time the full operating system debugger is
  27.     available. Windows CE OEMs are supplied with sample boot loader code
  28.     that runs on a particular development platform and CPU.
  29. Functions:
  30. Notes:
  31. --*/
  32. #include <windows.h>
  33. #include <pcireg.h>
  34. #include <ethdbg.h>
  35. #include <drv_glob.h>
  36. #include <nkintr.h>
  37. #include <pehdr.h>
  38. #include <romldr.h>
  39. #include <blcommon.h>
  40. #include <bootpart.h>
  41. #include <kitlprot.h>
  42. #include "s2440.h"
  43. #include "loader.h"
  44. #include "fmd.h"
  45. #include "cfnand.h"
  46. #include "warning.h"
  47. PDRIVER_GLOBALS pDriverGlobals = ((PDRIVER_GLOBALS) DRIVER_GLOBALS_PHYSICAL_MEMORY_START);
  48. extern BOOL UbootReadData (DWORD cbData, LPBYTE pbData);
  49. extern BOOL InitUSB ();
  50. extern void Isr_Init();
  51. //  Some global definitions
  52. #ifdef SIMULATOR
  53. void CleanExit(DWORD dwExitCode);
  54. #define SPIN_FOREVER    CleanExit(41);
  55. #else
  56. #define SPIN_FOREVER    {while(TRUE);}
  57. #endif
  58. //
  59. //  Global variables
  60. //
  61. static BOOLEAN  g_bDownloadImage  = TRUE;
  62. BOOLEAN         g_bWaitForConnect;
  63. DWORD           g_dwImageStartBlock;
  64. DWORD           g_ImageType;
  65. DWORD           g_dwMinImageStart;
  66. MultiBINInfo    g_BINRegionInfo;
  67. BOOL            g_bBootMediaExist = FALSE;
  68. BOOLEAN g_bUSBDownload = FALSE;
  69. #pragma pack(1)
  70. // N.B: only uses 1 sector for now.
  71. UCHAR g_TOC[SECTOR_SIZE];
  72. #pragma pack()
  73. const PTOC g_pTOC = (PTOC)&g_TOC;
  74. PBOOT_CFG  g_pBootCfg;
  75. DWORD      g_dwTocEntry;
  76. #ifdef DEBUG
  77. DWORD   EdbgDebugZone = 0;//ZONE_WARNING|ZONE_INIT; //ZONE_DHCP;
  78. #endif
  79. //  External functions
  80. extern void  InitClock();
  81. extern DWORD OEMAddressTable[];
  82. void Launch();
  83. void BootloaderMain (void);
  84. BOOL InitEthDevice(PBOOT_CFG  pBootCfg);
  85. static void SetDelay();
  86. static void SetCS8900MACAddress();
  87. //  Function prototypes
  88. static BOOL GetUserIPAddr (EDBG_ADDR *pMyAddr, LPDWORD pdwSubnetMask);
  89. #define LAST_LAUNCH_ADDR_VALID 0xBADBEEF6
  90. //  Local util function
  91. //
  92. DWORD
  93. ToPhysicalAddr(DWORD add)
  94. {
  95.     DWORD   padd = add;
  96.     DWORD * pt = OEMAddressTable;
  97.     DWORD   vir_start;
  98.     DWORD   vir_end;
  99.     DWORD   phy_start;
  100.     DWORD   sz;
  101. EdbgOutputDebugString("+ToPhysicalAddr:0x%xrn", add);
  102.     do
  103.     {
  104.         vir_start = *pt++;
  105.         phy_start = *pt++;
  106.         sz        = *pt++;
  107.         if (vir_start == 0 && phy_start == 0 && sz == 0) break;
  108.         vir_end = vir_start + sz * (1024 * 1024);
  109.         if (add >= vir_start && add < vir_end)
  110.         {
  111.             padd = add - vir_start + phy_start;
  112.             break;
  113.         }
  114.     } while (1);
  115. EdbgOutputDebugString("-ToPhysicalAddr:0x%xrn", padd);
  116.     return padd;
  117. }
  118. //  util function that should really be in blcommon
  119. //
  120. static void
  121. itoa10(
  122.     int n,
  123.     char s[]
  124.     )
  125. {
  126.     int i = 0;
  127.     // Get absolute value of number
  128.     unsigned int val = (unsigned int)((n < 0) ? -n : n);
  129.     // Extract digits in reverse order
  130.     do {
  131.         s[i++] = (val % 10) + '0';
  132.     } while (val /= 10);
  133.     // Add sign if number negative
  134.     if (n < 0) s[i++] = '-';
  135.     s[i--] = '';
  136.     // Reverse string
  137.     for (n = 0; n < i; n++, i--) {
  138.         char swap = s[n];
  139.         s[n] = s[i];
  140.         s[i] = swap;
  141.     }
  142. }
  143. static void
  144. CreateDeviceName(
  145.     EDBG_ADDR *pMyAddr,
  146.     char *szBuf
  147.     )
  148. {
  149.     strcpy(szBuf,PLATFORM_STRING);
  150.     szBuf += strlen(szBuf);
  151.     itoa10(((pMyAddr->wMAC[2]>>8) | ((pMyAddr->wMAC[2] & 0x00ff) << 8)), szBuf);
  152. }
  153. #ifdef TODO
  154. //  This routine programs the serial EEPROM and sets the
  155. //  Ethernet Address to 00 50 F2 08 NN NN (N=Debug board number).
  156. static void SetSerialNumber(USHORT dbgBoardSerialNumber) {
  157.     USHORT i;
  158.     EdbgOutputDebugString("SetSerialNumber: %u rn", dbgBoardSerialNumber);
  159.     if ((dbgBoardSerialNumber <0) || (dbgBoardSerialNumber > 32000)) {
  160.         EdbgOutputDebugString("Error Serial Number between 0 and 32000n");
  161.     }
  162.     for (i=0;i<16;i+=2) {
  163.         // Set all switch Areas to the same
  164.         SMCWriteEEPROM((UINT16)(0x0+i), 0xB0);
  165.         SMCWriteEEPROM((UINT16)(0x1+i), 0x1866);
  166.     }
  167.     for (i=16;i<0x20;i++) {
  168.         SMCWriteEEPROM(i,0x0);
  169.         }
  170.                                     // Avenger is 00-50-F2-03-XX-XX
  171.                                     // Trango  is 00-50-F2-08-XX-XX
  172.                                     // Catfish is 00-50-F2-08-XX-XX ??
  173.     SMCWriteEEPROM(0x20, 0x5000);   // Is 00-50-??-??-??-??
  174.     SMCWriteEEPROM(0x21, 0x08F2);   // Is ??-??-F2-08-??-??
  175.     SMCWriteEEPROM(0x22, htons((UINT16)(dbgBoardSerialNumber)));
  176.     SMCWriteEEPROM(0x23, 0x389D);
  177.     SMCWriteEEPROM(0x24, 0x4595);
  178.     SMCWriteEEPROM(0x25, 0xFFFF);
  179.     SMCWriteEEPROM(0x26, 0x00FC);
  180.     SMCWriteEEPROM(0x27, 0x0000);
  181.     SMCWriteEEPROM(0x28, 0x5765);
  182.     SMCWriteEEPROM(0x29, 0x2776);
  183.     SMCWriteEEPROM(0x2A, 0x6520);
  184.     SMCWriteEEPROM(0x2B, 0x7374);
  185.     SMCWriteEEPROM(0x2C, 0x696C);
  186.     SMCWriteEEPROM(0x2D, 0x6C20);
  187.     SMCWriteEEPROM(0x2E, 0x676F);
  188.     SMCWriteEEPROM(0x2F, 0x7420);
  189. }
  190. #endif
  191. //
  192. //  Functions called from blcommon
  193. //
  194. /*
  195.     @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
  196.                                      bootloader or not based on its address (this information is used later when deciding how to store the image in flash).
  197.     @rdesc  TRUE = Address specified is valid memory, FALSE = Address specified is *not* valid memory.
  198.     @comm
  199.     @xref
  200. */
  201. BOOL OEMVerifyMemory(DWORD dwStartAddr, DWORD dwLength)
  202. {
  203.     RETAILMSG(1, (TEXT("OEMVerifyMemory: StartAddr: 0x%x, Length:0x%x rn"), dwStartAddr, dwLength));
  204.     // Is the image being downloaded the bootloader?
  205.     if ((dwStartAddr >= EBOOT_STORE_ADDRESS) &&
  206.         ((dwStartAddr + dwLength - 1) < (EBOOT_STORE_ADDRESS + EBOOT_STORE_MAX_LENGTH)))
  207.     {
  208.         RETAILMSG(1, (TEXT("Downloading Bootloader imagern")));
  209.         g_ImageType = IMAGE_TYPE_LOADER;     // Bootloader image.
  210.         return TRUE;
  211.     }
  212.     // if it's MXIP don't test address to allow PPC images using funky addresses in their .BIN regions
  213.     else if ( g_BINRegionInfo.dwNumRegions > 1 )
  214.     {
  215.         RETAILMSG(1, (TEXT("Downloading %d regions of MXIP imagern"), g_BINRegionInfo.dwNumRegions));
  216.         // 1st region is RAMIMAGE, remaining are MXIP
  217.         g_ImageType = IMAGE_TYPE_RAMIMAGE | IMAGE_TYPE_BINFS | IMAGE_TYPE_MXIP;
  218.         return TRUE;
  219.     }
  220.     // Is it a ram image?
  221.     else if ((dwStartAddr >= ROM_RAMIMAGE_START) &&
  222.         ((dwStartAddr + dwLength - 1) < (ROM_RAMIMAGE_START + ROM_RAMIMAGE_SIZE)))
  223.     {
  224.         RETAILMSG(1, (TEXT("Downloading RAM imagern")));
  225.         g_ImageType = IMAGE_TYPE_RAMIMAGE;
  226.         return TRUE;
  227.     }
  228.     // HACKHACK: get around MXIP images with funky addresses
  229.     RETAILMSG(1, (TEXT("*** Downloading BIN image type ***rn")));
  230.     return TRUE;
  231. }
  232. /*
  233.     @func   void | OEMMultiBINNotify | Called by blcommon to nofity the OEM code of the number, size, and location of one or more BIN regions,
  234.                                        this routine collects the information and uses it when temporarily caching a flash image in RAM prior to final storage.
  235.     @rdesc  N/A.
  236.     @comm
  237.     @xref
  238. */
  239. void OEMMultiBINNotify(const PMultiBINInfo pInfo)
  240. {
  241.     BYTE nCount;
  242.     if (!pInfo || !pInfo->dwNumRegions)
  243.     {
  244.         EdbgOutputDebugString("WARNING: OEMMultiBINNotify: Invalid BIN region descriptor(s).rn");
  245.         return;
  246.     }
  247.     g_dwMinImageStart = pInfo->Region[0].dwRegionStart;
  248.     EdbgOutputDebugString("rnOEMMultiBINNotify: Download BIN file information:rn");
  249.     EdbgOutputDebugString("-----------------------------------------------------rn");
  250.     for (nCount = 0 ; nCount < pInfo->dwNumRegions ; nCount++)
  251.     {
  252.         EdbgOutputDebugString("[%d]: Base Address=0x%x  Length=0x%xrn" ,
  253.             nCount, pInfo->Region[nCount].dwRegionStart, pInfo->Region[nCount].dwRegionLength);
  254.         if (pInfo->Region[nCount].dwRegionStart < g_dwMinImageStart)
  255.         {
  256.             g_dwMinImageStart = pInfo->Region[nCount].dwRegionStart;
  257.             if (g_dwMinImageStart == 0)
  258.             {
  259.                 EdbgOutputDebugString("WARNING: OEMMultiBINNotify: Bad start address for region (%d).rn", nCount);
  260.                 return;
  261.             }
  262.         }
  263.     }
  264.     memcpy((LPBYTE)&g_BINRegionInfo, (LPBYTE)pInfo, sizeof(MultiBINInfo));
  265.     EdbgOutputDebugString("-----------------------------------------------------rn");
  266. }
  267. BOOL OEMReportError(DWORD dwReason, DWORD dwReserved)
  268. {
  269.     EdbgOutputDebugString("OEMReportError(%d, %d)rn", dwReason, dwReserved);
  270.     return TRUE;
  271. }
  272. /*
  273.     @func   BOOL | OEMDebugInit | Function wrapper for OEMInitDebugSerial.
  274.     @rdesc  TRUE = Success, FALSE = Failure.
  275.     @comm
  276.     @xref
  277. */
  278. BOOL OEMDebugInit()
  279. {
  280.     // Assign callback functions to be usec by blcommon.
  281.     //
  282.     g_pOEMReportError    = OEMReportError;
  283.     g_pOEMVerifyMemory   = OEMVerifyMemory;     // Verify memory to be used by downloaded image...
  284.     g_pOEMMultiBINNotify = OEMMultiBINNotify;   // Notified of all the BIN files to be downloaded...
  285.     OEMInitDebugSerial();
  286.     return TRUE;
  287. }
  288. /*
  289.     @func   BOOL | BootMonitor | Manages the bootloader monitor.
  290.     @rdesc  TRUE = user selected download image, FALSE = user selected launch stored image.
  291.     @comm
  292.     @xref
  293. */
  294. static BOOLEAN BootMonitor( )
  295. {
  296.     int  KeySelect = 0;
  297.     BOOLEAN bConfigChanged = FALSE;
  298.     BOOLEAN bDownload = TRUE;
  299.     while(1)
  300.     {
  301.         KeySelect = 0;
  302.         EdbgOutputDebugString ( "rnEthernet Boot Loader Configuration:rn");
  303.         EdbgOutputDebugString ( "---------------------------------------rn");
  304.         EdbgOutputDebugString ( "1) IP address: %srn", inet_ntoa(g_pBootCfg->EdbgAddr.dwIP));
  305.         EdbgOutputDebugString ( "   Subnet mask: %srn", inet_ntoa(g_pBootCfg->SubnetMask));
  306.         EdbgOutputDebugString ( "2) Boot delay: %d secondsrn", g_pBootCfg->BootDelay);
  307.         EdbgOutputDebugString ( "3) DHCP: %srn", (g_pBootCfg->ConfigFlags & CONFIG_FLAGS_DHCP) ? "ENABLED" : "DISABLED");
  308.         EdbgOutputDebugString ( "4) Reset TOC to defaultrn");
  309.         EdbgOutputDebugString ( "5) Startup image: %srn", (g_pBootCfg->ConfigFlags & BOOT_TYPE_DIRECT) ? "LAUNCH EXISTING" : "DOWNLOAD NEW");
  310.         EdbgOutputDebugString ( "6) Program RAM image into Boot Media: %srn", (g_pBootCfg->ConfigFlags & TARGET_TYPE_NAND) ? "ENABLED" : "DISABLED");
  311.         EdbgOutputDebugString ( "7) MAC address: %B:%B:%B:%B:%B:%Brn",
  312.                                g_pBootCfg->EdbgAddr.wMAC[0] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[0] >> 8,
  313.                                g_pBootCfg->EdbgAddr.wMAC[1] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[1] >> 8,
  314.                                g_pBootCfg->EdbgAddr.wMAC[2] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[2] >> 8);
  315.         EdbgOutputDebugString ( "8) Kernel Debugger: %srn", (g_pBootCfg->ConfigFlags & CONFIG_FLAGS_DEBUGGER) ? "ENABLED" : "DISABLED");
  316.         EdbgOutputDebugString ( "9) Format Boot Media for BinFSrn");
  317.         EdbgOutputDebugString ( "rn");
  318.         // N.B: we need this option here since BinFS is really a RAM image, where you "format" the media
  319.         // with an MBR. There is no way to parse the image to say it's ment to be BinFS enabled.
  320.         EdbgOutputDebugString ( "B) Support BinFS: %srn", (g_pTOC->id[g_dwTocEntry].dwImageType & IMAGE_TYPE_BINFS) ? "ENABLED" : "DISABLED");
  321.         EdbgOutputDebugString ( "D) DOWNLOAD image now(Etherent)rn");
  322. //        EdbgOutputDebugString ( "E) Image descriptor Entry: %u rn", g_dwTocEntry);
  323.         EdbgOutputDebugString ( "F) Low-level FORMAT Boot Mediarn");
  324.         EdbgOutputDebugString ( "L) LAUNCH existing Boot Media imagern");
  325. EdbgOutputDebugString ( "R) Read Configuration rn");
  326.         EdbgOutputDebugString ( "U) DOWNLOAD image now(USB)rn");
  327. EdbgOutputDebugString ( "W) Write Configuration Right Nowrn");
  328.         EdbgOutputDebugString ( "X) DOWNLOAD image to boot media, then LAUNCH it off the mediarn");
  329.         EdbgOutputDebugString ( "---------------------------------------rn");
  330.         EdbgOutputDebugString ( "rnEnter your selection: ");
  331.         while (! ( ( (KeySelect >= '0') && (KeySelect <= '9') ) ||
  332.                  ( (KeySelect == 'B') || (KeySelect == 'b') )   ||
  333.                  ( (KeySelect == 'E') || (KeySelect == 'e') )   ||
  334.                  ( (KeySelect == 'F') || (KeySelect == 'f') )   ||
  335.                  ( (KeySelect == 'D') || (KeySelect == 'd') )   ||
  336.                  ( (KeySelect == 'L') || (KeySelect == 'l') )   ||
  337.                  ( (KeySelect == 'R') || (KeySelect == 'r') )   ||
  338.                  ( (KeySelect == 'U') || (KeySelect == 'u') )   ||
  339.                  ( (KeySelect == 'W') || (KeySelect == 'w') )   ||
  340.                  ( (KeySelect == 'X') || (KeySelect == 'x') )
  341.                ))
  342.         {
  343.             KeySelect = OEMReadDebugByte();
  344.         }
  345.         EdbgOutputDebugString ( "%crn", KeySelect);
  346.         switch(KeySelect)
  347.         {
  348.         case '1':           // Change IP/Subnet address.
  349.             if ( GetUserIPAddr(&g_pBootCfg->EdbgAddr, &g_pBootCfg->SubnetMask) ) {
  350.                 g_pBootCfg->ConfigFlags &= ~CONFIG_FLAGS_DHCP;   // clear DHCP flag
  351.                 bConfigChanged = TRUE;
  352.             }
  353.             continue;
  354.             break;
  355.         case '2':           // Change autoboot delay.
  356.             SetDelay(g_pBootCfg);
  357.             bConfigChanged = TRUE;
  358.             continue;
  359.             break;
  360.         case '3':           // Toggle static/DHCP mode.
  361.             g_pBootCfg->ConfigFlags = (g_pBootCfg->ConfigFlags ^ CONFIG_FLAGS_DHCP);
  362.             bConfigChanged = TRUE;
  363.             continue;
  364.             break;
  365.         case '4':           // Reset TOC configuration.
  366.             RETAILMSG(1, (TEXT("Resetting default TOC...rn")));
  367.             TOC_Init(DEFAULT_IMAGE_DESCRIPTOR, (IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS), 0, 0, 0);
  368.             if ( !TOC_Write() ) {
  369.                 RETAILMSG(1, (TEXT("TOC_Write Failed!rn")));
  370.             }
  371.             RETAILMSG(1, (TEXT("...TOC completern")));
  372.             continue;
  373.             break;
  374.         case '5':           // Toggle download/launch status.
  375.             g_pBootCfg->ConfigFlags = (g_pBootCfg->ConfigFlags ^ BOOT_TYPE_DIRECT);
  376.             bConfigChanged = TRUE;
  377.             break;
  378.         case '6':           // Toggle boot media image store.
  379.             g_pBootCfg->ConfigFlags = (g_pBootCfg->ConfigFlags ^ TARGET_TYPE_NAND);
  380.             bConfigChanged = TRUE;
  381.             break;
  382.         case '7':           // Configure MAC address.
  383.             SetCS8900MACAddress();
  384.             bConfigChanged = TRUE;
  385.             continue;
  386.             break;
  387.         case '8':           // Toggle KD
  388.             g_pBootCfg->ConfigFlags = (g_pBootCfg->ConfigFlags ^ CONFIG_FLAGS_DEBUGGER);
  389.             g_bWaitForConnect = (g_pBootCfg->ConfigFlags & CONFIG_FLAGS_DEBUGGER) ? TRUE : FALSE;
  390.             bConfigChanged = TRUE;
  391.             continue;
  392.             break;
  393.         case '9':
  394.             // format the boot media for BinFS
  395.             // N.B: this does not destroy our OEM reserved sections (TOC, bootloaders, etc)
  396.             if ( !g_bBootMediaExist ) {
  397.                 RETAILMSG(1, (TEXT("ERROR: BootMonitor: boot media does not exist.rn")));
  398.                 continue;
  399.             }
  400.             // N.B: format offset by # of reserved blocks,
  401.             // decrease the ttl # blocks available by that amount.
  402.             if ( !BP_LowLevelFormat( g_dwImageStartBlock,
  403.                                      NUM_BLOCKS - g_dwImageStartBlock,
  404.                                      0) )
  405.             {
  406.                 RETAILMSG(1, (TEXT("ERROR: BootMonitor: Low-level boot media format failed.rn")));
  407.                 continue;
  408.             }
  409.             break;
  410.         case 'B':
  411.         case 'b':
  412.             g_pTOC->id[g_dwTocEntry].dwImageType = (g_pTOC->id[g_dwTocEntry].dwImageType ^ IMAGE_TYPE_BINFS);
  413.             g_ImageType = g_pTOC->id[g_dwTocEntry].dwImageType;
  414.             bConfigChanged = TRUE;
  415.             break;
  416.         case 'E':
  417.         case 'e':
  418.             // TODO
  419.             break;
  420.         case 'F':
  421.         case 'f':
  422.             // low-level format
  423.             // N.B: this erases images, BinFs, FATFS, user data, etc.
  424.             // However, we don't format Bootloaders & TOC bolcks; use JTAG for this.
  425.             if ( !g_bBootMediaExist ) {
  426.                 RETAILMSG(1, (TEXT("ERROR: BootMonitor: boot media does not exist.rn")));
  427.                 continue;
  428.             } else {
  429.                 DWORD i;
  430.                 SectorInfo si;
  431.                 // to keep bootpart off of our reserved blocks we must mark it as bad, reserved & read-only
  432.                 si.bOEMReserved = OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY;
  433.                 si.bBadBlock    = BADBLOCKMARK;
  434.                 si.dwReserved1  = 0;
  435.                 si.wReserved2   = 0;
  436.                 RETAILMSG(1, (TEXT("Reserving Blocks [0x%x - 0x%x] ...rn"), 0, IMAGE_START_BLOCK-1));
  437.                 for (i = 0; i < IMAGE_START_SECTOR; i++) {
  438.                     FMD_WriteSector(i, NULL, &si, 1);
  439.                 }
  440.                 RETAILMSG(1, (TEXT("...reserve complete.rn")));
  441.                 RETAILMSG(1, (TEXT("Low-level format Blocks [0x%x - 0x%x] ...rn"), IMAGE_START_BLOCK, NUM_BLOCKS-1));
  442.                 for (i = IMAGE_START_BLOCK; i < NUM_BLOCKS; i++) {
  443.                     FMD_EraseBlock(i);
  444.                 }
  445.                 RETAILMSG(1, (TEXT("...erase complete.rn")));
  446.             } break;
  447.         case 'D':           // Download? Yes.
  448.         case 'd':
  449.             bDownload = TRUE;
  450.             goto MENU_DONE;
  451.         case 'L':           // Download? No.
  452.         case 'l':
  453.             bDownload = FALSE;
  454.             goto MENU_DONE;
  455.         case 'R':
  456.         case 'r':
  457. TOC_Read();
  458. continue;
  459.             // TODO
  460.             break;
  461.         case 'U':           // Download? No.
  462.         case 'u':
  463.             g_bWaitForConnect = FALSE;
  464.             bConfigChanged = TRUE;
  465. g_bUSBDownload = TRUE;
  466.             bDownload = TRUE;
  467.             goto MENU_DONE;
  468.         case 'W':           // Configuration Write
  469.         case 'w':
  470.             if (!TOC_Write())
  471.             {
  472.                 RETAILMSG(1, (TEXT("WARNING: MainMenu: Failed to store updated eboot configuration in flash.rn")));
  473.             }
  474.             else
  475.             {
  476.                 RETAILMSG(1, (TEXT("Successfully Writtenrn")));
  477.                 bConfigChanged = FALSE;
  478.             }
  479.             break;
  480.         case 'X':           // Download to media, then launch that
  481.         case 'x':
  482.             bDownload = TRUE;
  483.             bConfigChanged = TRUE;
  484.             g_pBootCfg->ConfigFlags |= TARGET_TYPE_NAND | BOOT_TYPE_DIRECT;
  485.             goto MENU_DONE;
  486.         default:
  487.             break;
  488.         }
  489.     }
  490. MENU_DONE:
  491.     // If eboot settings were changed by user, save them.
  492.     //
  493.     if (bConfigChanged && !TOC_Write( ) )
  494.     {
  495.         RETAILMSG(1, (TEXT("WARNING: BootMonitor: Failed to store updated eboot configuration in flash.rn")));
  496.     }
  497.     return(bDownload);
  498. }
  499. /*
  500.     @func   BOOL | OEMPlatformInit | Initialize the platform hardware.
  501.     @rdesc  TRUE = Success, FALSE = Failure.
  502.     @comm
  503.     @xref
  504. */
  505. BOOL OEMPlatformInit()
  506. {
  507.     SYSTEMTIME  st;
  508.     SYSTEMTIME  defst = {2002, 1, 0, 1, 12, 0, 0, 0};
  509.     DWORD dwStartTime, dwPrevTime, dwCurrTime;
  510.     int   cKeySelect = 0;
  511.     DWORD dwBootDelay = 10; // seconds. N.B: change for retail device!
  512. #ifdef SIMULATOR
  513.     EdbgOutputDebugString("Microsoft Windows CE SMDK2440 Bootloader *** SIMULATOR *** rn");
  514. #else
  515.     EdbgOutputDebugString("Microsoft Windows CE SMDK2440 Bootloader Version %d.%d Built %s %s rn",
  516.                           EBOOT_VERSION_MAJOR, EBOOT_VERSION_MINOR, __DATE__, __TIME__);
  517. #endif
  518.     //  Initialize the globals
  519.     //
  520.     memset((LPVOID) &(pDriverGlobals->eth), 0, DBG_ETH_GLOBALS_SIZE);
  521.     memset((LPVOID) &g_TOC, 0, sizeof(g_TOC));
  522.     // This should not change unless reserved blocks are added/removed;
  523.     // made global to do the calc only once.
  524.     g_dwImageStartBlock = IMAGE_START_BLOCK;
  525.     // Check real time clock, initialize if necessary (used for polling in net routines)
  526.     //
  527.     OEMGetRealTime(&st);
  528.     if ((st.wYear < 2000) ||
  529.         (st.wMonth < 1) ||
  530.         (st.wMonth > 12) ||
  531.         (st.wDay < 1) ||
  532.         (st.wDay > 31) ||
  533.         (st.wHour > 23) ||
  534.         (st.wMinute > 59) ||
  535.         (st.wSecond > 59) ||
  536.         (st.wMilliseconds > 999)) {
  537.         OEMSetRealTime(&defst);
  538.     }
  539.     else {
  540.         OEMSetRealTime(&st);
  541.     }
  542. if (!InitUSB())
  543.     {
  544.         DEBUGMSG(1, (TEXT("OEMPlatformInit: Failed to initialize USB.rn")));
  545.         return(FALSE);
  546.     }
  547. Isr_Init();
  548.     // Try to initialize the boot media block driver and BinFS partition.
  549.     //
  550.     if ( !BP_Init((LPBYTE)BINFS_RAM_START, BINFS_RAM_LENGTH, NULL, NULL, NULL) )
  551.     {
  552.         EdbgOutputDebugString("WARNING: OEMPlatformInit failed to initialize Boot Media.rnrn");
  553.         g_bBootMediaExist = FALSE;
  554.     }
  555.     else
  556.         g_bBootMediaExist = TRUE;
  557.     // Try to retrieve TOC (and Boot config) from boot media
  558.     //
  559.     if ( !TOC_Read( ) ) {
  560.         // use default settings
  561.         TOC_Init(DEFAULT_IMAGE_DESCRIPTOR, (IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS), 0, 0, 0);
  562.     }
  563.     // Start boot monitor prompt
  564.     //
  565.     dwBootDelay = g_pBootCfg->BootDelay;
  566.     if (g_pBootCfg->ConfigFlags & BOOT_TYPE_DIRECT)
  567.     {
  568.         EdbgOutputDebugString ( "Press [ENTER] to launch image stored on boot media, or [SPACE] to enter boot monitor.rn");
  569.         EdbgOutputDebugString ( "rnInitiating image launch in %d seconds. ", dwBootDelay--);
  570.     } else
  571.     {
  572.         EdbgOutputDebugString ( "Press [ENTER] to download image now, or [SPACE] to enter boot monitor.rn");
  573.         EdbgOutputDebugString ( "rnInitiating image download in %d seconds. ", dwBootDelay--);
  574.     }
  575.     dwStartTime = OEMEthGetSecs();
  576.     dwPrevTime  = dwStartTime;
  577.     dwCurrTime  = dwStartTime;
  578.     // allow the user to break into boot monitor
  579.     while((dwCurrTime - dwStartTime) < dwBootDelay)
  580.     {
  581.         cKeySelect = OEMReadDebugByte();
  582.         if ((cKeySelect == 0x20) || (cKeySelect == 0x0d))
  583.             break;
  584.         dwCurrTime = OEMEthGetSecs();
  585.         if (dwCurrTime > dwPrevTime)
  586.         {
  587.             int i=0, j;
  588.             // 1 Second has elapsed - update the countdown timer.
  589.             dwPrevTime = dwCurrTime;
  590.             if (dwBootDelay < 9)
  591.                 i = 11;
  592.             else if (dwBootDelay < 99)
  593.                 i = 12;
  594.             else if (dwBootDelay < 999)
  595.                 i = 13;
  596.             for(j = 0; j < i; j++)
  597.                 OEMWriteDebugByte((BYTE)0x08); // print back space
  598.             EdbgOutputDebugString ( "%d seconds. ", dwBootDelay--);
  599.         }
  600.     }
  601.     EdbgOutputDebugString ( "rn");
  602.     switch(cKeySelect)
  603.     {
  604.     case 0x20: // Boot monitor.
  605.         g_bDownloadImage = BootMonitor( );
  606.         break;
  607.     case 0x00: // Fall through if no keys were pressed -or-
  608.     case 0x0d: // the user cancelled the countdown.
  609.     default:
  610.         if (g_pBootCfg->ConfigFlags & BOOT_TYPE_DIRECT)
  611.         {
  612.             EdbgOutputDebugString ( "rnLaunching image from boot media ... rn");
  613.             g_bDownloadImage = FALSE;
  614.         }
  615.         else
  616.         {
  617.             EdbgOutputDebugString ( "rnStarting auto-download ... rn");
  618.             g_bDownloadImage = TRUE;
  619.         }
  620.         break;
  621.     }
  622.     // NOTE - right now, we assume that if we're downloading, it's done over Ethernet.
  623.     // In the future, this may include other transports (USB, etc.).
  624.     //
  625.     if ( !g_bDownloadImage )
  626.     {
  627.         // User doesn't want to download image - load it from the boot media.
  628.         // We could read an entire nk.bin or nk.nb0 into ram and jump.
  629.         if ( !VALID_TOC(g_pTOC) ) {
  630.             EdbgOutputDebugString("OEMPlatformInit: ERROR_INVALID_TOC, can not autoboot.rn");
  631.             return FALSE;
  632.         }
  633.         switch (g_ImageType) {
  634.             case IMAGE_TYPE_LOADER:
  635.                 EdbgOutputDebugString("OEMPlatformInit: IMAGE_TYPE_LOADERrn");
  636.                 break;
  637.             case IMAGE_TYPE_RAMIMAGE:
  638.                 EdbgOutputDebugString("OEMPlatformInit: IMAGE_TYPE_RAMIMAGErn");
  639.                 if ( !ReadRamImageFromBootMedia( ) ) {
  640.                     RETAILMSG(1, (TEXT("OEMPlatformInit ERROR: Failed to load kernel region into RAM.rn")));
  641.                     return FALSE;
  642.                 }
  643.                 break;
  644.             case (IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS):
  645.             case (IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS|IMAGE_TYPE_MXIP):
  646.                 EdbgOutputDebugString("OEMPlatformInit: IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS|IMAGE_TYPE_MXIPrn");
  647.                 // N.B: this assumes the image is setup as multi-bin for BinFS.
  648.                 if ( !ReadKernelRegionFromBootMedia( ) ) {
  649.                     RETAILMSG(1, (TEXT("OEMPlatformInit ERROR: Failed to load kernel region into RAM.rn")));
  650.                     return FALSE;
  651.                 }
  652.                 break;
  653.             default:
  654.                 EdbgOutputDebugString("OEMPlatformInit ERROR: unknown image type: 0x%x rn", g_ImageType );
  655.                 return FALSE;
  656.         }
  657.     }
  658.     // If user specified a static IP address, use it (don't use DHCP).
  659.     //
  660.     if (g_bDownloadImage && !(g_pBootCfg->ConfigFlags & CONFIG_FLAGS_DHCP))
  661.     {
  662.         pDriverGlobals->eth.TargetAddr.dwIP = g_pBootCfg->EdbgAddr.dwIP;
  663.         pDriverGlobals->eth.SubnetMask      = g_pBootCfg->SubnetMask;
  664.     }
  665.     // Configure Ethernet controller.
  666. if ( g_pBootCfg->ConfigFlags & CONFIG_FLAGS_DEBUGGER )
  667. {
  668. if (!InitEthDevice(g_pBootCfg))
  669. {
  670. DEBUGMSG(1, (TEXT("OEMPlatformInit: Failed to initialize Ethernet controller.rn")));
  671. return(FALSE);
  672. }
  673. }
  674.     return TRUE;
  675. }
  676. /*
  677.     @func   DWORD | OEMPreDownload | Complete pre-download tasks - get IP address, initialize TFTP, etc.
  678.     @rdesc  BL_DOWNLOAD = Platform Builder is asking us to download an image,
  679.             BL_JUMP = Platform Builder is requesting we jump to an existing image,
  680.             BL_ERROR = Failure.
  681.     @comm
  682.     @xref
  683. */
  684. DWORD OEMPreDownload()
  685. {
  686.     char szDeviceName[EDBG_MAX_DEV_NAMELEN];
  687.     BOOL fGotJumpImg = FALSE;
  688.     DWORD DHCPLeaseTime = 0, *pDHCPLeaseTime = &DHCPLeaseTime;
  689.     // If user wants to jump to existing image with no KD - skip download...
  690.     //
  691.     if ( !g_bDownloadImage && !g_bWaitForConnect)
  692.     {
  693.         return(BL_JUMP);
  694.     }
  695.     if ( !g_bDownloadImage && g_bWaitForConnect )
  696.         fGotJumpImg = TRUE;
  697.     //
  698.     // Create device name based on MAC address.
  699.     //
  700.     memset(szDeviceName, 0, EDBG_MAX_DEV_NAMELEN);
  701.     CreateDeviceName(&g_pBootCfg->EdbgAddr, szDeviceName);
  702.     EdbgOutputDebugString("Using device name: '%s'n", szDeviceName);
  703.     // initialize TFTP transport
  704.     //
  705.     if ( !(g_pBootCfg->ConfigFlags & CONFIG_FLAGS_DHCP) ) {
  706.         pDHCPLeaseTime = NULL;  // the pDHCPLeaseTime parameter is overloaded.
  707.                                 // NULL indicates static IP
  708.         pDriverGlobals->eth.EdbgFlags = EDBG_FLAGS_STATIC_IP;
  709.     }
  710. #ifndef SIMULATOR
  711. if ( g_bUSBDownload == FALSE )
  712. {
  713. if (g_bDownloadImage &&
  714. !EbootInitEtherTransport (&g_pBootCfg->EdbgAddr, &g_pBootCfg->SubnetMask, &fGotJumpImg, pDHCPLeaseTime,
  715. EBOOT_VERSION_MAJOR, EBOOT_VERSION_MINOR, PLATFORM_STRING, szDeviceName, EDBG_CPUID, 0)) {
  716. return BL_ERROR;
  717. }
  718. }
  719. #endif
  720. //    SMCSetOptions(OPT_BROADCAST_FILTERING);
  721.     // update DHCP lease time
  722.     pDriverGlobals->eth.DHCPLeaseTime = DHCPLeaseTime;
  723. if ( g_bUSBDownload == TRUE )
  724.     EdbgOutputDebugString("Please send the Image through USBrn");
  725.     return fGotJumpImg? BL_JUMP : BL_DOWNLOAD;
  726. }
  727. /*
  728.     @func   void | OEMLaunch | Executes the stored/downloaded image.
  729.     @rdesc  N/A.
  730.     @comm
  731.     @xref
  732. */
  733. void OEMLaunch(DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr, const ROMHDR *pRomHdr)
  734. {
  735.     EDBG_OS_CONFIG_DATA *pCfgData;
  736.     EDBG_ADDR EshellHostAddr = {0,0,0};
  737.     EdbgOutputDebugString("::OEMLaunch, ImageStart:0x%x, ImageLength:0x%x, LaunchAddr:0x%xrn",
  738.         dwImageStart, dwImageLength, dwLaunchAddr);
  739.     // Wait for Platform Builder to connect after the download and send us IP and port settings for service
  740.     // connections - also sends us KITL flags.  This information is used later by the OS (KITL).
  741.     //
  742. #ifndef SIMULATOR
  743.     if ( g_bDownloadImage && g_bWaitForConnect )
  744.     {
  745.         EdbgOutputDebugString ("EbootWaitForHostConenctrn");
  746.         pCfgData = EbootWaitForHostConnect (&g_pBootCfg->EdbgAddr, &EshellHostAddr);
  747.         if (!pCfgData) {
  748.             EdbgOutputDebugString ("EbootWaitForHostConenct failed, spin foreverrn");
  749.             SPIN_FOREVER;
  750.         }
  751.         if (pCfgData->Flags & EDBG_FL_DBGMSG) {
  752.             EdbgOutputDebugString("Enabling debug messages over Ethernet, IP: %s, port:%un",
  753.                 inet_ntoa(pCfgData->DbgMsgIPAddr),ntohs(pCfgData->DbgMsgPort));
  754.             memcpy(&pDriverGlobals->eth.DbgHostAddr.wMAC,&EshellHostAddr.wMAC,6);
  755.             pDriverGlobals->eth.DbgHostAddr.dwIP  = pCfgData->DbgMsgIPAddr;
  756.             pDriverGlobals->eth.DbgHostAddr.wPort = pCfgData->DbgMsgPort;
  757.         }
  758.         if (pCfgData->Flags & EDBG_FL_PPSH) {
  759.             EdbgOutputDebugString("Enabling CESH over Ethernet,           IP: %s, port:%un",
  760.                 inet_ntoa(pCfgData->PpshIPAddr),ntohs(pCfgData->PpshPort));
  761.             memcpy(&pDriverGlobals->eth.PpshHostAddr.wMAC,&EshellHostAddr.wMAC,6);
  762.             pDriverGlobals->eth.PpshHostAddr.dwIP  = pCfgData->PpshIPAddr;
  763.             pDriverGlobals->eth.PpshHostAddr.wPort = pCfgData->PpshPort;
  764.         }
  765.         if (pCfgData->Flags & EDBG_FL_KDBG) {
  766.             EdbgOutputDebugString("Enabling KDBG over Ethernet,           IP: %s, port:%un",
  767.                 inet_ntoa(pCfgData->KdbgIPAddr),ntohs(pCfgData->KdbgPort));
  768.             memcpy(&pDriverGlobals->eth.KdbgHostAddr.wMAC,&EshellHostAddr.wMAC,6);
  769.             pDriverGlobals->eth.KdbgHostAddr.dwIP  = pCfgData->KdbgIPAddr;
  770.             pDriverGlobals->eth.KdbgHostAddr.wPort = pCfgData->KdbgPort;
  771.         }
  772.         memcpy(&pDriverGlobals->eth.DownloadHostAddr,&EshellHostAddr,sizeof(EDBG_ADDR));
  773.         pDriverGlobals->eth.etherFlags = pCfgData->Flags;
  774.         pDriverGlobals->eth.KitlTransport = pCfgData->KitlTransport;
  775.         EdbgOutputDebugString ("KitlTransport: 0x%xrn", pCfgData->KitlTransport);
  776.         pDriverGlobals->eth.EbootMagicNum = EBOOT_MAGIC_NUM;
  777.     }
  778.     else if ( !g_bDownloadImage && g_bWaitForConnect)
  779.     {
  780.         EdbgOutputDebugString ("Eboot setup Kitl from media bootrn");
  781.         pDriverGlobals->eth.KitlTransport = KTS_ETHER;
  782.         pDriverGlobals->eth.EbootMagicNum = EBOOT_MAGIC_NUM;
  783.     }
  784. #endif
  785.     // Update address info, in driver globals, and in EEPROM if necessary
  786.     memcpy (&pDriverGlobals->eth.TargetAddr, &g_pBootCfg->EdbgAddr, sizeof(g_pBootCfg->EdbgAddr));
  787.     pDriverGlobals->eth.SubnetMask = g_pBootCfg->SubnetMask;
  788.     // If the user requested an image be stored on media, do so now.  For multiple RAM BIN files, we need to map
  789.     // its RAM address to a flash address - the image base address offset in RAM is maintained in flash.
  790.     //
  791.     // Remember kernel launch address or recall stored address if this download didn't provide one
  792.     // (i.e., we didn't download the kernel region).
  793.     if (g_bDownloadImage && (g_pBootCfg->ConfigFlags & TARGET_TYPE_NAND))
  794.     {
  795. if (dwImageStart && dwImageLength)
  796. {
  797. g_pTOC->id[g_dwTocEntry].dwLoadAddress = dwImageStart;
  798. g_pTOC->id[g_dwTocEntry].dwTtlSectors = FILE_TO_SECTOR_SIZE(dwImageLength);
  799. }
  800.         switch ( g_ImageType ) {
  801.             case IMAGE_TYPE_LOADER:
  802.                 EdbgOutputDebugString("OEMLaunch: IMAGE_TYPE_LOADERrn");
  803.                 if ( !WriteRamImageToBootMedia(g_dwTocEntry) ) {
  804.                     RETAILMSG(1, (TEXT("OEMLaunch ERROR: Failed to write image to boot media.rn")));
  805.                     SPIN_FOREVER;
  806.                 }
  807.                 break;
  808.             case IMAGE_TYPE_RAMIMAGE:
  809.                 EdbgOutputDebugString("OEMLaunch: IMAGE_TYPE_RAMIMAGErn");
  810.                 if ( !WriteRamImageToBootMedia(g_dwTocEntry) ) {
  811.                     RETAILMSG(1, (TEXT("OEMLaunch ERROR: Failed to write image to boot media.rn")));
  812.                     SPIN_FOREVER;
  813.                 }
  814.                 break;
  815.             case (IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS|IMAGE_TYPE_MXIP):
  816.             case (IMAGE_TYPE_RAMIMAGE|IMAGE_TYPE_BINFS):
  817.                 EdbgOutputDebugString("OEMLaunch: (%s|IMAGE_TYPE_BINFS)rn",
  818.                     (g_ImageType & IMAGE_TYPE_MXIP) ? "IMAGE_TYPE_MXIP" : "IMAGE_TYPE_RAMIMAGE");
  819.                 if ( !WriteRegionsToBootMedia(dwImageStart, dwImageLength, dwLaunchAddr) ) {
  820.                     EdbgOutputDebugString("WARNING: OEMLaunch: Failed to store BinFS regions to boot media.rn");
  821.                     SPIN_FOREVER;
  822.                 }
  823.                 break;
  824.             default:
  825.                 EdbgOutputDebugString("OEMLaunch ERROR: unknown image type: 0x%x rn",
  826.                     g_pTOC->id[g_dwTocEntry].dwImageType);
  827.                 SPIN_FOREVER;
  828.         }
  829.     }
  830. // Remember kernel launch address or recall stored address if this download didn't provide one (i.e., we didn't download the kernel region).
  831. //
  832. if (dwLaunchAddr && (g_pTOC->id[g_dwTocEntry].dwJumpAddress != dwLaunchAddr))
  833. {
  834. g_pTOC->id[g_dwTocEntry].dwJumpAddress = dwLaunchAddr;
  835. if ( !TOC_Write() ) {
  836.             EdbgOutputDebugString("*** OEMLaunch ERROR: TOC_Write failed! Next boot may not load from disk *** rn");
  837. }
  838.         TOC_Print();
  839. }
  840. else
  841. {
  842. dwLaunchAddr= g_pTOC->id[g_dwTocEntry].dwJumpAddress;
  843. EdbgOutputDebugString("INFO: using TOC[%d] dwJumpAddress: 0x%xrn", g_dwTocEntry, dwLaunchAddr);
  844. }
  845.     EdbgOutputDebugString("rnJumping to image at virtual address 0x%Xhrn", dwLaunchAddr);
  846.     //  Our Launch function takes Physical address, so we need to convert it
  847.     //  to physical address
  848.     dwLaunchAddr = ToPhysicalAddr(dwLaunchAddr);
  849.     EdbgOutputDebugString("rn::: Physical Launch Address: 0x%Xhrn",dwLaunchAddr);
  850.     Launch(dwLaunchAddr);
  851.     // never returned
  852.     SPIN_FOREVER;
  853. }
  854. /*
  855.     @func   BOOL | OEMReadData | Generically read download data (abstracts actual transport read call).
  856.     @rdesc  TRUE = Success, FALSE = Failure.
  857.     @comm
  858.     @xref
  859. */
  860. BOOL OEMReadData (DWORD cbData, LPBYTE pbData)
  861. {
  862. if ( g_bUSBDownload == FALSE )
  863. {
  864. return EbootEtherReadData(cbData, pbData);
  865. }
  866. else
  867. {
  868. return UbootReadData(cbData, pbData);
  869. }
  870. }
  871. /*
  872.     @func   void | OEMShowProgress | Displays download progress for the user.
  873.     @rdesc  N/A.
  874.     @comm
  875.     @xref
  876. */
  877. void OEMShowProgress (DWORD dwPacketNum)
  878. {
  879. }
  880. #define BACKSPACE   8
  881. #define IPADDR_MAX  15
  882. // Read IP from command line
  883. static BOOL ReadIPLine (char *pbuf, DWORD dwTimeout)
  884. {
  885.     DWORD dwCurrSec = OEMEthGetSecs ();
  886.     char ch;
  887.     int nLen = 0;
  888.     while (OEMEthGetSecs () - dwCurrSec < dwTimeout) {
  889.         ch = (CHAR)OEMReadDebugByte();
  890.         switch (ch) {
  891.         case OEM_DEBUG_COM_ERROR:
  892.         case OEM_DEBUG_READ_NODATA:
  893.             // no data or error, keep reading
  894.             break;
  895.         case BACKSPACE:
  896.             nLen --;
  897.             OEMWriteDebugByte (ch);
  898.             break;
  899.         case 'r':
  900.         case 'n':
  901.             OEMWriteDebugByte ('n');
  902.             pbuf[nLen] = 0;
  903.             return TRUE;
  904.         default:
  905.             if ((ch == '.' || (ch >= '0' && ch <= '9')) && (nLen < IPADDR_MAX)) {
  906.                 pbuf[nLen ++] = ch;
  907.                 OEMWriteDebugByte (ch);
  908.             }
  909.         }
  910.     }
  911.     return FALSE;   // timeout
  912. }
  913. // get users IP / SubnetMask
  914. // return TRUE is changes made to either, else FALSE.
  915. static BOOL GetUserIPAddr (EDBG_ADDR *pMyAddr, DWORD *pdwSubnetMask)
  916. {
  917.     char  szbuf[IPADDR_MAX+1];
  918.     uchar changes = 0;
  919.     memset(szbuf, 0, sizeof(szbuf));
  920.     EdbgOutputDebugString ("rnEnter IP address, or CR for default (%s): ", inet_ntoa(pMyAddr->dwIP));
  921.     ReadIPLine (szbuf, INFINITE);
  922.     if (szbuf[0]) {
  923.         pMyAddr->dwIP = inet_addr(szbuf);
  924.         changes++;
  925.         memset(szbuf, 0, sizeof(szbuf));
  926.     }
  927.     EdbgOutputDebugString ("rnEnter Subnet Masks, or CR for default (%s): ", inet_ntoa(*pdwSubnetMask));
  928.     ReadIPLine (szbuf, INFINITE);
  929.     if (szbuf[0]) {
  930.         *pdwSubnetMask = inet_addr (szbuf);
  931.         changes++;
  932.     }
  933.     EdbgOutputDebugString ( "rnUsing IP Address %s, subnet mask %srn",
  934.                 inet_ntoa (pMyAddr->dwIP), inet_ntoa (*pdwSubnetMask));
  935.     return (changes ? TRUE : FALSE);
  936. }
  937. static ULONG mystrtoul(PUCHAR pStr, UCHAR nBase)
  938. {
  939.     UCHAR nPos=0;
  940.     BYTE c;
  941.     ULONG nVal = 0;
  942.     UCHAR nCnt=0;
  943.     ULONG n=0;
  944.     // fulllibc doesn't implement isctype or iswctype, which are needed by
  945.     // strtoul, rather than including coredll code, here's our own simple strtoul.
  946.     if (pStr == NULL)
  947.         return(0);
  948.     for (nPos=0 ; nPos < strlen(pStr) ; nPos++)
  949.     {
  950. //        c = tolower(*(pStr + strlen(pStr) - 1 - nPos));
  951.         c = (*(pStr + strlen(pStr) - 1 - nPos));
  952.         if (c >= '0' && c <= '9')
  953.             c -= '0';
  954.         else if (c >= 'a' && c <= 'f')
  955.         {
  956.             c -= 'a';
  957.             c  = (0xa + c);
  958.         }
  959.         for (nCnt = 0, n = 1 ; nCnt < nPos ; nCnt++)
  960.         {
  961.             n *= nBase;
  962.         }
  963.         nVal += (n * c);
  964.     }
  965.     return(nVal);
  966. }
  967. // since the startup code is in OAL and it branch to main, we'll just
  968. // implement a pseudo 'main' instead of changing the startup code
  969. void main (void)
  970. {
  971.     BootloaderMain ();
  972.     SPIN_FOREVER;
  973. }
  974. VOID SC_WriteDebugLED(WORD wIndex, DWORD dwPattern)
  975. {
  976.     OEMWriteDebugLED(wIndex,dwPattern);
  977. }
  978. /*
  979.     @func   void | SetDelay | Accepts an autoboot delay value from user input.
  980.     @rdesc  N/A.
  981.     @comm    
  982.     @xref   
  983. */
  984. static void SetDelay()
  985. {
  986.     CHAR szCount[16];
  987.     USHORT cwNumChars = 0;
  988.     USHORT InChar = 0;
  989.     EdbgOutputDebugString("rnEnter maximum number of seconds to delay [1-255]: ");
  990.     while(!((InChar == 0x0d) || (InChar == 0x0a)))
  991.     {
  992.         InChar = OEMReadDebugByte();
  993.         if (InChar != OEM_DEBUG_COM_ERROR && InChar != OEM_DEBUG_READ_NODATA) 
  994.         {
  995.             // If it's a number or a period, add it to the string.
  996.             //
  997.             if ((InChar >= '0' && InChar <= '9')) 
  998.             {
  999.                 if (cwNumChars < 16) 
  1000.                 {
  1001.                     szCount[cwNumChars++] = (char)InChar;
  1002.                     OEMWriteDebugByte((BYTE)InChar);
  1003.                 }
  1004.             }
  1005.             // If it's a backspace, back up.
  1006.             //
  1007.             else if (InChar == 8) 
  1008.             {
  1009.                 if (cwNumChars > 0) 
  1010.                 {
  1011.                     cwNumChars--;
  1012.                     OEMWriteDebugByte((BYTE)InChar);
  1013.                 }
  1014.             }
  1015.         }
  1016.     }
  1017.     // If it's a carriage return with an empty string, don't change anything.
  1018.     //
  1019.     if (cwNumChars) 
  1020.     {
  1021.         szCount[cwNumChars] = '';
  1022.         g_pBootCfg->BootDelay = atoi(szCount);
  1023.         if (g_pBootCfg->BootDelay > 255)
  1024.         {
  1025.             g_pBootCfg->BootDelay = 255;
  1026.         } 
  1027.         else if (g_pBootCfg->BootDelay < 1)
  1028.         {
  1029.             g_pBootCfg->BootDelay = 1;
  1030.         }
  1031.     }
  1032. }
  1033. static void CvtMAC(USHORT MacAddr[3], char *pszDottedD ) 
  1034. {
  1035.     DWORD cBytes;
  1036.     char *pszLastNum;
  1037.     int atoi (const char *s);
  1038.     int i=0;    
  1039.     BYTE *p = (BYTE *)MacAddr;
  1040.     // Replace the dots with NULL terminators
  1041.     pszLastNum = pszDottedD;
  1042.     for(cBytes = 0 ; cBytes < 6 ; cBytes++)
  1043.     {
  1044.         while(*pszDottedD != '.' && *pszDottedD != '')
  1045.         {
  1046.             pszDottedD++;
  1047.         }
  1048.         if (pszDottedD == '' && cBytes != 5)
  1049.         {
  1050.             // zero out the rest of MAC address
  1051.             while(i++ < 6)
  1052.             {
  1053.                 *p++ = 0;
  1054.             }
  1055.             break;
  1056.         }
  1057.         *pszDottedD = '';
  1058.         *p++ = (BYTE)(mystrtoul(pszLastNum, 16) & 0xFF);
  1059.         i++;
  1060.         pszLastNum = ++pszDottedD;
  1061.     }
  1062. }
  1063. static void SetCS8900MACAddress()
  1064. {
  1065.     CHAR szDottedD[24];
  1066.     USHORT cwNumChars = 0;
  1067.     USHORT InChar = 0;
  1068.     memset(szDottedD, '0', 24);
  1069.     EdbgOutputDebugString ( "rnEnter new MAC address in hexadecimal (hh.hh.hh.hh.hh.hh): ");
  1070.     while(!((InChar == 0x0d) || (InChar == 0x0a)))
  1071.     {
  1072.         InChar = OEMReadDebugByte();
  1073. //        InChar = tolower(InChar);
  1074.         if (InChar != OEM_DEBUG_COM_ERROR && InChar != OEM_DEBUG_READ_NODATA) 
  1075.         {
  1076.             // If it's a hex number or a period, add it to the string.
  1077.             //
  1078.             if (InChar == '.' || (InChar >= '0' && InChar <= '9') || (InChar >= 'a' && InChar <= 'f')) 
  1079.             {
  1080.                 if (cwNumChars < 17) 
  1081.                 {
  1082.                     szDottedD[cwNumChars++] = (char)InChar;
  1083.                     OEMWriteDebugByte((BYTE)InChar);
  1084.                 }
  1085.             }
  1086.             else if (InChar == 8)       // If it's a backspace, back up.
  1087.             {
  1088.                 if (cwNumChars > 0) 
  1089.                 {
  1090.                     cwNumChars--;
  1091.                     OEMWriteDebugByte((BYTE)InChar);
  1092.                 }
  1093.             }
  1094.         }
  1095.     }
  1096.     EdbgOutputDebugString ( "rn");
  1097.     // If it's a carriage return with an empty string, don't change anything.
  1098.     //
  1099.     if (cwNumChars) 
  1100.     {
  1101.         szDottedD[cwNumChars] = '';
  1102.         CvtMAC(g_pBootCfg->EdbgAddr.wMAC, szDottedD);
  1103.         EdbgOutputDebugString("INFO: MAC address set to: %x:%x:%x:%x:%x:%xrn",
  1104.                   g_pBootCfg->EdbgAddr.wMAC[0] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[0] >> 8,
  1105.                   g_pBootCfg->EdbgAddr.wMAC[1] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[1] >> 8,
  1106.                   g_pBootCfg->EdbgAddr.wMAC[2] & 0x00FF, g_pBootCfg->EdbgAddr.wMAC[2] >> 8);
  1107.     }
  1108.     else
  1109.     {
  1110.         EdbgOutputDebugString("WARNING: SetCS8900MACAddress: Invalid MAC address.rn");
  1111.     }
  1112. }