Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3501 lines
102 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. ramdisk.c
  5. Abstract:
  6. Provides the ARC emulation routines for I/O to a RAM disk device.
  7. Author:
  8. Chuck Lenzmeier (chuckl) 29-Apr-2001
  9. Revision History:
  10. Bassam Tabbara (bassamt) 06-Aug-2001 Added Ramdisk Building Support
  11. --*/
  12. #include "bootlib.h"
  13. #include "arccodes.h"
  14. #include "stdlib.h"
  15. #include "string.h"
  16. #if defined(_X86_)
  17. #include "bootx86.h"
  18. #endif
  19. #if defined(_IA64_)
  20. #include "bootia64.h"
  21. #endif
  22. #include "ramdisk.h"
  23. #include "netfs.h"
  24. #include "bmbuild.h"
  25. #include "ntexapi.h"
  26. #include "haldtect.h"
  27. #include "pci.h"
  28. #include "pbios.h"
  29. #include "bldr.h"
  30. #include <sdistructs.h>
  31. //
  32. // Debug helpers
  33. //
  34. #define ERR 0
  35. #define INFO 1
  36. #define VERBOSE 2
  37. #define PAINFUL 3
  38. #define DBGPRINT(lvl, _fmt_) if (RamdiskDebug && lvl <= RamdiskDebugLevel) DbgPrint _fmt_
  39. #define DBGLVL(x) (RamdiskDebug && RamdiskDebugLevel == x)
  40. BOOLEAN RamdiskDebug = TRUE;
  41. BOOLEAN RamdiskDebugLevel = INFO;
  42. BOOLEAN RamdiskBreak = FALSE;
  43. //
  44. // Macros
  45. //
  46. #define BL_INVALID_FILE_ID (ULONG)-1
  47. #define TEST_BIT(value, b) (((value) & (b)) == (b))
  48. #define ROUND2(_val, _round) (((_val) + ((_round) - 1)) & ~((_round) - 1))
  49. //
  50. // PCI Device struct as persisted in registry by ntdetect.com
  51. //
  52. #include <pshpack1.h>
  53. typedef struct _PCIDEVICE {
  54. USHORT BusDevFunc;
  55. PCI_COMMON_CONFIG Config;
  56. } PCIDEVICE, *PPCIDEVICE;
  57. #include <poppack.h>
  58. //
  59. // Externs
  60. //
  61. extern PVOID InfFile;
  62. extern BOOLEAN GraphicsMode;
  63. extern BOOLEAN BlShowProgressBar;
  64. extern BOOLEAN BlOutputDots;
  65. extern BOOLEAN DisplayLogoOnBoot;
  66. //
  67. // Global Ramdisk options.
  68. // NOTE: All Ip addresses and ports are in network byte order.
  69. //
  70. BOOLEAN RamdiskBuild = FALSE;
  71. //
  72. // Used if downloading a ramdisk directly. RamdiskBuild = FALSE
  73. //
  74. PCHAR RamdiskPath = NULL;
  75. ULONG RamdiskTFTPAddr = 0; // network byte order
  76. ULONG RamdiskMTFTPAddr = 0; // network byte order
  77. USHORT RamdiskMTFTPCPort = 0; // network byte order
  78. USHORT RamdiskMTFTPSPort = 0; // network byte order
  79. USHORT RamdiskMTFTPTimeout = 5;
  80. USHORT RamdiskMTFTPDelay = 5;
  81. LONGLONG RamdiskMTFTPFileSize = 0;
  82. LONGLONG RamdiskMTFTPChunkSize = 0;
  83. //
  84. // Used if Building a ramdisk. RamdiskBuild = TRUE
  85. //
  86. #define RAMDISK_MAX_SERVERS 10
  87. #define RAMDISK_MAX_TIMEOUT 60
  88. #define RAMDISK_UI_WAIT 3
  89. GUID RamdiskGuid = {0,0,0,0};
  90. ULONG RamdiskDiscovery = 0xFFFFFFFF;
  91. ULONG RamdiskMCastAddr = 0; // network byte order
  92. ULONG RamdiskServerCount = 0;
  93. ULONG RamdiskServers[RAMDISK_MAX_SERVERS]; // network byte order
  94. USHORT RamdiskBuildPort = BMBUILD_SERVER_PORT_DEFAULT;
  95. USHORT RamdiskTimeout = 4;
  96. USHORT RamdiskRetry = 5;
  97. //
  98. // Globals
  99. //
  100. BOOLEAN RamdiskActive = FALSE;
  101. ULONG RamdiskBasePage = 0;
  102. LONGLONG RamdiskFileSize = 0;
  103. ULONG RamdiskFileSizeInPages = 0;
  104. ULONG RamdiskImageOffset = 0;
  105. LONGLONG RamdiskImageLength = 0;
  106. ULONG_PTR SdiAddress = 0;
  107. ULONG RamdiskMaxPacketSize = 0;
  108. ULONG RamdiskXID = 0;
  109. BL_DEVICE_ENTRY_TABLE RamdiskEntryTable =
  110. {
  111. (PARC_CLOSE_ROUTINE)RamdiskClose,
  112. (PARC_MOUNT_ROUTINE)RamdiskMount,
  113. (PARC_OPEN_ROUTINE)RamdiskOpen,
  114. (PARC_READ_ROUTINE)RamdiskRead,
  115. (PARC_READ_STATUS_ROUTINE)RamdiskReadStatus,
  116. (PARC_SEEK_ROUTINE)RamdiskSeek,
  117. (PARC_WRITE_ROUTINE)RamdiskWrite,
  118. (PARC_GET_FILE_INFO_ROUTINE)RamdiskGetFileInfo,
  119. (PARC_SET_FILE_INFO_ROUTINE)RamdiskSetFileInfo,
  120. (PRENAME_ROUTINE)RamdiskRename,
  121. (PARC_GET_DIRECTORY_ENTRY_ROUTINE)RamdiskGetDirectoryEntry,
  122. (PBOOTFS_INFO)NULL
  123. };
  124. //
  125. // forward decls
  126. //
  127. PVOID
  128. MapRamdisk (
  129. IN LONGLONG Offset,
  130. OUT PLONGLONG AvailableLength
  131. );
  132. ARC_STATUS
  133. RamdiskParseOptions (
  134. IN PCHAR LoadOptions
  135. );
  136. ARC_STATUS
  137. RamdiskInitializeFromPath(
  138. );
  139. ARC_STATUS
  140. RamdiskBuildAndInitialize(
  141. );
  142. VOID
  143. RamdiskFatalError(
  144. IN ULONG Message1,
  145. IN ULONG Message2
  146. );
  147. ARC_STATUS
  148. RamdiskInitialize(
  149. IN PCHAR LoadOptions,
  150. IN BOOLEAN SdiBoot
  151. )
  152. /*++
  153. Routine Description:
  154. This function will initiate the boot from a RAMDISK. Depending
  155. on the options passed in the the boot will either happen from
  156. a static RAMDISK (using the /RDPATH option) or from a dynamic
  157. RAMDISK (using the /RDBUILD option).
  158. Arguments:
  159. LoadOptions - boot.ini parameters
  160. SdiBoot - indicates whether this is an SDI boot. If it is, LoadOptions
  161. is ignored. The global variable SdiAddress gives the pointer to
  162. the SDI image.
  163. Return Value:
  164. none
  165. --*/
  166. {
  167. ARC_STATUS status;
  168. BOOLEAN OldOutputDots = FALSE;
  169. BOOLEAN OldShowProgressBar = FALSE;
  170. ULONG oldBase;
  171. ULONG oldLimit;
  172. //
  173. // Debug Break on entry
  174. //
  175. if (RamdiskBreak) {
  176. DbgBreakPoint();
  177. }
  178. //
  179. // If the ramdisk has already been initialized, just return. We know the
  180. // ramdisk has been initialized if SdiBoot is FALSE (implying that this is
  181. // NOT the call from BlStartup(), but the call from BlOsLoader()) and
  182. // RamdiskBasePage is not NULL (implying that we were previously called
  183. // from BlStartup() to initialize the SDI boot.
  184. //
  185. if ( !SdiBoot && (RamdiskBasePage != 0) ) {
  186. //
  187. // Now that ntdetect has been run, we can free up the pages that
  188. // we allocated earlier (see below).
  189. //
  190. BlFreeDescriptor( 0x10 );
  191. return ESUCCESS;
  192. }
  193. //
  194. // If this is an SDI boot, then we must have a pointer to the SDI image.
  195. //
  196. if ( SdiBoot && (SdiAddress == 0) ) {
  197. RamdiskFatalError( RAMDISK_GENERAL_FAILURE,
  198. RAMDISK_INVALID_OPTIONS );
  199. return EINVAL;
  200. }
  201. //
  202. // If this is not an SDI boot, parse all ramdisk options (if any).
  203. //
  204. if ( !SdiBoot ) {
  205. status = RamdiskParseOptions ( LoadOptions );
  206. if (status != ESUCCESS) {
  207. RamdiskFatalError( RAMDISK_GENERAL_FAILURE,
  208. RAMDISK_INVALID_OPTIONS );
  209. return status;
  210. }
  211. }
  212. #if defined(_IA64_)
  213. // Ramdisk boot path not supported on IA64 as of yet
  214. if ( RamdiskBuild ) {
  215. return ESUCCESS;
  216. }
  217. #endif
  218. //
  219. // Show the progress bar in text mode
  220. //
  221. if ( RamdiskBuild || RamdiskPath ) {
  222. // If booting from a ramdisk, graphics mode is off permanently
  223. DisplayLogoOnBoot = FALSE;
  224. GraphicsMode = FALSE;
  225. OldShowProgressBar = BlShowProgressBar;
  226. BlShowProgressBar = TRUE;
  227. OldOutputDots = BlOutputDots;
  228. BlOutputDots = TRUE;
  229. }
  230. #if defined(i386)
  231. if ( RamdiskBuild ) {
  232. //
  233. // We will need to build the ramdisk first
  234. //
  235. ASSERT( RamdiskPath == NULL );
  236. status = RamdiskBuildAndInitialize();
  237. if (status != ESUCCESS) {
  238. RamdiskFatalError( RAMDISK_GENERAL_FAILURE,
  239. RAMDISK_BUILD_FAILURE );
  240. return status;
  241. }
  242. }
  243. #endif
  244. if ( RamdiskPath ) {
  245. //
  246. // Initialize the Ramdisk from the RamdiskPath
  247. //
  248. status = RamdiskInitializeFromPath();
  249. if (status != ESUCCESS) {
  250. RamdiskFatalError( RAMDISK_GENERAL_FAILURE,
  251. RAMDISK_BOOT_FAILURE );
  252. return status;
  253. }
  254. } else if ( SdiBoot ) {
  255. //
  256. // This is an SDI boot. Find the ramdisk image within the SDI image
  257. // and allocate the pages in which the ramdisk image resides.
  258. //
  259. ULONG basePage;
  260. ULONG pageCount;
  261. PSDI_HEADER sdiHeader;
  262. ULONG i;
  263. ULONG_PTR ramdiskAddress;
  264. //
  265. // Temporarily allocate the pages that will be occupied by ntdetect
  266. // while it runs. BlDetectHardware() just assumes that these pages
  267. // are free for loading ntdetect. But we're going to allocate and map
  268. // the ramdisk image, which will result in the allocation of many
  269. // page table pages, some of which might end up in the place where
  270. // ntdetect will be loaded. So we allocate the ntdetect range here,
  271. // then free it later (see above).
  272. //
  273. basePage = 0x10;
  274. pageCount = 0x10;
  275. status = BlAllocateAlignedDescriptor(
  276. LoaderFirmwareTemporary,
  277. basePage,
  278. pageCount,
  279. 0,
  280. &basePage
  281. );
  282. //
  283. // Allocate the page that contains the SDI header. This will cause
  284. // it to be mapped, which will allow us to read the header to find
  285. // the ramdisk image.
  286. //
  287. oldBase = BlUsableBase;
  288. oldLimit = BlUsableLimit;
  289. BlUsableBase = BL_XIPROM_RANGE_LOW;
  290. BlUsableLimit = BL_XIPROM_RANGE_HIGH;
  291. basePage = (ULONG)(SdiAddress >> PAGE_SHIFT);
  292. pageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES( SdiAddress, sizeof(SDI_HEADER) );
  293. status = BlAllocateAlignedDescriptor(
  294. LoaderFirmwareTemporary,
  295. basePage,
  296. pageCount,
  297. 0,
  298. &basePage
  299. );
  300. BlUsableBase = oldBase;
  301. BlUsableLimit = oldLimit;
  302. //
  303. // Find the ramdisk image by looking through the TOC in the SDI header.
  304. //
  305. sdiHeader = (PSDI_HEADER)SdiAddress;
  306. for ( i = 0; i < SDI_TOCMAXENTRIES; i++ ) {
  307. if ( sdiHeader->ToC[i].dwType == SDI_BLOBTYPE_PART ) {
  308. break;
  309. }
  310. }
  311. if ( i >= SDI_TOCMAXENTRIES ) {
  312. RamdiskFatalError( RAMDISK_GENERAL_FAILURE,
  313. RAMDISK_BOOT_FAILURE );
  314. return ENOENT;
  315. }
  316. //
  317. // Calculate the starting address and page of the ramdisk image, the
  318. // length of the ramdisk image, and the offset within the starting page
  319. // to the image. The offset should be 0, because everything in the SDI
  320. // image should be page-aligned.
  321. //
  322. ramdiskAddress = (ULONG_PTR)(SdiAddress + sdiHeader->ToC[i].llOffset.QuadPart);
  323. RamdiskBasePage = (ULONG)(ramdiskAddress >> PAGE_SHIFT);
  324. RamdiskImageOffset = (ULONG)(ramdiskAddress - ((ULONG_PTR)RamdiskBasePage << PAGE_SHIFT));
  325. RamdiskImageLength = sdiHeader->ToC[i].llSize.QuadPart;
  326. RamdiskFileSizeInPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  327. ramdiskAddress,
  328. RamdiskImageLength
  329. );
  330. RamdiskFileSize = (LONGLONG)RamdiskFileSizeInPages << PAGE_SHIFT;
  331. //
  332. // Release the page(s) occupied by the SDI header.
  333. //
  334. BlFreeDescriptor( basePage );
  335. //
  336. // Tell the memory allocator about the pages occupied by the ramdisk
  337. // by allocating those pages.
  338. //
  339. oldBase = BlUsableBase;
  340. oldLimit = BlUsableLimit;
  341. BlUsableBase = BL_XIPROM_RANGE_LOW;
  342. BlUsableLimit = BL_XIPROM_RANGE_HIGH;
  343. basePage = RamdiskBasePage;
  344. pageCount = RamdiskFileSizeInPages;
  345. status = BlAllocateAlignedDescriptor(
  346. LoaderXIPRom,
  347. basePage,
  348. pageCount,
  349. 0,
  350. &basePage
  351. );
  352. BlUsableBase = oldBase;
  353. BlUsableLimit = oldLimit;
  354. ASSERT( status == ESUCCESS );
  355. ASSERT( basePage == RamdiskBasePage );
  356. DBGPRINT(VERBOSE, ("Ramdisk is active\n") );
  357. RamdiskActive = TRUE;
  358. }
  359. //
  360. // Restore old progress bar settings
  361. //
  362. if ( RamdiskBuild || RamdiskPath ) {
  363. BlShowProgressBar = OldShowProgressBar;
  364. BlOutputDots = OldOutputDots;
  365. BlClearScreen();
  366. }
  367. return ESUCCESS;
  368. }
  369. ARC_STATUS
  370. RamdiskReadImage(
  371. PCHAR RamdiskPath
  372. )
  373. /*++
  374. Routine Description:
  375. This function will load a ramdisk image from the network
  376. or another ARC boot device.
  377. Arguments:
  378. RamdiskPath - name of the file to load
  379. Return Value:
  380. status
  381. --*/
  382. {
  383. ARC_STATUS status;
  384. ULONG RamdiskDeviceId;
  385. ULONG RamdiskFileId = BL_INVALID_FILE_ID;
  386. PCHAR p;
  387. FILE_INFORMATION fileInformation;
  388. LARGE_INTEGER offset;
  389. LONGLONG remainingLength;
  390. ULONG oldBase;
  391. ULONG oldLimit;
  392. BOOLEAN retry = TRUE;
  393. ULONG lastProgressPercent = 0;
  394. BOOLEAN ForceDisplayFirstTime = TRUE; // force display initially
  395. ULONG currentProgressPercent;
  396. PUCHAR ip;
  397. PTCHAR FormatString = NULL;
  398. TCHAR Buffer[256];
  399. //
  400. // Show text progress bar
  401. //
  402. BlOutputStartupMsg(RAMDISK_DOWNLOAD);
  403. BlUpdateProgressBar(0);
  404. DBGPRINT(VERBOSE, ("RamdiskReadImage(%s)\n", RamdiskPath));
  405. //
  406. // Open the device that the RAM disk image is on.
  407. //
  408. p = strchr(RamdiskPath, '\\');
  409. if (p == NULL) {
  410. DBGPRINT(ERR, ("no \\ found in path\n"));
  411. return EINVAL;
  412. }
  413. *p = 0;
  414. try_again:
  415. status = ArcOpen(RamdiskPath, ArcOpenReadWrite, &RamdiskDeviceId);
  416. if (status != ESUCCESS) {
  417. DBGPRINT(ERR, ("ArcOpen(%s) failed: %d\n", RamdiskPath, status));
  418. if ( retry ) {
  419. retry = FALSE;
  420. _strlwr(RamdiskPath);
  421. goto try_again;
  422. }
  423. *p = '\\';
  424. return status;
  425. }
  426. *p++ = '\\';
  427. //
  428. // If the RAM disk image is on the network, use TftpGetPut to read it.
  429. // Otherwise, use normal I/O.
  430. //
  431. oldBase = BlUsableBase;
  432. oldLimit = BlUsableLimit;
  433. BlUsableBase = BL_XIPROM_RANGE_LOW;
  434. BlUsableLimit = BL_XIPROM_RANGE_HIGH;
  435. #ifdef EFI // multicast ramdisk download only supported on non-EFI machines for now
  436. if ( RamdiskDeviceId == NET_DEVICE_ID && RamdiskMTFTPAddr != 0 )
  437. {
  438. ArcClose( RamdiskDeviceId );
  439. return EBADF;
  440. }
  441. #endif
  442. if ( RamdiskDeviceId == NET_DEVICE_ID && RamdiskMTFTPAddr == 0) {
  443. //
  444. // Network device using UNICAST download. We will use the TFTP
  445. // client implementation in TFTPLIB for the download.
  446. //
  447. TFTP_REQUEST request;
  448. NTSTATUS ntStatus;
  449. request.RemoteFileName = (PUCHAR)p;
  450. request.ServerIpAddress = RamdiskTFTPAddr;
  451. request.MemoryAddress = NULL;
  452. request.MaximumLength = 0;
  453. request.BytesTransferred = 0xbadf00d;
  454. request.Operation = TFTP_RRQ;
  455. request.MemoryType = LoaderXIPRom;
  456. #if defined(REMOTE_BOOT_SECURITY)
  457. request.SecurityHandle = TftpSecurityHandle;
  458. #endif // defined(REMOTE_BOOT_SECURITY)
  459. request.ShowProgress = TRUE;
  460. //
  461. // Print progress message
  462. //
  463. ip = (PUCHAR) &RamdiskTFTPAddr;
  464. FormatString = BlFindMessage( RAMDISK_DOWNLOAD_NETWORK );
  465. if ( FormatString != NULL ) {
  466. _stprintf(Buffer, FormatString, ip[0], ip[1], ip[2], ip[3] );
  467. BlOutputTrailerMsgStr( Buffer );
  468. }
  469. //
  470. // Download the image using TFTP
  471. //
  472. DBGPRINT(VERBOSE, ("calling TftpGetPut(%s,0x%x)\n", p, NetServerIpAddress));
  473. ntStatus = TftpGetPut( &request );
  474. DBGPRINT(VERBOSE, ("status from TftpGetPut 0x%x\n", ntStatus));
  475. BlUsableBase = oldBase;
  476. BlUsableLimit = oldLimit;
  477. if ( !NT_SUCCESS(ntStatus) ) {
  478. if ( request.MemoryAddress != NULL ) {
  479. BlFreeDescriptor( (ULONG)((ULONG_PTR)request.MemoryAddress & ~KSEG0_BASE) >> PAGE_SHIFT);
  480. }
  481. ArcClose( RamdiskDeviceId );
  482. if ( ntStatus == STATUS_INSUFFICIENT_RESOURCES ) {
  483. return ENOMEM;
  484. }
  485. return EROFS;
  486. }
  487. RamdiskBasePage = (ULONG)((ULONG_PTR)request.MemoryAddress & ~KSEG0_BASE) >> PAGE_SHIFT;
  488. RamdiskFileSize = request.MaximumLength;
  489. RamdiskFileSizeInPages = (ULONG) BYTES_TO_PAGES(RamdiskFileSize);
  490. if ( (RamdiskImageLength == 0) ||
  491. (RamdiskImageLength > (RamdiskFileSize - RamdiskImageOffset)) ) {
  492. RamdiskImageLength = RamdiskFileSize - RamdiskImageOffset;
  493. }
  494. #ifndef EFI // multicast ramdisk download only supported on non-EFI machines for now
  495. } else if ( RamdiskDeviceId == NET_DEVICE_ID && RamdiskMTFTPAddr != 0) {
  496. LONGLONG FileOffset = 0;
  497. LONGLONG VirtualAddressOfOffset;
  498. ULONG DownloadSize;
  499. USHORT ClientPort;
  500. USHORT ServerPort;
  501. ULONG iSession = 0;
  502. //
  503. // Network device and using multicast download. For multicast
  504. // downloads we will use the MTFTP implementation in the ROM.
  505. // A single MTFTP transfer is limited to 16-bit block counts.
  506. // This translates to ~32MB for 512 block sizes and ~90MB for
  507. // 1468 block sizes. In order to support larger files, we will
  508. // use multiple MTFTP sessions to bring the file down in chunks.
  509. // The MTFTP server will need to understand the chunking semantics.
  510. //
  511. //
  512. // Print progress message
  513. //
  514. ip = (PUCHAR) &RamdiskMTFTPAddr;
  515. FormatString = BlFindMessage( RAMDISK_DOWNLOAD_NETWORK_MCAST );
  516. if ( FormatString != NULL ) {
  517. _stprintf(Buffer, FormatString, ip[0], ip[1], ip[2], ip[3], SWAP_WORD( RamdiskMTFTPSPort ) );
  518. BlOutputTrailerMsgStr( Buffer );
  519. }
  520. //
  521. // Allocate the memory for the entire RAMDisk
  522. //
  523. RamdiskFileSize = RamdiskMTFTPFileSize;
  524. RamdiskFileSizeInPages = (ULONG)BYTES_TO_PAGES(RamdiskFileSize);
  525. if ( (RamdiskImageLength == 0) ||
  526. (RamdiskImageLength > (RamdiskFileSize - RamdiskImageOffset)) ) {
  527. RamdiskImageLength = RamdiskFileSize - RamdiskImageOffset;
  528. }
  529. DBGPRINT(INFO, ("Downloading Ramdisk using MTFTP. File Size=0x%I64x Chunk Size=0x%I64x\n", RamdiskFileSize, RamdiskMTFTPChunkSize ));
  530. status = BlAllocateAlignedDescriptor(
  531. LoaderXIPRom,
  532. 0,
  533. RamdiskFileSizeInPages,
  534. 0,
  535. &RamdiskBasePage
  536. );
  537. BlUsableBase = oldBase;
  538. BlUsableLimit = oldLimit;
  539. if (status != ESUCCESS) {
  540. DBGPRINT(ERR, ("BlAllocateAlignedDescriptor(%d pages) failed: %d\n", RamdiskFileSizeInPages, status));
  541. ArcClose( RamdiskDeviceId );
  542. return status;
  543. }
  544. DBGPRINT(VERBOSE, ("Allocated %d pages at page %x for RAM disk\n", RamdiskFileSizeInPages, RamdiskBasePage ));
  545. //
  546. // Download the ramdisk file using MTFTP
  547. //
  548. if ( RamdiskMTFTPChunkSize == 0 ) {
  549. RamdiskMTFTPChunkSize = RamdiskMTFTPFileSize;
  550. }
  551. // starting client and server port (in Intel byte order to
  552. // allow increment operators to work )
  553. ClientPort = SWAP_WORD( RamdiskMTFTPCPort );
  554. ServerPort = SWAP_WORD( RamdiskMTFTPSPort );
  555. while ( FileOffset < RamdiskFileSize ) {
  556. //
  557. // Call the ROM implementation to download a single chunk
  558. //
  559. VirtualAddressOfOffset = ((LONGLONG)KSEG0_BASE | (RamdiskBasePage << PAGE_SHIFT)) + FileOffset;
  560. ip = (PUCHAR)&RamdiskMTFTPAddr;
  561. DBGPRINT(INFO, ("MTFTP Session %d: %s from %u.%u.%u.%u sport=%d cport=%d offset=0x%I64x\n",
  562. iSession, p,
  563. ip[0], ip[1], ip[2], ip[3], ClientPort, ServerPort,
  564. VirtualAddressOfOffset ));
  565. //
  566. // the high 32 bits are going to be lost when calling RomMtftpReadFile.
  567. // find out now, if this is happening
  568. //
  569. ASSERT( (VirtualAddressOfOffset >> 32) == 0 );
  570. status = RomMtftpReadFile ( (PUCHAR)p,
  571. (PVOID)(ULONG)VirtualAddressOfOffset,
  572. (ULONG)RamdiskMTFTPChunkSize,
  573. RamdiskTFTPAddr,
  574. RamdiskMTFTPAddr,
  575. SWAP_WORD( ClientPort ),
  576. SWAP_WORD( ServerPort ),
  577. RamdiskMTFTPTimeout,
  578. RamdiskMTFTPDelay,
  579. &DownloadSize );
  580. if ( status != ESUCCESS ) {
  581. DBGPRINT(ERR, ("RomMtftpReadFile failed %d\n", status ));
  582. BlFreeDescriptor( RamdiskBasePage );
  583. ArcClose( RamdiskDeviceId );
  584. return status;
  585. }
  586. #if 1 || INTEL_MTFTP_SERVER_TEST
  587. p[strlen(p) - 1]++;
  588. RamdiskMTFTPAddr += 0x01000000;
  589. #else
  590. ClientPort++;
  591. ServerPort++;
  592. #endif
  593. FileOffset += DownloadSize;
  594. iSession++;
  595. // update progress bar
  596. currentProgressPercent = (ULONG)(((LONGLONG)FileOffset * 100) / RamdiskFileSize);
  597. if ( ForceDisplayFirstTime || (currentProgressPercent != lastProgressPercent) ) {
  598. BlUpdateProgressBar( currentProgressPercent );
  599. ForceDisplayFirstTime = FALSE;
  600. }
  601. lastProgressPercent = currentProgressPercent;
  602. }
  603. DBGPRINT(INFO, ("MTFTP Download complete. 0x%I64x bytes transferred using %d sessions\n", RamdiskFileSize, iSession));
  604. #endif
  605. } else {
  606. //
  607. // Open the RAM disk image.
  608. //
  609. status = BlOpen( RamdiskDeviceId, p, ArcOpenReadOnly, &RamdiskFileId );
  610. if (status != ESUCCESS) {
  611. DBGPRINT(ERR, ("BlOpen(%s) failed: %d\n", p, status));
  612. ArcClose( RamdiskDeviceId );
  613. return status;
  614. }
  615. //
  616. // Get the size of the RAM disk image.
  617. //
  618. status = BlGetFileInformation( RamdiskFileId, &fileInformation );
  619. if (status != ESUCCESS) {
  620. DBGPRINT(ERR, ("BlGetFileInformation(%s) failed: %d\n", p, status));
  621. BlClose( RamdiskFileId );
  622. ArcClose( RamdiskDeviceId );
  623. return status;
  624. }
  625. RamdiskFileSize = fileInformation.EndingAddress.QuadPart;
  626. RamdiskFileSizeInPages = (ULONG) BYTES_TO_PAGES(RamdiskFileSize);
  627. if ( (RamdiskImageLength == 0) ||
  628. (RamdiskImageLength > (RamdiskFileSize - RamdiskImageOffset)) ) {
  629. RamdiskImageLength = RamdiskFileSize - RamdiskImageOffset;
  630. }
  631. //
  632. // Allocate pages to hold the RAM disk image.
  633. //
  634. status = BlAllocateAlignedDescriptor(
  635. LoaderXIPRom,
  636. 0,
  637. RamdiskFileSizeInPages,
  638. 0,
  639. &RamdiskBasePage
  640. );
  641. BlUsableBase = oldBase;
  642. BlUsableLimit = oldLimit;
  643. if (status != ESUCCESS) {
  644. DBGPRINT(ERR, ("BlAllocateAlignedDescriptor(%d pages) failed: %d\n", RamdiskFileSizeInPages, status));
  645. BlClose( RamdiskFileId );
  646. ArcClose( RamdiskDeviceId );
  647. return status;
  648. }
  649. DBGPRINT(VERBOSE, ("Allocated %d pages at page %x for RAM disk\n", RamdiskFileSizeInPages, RamdiskBasePage ));
  650. //
  651. // Read the RAM disk image into memory.
  652. //
  653. #define MAX_DISK_READ (1024 * 1024)
  654. offset.QuadPart = 0;
  655. remainingLength = RamdiskFileSize;
  656. while ( offset.QuadPart < RamdiskFileSize ) {
  657. LONGLONG availableLength;
  658. ULONG readLength;
  659. PVOID va;
  660. ULONG count;
  661. va = MapRamdisk( offset.QuadPart, &availableLength );
  662. if ( remainingLength > availableLength ) {
  663. readLength = (ULONG)availableLength;
  664. } else {
  665. readLength = (ULONG)remainingLength;
  666. }
  667. if ( readLength > MAX_DISK_READ ) {
  668. readLength = MAX_DISK_READ;
  669. }
  670. status = BlSeek( RamdiskFileId, &offset, SeekAbsolute );
  671. if ( status != ESUCCESS ) {
  672. DBGPRINT(ERR, ("Unable to seek RAM disk image: %d\n", status));
  673. BlClose( RamdiskFileId );
  674. ArcClose( RamdiskDeviceId );
  675. return status;
  676. }
  677. status = BlRead( RamdiskFileId, va, readLength, &count );
  678. if ( (status != ESUCCESS) || (count != readLength) ) {
  679. DBGPRINT(ERR, ( "Unable to read RAM disk image: status %d count %x (wanted %x)\n", status, count, readLength) );
  680. BlClose( RamdiskFileId );
  681. ArcClose( RamdiskDeviceId );
  682. return status;
  683. }
  684. offset.QuadPart += readLength;
  685. remainingLength -= readLength;
  686. // update progress bar
  687. currentProgressPercent = (ULONG)(((LONGLONG)offset.QuadPart * 100) / RamdiskFileSize);
  688. if ( ForceDisplayFirstTime || (currentProgressPercent != lastProgressPercent) ) {
  689. BlUpdateProgressBar( currentProgressPercent );
  690. ForceDisplayFirstTime = FALSE;
  691. }
  692. lastProgressPercent = currentProgressPercent;
  693. }
  694. DBGPRINT(VERBOSE, ( "Done reading ramdisk\n" ) );
  695. BlClose( RamdiskFileId );
  696. RamdiskFileId = BL_INVALID_FILE_ID;
  697. }
  698. ArcClose( RamdiskDeviceId );
  699. return status;
  700. } // RamdiskReadImage
  701. ARC_STATUS
  702. RamdiskInitializeFromPath(
  703. )
  704. /*++
  705. Routine Description:
  706. This function will load a ramdisk image from the network
  707. or another ARC boot device.
  708. Arguments:
  709. none
  710. Return Value:
  711. status
  712. --*/
  713. {
  714. ARC_STATUS status;
  715. ASSERT( RamdiskPath );
  716. DBGPRINT(VERBOSE, ("RamdiskInitializeFromPath(%s)\n", RamdiskPath));
  717. status = RamdiskReadImage( RamdiskPath );
  718. if ( status == ESUCCESS ) {
  719. DBGPRINT(VERBOSE, ("Ramdisk is active\n") );
  720. RamdiskActive = TRUE;
  721. }
  722. return status;
  723. } // RamdiskInitializeFromPath
  724. ARC_STATUS
  725. RamdiskClose(
  726. IN ULONG FileId
  727. )
  728. /*++
  729. Routine Description:
  730. Closes the specified device
  731. Arguments:
  732. FileId - Supplies file id of the device to be closed
  733. Return Value:
  734. ESUCCESS - Device closed successfully
  735. !ESUCCESS - Device was not closed.
  736. --*/
  737. {
  738. if (BlFileTable[FileId].Flags.Open == 0) {
  739. #if DBG
  740. BlPrint(TEXT("ERROR - Unopened fileid %lx closed\r\n"),FileId);
  741. #endif
  742. }
  743. BlFileTable[FileId].Flags.Open = 0;
  744. return(ESUCCESS);
  745. }
  746. ARC_STATUS
  747. RamdiskOpen(
  748. IN PCHAR OpenPath,
  749. IN OPEN_MODE OpenMode,
  750. OUT PULONG FileId
  751. )
  752. /*++
  753. Routine Description:
  754. Opens a RAM disk for raw sector access.
  755. Arguments:
  756. OpenPath - Supplies a pointer to the name of the RAM disk.
  757. OpenMode - Supplies the mode of the open
  758. FileId - Supplies a pointer to a variable that specifies the file
  759. table entry that is filled in if the open is successful.
  760. Return Value:
  761. ESUCCESS is returned if the open operation is successful. Otherwise,
  762. an unsuccessful status is returned that describes the reason for failure.
  763. --*/
  764. {
  765. ULONG Key;
  766. PDRIVE_CONTEXT Context;
  767. UNREFERENCED_PARAMETER( OpenMode );
  768. //BlPrint(TEXT("RamdiskOpen entered\r\n"));
  769. if ( !RamdiskActive ) {
  770. //BlPrint(TEXT("RamdiskOpen: not active\r\n"));
  771. return EBADF;
  772. }
  773. if(FwGetPathMnemonicKey(OpenPath,"ramdisk",&Key)) {
  774. DBGPRINT(VERBOSE, ("RamdiskOpen: not a ramdisk path\n"));
  775. return EBADF;
  776. }
  777. if ( Key != 0 ) {
  778. DBGPRINT(ERR, ("RamdiskOpen: not ramdisk 0\n"));
  779. return EBADF;
  780. }
  781. //
  782. // Find an available FileId descriptor to open the device with
  783. //
  784. *FileId=2;
  785. while (BlFileTable[*FileId].Flags.Open != 0) {
  786. *FileId += 1;
  787. if(*FileId == BL_FILE_TABLE_SIZE) {
  788. DBGPRINT(ERR, ("RamdiskOpen: no file table entry available\n"));
  789. return(ENOENT);
  790. }
  791. }
  792. //
  793. // We found an entry we can use, so mark it as open.
  794. //
  795. BlFileTable[*FileId].Flags.Open = 1;
  796. BlFileTable[*FileId].DeviceEntryTable = &RamdiskEntryTable;
  797. Context = &(BlFileTable[*FileId].u.DriveContext);
  798. Context->Drive = (UCHAR)Key;
  799. Context->xInt13 = TRUE;
  800. DBGPRINT(VERBOSE, ("RamdiskOpen: exit success\n"));
  801. return(ESUCCESS);
  802. }
  803. ARC_STATUS
  804. RamdiskSeek (
  805. IN ULONG FileId,
  806. IN PLARGE_INTEGER Offset,
  807. IN SEEK_MODE SeekMode
  808. )
  809. /*++
  810. Routine Description:
  811. Changes the current offset of the file specified by FileId
  812. Arguments:
  813. FileId - specifies the file on which the current offset is to
  814. be changed.
  815. Offset - New offset into file.
  816. SeekMode - Either SeekAbsolute or SeekRelative
  817. SeekEndRelative is not supported
  818. Return Value:
  819. ESUCCESS - Operation completed succesfully
  820. EBADF - Operation did not complete successfully.
  821. --*/
  822. {
  823. switch (SeekMode) {
  824. case SeekAbsolute:
  825. BlFileTable[FileId].Position = *Offset;
  826. break;
  827. case SeekRelative:
  828. BlFileTable[FileId].Position.QuadPart += Offset->QuadPart;
  829. break;
  830. default:
  831. #if DBG
  832. BlPrint(TEXT("SeekMode %lx not supported\r\n"),SeekMode);
  833. #endif
  834. return(EACCES);
  835. }
  836. return(ESUCCESS);
  837. }
  838. ARC_STATUS
  839. RamdiskWrite(
  840. IN ULONG FileId,
  841. OUT PVOID Buffer,
  842. IN ULONG Length,
  843. OUT PULONG Count
  844. )
  845. /*++
  846. Routine Description:
  847. Writes sectors directly to an open RAM disk.
  848. Arguments:
  849. FileId - Supplies the file to write to
  850. Buffer - Supplies buffer with data to write
  851. Length - Supplies number of bytes to write
  852. Count - Returns actual bytes written
  853. Return Value:
  854. ESUCCESS - write completed successfully
  855. !ESUCCESS - write failed
  856. --*/
  857. {
  858. PUCHAR buffer;
  859. LONGLONG offset;
  860. ULONG remainingLength;
  861. LONGLONG availableLength;
  862. ULONG bytesWritten;
  863. ULONG bytesThisPage;
  864. PVOID va;
  865. DBGPRINT(ERR, ("RamdiskWrite entered\n"));
  866. //DbgBreakPoint();
  867. buffer = Buffer;
  868. offset = BlFileTable[FileId].Position.QuadPart;
  869. remainingLength = Length;
  870. if ( offset >= RamdiskImageLength ) {
  871. return EINVAL;
  872. }
  873. if ( remainingLength > (RamdiskImageLength - offset) ) {
  874. remainingLength = (ULONG)(RamdiskImageLength - offset);
  875. }
  876. bytesWritten = 0;
  877. while ( remainingLength != 0 ) {
  878. va = MapRamdisk( RamdiskImageOffset + offset, &availableLength );
  879. bytesThisPage = remainingLength;
  880. if ( remainingLength > availableLength ) {
  881. bytesThisPage = (ULONG)availableLength;
  882. }
  883. memcpy( va, buffer, bytesThisPage );
  884. offset += bytesThisPage;
  885. buffer += bytesThisPage;
  886. remainingLength -= bytesThisPage;
  887. bytesWritten += bytesThisPage;
  888. }
  889. BlFileTable[FileId].Position.QuadPart += bytesWritten;
  890. *Count = bytesWritten;
  891. return ESUCCESS;
  892. }
  893. ARC_STATUS
  894. RamdiskRead(
  895. IN ULONG FileId,
  896. OUT PVOID Buffer,
  897. IN ULONG Length,
  898. OUT PULONG Count
  899. )
  900. /*++
  901. Routine Description:
  902. Reads sectors directly from an open RAM disk.
  903. Arguments:
  904. FileId - Supplies the file to read from
  905. Buffer - Supplies buffer to read into
  906. Length - Supplies number of bytes to read
  907. Count - Returns actual bytes read
  908. Return Value:
  909. ESUCCESS - read completed successfully
  910. !ESUCCESS - read failed
  911. --*/
  912. {
  913. PUCHAR buffer;
  914. LONGLONG offset;
  915. ULONG remainingLength;
  916. LONGLONG availableLength;
  917. ULONG bytesRead;
  918. ULONG bytesThisPage;
  919. PVOID va;
  920. buffer = Buffer;
  921. offset = BlFileTable[FileId].Position.QuadPart;
  922. DBGPRINT(VERBOSE, ( "RamdiskRead: offset %x, length %x, buffer %p\n", (ULONG)offset, Length, buffer ));
  923. remainingLength = Length;
  924. if ( offset >= RamdiskImageLength ) {
  925. DBGPRINT(ERR, ( "RamdiskRead: read beyond EOF\n" ) );
  926. return EINVAL;
  927. }
  928. if ( remainingLength > (RamdiskImageLength - offset) ) {
  929. remainingLength = (ULONG)(RamdiskImageLength - offset);
  930. }
  931. bytesRead = 0;
  932. while ( remainingLength != 0 ) {
  933. va = MapRamdisk( RamdiskImageOffset + offset, &availableLength );
  934. DBGPRINT(VERBOSE, ( "Mapped offset %x, va %p, availableLength %x\n", (ULONG)offset, va, availableLength ) );
  935. bytesThisPage = remainingLength;
  936. if ( remainingLength > availableLength ) {
  937. bytesThisPage = (ULONG)availableLength;
  938. }
  939. memcpy( buffer, va, bytesThisPage );
  940. offset += bytesThisPage;
  941. buffer += bytesThisPage;
  942. remainingLength -= bytesThisPage;
  943. bytesRead += bytesThisPage;
  944. }
  945. BlFileTable[FileId].Position.QuadPart += bytesRead;
  946. *Count = bytesRead;
  947. return ESUCCESS;
  948. }
  949. ARC_STATUS
  950. RamdiskGetFileInfo(
  951. IN ULONG FileId,
  952. OUT PFILE_INFORMATION Finfo
  953. )
  954. /*++
  955. Routine Description:
  956. Returns file information about a RAMDISK file.
  957. Arguments:
  958. FileId - id of the file
  959. Finfo - file information structure to be filled in
  960. Return Value:
  961. ESUCCESS - write completed successfully
  962. !ESUCCESS - write failed
  963. --*/
  964. {
  965. RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION));
  966. Finfo->EndingAddress.QuadPart = RamdiskImageLength;
  967. Finfo->CurrentPosition.QuadPart = BlFileTable[FileId].Position.QuadPart;
  968. Finfo->Type = DiskPeripheral;
  969. return ESUCCESS;
  970. }
  971. ARC_STATUS
  972. RamdiskMount(
  973. IN CHAR * FIRMWARE_PTR MountPath,
  974. IN MOUNT_OPERATION Operation
  975. )
  976. {
  977. UNREFERENCED_PARAMETER( MountPath );
  978. UNREFERENCED_PARAMETER( Operation );
  979. DBGPRINT(VERBOSE, ( "RamdiskMount called\n" ));
  980. return EINVAL;
  981. }
  982. ARC_STATUS
  983. RamdiskReadStatus(
  984. IN ULONG FileId
  985. )
  986. {
  987. UNREFERENCED_PARAMETER( FileId );
  988. DBGPRINT(VERBOSE, ( "RamdiskReadStatus called\n" ) );
  989. return EINVAL;
  990. }
  991. ARC_STATUS
  992. RamdiskSetFileInfo (
  993. IN ULONG FileId,
  994. IN ULONG AttributeFlags,
  995. IN ULONG AttributeMask
  996. )
  997. {
  998. UNREFERENCED_PARAMETER( FileId );
  999. UNREFERENCED_PARAMETER( AttributeFlags );
  1000. UNREFERENCED_PARAMETER( AttributeMask );
  1001. DBGPRINT(VERBOSE, ( "RamdiskSetFileInfo called\n" ));
  1002. return EINVAL;
  1003. }
  1004. ARC_STATUS
  1005. RamdiskRename (
  1006. IN ULONG FileId,
  1007. IN CHAR * FIRMWARE_PTR NewName
  1008. )
  1009. {
  1010. UNREFERENCED_PARAMETER( FileId );
  1011. UNREFERENCED_PARAMETER( NewName );
  1012. DBGPRINT(VERBOSE, ( "RamdiskRename called\n" ));
  1013. return EINVAL;
  1014. }
  1015. ARC_STATUS
  1016. RamdiskGetDirectoryEntry (
  1017. IN ULONG FileId,
  1018. OUT PDIRECTORY_ENTRY Buffer,
  1019. IN ULONG Length,
  1020. OUT ULONG * FIRMWARE_PTR Count
  1021. )
  1022. {
  1023. UNREFERENCED_PARAMETER( FileId );
  1024. UNREFERENCED_PARAMETER( Buffer );
  1025. UNREFERENCED_PARAMETER( Length );
  1026. UNREFERENCED_PARAMETER( Count );
  1027. DBGPRINT(VERBOSE, ( "RamdiskGetDirectoryEntry called\n" ));
  1028. return EINVAL;
  1029. }
  1030. PVOID
  1031. MapRamdisk (
  1032. LONGLONG Offset,
  1033. PLONGLONG AvailableLength
  1034. )
  1035. {
  1036. LONGLONG VirtualAddressOfOffset;
  1037. VirtualAddressOfOffset = ((LONGLONG)(KSEG0_BASE | (RamdiskBasePage << PAGE_SHIFT))) + Offset;
  1038. *AvailableLength = RamdiskFileSize - Offset;
  1039. #if defined(_X86_)
  1040. //
  1041. // the high 32 bits of physicalAddressOfOffset are
  1042. // going to be lost when returning the address as a pvoid.
  1043. // find out if this is happening now.
  1044. //
  1045. ASSERT( (VirtualAddressOfOffset >> 32) == 0 );
  1046. return (PVOID)(ULONG)VirtualAddressOfOffset;
  1047. #else
  1048. return (PVOID)VirtualAddressOfOffset;
  1049. #endif
  1050. }
  1051. PCHAR
  1052. RamdiskGetOptionValue(
  1053. IN PCHAR LoadOptions,
  1054. IN PCHAR OptionName
  1055. )
  1056. /*++
  1057. Routine Description:
  1058. Parse the load options string returning a value of one of the
  1059. options.
  1060. Format supported: /OPTIONNAME=VALUE
  1061. Note there is no space before or after the '='.
  1062. Value is terminated with a '\r','\n',' ','/', or '\t'
  1063. Arguments:
  1064. LoadOptions - Loader options from boot.ini. Must be all caps.
  1065. OptionName - Name of the option to find.
  1066. Return Value:
  1067. Pointer to a value string that has been allocated with
  1068. BlAllocateHeap or NULL if the option has not found.
  1069. --*/
  1070. {
  1071. PCHAR retValue = NULL;
  1072. PCHAR value;
  1073. PCHAR p;
  1074. ULONG n;
  1075. ASSERT( LoadOptions );
  1076. ASSERT( OptionName );
  1077. if ( (p = strstr( LoadOptions, OptionName )) != 0 ) {
  1078. value = strchr( p , '=' );
  1079. if (value) {
  1080. value++;
  1081. for (p = value; *p; p++) {
  1082. if (*p == ' ') break;
  1083. if (*p == '/') break;
  1084. if (*p == '\n') break;
  1085. if (*p == '\r') break;
  1086. if (*p == '\t') break;
  1087. }
  1088. n = (ULONG)(p - value);
  1089. retValue = (PCHAR)BlAllocateHeap( n+1 );
  1090. if ( retValue ) {
  1091. strncpy( retValue, value, n );
  1092. }
  1093. }
  1094. }
  1095. return retValue;
  1096. }
  1097. ULONG
  1098. RamdiskParseIPAddr(
  1099. IN PCHAR psz
  1100. )
  1101. /*++
  1102. Routine Description:
  1103. parses an ip address from a string
  1104. Arguments: [psz] - Ip address string
  1105. Returns: ipaddress (in network byte order) or 0.
  1106. --*/
  1107. {
  1108. ULONG nAddr = 0;
  1109. ULONG nDigit = 0;
  1110. ULONG cDigits = 0;
  1111. for (; (psz!= NULL && *psz != 0); psz++) {
  1112. if (*psz >= '0' && *psz <= '9') {
  1113. nDigit = nDigit * 10 + *psz - '0';
  1114. if ( nDigit > 255 ) {
  1115. return 0;
  1116. }
  1117. }
  1118. else if (*psz == '.') {
  1119. nAddr = (nAddr << 8) | nDigit;
  1120. nDigit = 0;
  1121. cDigits++;
  1122. } else {
  1123. break;
  1124. }
  1125. }
  1126. if (cDigits != 3) {
  1127. return 0;
  1128. }
  1129. nAddr = (nAddr << 8) | nDigit;
  1130. return SWAP_DWORD( nAddr );
  1131. }
  1132. BOOLEAN
  1133. RamdiskHexStringToDword(
  1134. IN PCHAR psz,
  1135. OUT PULONG RetValue,
  1136. IN USHORT cDigits,
  1137. IN CHAR chDelim
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. scan psz for a number of hex digits (at most 8); update psz
  1142. return value in Value; check for chDelim;
  1143. Arguments: [psz] - the hex string to convert
  1144. [Value] - the returned value
  1145. [cDigits] - count of digits
  1146. Returns: TRUE for success
  1147. --*/
  1148. {
  1149. USHORT Count;
  1150. ULONG Value;
  1151. Value = 0;
  1152. for (Count = 0; Count < cDigits; Count++, psz++)
  1153. {
  1154. if (*psz >= '0' && *psz <= '9') {
  1155. Value = (Value << 4) + *psz - '0';
  1156. } else if (*psz >= 'A' && *psz <= 'F') {
  1157. Value = (Value << 4) + *psz - 'A' + 10;
  1158. } else if (*psz >= 'a' && *psz <= 'f') {
  1159. Value = (Value << 4) + *psz - 'a' + 10;
  1160. } else {
  1161. return(FALSE);
  1162. }
  1163. }
  1164. *RetValue = Value;
  1165. if (chDelim != 0) {
  1166. return *psz++ == chDelim;
  1167. } else {
  1168. return TRUE;
  1169. }
  1170. }
  1171. BOOLEAN
  1172. RamdiskUUIDFromString(
  1173. IN PCHAR psz,
  1174. OUT LPGUID pguid
  1175. )
  1176. /**
  1177. Routine Description:
  1178. Parse UUID such as 00000000-0000-0000-0000-000000000000
  1179. Arguments:
  1180. [psz] - Supplies the UUID string to convert
  1181. [pguid] - Returns the GUID.
  1182. Returns: TRUE if successful
  1183. **/
  1184. {
  1185. ULONG dw;
  1186. if (!RamdiskHexStringToDword(psz, &pguid->Data1, sizeof(ULONG)*2, '-')) {
  1187. return FALSE;
  1188. }
  1189. psz += sizeof(ULONG)*2 + 1;
  1190. if (!RamdiskHexStringToDword(psz, &dw, sizeof(USHORT)*2, '-')) {
  1191. return FALSE;
  1192. }
  1193. psz += sizeof(USHORT)*2 + 1;
  1194. pguid->Data2 = (USHORT)dw;
  1195. if (!RamdiskHexStringToDword(psz, &dw, sizeof(USHORT)*2, '-')) {
  1196. return FALSE;
  1197. }
  1198. psz += sizeof(USHORT)*2 + 1;
  1199. pguid->Data3 = (USHORT)dw;
  1200. if (!RamdiskHexStringToDword(psz, &dw, sizeof(UCHAR)*2, 0)) {
  1201. return FALSE;
  1202. }
  1203. psz += sizeof(UCHAR)*2;
  1204. pguid->Data4[0] = (UCHAR)dw;
  1205. if (!RamdiskHexStringToDword(psz, &dw, sizeof(UCHAR)*2, '-')) {
  1206. return FALSE;
  1207. }
  1208. psz += sizeof(UCHAR)*2+1;
  1209. pguid->Data4[1] = (UCHAR)dw;
  1210. if (!RamdiskHexStringToDword(psz, &dw, sizeof(UCHAR)*2, 0)) {
  1211. return FALSE;
  1212. }
  1213. psz += sizeof(UCHAR)*2;
  1214. pguid->Data4[2] = (UCHAR)dw;
  1215. if (!RamdiskHexStringToDword(psz, &dw, sizeof(UCHAR)*2, 0)) {
  1216. return FALSE;
  1217. }
  1218. psz += sizeof(UCHAR)*2;
  1219. pguid->Data4[3] = (UCHAR)dw;
  1220. if (!RamdiskHexStringToDword(psz, &dw, sizeof(UCHAR)*2, 0)) {
  1221. return FALSE;
  1222. }
  1223. psz += sizeof(UCHAR)*2;
  1224. pguid->Data4[4] = (UCHAR)dw;
  1225. if (!RamdiskHexStringToDword(psz, &dw, sizeof(UCHAR)*2, 0)) {
  1226. return FALSE;
  1227. }
  1228. psz += sizeof(UCHAR)*2;
  1229. pguid->Data4[5] = (UCHAR)dw;
  1230. if (!RamdiskHexStringToDword(psz, &dw, sizeof(UCHAR)*2, 0)) {
  1231. return FALSE;
  1232. }
  1233. psz += sizeof(UCHAR)*2;
  1234. pguid->Data4[6] = (UCHAR)dw;
  1235. if (!RamdiskHexStringToDword(psz, &dw, sizeof(UCHAR)*2, 0)) {
  1236. return FALSE;
  1237. }
  1238. psz += sizeof(UCHAR)*2;
  1239. pguid->Data4[7] = (UCHAR)dw;
  1240. return TRUE;
  1241. }
  1242. BOOLEAN
  1243. RamdiskGUIDFromString(
  1244. IN PCHAR psz,
  1245. OUT LPGUID pguid
  1246. )
  1247. /**
  1248. Routine Description:
  1249. Parse GUID such as {00000000-0000-0000-0000-000000000000}
  1250. Arguments:
  1251. [psz] - Supplies the UUID string to convert
  1252. [pguid] - Returns the GUID.
  1253. Returns: TRUE if successful
  1254. **/
  1255. {
  1256. if (*psz == '{' ) {
  1257. psz++;
  1258. }
  1259. if (RamdiskUUIDFromString(psz, pguid) != TRUE) {
  1260. return FALSE;
  1261. }
  1262. psz += 36;
  1263. if (*psz == '}' ) {
  1264. psz++;
  1265. }
  1266. if (*psz != '\0') {
  1267. return FALSE;
  1268. }
  1269. return TRUE;
  1270. }
  1271. ARC_STATUS
  1272. RamdiskParseOptions (
  1273. IN PCHAR LoadOptions
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. Parses all the Ramdisk params from the boot.ini option string.
  1278. Arguments:
  1279. LoadOptions - Loader options from boot.ini. Must be all caps.
  1280. /RDPATH - Indicates that the boot ramdisk should be downloaded
  1281. from the specified path. This option takes
  1282. precedence over RDBUILD.
  1283. Example: /RDPATH=net(0)\boot\ramdisk.dat
  1284. /RDMTFTPADDR - Specifies the Multicast Address where the ramdisk
  1285. image should be downloaded from. If not specified
  1286. a unicast download from the PXE boot server will
  1287. be performed.
  1288. /RDMTFTPCPORT - Specifies the Multicast Client port to use.
  1289. /RDMTFTPSPORT - Specifies the Multicast Server port to use.
  1290. /RDMTFTPDELAY - Specifies the delay before starting a new MTFTP session.
  1291. /RDMTFTPTIMEOUT - Specifies the timeout before restarting a MTFTP session.
  1292. /RDIMAGEOFFSET - Specifies the offset into the downloaded file at which the
  1293. actual disk image begins. If not specified, 0 is used.
  1294. /RDIMAGELENGTH - Specifies the length of the actual disk image. If not
  1295. specified, the size of the downloaded file minus the offset
  1296. to the image (RDIMAGEOFFSET) is used.
  1297. /RDFILESIZE - Specifies the size of the file to be downloaded.
  1298. /RDCHUNKSIZE - Specifies the size of each file chunck when more than
  1299. one MTFTP session is required to download a large file. If the
  1300. file is to be downloaded with one chunk this option is omitted
  1301. or is set to zero.
  1302. This is used to workaround a size limitation in the MTFTP
  1303. protcol. MTFTP currently has 16-bit block counts, therefore
  1304. when using 512 byte blocks we are limited to ~32MB files.
  1305. Example 1: assume we want to download a 85MB file
  1306. using 512 byte TFTP block sizes.
  1307. /RDMTFTPADDR=224.1.1.1 /RDMTFTPCPORT=100 /RDMTFTPSPORT=200
  1308. /RDCHUNKSIZE=31457280 /RDFILESIZE=89128960
  1309. 1st MTFTP session on CPort=100, SPort=200 Size=31457280 (30MB)
  1310. 2nd MTFTP session on CPort=101, SPort=201 Size=31457280 (30MB)
  1311. 3rd MTFTP session on CPort=102, SPort=202 Size=26214400 (25MB)
  1312. Example 2: assume we want to download a 300MB file
  1313. using 1468 byte TFTP block sizes.
  1314. /RDMTFTPADDR=224.1.1.2 /RDMTFTPCPORT=100 /RDMTFTPSPORT=200
  1315. /RDCHUNKSIZE=94371840 /RDFILESIZE=314572800
  1316. 1st MTFTP session on CPort=100, SPort=200 Size=94371840 (90MB)
  1317. 2nd MTFTP session on CPort=101, SPort=201 Size=94371840 (90MB)
  1318. 3rd MTFTP session on CPort=102, SPort=202 Size=94371840 (90MB)
  1319. 4th MTFTP session on CPort=103, SPort=203 Size=31457280 (30MB)
  1320. /RDBUILD - Indicates that the boot ramdisk should be built
  1321. from the build server. This is ignored if the RDPATH
  1322. option is set.
  1323. Example: /RDBUILD
  1324. /RDGUID - Specifies the GUID of the configuration to be built
  1325. by the build server.
  1326. Example: /RDGUID={54C7D140-09EF-11D1-B25A-F5FE627ED95E}
  1327. /RDDISCOVERY - Indicates what address discovery packets should be sent to.
  1328. If this option doesn't exist, then we will not do discovery
  1329. and default to using the list of servers in RDSERVERS. If
  1330. Examples:
  1331. /RDDISCOVERY=255.255.255.255
  1332. This will send a broadcast packet to the local
  1333. network that the machine is connected to.
  1334. /RDDISCOVERY=224.100.100.100
  1335. This will send a multicast packet to the
  1336. address specified.
  1337. /RDSERVERS Specifies a list of Build Servers to send build
  1338. requests to. This will override any setting that
  1339. RDDISCOVERY has set. A maximum of 10 servers are supported.
  1340. Example: /RDSERVERS={10.0.0.3, 10.0.0.4}
  1341. /RDSERVERPORT Specifies the default port to send build packets to.
  1342. If this is not set, it defaults to 4012.
  1343. Example: /RDSERVERPORT=5623
  1344. /RDTIMEOUT Specifies the timeout period to wait for a response in
  1345. seconds. Default is 4 secs.
  1346. Example: /RDTIMEOUT=10
  1347. /RDRETRY Specifies the number of times to retry finding a build
  1348. server. Default is 5 times.
  1349. Example: /RDRETRY=5
  1350. Return Value:
  1351. ESUCCESS - read completed successfully
  1352. !ESUCCESS - read failed
  1353. --*/
  1354. {
  1355. PCHAR value;
  1356. PUCHAR p;
  1357. USHORT i;
  1358. if ( LoadOptions == NULL ) {
  1359. return ESUCCESS;
  1360. }
  1361. //
  1362. // Get RDPATH and its associated options
  1363. //
  1364. RamdiskPath = RamdiskGetOptionValue( LoadOptions, "RDPATH" );
  1365. if (RamdiskPath) {
  1366. value = RamdiskGetOptionValue( LoadOptions, "RDIMAGEOFFSET" );
  1367. if (value) RamdiskImageOffset = atoi( value );
  1368. value = RamdiskGetOptionValue( LoadOptions, "RDIMAGELENGTH" );
  1369. if (value) RamdiskImageLength = _atoi64( value );
  1370. //
  1371. // By Default the PXE Boot Server is the TFTP address
  1372. //
  1373. RamdiskTFTPAddr = NetServerIpAddress;
  1374. //
  1375. // Get the MTFTP Address used to download the image.
  1376. // if not specified, the image will be downloaded
  1377. // from the same place as ntldr (i.e. the PXE
  1378. // boot server).
  1379. //
  1380. value = RamdiskGetOptionValue( LoadOptions, "RDMTFTPADDR" );
  1381. if ( value ) {
  1382. RamdiskMTFTPAddr = RamdiskParseIPAddr( value );
  1383. value = RamdiskGetOptionValue( LoadOptions, "RDMTFTPCPORT" );
  1384. if ( value ) RamdiskMTFTPCPort = SWAP_WORD( (USHORT)atoi( value ) );
  1385. value = RamdiskGetOptionValue( LoadOptions, "RDMTFTPSPORT" );
  1386. if (value) RamdiskMTFTPSPort = SWAP_WORD( (USHORT)atoi( value ) );
  1387. value = RamdiskGetOptionValue( LoadOptions, "RDMTFTPDELAY" );
  1388. if (value) RamdiskMTFTPDelay = (USHORT)atoi( value );
  1389. value = RamdiskGetOptionValue( LoadOptions, "RDMTFTPTIMEOUT" );
  1390. if (value) RamdiskMTFTPTimeout = (USHORT)atoi( value );
  1391. value = RamdiskGetOptionValue( LoadOptions, "RDFILESIZE" );
  1392. if (value) RamdiskMTFTPFileSize = _atoi64( value );
  1393. value = RamdiskGetOptionValue( LoadOptions, "RDCHUNKSIZE" );
  1394. if (value) RamdiskMTFTPChunkSize = _atoi64( value );
  1395. // Validate options
  1396. if ( RamdiskMTFTPAddr == 0 ||
  1397. RamdiskMTFTPCPort == 0 ||
  1398. RamdiskMTFTPSPort == 0 ||
  1399. RamdiskMTFTPDelay == 0 ||
  1400. RamdiskMTFTPTimeout == 0 ||
  1401. RamdiskMTFTPFileSize == 0 ||
  1402. RamdiskMTFTPChunkSize > RamdiskMTFTPFileSize ) {
  1403. return EINVAL;
  1404. }
  1405. }
  1406. if (DBGLVL(INFO)) {
  1407. DbgPrint( "RAMDISK options:\n");
  1408. DbgPrint( "RDPATH = %s\n", RamdiskPath);
  1409. p = (PUCHAR) &RamdiskMTFTPAddr;
  1410. DbgPrint( "RDMTFTPADDR = %u.%u.%u.%u\n", p[0], p[1], p[2], p[3]);
  1411. DbgPrint( "RDMTFTPCPORT = %d\n", SWAP_WORD( RamdiskMTFTPCPort ));
  1412. DbgPrint( "RDMTFTPSPORT = %d\n", SWAP_WORD( RamdiskMTFTPSPort ));
  1413. DbgPrint( "RDMTFTPDELAY = %d\n", RamdiskMTFTPDelay);
  1414. DbgPrint( "RDMTFTPTIMEOUT = %d\n", RamdiskMTFTPTimeout);
  1415. DbgPrint( "RDFILESIZE = 0x%0I64x bytes\n", RamdiskMTFTPFileSize );
  1416. DbgPrint( "RDCHUNKSIZE = 0x%0I64x bytes\n", RamdiskMTFTPChunkSize );
  1417. DbgPrint( "RDIMAGEOFFSET = 0x%x bytes\n", RamdiskImageOffset );
  1418. DbgPrint( "RDIMAGELENGTH = 0x%0I64x bytes\n", RamdiskImageLength );
  1419. }
  1420. // we are done if RDPATH was specified.
  1421. return ESUCCESS;
  1422. }
  1423. //
  1424. // Check if RDBUILD exists
  1425. //
  1426. if ( strstr( LoadOptions, "RDBUILD" ) ) {
  1427. RamdiskBuild = TRUE;
  1428. value = RamdiskGetOptionValue( LoadOptions, "RDGUID" );
  1429. if ( value == NULL ||
  1430. RamdiskGUIDFromString( value, &RamdiskGuid ) == FALSE ) {
  1431. return EINVAL;
  1432. }
  1433. value = RamdiskGetOptionValue( LoadOptions, "RDDISCOVERY" );
  1434. if ( value ) RamdiskDiscovery = RamdiskParseIPAddr( value );
  1435. value = RamdiskGetOptionValue(LoadOptions, "RDSERVERPORT");
  1436. if (value) RamdiskBuildPort = SWAP_WORD((USHORT)atoi(value));
  1437. value = RamdiskGetOptionValue( LoadOptions, "RDSERVERS" );
  1438. if ( value && *value == '{' ) {
  1439. PCHAR e = strchr( value, '}' );
  1440. if ( e && (ULONG)(e - value) > 7 ) { // at least seven characters for X.X.X.X
  1441. while ( value && value < e && RamdiskServerCount < RAMDISK_MAX_SERVERS) {
  1442. value++;
  1443. RamdiskServers[RamdiskServerCount] = RamdiskParseIPAddr( value );
  1444. RamdiskServerCount++;
  1445. value = strchr(value, ',' );
  1446. }
  1447. }
  1448. }
  1449. value = RamdiskGetOptionValue( LoadOptions, "RDTIMEOUT" );
  1450. if (value) RamdiskTimeout = (USHORT)atoi( value );
  1451. value = RamdiskGetOptionValue( LoadOptions, "RDRETRY" );
  1452. if (value) RamdiskRetry = (USHORT)atoi( value );
  1453. // Validate options
  1454. if (((RamdiskDiscovery == 0) && (RamdiskServerCount == 0)) ||
  1455. (RamdiskBuildPort == 0) ||
  1456. (RamdiskTimeout == 0) ||
  1457. (RamdiskRetry == 0)) {
  1458. return EINVAL;
  1459. }
  1460. //
  1461. // Print out debug information
  1462. //
  1463. if (DBGLVL(INFO)) {
  1464. DbgPrint("RDBUILD options:\n");
  1465. DbgPrint("RDGUID = {%x-%x-%x-%x%x%x%x%x%x%x%x}\n",
  1466. RamdiskGuid.Data1, RamdiskGuid.Data2,
  1467. RamdiskGuid.Data3,
  1468. RamdiskGuid.Data4[0], RamdiskGuid.Data4[1],
  1469. RamdiskGuid.Data4[2], RamdiskGuid.Data4[3],
  1470. RamdiskGuid.Data4[4], RamdiskGuid.Data4[5],
  1471. RamdiskGuid.Data4[6], RamdiskGuid.Data4[7]);
  1472. p = (PUCHAR) &RamdiskDiscovery;
  1473. DbgPrint("RDDISCOVERY = %u.%u.%u.%u\n", p[0], p[1], p[2], p[3]);
  1474. DbgPrint("RDBUILDPORT = %d\n", RamdiskBuildPort);
  1475. DbgPrint("RDSERVERS = %d\n", RamdiskServerCount);
  1476. for (i = 0; i < RamdiskServerCount; i++) {
  1477. p = (PUCHAR) &RamdiskServers[i];
  1478. DbgPrint("RDSERVER[%d] = %u.%u.%u.%u\n", i, p[0], p[1], p[2], p[3]);
  1479. }
  1480. DbgPrint("RDTIMEOUT = %d\n", RamdiskTimeout);
  1481. DbgPrint("RDRETRY = %d\n", RamdiskRetry);
  1482. }
  1483. }
  1484. return ESUCCESS;
  1485. }
  1486. #if defined(i386) // RDBUILD is only supported on x86 machines for now
  1487. VOID
  1488. RamdiskDeviceInfoToString(
  1489. DEVICE_INFO * Device,
  1490. PCHAR DeviceString
  1491. )
  1492. /*++
  1493. Routine Description:
  1494. This routine generates a string representation of the Device info for
  1495. debugging purposes.
  1496. Arguments:
  1497. Device - Pointer to the device info structure
  1498. DeviceString - a pointer to a buffer that will hold the final string. The buffer
  1499. must be at least 128 * sizeof(CHAR) bytes.
  1500. Return Value:
  1501. NONE.
  1502. --*/
  1503. {
  1504. const CHAR HexToCharTable[17] = "0123456789ABCDEF";
  1505. if (Device->DeviceType == BMBUILD_DEVICE_TYPE_PCI) {
  1506. sprintf ( DeviceString,
  1507. "%d.%d.%d PCI\\VEN_%04X&DEV_%04X&SUBSYS_%04X%04X&REV_%02X&CC_%02X%02X%02X",
  1508. BUSDEVFUNC_TO_BUS( Device->info.pci.BusDevFunc ),
  1509. BUSDEVFUNC_TO_DEVICE( Device->info.pci.BusDevFunc ),
  1510. BUSDEVFUNC_TO_FUNCTION( Device->info.pci.BusDevFunc ),
  1511. Device->info.pci.VendorID,
  1512. Device->info.pci.DeviceID,
  1513. Device->info.pci.SubVendorID,
  1514. Device->info.pci.SubDeviceID,
  1515. Device->info.pci.RevisionID,
  1516. Device->info.pci.BaseClass,
  1517. Device->info.pci.SubClass,
  1518. Device->info.pci.ProgIntf );
  1519. } else if (Device->DeviceType == BMBUILD_DEVICE_TYPE_PCI_BRIDGE ) {
  1520. sprintf ( DeviceString,
  1521. "%d.%d.%d PCI\\VEN_%04X&DEV_%04X&REV_%02X&CC_%02X%02X%02X Bridge %d->%d Sub = %d",
  1522. BUSDEVFUNC_TO_BUS( Device->info.pci_bridge.BusDevFunc ),
  1523. BUSDEVFUNC_TO_DEVICE( Device->info.pci_bridge.BusDevFunc ),
  1524. BUSDEVFUNC_TO_FUNCTION( Device->info.pci_bridge.BusDevFunc ),
  1525. Device->info.pci_bridge.VendorID,
  1526. Device->info.pci_bridge.DeviceID,
  1527. Device->info.pci_bridge.RevisionID,
  1528. Device->info.pci_bridge.BaseClass,
  1529. Device->info.pci_bridge.SubClass,
  1530. Device->info.pci_bridge.ProgIntf,
  1531. Device->info.pci_bridge.PrimaryBus,
  1532. Device->info.pci_bridge.SecondaryBus,
  1533. Device->info.pci_bridge.SubordinateBus );
  1534. } else if (Device->DeviceType == BMBUILD_DEVICE_TYPE_PNP) {
  1535. CHAR ProductIDStr[8];
  1536. PUCHAR id = (PUCHAR)&Device->info.pnp.EISADevID;
  1537. ProductIDStr[0] = (id[0] >> 2) + 0x40;
  1538. ProductIDStr[1] = (((id[0] & 0x03) << 3) | (id[1] >> 5)) + 0x40;
  1539. ProductIDStr[2] = (id[1] & 0x1f) + 0x40;
  1540. ProductIDStr[3] = HexToCharTable[id[2] >> 4];
  1541. ProductIDStr[4] = HexToCharTable[id[2] & 0x0F];
  1542. ProductIDStr[5] = HexToCharTable[id[3] >> 4];
  1543. ProductIDStr[6] = HexToCharTable[id[3] & 0x0F];
  1544. ProductIDStr[7] = 0x00;
  1545. sprintf( DeviceString,
  1546. "%d %s CC_%02X%02X%02X",
  1547. Device->info.pnp.CardSelNum,
  1548. ProductIDStr,
  1549. Device->info.pnp.BaseClass,
  1550. Device->info.pnp.SubClass,
  1551. Device->info.pnp.ProgIntf );
  1552. }
  1553. }
  1554. VOID
  1555. RamdiskWait(
  1556. ULONG WaitTime
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. This routine will spin a loop so you can wait for the specified time.
  1561. Arguments:
  1562. WaitTime - The time to wait in seconds
  1563. Return Value:
  1564. NONE.
  1565. --*/
  1566. {
  1567. ULONG startTime = SysGetRelativeTime();
  1568. while ((SysGetRelativeTime() - startTime) < WaitTime) {
  1569. }
  1570. }
  1571. VOID
  1572. RamdiskPrintBuildProgress(
  1573. ULONG MsgId,
  1574. ULONG BuildServerIpAddress
  1575. )
  1576. /*++
  1577. Routine Description:
  1578. This routine will look up the passed in message id and display it on the screen
  1579. using the address as arguments.
  1580. Arguments:
  1581. MsgId - The Id of the message to display
  1582. BuildServerIpAddress - The ip address to use as agruments to the message
  1583. Return Value:
  1584. NONE.
  1585. --*/
  1586. {
  1587. PUCHAR address;
  1588. PTCHAR formatString = NULL;
  1589. TCHAR buffer[256];
  1590. //
  1591. // look up format message
  1592. //
  1593. formatString = BlFindMessage(MsgId);
  1594. if (formatString != NULL) {
  1595. //
  1596. // print progress message
  1597. //
  1598. address = (PUCHAR) &BuildServerIpAddress;
  1599. _stprintf(buffer, formatString, address[0], address[1], address[2], address[3]);
  1600. BlOutputTrailerMsgStr(buffer);
  1601. }
  1602. }
  1603. ARC_STATUS
  1604. RamdiskBuildDiscover(
  1605. IN BMBUILD_DISCOVER_PACKET * Discover,
  1606. IN ULONG DiscoverLengthMax,
  1607. OUT ULONG * DiscoverLength
  1608. )
  1609. /*++
  1610. Routine Description:
  1611. This routine will build a discover packet based on the Ramdisk parameters in the
  1612. boot.ini.
  1613. Arguments:
  1614. Discover - The buffer to fill in with data
  1615. DiscoverLengthMax - The maximum size the discovery packet could be
  1616. DiscoverLength - The final size of the discovery packet
  1617. Return Value:
  1618. ESUCCESS - If the packet was filled in correctly.
  1619. EINVAL - If the packet couldn't be filled in correctly
  1620. --*/
  1621. {
  1622. ULONG GuidLength;
  1623. PUCHAR Guid;
  1624. ASSERT(Discover);
  1625. ASSERT(DiscoverLength);
  1626. if (DiscoverLengthMax < sizeof(BMBUILD_DISCOVER_PACKET)) {
  1627. return EINVAL;
  1628. }
  1629. RtlZeroMemory(Discover, DiscoverLengthMax);
  1630. //
  1631. // Set the protocol defaults
  1632. //
  1633. Discover->Version = BMBUILD_PACKET_VERSION;
  1634. Discover->OpCode = BMBUILD_OPCODE_DISCOVER;
  1635. //
  1636. // Get the SMBIOS UUID (or PXE MAC address)
  1637. //
  1638. GetGuid(&Guid, &GuidLength);
  1639. ASSERT(GuidLength == sizeof(Discover->MachineGuid));
  1640. if (GuidLength == sizeof(Discover->MachineGuid)) {
  1641. memcpy(&Discover->MachineGuid, Guid, GuidLength);
  1642. }
  1643. //
  1644. // Set the product guid from boot.ini
  1645. //
  1646. memcpy(&Discover->ProductGuid, &RamdiskGuid, sizeof(GUID));
  1647. //
  1648. // Debug prints
  1649. //
  1650. if (DBGLVL(INFO)) {
  1651. DbgPrint("RAMDISK Build Discover\n");
  1652. DbgPrint("MachineGuid = {%x-%x-%x-%x%x%x%x%x%x%x%x}\n",
  1653. Discover->MachineGuid.Data1, Discover->MachineGuid.Data2,
  1654. Discover->MachineGuid.Data3,
  1655. Discover->MachineGuid.Data4[0], Discover->MachineGuid.Data4[1],
  1656. Discover->MachineGuid.Data4[2], Discover->MachineGuid.Data4[3],
  1657. Discover->MachineGuid.Data4[4], Discover->MachineGuid.Data4[5],
  1658. Discover->MachineGuid.Data4[6], Discover->MachineGuid.Data4[7]);
  1659. DbgPrint("ProductGuid = {%x-%x-%x-%x%x%x%x%x%x%x%x}\n",
  1660. Discover->ProductGuid.Data1, Discover->ProductGuid.Data2,
  1661. Discover->ProductGuid.Data3,
  1662. Discover->ProductGuid.Data4[0], Discover->ProductGuid.Data4[1],
  1663. Discover->ProductGuid.Data4[2], Discover->ProductGuid.Data4[3],
  1664. Discover->ProductGuid.Data4[4], Discover->ProductGuid.Data4[5],
  1665. Discover->ProductGuid.Data4[6], Discover->ProductGuid.Data4[7]);
  1666. }
  1667. *DiscoverLength = sizeof(BMBUILD_DISCOVER_PACKET);
  1668. return ESUCCESS;
  1669. }
  1670. ARC_STATUS
  1671. RamdiskBuildRequest(
  1672. IN PBMBUILD_REQUEST_PACKET pRequest,
  1673. IN ULONG RequestLengthMax,
  1674. OUT ULONG * pLength
  1675. )
  1676. /*++
  1677. Routine Description:
  1678. This routine will build a request packet based on the Ramdisk parameters in the
  1679. boot.ini and the machine configuration.
  1680. Arguments:
  1681. pRequest - a pointer to a buffer that will hold the request
  1682. RequestLengthMax - the maximum size that the request packet can be
  1683. pLength - the final size of the request packet
  1684. Return Value:
  1685. ESUCCESS - If the packet was filled in correctly.
  1686. !ESUCCESS - If the packet couldn't be filled in correctly
  1687. --*/
  1688. {
  1689. ARC_STATUS status;
  1690. PDEVICE_INFO pDevice;
  1691. t_PXENV_UNDI_GET_NIC_TYPE PxeNicType;
  1692. PCONFIGURATION_COMPONENT_DATA Node = NULL;
  1693. PCONFIGURATION_COMPONENT_DATA CurrentNode = NULL;
  1694. PCONFIGURATION_COMPONENT_DATA ResumeNode = NULL;
  1695. PPCIDEVICE pPCIDevice;
  1696. PPNP_BIOS_INSTALLATION_CHECK pPNPBios;
  1697. PPNP_BIOS_DEVICE_NODE pDevNode;
  1698. PCM_PARTIAL_RESOURCE_LIST pPartialList;
  1699. PUCHAR pCurr;
  1700. USHORT cDevices;
  1701. USHORT i;
  1702. ULONG lengthRemaining;
  1703. ULONG GuidLength;
  1704. PUCHAR Guid;
  1705. PCHAR HalName;
  1706. ULONG HalNameSize;
  1707. BOOLEAN fNICFound = FALSE;
  1708. ASSERT(pRequest);
  1709. ASSERT(RequestLengthMax);
  1710. ASSERT(pLength);
  1711. RtlZeroMemory(pRequest, RequestLengthMax);
  1712. //
  1713. // Set the protocol defaults
  1714. //
  1715. pRequest->Version = BMBUILD_PACKET_VERSION;
  1716. pRequest->OpCode = BMBUILD_OPCODE_REQUEST;
  1717. //
  1718. // Get the SMBIOS UUID (or PXE MAC address)
  1719. //
  1720. GetGuid(&Guid, &GuidLength);
  1721. ASSERT(GuidLength == sizeof(pRequest->MachineGuid));
  1722. if (GuidLength == sizeof(pRequest->MachineGuid)) {
  1723. memcpy(&pRequest->MachineGuid, Guid, GuidLength);
  1724. }
  1725. //
  1726. // Set the product guid from boot.ini
  1727. //
  1728. memcpy(&pRequest->ProductGuid, &RamdiskGuid, sizeof(GUID));
  1729. pRequest->Flags = 0;
  1730. #ifdef _IA64_
  1731. pRequest->Architecture = PROCESSOR_ARCHITECTURE_IA64;
  1732. #else
  1733. pRequest->Architecture = PROCESSOR_ARCHITECTURE_INTEL;
  1734. #endif
  1735. //
  1736. // Detect the appropriate HAL using TextMode Setup methods.
  1737. //
  1738. #ifdef DOWNLOAD_TXTSETUP_SIF
  1739. status = SlInitIniFile( "net(0)",
  1740. 0,
  1741. "boot\\txtsetup.sif",
  1742. &InfFile,
  1743. NULL,
  1744. NULL,
  1745. &x);
  1746. #endif
  1747. //
  1748. // The device list start right after the fixed portion of the packet
  1749. pRequest->DeviceCount = 0;
  1750. //
  1751. // Make sure that the device array starts on a valid boundary
  1752. //
  1753. ASSERT(ROUND2(BMBUILD_FIELD_OFFSET(BMBUILD_REQUEST_PACKET, Data), 4) < 0xFFFF);
  1754. pRequest->DeviceOffset = ROUND2(BMBUILD_FIELD_OFFSET(BMBUILD_REQUEST_PACKET, Data), 4);
  1755. pDevice = (PDEVICE_INFO)((PUCHAR)pRequest + pRequest->DeviceOffset);
  1756. //
  1757. // Get the PXE NIC information
  1758. //
  1759. RtlZeroMemory(&PxeNicType, sizeof(PxeNicType));
  1760. status = RomGetNicType(&PxeNicType);
  1761. if ((status != PXENV_EXIT_SUCCESS) || (PxeNicType.Status != PXENV_EXIT_SUCCESS)) {
  1762. DBGPRINT(ERR, ("RAMDISK ERROR: Couldn't get the NIC type from PXE. Failed with %x, status = %x\n", status, PxeNicType.Status));
  1763. return ENODEV;
  1764. }
  1765. //
  1766. // Fill in PCI Device information
  1767. //
  1768. Node = KeFindConfigurationEntry(FwConfigurationTree,
  1769. PeripheralClass,
  1770. RealModePCIEnumeration,
  1771. NULL);
  1772. ASSERT(Node != NULL);
  1773. if (Node == NULL) {
  1774. return ENODEV;
  1775. }
  1776. ASSERT(Node->ComponentEntry.ConfigurationDataLength > 0);
  1777. ASSERT(Node->ConfigurationData != NULL);
  1778. pPCIDevice = (PPCIDEVICE)((PUCHAR)Node->ConfigurationData + sizeof(CM_PARTIAL_RESOURCE_LIST));
  1779. cDevices = (USHORT)(Node->ComponentEntry.ConfigurationDataLength - sizeof (CM_PARTIAL_RESOURCE_LIST)) / sizeof (PCIDEVICE);
  1780. if (cDevices > BMBUILD_MAX_DEVICES(RequestLengthMax)) {
  1781. DBGPRINT(ERR, ("RAMDISK ERROR: Too many PCI devices to fit in a request\n"));
  1782. return EINVAL;
  1783. }
  1784. for (i = 0; i < cDevices; i++ ) {
  1785. //
  1786. // check if this is a bridge or a normal device
  1787. //
  1788. if ((pPCIDevice->Config.HeaderType & (~PCI_MULTIFUNCTION) ) == PCI_BRIDGE_TYPE) {
  1789. //
  1790. // Bridge.
  1791. //
  1792. pDevice[i].DeviceType = BMBUILD_DEVICE_TYPE_PCI_BRIDGE;
  1793. pDevice[i].info.pci_bridge.BusDevFunc = pPCIDevice->BusDevFunc;
  1794. pDevice[i].info.pci_bridge.VendorID = pPCIDevice->Config.VendorID;
  1795. pDevice[i].info.pci_bridge.DeviceID = pPCIDevice->Config.DeviceID;
  1796. pDevice[i].info.pci_bridge.BaseClass = pPCIDevice->Config.BaseClass;
  1797. pDevice[i].info.pci_bridge.SubClass = pPCIDevice->Config.SubClass;
  1798. pDevice[i].info.pci_bridge.ProgIntf = pPCIDevice->Config.ProgIf;
  1799. pDevice[i].info.pci_bridge.RevisionID = pPCIDevice->Config.RevisionID;
  1800. pDevice[i].info.pci_bridge.PrimaryBus = pPCIDevice->Config.u.type1.PrimaryBus;
  1801. pDevice[i].info.pci_bridge.SecondaryBus = pPCIDevice->Config.u.type1.SecondaryBus;
  1802. pDevice[i].info.pci_bridge.SubordinateBus = pPCIDevice->Config.u.type1.SubordinateBus;
  1803. } else {
  1804. //
  1805. // Non-bridge PCI device
  1806. //
  1807. pDevice[i].DeviceType = BMBUILD_DEVICE_TYPE_PCI;
  1808. pDevice[i].info.pci.BusDevFunc = pPCIDevice->BusDevFunc;
  1809. pDevice[i].info.pci.VendorID = pPCIDevice->Config.VendorID;
  1810. pDevice[i].info.pci.DeviceID = pPCIDevice->Config.DeviceID;
  1811. pDevice[i].info.pci.BaseClass = pPCIDevice->Config.BaseClass;
  1812. pDevice[i].info.pci.SubClass = pPCIDevice->Config.SubClass;
  1813. pDevice[i].info.pci.ProgIntf = pPCIDevice->Config.ProgIf;
  1814. pDevice[i].info.pci.RevisionID = pPCIDevice->Config.RevisionID;
  1815. pDevice[i].info.pci.SubVendorID = pPCIDevice->Config.u.type0.SubVendorID;
  1816. pDevice[i].info.pci.SubDeviceID = pPCIDevice->Config.u.type0.SubSystemID;
  1817. //
  1818. // Check if this device is the PXE boot device
  1819. //
  1820. if ((PxeNicType.NicType == 2) &&
  1821. (PxeNicType.pci_pnp_info.pci.BusDevFunc == pPCIDevice->BusDevFunc)) {
  1822. pRequest->PrimaryNicIndex = i;
  1823. fNICFound = TRUE;
  1824. }
  1825. }
  1826. pPCIDevice++;
  1827. }
  1828. pRequest->DeviceCount = pRequest->DeviceCount + cDevices;
  1829. pDevice += cDevices;
  1830. //
  1831. // Fill in PNP Device information (if there)
  1832. //
  1833. Node = NULL;
  1834. while ((CurrentNode = KeFindConfigurationNextEntry(
  1835. FwConfigurationTree,
  1836. AdapterClass,
  1837. MultiFunctionAdapter,
  1838. NULL,
  1839. &ResumeNode)) != 0) {
  1840. if (!(strcmp(CurrentNode->ComponentEntry.Identifier,"PNP BIOS"))) {
  1841. Node = CurrentNode;
  1842. break;
  1843. }
  1844. ResumeNode = CurrentNode;
  1845. }
  1846. if (Node != NULL) {
  1847. //
  1848. // Set the PnP BIOS devices if found
  1849. //
  1850. ASSERT(Node->ComponentEntry.ConfigurationDataLength > 0);
  1851. ASSERT(Node->ConfigurationData != NULL);
  1852. pPartialList = (PCM_PARTIAL_RESOURCE_LIST)Node->ConfigurationData;
  1853. pPNPBios = (PPNP_BIOS_INSTALLATION_CHECK)((PUCHAR)Node->ConfigurationData + sizeof(CM_PARTIAL_RESOURCE_LIST));
  1854. pCurr = (PUCHAR)pPNPBios + pPNPBios->Length;
  1855. lengthRemaining = pPartialList->PartialDescriptors[0].u.DeviceSpecificData.DataSize - pPNPBios->Length;
  1856. for (cDevices = 0; lengthRemaining > sizeof(PNP_BIOS_DEVICE_NODE); cDevices++) {
  1857. if ((pRequest->DeviceCount + cDevices + 1) > BMBUILD_MAX_DEVICES(RamdiskMaxPacketSize)) {
  1858. DBGPRINT(ERR, ("RAMDISK ERROR: Too many PNP devices to fit in a request\n"));
  1859. return EINVAL;
  1860. }
  1861. pDevNode = (PPNP_BIOS_DEVICE_NODE)pCurr;
  1862. if (pDevNode->Size > lengthRemaining) {
  1863. DBGPRINT(ERR, ("PNP Node # %d, invalid size (%d), length remaining (%d)\n",
  1864. pDevNode->Node, pDevNode->Size, lengthRemaining));
  1865. ASSERT(FALSE);
  1866. // REVIEW: [bassamt] Should I fail here?
  1867. break;
  1868. }
  1869. pDevice->DeviceType = BMBUILD_DEVICE_TYPE_PNP;
  1870. pDevice->info.pnp.EISADevID = pDevNode->ProductId;
  1871. pDevice->info.pnp.BaseClass = pDevNode->DeviceType[0];
  1872. pDevice->info.pnp.SubClass = pDevNode->DeviceType[1];
  1873. pDevice->info.pnp.ProgIntf = pDevNode->DeviceType[2];
  1874. pDevice->info.pnp.CardSelNum = pDevNode->Node;
  1875. if ((PxeNicType.NicType == 3) &&
  1876. (PxeNicType.pci_pnp_info.pnp.EISA_Dev_ID == pDevNode->ProductId) &&
  1877. (PxeNicType.pci_pnp_info.pnp.CardSelNum == pDevNode->Node)) {
  1878. pRequest->PrimaryNicIndex = pRequest->DeviceCount + cDevices;
  1879. fNICFound = TRUE;
  1880. }
  1881. pCurr += pDevNode->Size;
  1882. lengthRemaining -= pDevNode->Size;
  1883. pDevice++;
  1884. }
  1885. pRequest->DeviceCount = pRequest->DeviceCount + cDevices;
  1886. }
  1887. //
  1888. // We better have found the primary NIC or the packet is invalid
  1889. //
  1890. if (!fNICFound) {
  1891. DBGPRINT(ERR, ("RAMDISK ERROR: Could not find the primary NIC\n"));
  1892. return ENODEV;
  1893. }
  1894. //
  1895. // The hal starts right after the array of device infos
  1896. //
  1897. pRequest->HalDataOffset = pRequest->DeviceOffset + (pRequest->DeviceCount * sizeof(DEVICE_INFO));
  1898. //
  1899. // Figure out which hal to use
  1900. //
  1901. HalName = SlDetectHal();
  1902. if (HalName == NULL) {
  1903. DBGPRINT(ERR, ("RAMDISK ERROR: Couldn't get the HAL name.\n"));
  1904. return ENODEV;
  1905. }
  1906. HalNameSize = strlen(HalName);
  1907. if (HalNameSize > (RequestLengthMax - pRequest->HalDataOffset)) {
  1908. DBGPRINT(ERR, ("RAMDISK ERROR: HAL name, %s, is too big for request, size = %d.\n",
  1909. HalName, RequestLengthMax - pRequest->HalDataOffset));
  1910. return ENOMEM;
  1911. }
  1912. //
  1913. // Copy over the hal
  1914. //
  1915. memcpy((PUCHAR)pRequest + pRequest->HalDataOffset, HalName, HalNameSize);
  1916. pRequest->HalDataLength = RESET_SIZE_AT_USHORT_MAX(HalNameSize);
  1917. //
  1918. // Return the length
  1919. //
  1920. *pLength = pRequest->HalDataOffset + pRequest->HalDataLength;
  1921. //
  1922. // Debug prints
  1923. //
  1924. if (DBGLVL(INFO)) {
  1925. DbgPrint("RAMDISK Build Request\n");
  1926. DbgPrint("Architecture = %d\n", pRequest->Architecture);
  1927. DbgPrint("MachineGuid = {%x-%x-%x-%x%x%x%x%x%x%x%x}\n",
  1928. pRequest->MachineGuid.Data1, pRequest->MachineGuid.Data2,
  1929. pRequest->MachineGuid.Data3,
  1930. pRequest->MachineGuid.Data4[0], pRequest->MachineGuid.Data4[1],
  1931. pRequest->MachineGuid.Data4[2], pRequest->MachineGuid.Data4[3],
  1932. pRequest->MachineGuid.Data4[4], pRequest->MachineGuid.Data4[5],
  1933. pRequest->MachineGuid.Data4[6], pRequest->MachineGuid.Data4[7]);
  1934. DbgPrint("ProductGuid = {%x-%x-%x-%x%x%x%x%x%x%x%x}\n",
  1935. pRequest->ProductGuid.Data1, pRequest->ProductGuid.Data2,
  1936. pRequest->ProductGuid.Data3,
  1937. pRequest->ProductGuid.Data4[0], pRequest->ProductGuid.Data4[1],
  1938. pRequest->ProductGuid.Data4[2], pRequest->ProductGuid.Data4[3],
  1939. pRequest->ProductGuid.Data4[4], pRequest->ProductGuid.Data4[5],
  1940. pRequest->ProductGuid.Data4[6], pRequest->ProductGuid.Data4[7]);
  1941. DbgPrint("HALName = %s\n", HalName);
  1942. DbgPrint("Flags = 0x%x\n", pRequest->Flags);
  1943. DbgPrint("DeviceCount = %d\n", pRequest->DeviceCount);
  1944. pDevice = (PDEVICE_INFO)( (PUCHAR)pRequest + pRequest->DeviceOffset );
  1945. for (i = 0; i < pRequest->DeviceCount; i++ ) {
  1946. CHAR DeviceString[128];
  1947. RamdiskDeviceInfoToString( pDevice, DeviceString );
  1948. DbgPrint("[%d] %s %s\n", i, DeviceString, (i == pRequest->PrimaryNicIndex? "PRIMARY NIC" : ""));
  1949. pDevice++;
  1950. }
  1951. }
  1952. return ESUCCESS;
  1953. }
  1954. ARC_STATUS
  1955. RamdiskSendDiscoverAndWait(
  1956. IN PBMBUILD_DISCOVER_PACKET Discover,
  1957. IN ULONG DiscoverSize,
  1958. IN ULONG Timeout
  1959. )
  1960. /*++
  1961. Routine Description:
  1962. This routine will send a discovery packet on the network in
  1963. accordance with the RamdiskDiscovery parameters. It will then
  1964. wait for the specified timeout period and collect the responses
  1965. from the build servers. It will add each of these servers to the
  1966. RamdiskServers list. If we don't get any responses in the timeout
  1967. period, we will return EIO.
  1968. Arguments:
  1969. Discover - Discover packet to send out
  1970. DiscoverSize - the size of the discover packet
  1971. Timeout - timeout interval
  1972. Return Value:
  1973. ESUCCESS - received at least one response from a build server
  1974. EIO - if we timed out waiting for a response from a build server
  1975. EINVAL - couldn't send the discover packet
  1976. --*/
  1977. {
  1978. ULONG waitStartTime;
  1979. BMBUILD_ACCEPT_PACKET accept;
  1980. PUCHAR address = (PUCHAR) &RamdiskDiscovery;
  1981. BOOLEAN receivedAccept;
  1982. ULONG length;
  1983. ULONG remoteHost;
  1984. USHORT remotePort;
  1985. ASSERT(RamdiskServerCount < RAMDISK_MAX_SERVERS);
  1986. ASSERT(RamdiskDiscovery != 0);
  1987. ASSERT(RamdiskBuildPort != 0);
  1988. //
  1989. // Send the discovery packet to the destination address
  1990. //
  1991. length = RomSendUdpPacket(Discover, DiscoverSize, RamdiskDiscovery, RamdiskBuildPort);
  1992. if (length != DiscoverSize) {
  1993. DBGPRINT(ERR, ("FAILED to send discovery packet to %u.%u.%u.%u:%u\n",
  1994. address[0], address[1], address[2], address[3],
  1995. SWAP_WORD(RamdiskBuildPort)));
  1996. return EINVAL;
  1997. }
  1998. DBGPRINT(INFO, ("Waiting for response (Timeout = %d secs).\n", Timeout));
  1999. //
  2000. // Wait for the responses. We will wait for the timeout period and
  2001. // collect the ACCEPT packets we get within this timeout.
  2002. //
  2003. waitStartTime = SysGetRelativeTime();
  2004. receivedAccept = FALSE;
  2005. while ((SysGetRelativeTime() - waitStartTime) < Timeout) {
  2006. length = RomReceiveUdpPacket(&accept, sizeof(accept), 0, &remoteHost, &remotePort);
  2007. if (length != 0) {
  2008. //
  2009. // Make sure the packet is one of the ones we expect.
  2010. //
  2011. if ((remoteHost == 0) || (remoteHost == 0xFFFFFFFF) || (RamdiskBuildPort != remotePort)) {
  2012. PUCHAR bad = (PUCHAR) &remoteHost;
  2013. //
  2014. // Recieved a packet from the wrong server/port
  2015. //
  2016. DBGPRINT(ERR, ("RamdiskSendDiscoverPacketAndWait: received an unexpected packet, "
  2017. "expected %u, received %u.%u.%u.%u:%u\n",
  2018. SWAP_WORD(RamdiskBuildPort),
  2019. bad[0], bad[1], bad[2], bad[3], SWAP_WORD(remotePort)));
  2020. } else if (length < sizeof(BMBUILD_ACCEPT_PACKET)) {
  2021. //
  2022. // Recieved a packet that's too small
  2023. //
  2024. DBGPRINT(ERR, ("RamdiskSendDiscoverPacketAndWait: packet size too small, %d\n", length));
  2025. } else if ((accept.Version != BMBUILD_PACKET_VERSION) ||
  2026. (accept.OpCode != BMBUILD_OPCODE_ACCEPT) ||
  2027. (accept.XID != Discover->XID)) {
  2028. //
  2029. // The packet is corrupt
  2030. //
  2031. address = (PUCHAR) &remoteHost;
  2032. DBGPRINT(ERR, ("RamdiskSendDiscoverPacketAndWait: expected ACCEPT with XID %d, "
  2033. "received Version %d, OpCode %d, XID %d from %u.%u.%u.%u:%u\n",
  2034. Discover->XID, accept.Version, accept.OpCode, accept.XID,
  2035. address[0], address[1], address[2], address[3], SWAP_WORD(remotePort)));
  2036. } else {
  2037. address = (PUCHAR) &remoteHost;
  2038. DBGPRINT(INFO, ("Received ACCEPT packet XID = %d from %u.%u.%u.%u:%u\n",
  2039. accept.XID, address[0], address[1], address[2], address[3],
  2040. SWAP_WORD(remotePort)));
  2041. //
  2042. // We have a valid packet from a build server. Add it to
  2043. // the list.
  2044. //
  2045. receivedAccept = TRUE;
  2046. ASSERT(RamdiskServerCount < RAMDISK_MAX_SERVERS);
  2047. RamdiskServers[RamdiskServerCount] = remoteHost;
  2048. RamdiskServerCount++;
  2049. //
  2050. // If we filled up the maximum number of servers
  2051. // then we are done
  2052. //
  2053. if (RamdiskServerCount == RAMDISK_MAX_SERVERS) {
  2054. break;
  2055. }
  2056. }
  2057. }
  2058. }
  2059. //
  2060. // Did we get anything
  2061. //
  2062. if (receivedAccept) {
  2063. return ESUCCESS;
  2064. } else {
  2065. address = (PUCHAR) &RamdiskDiscovery;
  2066. DBGPRINT(ERR, ("Timed out waiting for accepts using %u.%u.%u.%u:%u "
  2067. "(Timeout = %d secs).\n", address[0], address[1], address[2],
  2068. address[3], SWAP_WORD(RamdiskBuildPort), Timeout));
  2069. return EIO;
  2070. }
  2071. }
  2072. ARC_STATUS
  2073. RamdiskDiscoverBuildServer(
  2074. )
  2075. /*++
  2076. Routine Description:
  2077. This routine will discover a list of build server based on the
  2078. ramdisk build parameters listed in boot.ini. If we already have
  2079. a list of build server listed in boot.ini, we will use that list
  2080. as the possible build servers. If we get a response from any
  2081. build server, we will stop the discover stage and use the list
  2082. of servers we have heard back from as the list of possible build
  2083. servers to use. We will retry a number of times to get responses.
  2084. If we get no response after retrying, we will fail.
  2085. Arguments:
  2086. None
  2087. Return Value:
  2088. ESUCCESS - We have a list of build servers
  2089. EIO - We timed out waiting for responses from the build servers
  2090. otherwise, something else failed
  2091. --*/
  2092. {
  2093. ARC_STATUS status;
  2094. USHORT localPort;
  2095. BMBUILD_DISCOVER_PACKET discover;
  2096. ULONG discoverLength;
  2097. ULONG iRetry;
  2098. ULONG timeout;
  2099. ULONG lastProgressPercent = 0;
  2100. BOOLEAN forceDisplayFirstTime = TRUE;
  2101. ULONG currentProgressPercent;
  2102. PUCHAR address = (PUCHAR) &RamdiskDiscovery;
  2103. //
  2104. // Short-circuit discovery if we already have a list of servers
  2105. //
  2106. if (RamdiskServerCount > 0) {
  2107. ASSERT(RamdiskServers[0] != 0);
  2108. ASSERT(RamdiskServers[0] != 0xFFFFFFFF);
  2109. return ESUCCESS;
  2110. }
  2111. ASSERT(RamdiskDiscovery != 0);
  2112. //
  2113. // Grab an unused port
  2114. //
  2115. localPort = UdpAssignUnicastPort();
  2116. DBGPRINT(INFO, ("Sending builder discovers using port %d.\n", SWAP_WORD(localPort)));
  2117. //
  2118. // Create discover packet
  2119. //
  2120. status = RamdiskBuildDiscover(&discover, sizeof(discover), &discoverLength);
  2121. if (status != ESUCCESS) {
  2122. return status;
  2123. }
  2124. //
  2125. // Start the discovery. Note that this will be repeated a number
  2126. // of times to account for network congestion and load on the servers.
  2127. //
  2128. BlOutputStartupMsg(RAMDISK_BUILD_DISCOVER);
  2129. BlUpdateProgressBar(0);
  2130. timeout = RamdiskTimeout;
  2131. for (iRetry = 0; iRetry < RamdiskRetry; iRetry++) {
  2132. //
  2133. // Each Discover gets its own transaction ID.
  2134. //
  2135. discover.XID = ++RamdiskXID;
  2136. //
  2137. // update progress bar. this happens here since a timed out packet
  2138. // might take some time.
  2139. //
  2140. currentProgressPercent = (iRetry * 100) / RamdiskRetry;
  2141. if (forceDisplayFirstTime || (currentProgressPercent != lastProgressPercent)) {
  2142. BlUpdateProgressBar(currentProgressPercent);
  2143. forceDisplayFirstTime = FALSE;
  2144. }
  2145. lastProgressPercent = currentProgressPercent;
  2146. DBGPRINT(INFO, ("Sending discovery packet XID = %d to %u.%u.%u.%u:%u. "
  2147. "Retry %d out of %d. Timeout = %d\n", discover.XID,
  2148. address[0], address[1], address[2], address[3],
  2149. SWAP_WORD(RamdiskBuildPort), iRetry, RamdiskRetry, timeout));
  2150. status = RamdiskSendDiscoverAndWait(&discover, discoverLength, timeout);
  2151. if (status == ESUCCESS) {
  2152. //
  2153. // we found at least one server. we are done.
  2154. //
  2155. BlUpdateProgressBar(100);
  2156. return ESUCCESS;
  2157. }
  2158. //
  2159. // double the timeout, but max out at RAMDISK_MAX_TIMEOUT seconds
  2160. //
  2161. if ((timeout * 2) < RAMDISK_MAX_TIMEOUT) {
  2162. timeout = timeout * 2;
  2163. } else {
  2164. timeout = RAMDISK_MAX_TIMEOUT;
  2165. }
  2166. }
  2167. BlUpdateProgressBar(100);
  2168. return EIO;
  2169. }
  2170. ARC_STATUS
  2171. RamdiskVerifyResponse(
  2172. BMBUILD_RESPONSE_PACKET * Response,
  2173. ULONG ResponseSize,
  2174. ULONG XID
  2175. )
  2176. /*++
  2177. Routine Description:
  2178. This routine will verify that the response packet is valid.
  2179. Arguments:
  2180. Response - the response to validate
  2181. ResponseSize - the size of the response packet
  2182. XID - the XID this packet is supposed to contain
  2183. Return Value:
  2184. ESUCCESS - This packet is valid
  2185. EINVAL - The packet is invalid/misformatted
  2186. --*/
  2187. {
  2188. if (ResponseSize < BMBUILD_RESPONSE_FIXED_PACKET_LENGTH) {
  2189. //
  2190. // Recieved a packet that's too small
  2191. //
  2192. DBGPRINT(ERR, ("RamdiskVerifyResponse: packet size too small, %d\n", ResponseSize));
  2193. return EINVAL;
  2194. } else if ((Response->Version != BMBUILD_PACKET_VERSION) ||
  2195. (Response->OpCode != BMBUILD_OPCODE_RESPONSE) ||
  2196. (Response->XID != XID)) {
  2197. //
  2198. // The packet is corrupt
  2199. //
  2200. DBGPRINT(ERR, ("RamdiskVerifyResponse: expected RESPONSE with XID %d, "
  2201. "received Version %d, OpCode %d, XID %d\n",
  2202. XID, Response->Version, Response->OpCode, Response->XID));
  2203. return EINVAL;
  2204. } else {
  2205. switch (Response->Status) {
  2206. case BMBUILD_S_REQUEST_COMPLETE:
  2207. if ((Response->ImagePathOffset < BMBUILD_RESPONSE_FIXED_PACKET_LENGTH) ||
  2208. (Response->ImagePathLength == 0) ||
  2209. ((ULONG)(Response->ImagePathOffset + Response->ImagePathLength) > ResponseSize)) {
  2210. //
  2211. // The packet is corrupt
  2212. //
  2213. DBGPRINT(ERR, ("RamdiskVerifyResponse: the image path isn't correctly "
  2214. "formatted. ImageOffset = %d, Imagelength = %d, PacketLength = %d.\n",
  2215. Response->ImagePathOffset, Response->ImagePathLength, ResponseSize));
  2216. return EINVAL;
  2217. }
  2218. break;
  2219. case BMBUILD_S_REQUEST_PENDING:
  2220. case BMBUILD_E_WRONGVERSION:
  2221. case BMBUILD_E_BUSY:
  2222. case BMBUILD_E_ACCESSDENIED:
  2223. case BMBUILD_E_ILLEGAL_OPCODE:
  2224. case BMBUILD_E_PRODUCT_NOT_FOUND:
  2225. case BMBUILD_E_BUILD_FAILED:
  2226. case BMBUILD_E_INVALID_PACKET:
  2227. //
  2228. // No specific checks for these status codes
  2229. //
  2230. break;
  2231. default:
  2232. //
  2233. // The packet is corrupt
  2234. //
  2235. DBGPRINT(ERR, ("RamdiskVerifyResponse: unexpected RESPONSE status %d.\n", Response->Status));
  2236. return EINVAL;
  2237. break;
  2238. }
  2239. }
  2240. return ESUCCESS;
  2241. }
  2242. ARC_STATUS
  2243. RamdiskSendRequestAndWait(
  2244. IN BMBUILD_REQUEST_PACKET * Request,
  2245. IN ULONG RequestSize,
  2246. IN ULONG BuilderAddress,
  2247. IN ULONG Timeout,
  2248. IN BMBUILD_RESPONSE_PACKET * Response,
  2249. IN ULONG ResponseSizeMax
  2250. )
  2251. /*++
  2252. Routine Description:
  2253. This routine will send a request packet to the specified server.
  2254. It will wait for the specified timeout period for a reply from
  2255. the server. On successful return, the response parameter will
  2256. contain a valid response.
  2257. Arguments:
  2258. Request - the request packet to send out
  2259. RequestSize - the size of the request packet
  2260. BuilderAddress - the builder server to send the request to
  2261. Timeout - the amount of time to wait for a response, in seconds
  2262. Response - the response packet that should be filled in
  2263. ResponseSizeMax - the maximum size of the response packet
  2264. Return Value:
  2265. ESUCCESS - the response packet was received from the server and is valid
  2266. EIO - we timed out waiting for a response from the server
  2267. EINVAL - we couldn't send the packet to the server
  2268. --*/
  2269. {
  2270. ULONG waitStartTime;
  2271. PUCHAR address = (PUCHAR) &BuilderAddress;
  2272. ULONG length;
  2273. ULONG remoteHost;
  2274. USHORT remotePort;
  2275. ASSERT(Request != NULL);
  2276. ASSERT(RequestSize != 0);
  2277. ASSERT(BuilderAddress != 0);
  2278. ASSERT(BuilderAddress != 0xFFFFFFFF);
  2279. ASSERT(Timeout != 0);
  2280. ASSERT(Response != NULL);
  2281. ASSERT(ResponseSizeMax != 0);
  2282. ASSERT(RamdiskBuildPort != 0);
  2283. //
  2284. // Send the discovery packet to the destination address
  2285. //
  2286. length = RomSendUdpPacket(Request, RequestSize, BuilderAddress, RamdiskBuildPort);
  2287. if (length != RequestSize) {
  2288. DBGPRINT(ERR, ("FAILED to send request packet to %u.%u.%u.%u:%u\n",
  2289. address[0], address[1], address[2], address[3],
  2290. SWAP_WORD(RamdiskBuildPort)));
  2291. return EINVAL;
  2292. }
  2293. DBGPRINT(INFO, ("Waiting for response (Timeout = %d secs).\n", Timeout));
  2294. //
  2295. // Wait for the responses. We will wait for the timeout period and
  2296. // select the best ACCEPT we get within this timeout. The best accept
  2297. // is the one with the lowest build time.
  2298. //
  2299. waitStartTime = SysGetRelativeTime();
  2300. while ((SysGetRelativeTime() - waitStartTime) < Timeout) {
  2301. length = RomReceiveUdpPacket(Response, ResponseSizeMax, 0, &remoteHost, &remotePort);
  2302. if (length != 0) {
  2303. //
  2304. // Make sure the packet is one of the ones we expect.
  2305. //
  2306. if ((BuilderAddress != remoteHost) || (RamdiskBuildPort != remotePort)) {
  2307. PUCHAR bad = (PUCHAR) &remoteHost;
  2308. PUCHAR good = (PUCHAR) &BuilderAddress;
  2309. //
  2310. // Recieved a packet from the wrong server/port
  2311. //
  2312. DBGPRINT(ERR, ("RamdiskSendRequest: received an unexpected packet, "
  2313. "expected %u.%u.%u.%u:%u, received %u.%u.%u.%u:%u\n",
  2314. good[0], good[1], good[2], good[3], SWAP_WORD(RamdiskBuildPort),
  2315. bad[0], bad[1], bad[2], bad[3], SWAP_WORD(remotePort)));
  2316. } else if (RamdiskVerifyResponse(Response, length, Request->XID) == ESUCCESS) {
  2317. PUCHAR good = (PUCHAR) &remoteHost;
  2318. DBGPRINT(INFO, ("Received RESPONSE packet (%d bytes) XID = %d status "
  2319. "= %d from %u.%u.%u.%u:%u.\n", length, Response->XID,
  2320. Response->Status, good[0], good[1], good[2],
  2321. good[3], SWAP_WORD(remotePort)));
  2322. return ESUCCESS;
  2323. }
  2324. }
  2325. }
  2326. address = (PUCHAR) &BuilderAddress;
  2327. DBGPRINT(ERR, ("Timed out waiting for a response from %u.%u.%u.%u:%u "
  2328. "(Timeout = %d secs).\n", address[0], address[1], address[2],
  2329. address[3], SWAP_WORD(RamdiskBuildPort), Timeout));
  2330. //
  2331. // We timed out
  2332. //
  2333. return EIO;
  2334. }
  2335. ARC_STATUS
  2336. RamdiskGetResponse(
  2337. BMBUILD_RESPONSE_PACKET * Response,
  2338. ULONG ResponseSizeMax)
  2339. /*++
  2340. Routine Description:
  2341. This routine will get a response that contains a valid image path and download
  2342. parameter from a server. This routine will use the RamdiskServers list to send
  2343. requests to until it receives a valid response indicating that the image has
  2344. been built. It will use the networking parameters specified in boot.ini.
  2345. Arguments:
  2346. Response - the response packet that should be contain the image path and
  2347. downloading parameters
  2348. ResponseSizeMax - the maximum size of the response packet
  2349. Return Value:
  2350. ESUCCESS - the response packet contains the image path and downloading parameters
  2351. EIO - we timed out waiting for a response from the server
  2352. EINVAL - we couldn't send the packet to the server
  2353. otherwise - something else stopped us from receiving a valid response
  2354. --*/
  2355. {
  2356. ARC_STATUS status;
  2357. BMBUILD_REQUEST_PACKET * request;
  2358. ULONG requestSize;
  2359. USHORT localPort;
  2360. ULONG timeout;
  2361. ULONG iRetry;
  2362. ULONG iServers;
  2363. PUCHAR address;
  2364. ULONG progressMax;
  2365. ULONG lastProgressPercent = 0;
  2366. BOOLEAN forceDisplayFirstTime = TRUE;
  2367. ULONG currentProgressPercent;
  2368. request = BlAllocateHeap(RamdiskMaxPacketSize);
  2369. if (request == NULL) {
  2370. DBGPRINT(ERR, ("Failed to allocate request packet of size %d.\n", RamdiskMaxPacketSize));
  2371. return ENOMEM;
  2372. }
  2373. //
  2374. // Grab an unused port
  2375. //
  2376. localPort = UdpAssignUnicastPort();
  2377. DBGPRINT(INFO, ("Sending builder requests using port %d.\n", SWAP_WORD(localPort)));
  2378. //
  2379. // Build request packet
  2380. //
  2381. status = RamdiskBuildRequest(request, RamdiskMaxPacketSize, &requestSize);
  2382. if (status != ESUCCESS) {
  2383. return status;
  2384. }
  2385. //
  2386. // We will be sending a maximum of RamdiskRetry request packets
  2387. // to RamdiskServerCount servers
  2388. //
  2389. progressMax = RamdiskServerCount * RamdiskRetry;
  2390. //
  2391. // Reset the progress information
  2392. //
  2393. BlOutputStartupMsg(RAMDISK_BUILD_REQUEST);
  2394. BlUpdateProgressBar(0);
  2395. DBGPRINT(INFO, ("Requesting appropriate image for this computer...\n"));
  2396. for (iServers = 0; iServers < RamdiskServerCount; iServers++) {
  2397. //
  2398. // Set our initial time out
  2399. //
  2400. timeout = RamdiskTimeout;
  2401. RamdiskPrintBuildProgress(RAMDISK_BUILD_PROGRESS, RamdiskServers[iServers]);
  2402. for (iRetry = 0; iRetry < RamdiskRetry; iRetry++) {
  2403. //
  2404. // allocate a new transaction ID for this session
  2405. //
  2406. request->XID = ++RamdiskXID;
  2407. //
  2408. // update progress bar. this happens here since a timed out packet
  2409. // might take some time.
  2410. //
  2411. currentProgressPercent = ((iServers * RamdiskRetry + iRetry) * 100) / progressMax;
  2412. if (forceDisplayFirstTime || (currentProgressPercent != lastProgressPercent)) {
  2413. BlUpdateProgressBar(currentProgressPercent);
  2414. forceDisplayFirstTime = FALSE;
  2415. }
  2416. lastProgressPercent = currentProgressPercent;
  2417. address = (PUCHAR) &(RamdiskServers[iServers]);
  2418. DBGPRINT(INFO, ("Sending request packet XID = %d to %u.%u.%u.%u:%u. "
  2419. "Retry %d out of %d. Timeout = %d\n", request->XID,
  2420. address[0], address[1], address[2], address[3],
  2421. SWAP_WORD(RamdiskBuildPort), iRetry, RamdiskRetry, timeout));
  2422. status = RamdiskSendRequestAndWait(request, requestSize, RamdiskServers[iServers],
  2423. timeout, Response, ResponseSizeMax);
  2424. if (status == ESUCCESS) {
  2425. //
  2426. // Now that we have a valid response, check to see what we are
  2427. // supposed to do with it. We assume that any validation was
  2428. // already done in RamdiskSendRequestAndWait
  2429. //
  2430. address = (PUCHAR) &(RamdiskServers[iServers]);
  2431. if (Response->Status == BMBUILD_S_REQUEST_COMPLETE) {
  2432. DBGPRINT(INFO, ("Request is complete from server %u.%u.%u.%u:%u.\n",
  2433. address[0], address[1], address[2], address[3],
  2434. SWAP_WORD(RamdiskBuildPort)));
  2435. BlUpdateProgressBar(100);
  2436. return ESUCCESS;
  2437. } else if (Response->Status == BMBUILD_S_REQUEST_PENDING) {
  2438. DBGPRINT(INFO, ("Request is pending. Instructed to wait for %d secs "
  2439. "by server %u.%u.%u.%u:%u.\n", Response->WaitTime,
  2440. address[0], address[1], address[2], address[3],
  2441. SWAP_WORD(RamdiskBuildPort)));
  2442. RamdiskPrintBuildProgress(RAMDISK_BUILD_PROGRESS_PENDING, RamdiskServers[iServers]);
  2443. RamdiskWait(Response->WaitTime);
  2444. } else if (Response->Status == BMBUILD_E_BUSY) {
  2445. DBGPRINT(INFO, ("Server %u.%u.%u.%u:%u is busy. Waiting for %d secs.\n",
  2446. address[0], address[1], address[2], address[3],
  2447. SWAP_WORD(RamdiskBuildPort), RamdiskTimeout));
  2448. RamdiskPrintBuildProgress(RAMDISK_BUILD_PROGRESS_ERROR, RamdiskServers[iServers]);
  2449. RamdiskWait(RAMDISK_UI_WAIT);
  2450. } else {
  2451. RamdiskPrintBuildProgress(RAMDISK_BUILD_PROGRESS_ERROR, RamdiskServers[iServers]);
  2452. RamdiskWait(RAMDISK_UI_WAIT);
  2453. //
  2454. // Try a different server
  2455. //
  2456. break;
  2457. }
  2458. } else if (status == EIO) {
  2459. RamdiskPrintBuildProgress(RAMDISK_BUILD_PROGRESS_TIMEOUT, RamdiskServers[iServers]);
  2460. RamdiskWait(RAMDISK_UI_WAIT);
  2461. //
  2462. // double the timeout, but max out at RAMDISK_MAX_TIMEOUT seconds
  2463. //
  2464. if ((timeout * 2) < RAMDISK_MAX_TIMEOUT) {
  2465. timeout = timeout * 2;
  2466. } else {
  2467. timeout = RAMDISK_MAX_TIMEOUT;
  2468. }
  2469. } else {
  2470. RamdiskPrintBuildProgress(RAMDISK_BUILD_PROGRESS_ERROR, RamdiskServers[iServers]);
  2471. RamdiskWait(RAMDISK_UI_WAIT);
  2472. //
  2473. // Try a different server
  2474. //
  2475. break;
  2476. }
  2477. }
  2478. }
  2479. //
  2480. // We completely timed out
  2481. //
  2482. BlUpdateProgressBar(100);
  2483. return EIO;
  2484. }
  2485. ARC_STATUS
  2486. RamdiskBuildAndInitialize(
  2487. )
  2488. /*++
  2489. Routine Description:
  2490. This routine will communicate with a build server to build
  2491. a ramdisk and obtain a RDPATH.
  2492. Arguments:
  2493. Return Value:
  2494. ESUCCESS - image was successfully built and we have a valid RDPATH
  2495. !ESUCCESS - we failed to build the image
  2496. --*/
  2497. {
  2498. ARC_STATUS status;
  2499. PBMBUILD_RESPONSE_PACKET response = NULL;
  2500. PUCHAR imagePath;
  2501. PUCHAR address;
  2502. //
  2503. // Set the max packet size. This is calculated from the
  2504. // MTU size of the network (1500 for Ethernet) minus
  2505. // the IP and UDP headers ( which account to 28 bytes ).
  2506. //
  2507. RamdiskMaxPacketSize = NetMaxTranUnit - 28;
  2508. ASSERT(RamdiskMaxPacketSize > 0);
  2509. response = BlAllocateHeap(RamdiskMaxPacketSize);
  2510. if (response == NULL) {
  2511. DBGPRINT(ERR, ("Failed to allocate response packet of size %d.\n", RamdiskMaxPacketSize));
  2512. return ENOMEM;
  2513. }
  2514. RtlZeroMemory(response, RamdiskMaxPacketSize);
  2515. //
  2516. // Discover build server
  2517. //
  2518. status = RamdiskDiscoverBuildServer();
  2519. if (status != ESUCCESS) {
  2520. goto Error;
  2521. }
  2522. //
  2523. // Get the response from the build server
  2524. //
  2525. status = RamdiskGetResponse(response, RamdiskMaxPacketSize);
  2526. if (status != ESUCCESS) {
  2527. goto Error;
  2528. }
  2529. ASSERT (RamdiskPath == NULL);
  2530. //
  2531. // Set the MTFTP options
  2532. //
  2533. RamdiskTFTPAddr = response->TFTPAddr.Address;
  2534. RamdiskMTFTPAddr = response->MTFTPAddr.Address;
  2535. RamdiskMTFTPCPort = response->MTFTPCPort;
  2536. RamdiskMTFTPSPort = response->MTFTPSPort;
  2537. RamdiskMTFTPTimeout = response->MTFTPTimeout;
  2538. RamdiskMTFTPDelay = response->MTFTPDelay;
  2539. RamdiskMTFTPFileSize = response->MTFTPFileSize;
  2540. RamdiskMTFTPChunkSize = response->MTFTPChunkSize;
  2541. //
  2542. // Set the image offset and length
  2543. //
  2544. RamdiskImageOffset = response->ImageFileOffset;
  2545. RamdiskImageLength = response->ImageFileSize;
  2546. imagePath = (PUCHAR)((ULONG_PTR)response + response->ImagePathOffset);
  2547. RamdiskPath = BlAllocateHeap(response->ImagePathLength + sizeof("net(0)\\"));
  2548. if (RamdiskPath == NULL) {
  2549. DBGPRINT(ERR, ("Failed to allocate memory for RamdiskPath size %d.\n",
  2550. response->ImagePathLength + sizeof("net(0)\\")));
  2551. return ENOMEM;
  2552. }
  2553. strcpy(RamdiskPath, "net(0)\\");
  2554. memcpy(RamdiskPath + sizeof("net(0)\\") - 1, imagePath, response->ImagePathLength);
  2555. RamdiskPath[sizeof("net(0)\\") + response->ImagePathLength - 1] = '\0';
  2556. if (DBGLVL(INFO)) {
  2557. DbgPrint("RDPATH = %s\n", RamdiskPath);
  2558. address = (PUCHAR) &RamdiskTFTPAddr;
  2559. DbgPrint("RDTFTPADDR = %u.%u.%u.%u\n", address[0], address[1], address[2], address[3]);
  2560. address = (PUCHAR) &RamdiskMTFTPAddr;
  2561. DbgPrint("RDMTFTPADDR = %u.%u.%u.%u\n", address[0], address[1], address[2], address[3]);
  2562. DbgPrint("RDMTFTPCPORT = %d\n", SWAP_WORD( RamdiskMTFTPCPort));
  2563. DbgPrint("RDMTFTPSPORT = %d\n", SWAP_WORD( RamdiskMTFTPSPort));
  2564. DbgPrint("RDMTFTPDELAY = %d\n", RamdiskMTFTPDelay);
  2565. DbgPrint("RDMTFTPTIMEOUT = %d\n", RamdiskMTFTPTimeout);
  2566. DbgPrint("RDFILESIZE = 0x%0I64x bytes\n", RamdiskMTFTPFileSize);
  2567. DbgPrint("RDCHUNKSIZE = 0x%0I64x bytes\n", RamdiskMTFTPChunkSize);
  2568. DbgPrint("RDIMAGEOFFSET = 0x%x bytes\n", RamdiskImageOffset);
  2569. DbgPrint("RDIMAGELENGTH = 0x%0I64x bytes\n", RamdiskImageLength);
  2570. }
  2571. return ESUCCESS;
  2572. Error:
  2573. DBGPRINT(ERR, ("RamdiskBuildAndInitialize: Failed, %d.\n", status));
  2574. //
  2575. // We should be rebooting the machine here
  2576. //
  2577. return status;
  2578. }
  2579. #endif
  2580. VOID
  2581. RamdiskFatalError(
  2582. IN ULONG Message1,
  2583. IN ULONG Message2
  2584. )
  2585. /*++
  2586. Routine Description:
  2587. This function looks up a message to display at a error condition.
  2588. Arguments:
  2589. Message - message that describes the class of problem.
  2590. Return Value:
  2591. none
  2592. --*/
  2593. {
  2594. PTCHAR Text;
  2595. TCHAR Buffer[40];
  2596. ULONG Count;
  2597. BlClearScreen();
  2598. Text = BlFindMessage(Message1);
  2599. if (Text == NULL) {
  2600. _stprintf(Buffer,TEXT("%08lx\r\n"),Message1);
  2601. Text = Buffer;
  2602. }
  2603. ArcWrite(BlConsoleOutDeviceId,
  2604. Text,
  2605. (ULONG)_tcslen(Text)*sizeof(TCHAR),
  2606. &Count);
  2607. Text = BlFindMessage(Message2);
  2608. if (Text == NULL) {
  2609. _stprintf(Buffer,TEXT("%08lx\r\n"),Message2);
  2610. Text = Buffer;
  2611. }
  2612. ArcWrite(BlConsoleOutDeviceId,
  2613. Text,
  2614. (ULONG)_tcslen(Text)*sizeof(TCHAR),
  2615. &Count);
  2616. #if defined(ENABLE_LOADER_DEBUG) || DBG
  2617. #if (defined(_X86_) || defined(_ALPHA_) || defined(_IA64_)) && !defined(ARCI386) // everything but ARCI386
  2618. if(BdDebuggerEnabled) {
  2619. DbgBreakPoint();
  2620. }
  2621. #endif
  2622. #endif
  2623. return;
  2624. }
  2625. #if defined(_X86_)
  2626. VOID
  2627. RamdiskSdiBoot(
  2628. IN PCHAR SdiFile
  2629. )
  2630. {
  2631. ARC_STATUS status;
  2632. PSDI_HEADER sdiHeader;
  2633. PUCHAR startromAddress;
  2634. ULONG startromLength;
  2635. BOOLEAN OldShowProgressBar;
  2636. LONGLONG availableLength;
  2637. //
  2638. // Read the SDI image into memory.
  2639. //
  2640. RamdiskTFTPAddr = NetServerIpAddress;
  2641. RamdiskImageOffset = 0;
  2642. RamdiskImageLength = 0;
  2643. OldShowProgressBar = BlShowProgressBar;
  2644. BlShowProgressBar = TRUE;
  2645. status = RamdiskReadImage( SdiFile );
  2646. if ( status != ESUCCESS ) {
  2647. RamdiskFatalError( RAMDISK_GENERAL_FAILURE,
  2648. RAMDISK_BOOT_FAILURE );
  2649. return;
  2650. }
  2651. BlShowProgressBar = OldShowProgressBar;
  2652. //
  2653. // Copy startrom.com from the SDI image to 0x7c00.
  2654. //
  2655. sdiHeader = MapRamdisk( 0, &availableLength );
  2656. ASSERT( availableLength >= sizeof(SDI_HEADER) );
  2657. ASSERT( availableLength >=
  2658. (sdiHeader->liBootCodeOffset.QuadPart + sdiHeader->liBootCodeSize.QuadPart) );
  2659. ASSERT( sdiHeader->liBootCodeOffset.HighPart == 0 );
  2660. ASSERT( sdiHeader->liBootCodeSize.HighPart == 0 );
  2661. startromAddress = (PUCHAR)sdiHeader + sdiHeader->liBootCodeOffset.LowPart;
  2662. startromLength = sdiHeader->liBootCodeSize.LowPart;
  2663. RtlMoveMemory( (PVOID)0x7c00, startromAddress, startromLength );
  2664. //
  2665. // Shut down PXE.
  2666. //
  2667. if ( BlBootingFromNet ) {
  2668. NetTerminate();
  2669. }
  2670. //
  2671. // Inform boot debugger that the boot phase is complete.
  2672. //
  2673. #if defined(ENABLE_LOADER_DEBUG) || DBG
  2674. #if (defined(_X86_) || defined(_ALPHA_)) && !defined(ARCI386)
  2675. {
  2676. if (BdDebuggerEnabled == TRUE) {
  2677. DbgUnLoadImageSymbols(NULL, (PVOID)-1, 0);
  2678. }
  2679. }
  2680. #endif
  2681. #endif
  2682. REBOOT( (ULONG)sdiHeader | 3 );
  2683. return;
  2684. }
  2685. #endif