Source code of Windows XP (NT5)
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.

1031 lines
26 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. net.c
  5. Abstract:
  6. This module implements the net boot file system used by the operating
  7. system loader.
  8. It only contains those functions which are firmware/BIOS dependent.
  9. Author:
  10. Revision History:
  11. --*/
  12. #include "..\bootlib.h"
  13. #include "stdio.h"
  14. #ifdef UINT16
  15. #undef UINT16
  16. #endif
  17. #ifdef INT16
  18. #undef INT16
  19. #endif
  20. #include <dhcp.h>
  21. #include <netfs.h>
  22. #include <pxe_cmn.h>
  23. #include <pxe_api.h>
  24. #include <udp_api.h>
  25. #include <tftp_api.h>
  26. #include "bldr.h"
  27. #include "bootia64.h"
  28. #include "efi.h"
  29. #include "efip.h"
  30. #include "bldria64.h"
  31. #include "extern.h"
  32. #include "smbios.h"
  33. #ifndef BOOL
  34. typedef int BOOL;
  35. #endif
  36. #ifndef FALSE
  37. #define FALSE 0
  38. #endif
  39. #ifndef TRUE
  40. #define TRUE 1
  41. #endif
  42. #ifndef BYTE
  43. typedef unsigned char BYTE;
  44. #endif
  45. #ifndef LPBYTE
  46. typedef BYTE *LPBYTE;
  47. #endif
  48. #define MAX_PATH 260
  49. //
  50. // Define global data.
  51. //
  52. CHAR NetBootPath[129];
  53. EFI_PXE_BASE_CODE *PXEClient;
  54. EFI_HANDLE PXEHandle;
  55. ULONG NetLocalIpAddress;
  56. ULONG NetLocalSubnetMask;
  57. ULONG NetServerIpAddress;
  58. ULONG NetGatewayIpAddress;
  59. UCHAR NetLocalHardwareAddress[16];
  60. UCHAR MyGuid[16];
  61. ULONG MyGuidLength = sizeof(MyGuid);
  62. BOOLEAN MyGuidValid = FALSE;
  63. TFTP_RESTART_BLOCK gTFTPRestartBlock;
  64. VOID
  65. EfiDumpBuffer(
  66. PVOID Buffer,
  67. ULONG BufferSize
  68. )
  69. /*++
  70. Routine Description:
  71. Dumps the buffer content on to the debugger output.
  72. Arguments:
  73. Buffer: buffer pointer.
  74. BufferSize: size of the buffer.
  75. Return Value:
  76. none
  77. --*/
  78. {
  79. #define NUM_CHARS 16
  80. ULONG i, limit;
  81. CHAR TextBuffer[NUM_CHARS + 1];
  82. PUCHAR BufferPtr = Buffer;
  83. BlPrint(TEXT("------------------------------------\r\n"));
  84. //
  85. // Hex dump of the bytes
  86. //
  87. limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
  88. for (i = 0; i < limit; i++) {
  89. if (i < BufferSize) {
  90. BlPrint(TEXT("%x "), (UCHAR)BufferPtr[i]);
  91. if (BufferPtr[i] < 31 ) {
  92. TextBuffer[i % NUM_CHARS] = '.';
  93. } else if (BufferPtr[i] == '\0') {
  94. TextBuffer[i % NUM_CHARS] = ' ';
  95. } else {
  96. TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i];
  97. }
  98. } else {
  99. BlPrint(TEXT(" "));
  100. TextBuffer[i % NUM_CHARS] = ' ';
  101. }
  102. if ((i + 1) % NUM_CHARS == 0) {
  103. TextBuffer[NUM_CHARS] = 0;
  104. BlPrint(TEXT(" %s\r\n"), TextBuffer);
  105. }
  106. }
  107. BlPrint(TEXT("------------------------------------\r\n"));
  108. #if 0
  109. //
  110. // enable this to make it pause after dumping the buffer.
  111. //
  112. DBG_EFI_PAUSE();
  113. #endif
  114. }
  115. ARC_STATUS
  116. GetParametersFromRom (
  117. VOID
  118. )
  119. {
  120. UINTN BufferSize = sizeof(EFI_HANDLE);
  121. INTN Count = 0;
  122. EFI_GUID PXEGuid = EFI_PXE_BASE_CODE_PROTOCOL;
  123. UINT16 layer = 0;
  124. EFI_STATUS Status = EFI_UNSUPPORTED;
  125. PUCHAR p;
  126. //
  127. // Get a pointer to all the PXE APIs.
  128. //
  129. FlipToPhysical();
  130. Status = EfiST->BootServices->LocateHandle( ByProtocol,
  131. &PXEGuid,
  132. NULL,
  133. &BufferSize,
  134. &PXEHandle );
  135. FlipToVirtual();
  136. if( Status != EFI_SUCCESS ) {
  137. if( BdDebuggerEnabled ) {
  138. DbgPrint( "GetParametersFromRom: LocateHandle failed (%d)\n", Status);
  139. }
  140. return (ARC_STATUS)Status;
  141. }
  142. FlipToPhysical();
  143. Status = EfiST->BootServices->HandleProtocol( PXEHandle,
  144. &PXEGuid,
  145. &PXEClient );
  146. FlipToVirtual();
  147. if( Status != EFI_SUCCESS ) {
  148. if( BdDebuggerEnabled ) {
  149. DbgPrint( "GetParametersFromRom: HandleProtocol failed (%d)\n", Status);
  150. }
  151. return (ARC_STATUS)Status;
  152. }
  153. //
  154. // Our IP address is down in:
  155. // PXEClient->Mode->StationIp.v4
  156. //
  157. // The server's IP address is down in:
  158. // PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr
  159. //
  160. // Our NIC's GUID should be down in:
  161. // PXEClient->Mode->ProxyOffer.Dhcpv4.BootpHwAddr
  162. //
  163. NetServerIpAddress = 0;
  164. NetLocalIpAddress = 0;
  165. for( Count = 0; Count < 4; Count++ ) {
  166. NetServerIpAddress = (NetServerIpAddress << 8) + PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr[Count];
  167. NetLocalIpAddress = (NetLocalIpAddress << 8) + PXEClient->Mode->StationIp.v4.Addr[Count];
  168. }
  169. memcpy( NetLocalHardwareAddress, PXEClient->Mode->ProxyOffer.Dhcpv4.BootpHwAddr, sizeof(NetLocalHardwareAddress) );
  170. //
  171. // Get the path where we were launched from. We what to remove the
  172. // actual file name (oschoice.efi in this case), but leave that trailing
  173. // '\'.
  174. //
  175. strcpy( NetBootPath, PXEClient->Mode->ProxyOffer.Dhcpv4.BootpBootFile );
  176. p = strrchr( NetBootPath, '\\' );
  177. if( p ) {
  178. p++;
  179. *p = '\0';
  180. }
  181. return ESUCCESS;
  182. }
  183. VOID
  184. EfiNetTerminate(
  185. VOID
  186. )
  187. {
  188. FlipToPhysical();
  189. PXEClient->Stop( PXEClient );
  190. FlipToVirtual();
  191. }
  192. VOID
  193. GetGuid(
  194. OUT PUCHAR *Guid,
  195. OUT PULONG GuidLength
  196. )
  197. /*++
  198. Routine Description:
  199. This routine returns the Guid of this machine.
  200. Arguments:
  201. Guid - Place to store pointer to the guid.
  202. GuidLength - Place to store the length in bytes of the guid.
  203. Return Value:
  204. None.
  205. --*/
  206. {
  207. PSMBIOS_SYSTEM_INFORMATION_STRUCT SystemInfoHeader = NULL;
  208. *Guid = NULL;
  209. *GuidLength = 0;
  210. SystemInfoHeader = (PSMBIOS_SYSTEM_INFORMATION_STRUCT)FindSMBIOSTable( SMBIOS_SYSTEM_INFORMATION );
  211. if( SystemInfoHeader ) {
  212. if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed Alloc.\r\n" ); }
  213. *Guid = (PUCHAR)BlAllocateHeap( SYSID_UUID_DATA_SIZE );
  214. if( *Guid ) {
  215. *GuidLength = SYSID_UUID_DATA_SIZE;
  216. RtlCopyMemory( *Guid,
  217. SystemInfoHeader->Uuid,
  218. SYSID_UUID_DATA_SIZE );
  219. } else {
  220. if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed Alloc.\r\n" ); }
  221. *GuidLength = 0;
  222. }
  223. } else {
  224. if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed to find a SMBIOS_SYSTEM_INFORMATION table.\n" ); }
  225. }
  226. }
  227. ULONG
  228. CalculateChecksum(
  229. IN PLONG Block,
  230. IN ULONG Length
  231. )
  232. /*++
  233. Routine Description:
  234. This routine calculates a simple two's-complement checksum of a block of
  235. memory. If the returned value is stored in the block (in a word that was
  236. zero during the calculation), then new checksum of the block will be zero.
  237. Arguments:
  238. Block - Address of a block of data. Must be 4-byte aligned.
  239. Length - Length of the block. Must be a multiple of 4.
  240. Return Value:
  241. ULONG - Two's complement additive checksum of the input block.
  242. --*/
  243. {
  244. LONG checksum = 0;
  245. ASSERT( ((ULONG_PTR)Block & 3) == 0 );
  246. ASSERT( (Length & 3) == 0 );
  247. for ( ; Length != 0; Length -= 4 ) {
  248. checksum += *Block;
  249. Block++;
  250. }
  251. return -checksum;
  252. }
  253. UINTN
  254. DevicePathSize (
  255. IN EFI_DEVICE_PATH *DevPath
  256. )
  257. {
  258. EFI_DEVICE_PATH *Start;
  259. /*
  260. * Search for the end of the device path structure
  261. * */
  262. Start = DevPath;
  263. while (!IsDevicePathEnd(DevPath)) {
  264. DevPath = NextDevicePathNode(DevPath);
  265. }
  266. /*
  267. * Compute the size
  268. */
  269. return ((UINTN) DevPath - (UINTN) Start) + sizeof(EFI_DEVICE_PATH);
  270. }
  271. EFI_DEVICE_PATH *
  272. DevicePathInstance (
  273. IN OUT EFI_DEVICE_PATH **DevicePath,
  274. OUT UINTN *Size
  275. )
  276. {
  277. EFI_DEVICE_PATH *Start, *Next, *DevPath;
  278. UINTN Count;
  279. DevPath = *DevicePath;
  280. Start = DevPath;
  281. if (!DevPath) {
  282. return NULL;
  283. }
  284. /*
  285. * Check for end of device path type
  286. * */
  287. for (Count = 0; ; Count++) {
  288. Next = NextDevicePathNode(DevPath);
  289. if (IsDevicePathEndType(DevPath)) {
  290. break;
  291. }
  292. if (Count > 01000) {
  293. break;
  294. }
  295. DevPath = Next;
  296. }
  297. ASSERT (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE ||
  298. DevicePathSubType(DevPath) == END_INSTANCE_DEVICE_PATH_SUBTYPE);
  299. /*
  300. * Set next position
  301. */
  302. if (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
  303. Next = NULL;
  304. }
  305. *DevicePath = Next;
  306. /*
  307. * Return size and start of device path instance
  308. */
  309. *Size = ((UINT8 *) DevPath) - ((UINT8 *) Start);
  310. return Start;
  311. }
  312. UINTN
  313. DevicePathInstanceCount (
  314. IN EFI_DEVICE_PATH *DevicePath
  315. )
  316. {
  317. UINTN Count, Size;
  318. Count = 0;
  319. while (DevicePathInstance(&DevicePath, &Size)) {
  320. Count += 1;
  321. }
  322. return Count;
  323. }
  324. EFI_DEVICE_PATH *
  325. AppendDevicePath (
  326. IN EFI_DEVICE_PATH *Src1,
  327. IN EFI_DEVICE_PATH *Src2
  328. )
  329. /* Src1 may have multiple "instances" and each instance is appended
  330. * Src2 is appended to each instance is Src1. (E.g., it's possible
  331. * to append a new instance to the complete device path by passing
  332. * it in Src2) */
  333. {
  334. UINTN Src1Size, Src1Inst, Src2Size, Size;
  335. EFI_DEVICE_PATH *Dst, *Inst;
  336. UINT8 *DstPos;
  337. EFI_DEVICE_PATH EndInstanceDevicePath[] = { END_DEVICE_PATH_TYPE,
  338. END_INSTANCE_DEVICE_PATH_SUBTYPE,
  339. END_DEVICE_PATH_LENGTH,
  340. 0 };
  341. EFI_DEVICE_PATH EndDevicePath[] = { END_DEVICE_PATH_TYPE,
  342. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  343. END_DEVICE_PATH_LENGTH,
  344. 0 };
  345. Src1Size = DevicePathSize(Src1);
  346. Src1Inst = DevicePathInstanceCount(Src1);
  347. Src2Size = DevicePathSize(Src2);
  348. Size = Src1Size * Src1Inst + Src2Size;
  349. EfiST->BootServices->AllocatePool( EfiLoaderData,
  350. Size,
  351. (VOID **) &Dst );
  352. if (Dst) {
  353. DstPos = (UINT8 *) Dst;
  354. /*
  355. * Copy all device path instances
  356. */
  357. while (Inst = DevicePathInstance (&Src1, &Size)) {
  358. RtlCopyMemory(DstPos, Inst, Size);
  359. DstPos += Size;
  360. RtlCopyMemory(DstPos, Src2, Src2Size);
  361. DstPos += Src2Size;
  362. RtlCopyMemory(DstPos, EndInstanceDevicePath, sizeof(EFI_DEVICE_PATH));
  363. DstPos += sizeof(EFI_DEVICE_PATH);
  364. }
  365. /* Change last end marker */
  366. DstPos -= sizeof(EFI_DEVICE_PATH);
  367. RtlCopyMemory(DstPos, EndDevicePath, sizeof(EFI_DEVICE_PATH));
  368. }
  369. return Dst;
  370. }
  371. NTSTATUS
  372. NetSoftReboot(
  373. IN PUCHAR NextBootFile,
  374. IN ULONGLONG Param,
  375. IN PUCHAR RebootFile OPTIONAL,
  376. IN PUCHAR SifFile OPTIONAL,
  377. IN PUCHAR User OPTIONAL,
  378. IN PUCHAR Domain OPTIONAL,
  379. IN PUCHAR Password OPTIONAL,
  380. IN PUCHAR AdministratorPassword OPTIONAL
  381. )
  382. /*++
  383. Routine Description:
  384. This routine will load the specified file, build a parameter
  385. list and transfer control to the loaded file.
  386. Arguments:
  387. NextBootFile - Fully qualified path name of the file to download.
  388. Param - Reboot parameter to set.
  389. RebootFile - String identifying the file to reboot to when after the current reboot is done.
  390. SifFile - Optional SIF file to pass to the next loader.
  391. User/Domain/Password/AdministratorPassword - Optional credentials to pass to the next loader.
  392. Return Value:
  393. Should not return if successful.
  394. --*/
  395. {
  396. NTSTATUS Status = STATUS_SUCCESS;
  397. EFI_DEVICE_PATH *ldrDevicePath = NULL, *Eop = NULL;
  398. EFI_HANDLE ImageHandle = NULL;
  399. UINTN i = 0;
  400. EFI_STATUS EfiStatus = EFI_SUCCESS;
  401. WCHAR WideNextBootFile[MAX_PATH];
  402. FILEPATH_DEVICE_PATH *FilePath = NULL;
  403. UNICODE_STRING uString;
  404. ANSI_STRING aString;
  405. EFI_GUID EfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
  406. EFI_GUID EfiDevicePathProtocol = DEVICE_PATH_PROTOCOL;
  407. EFI_LOADED_IMAGE *OriginalEfiImageInfo = NULL;
  408. EFI_LOADED_IMAGE *LoadedEfiImageInfo = NULL;
  409. EFI_DEVICE_PATH *OriginalEfiDevicePath = NULL;
  410. PTFTP_RESTART_BLOCK restartBlock = NULL;
  411. PTFTP_RESTART_BLOCK_V1 restartBlockV1 = NULL;
  412. ULONG BootFileId = 0;
  413. PUCHAR LoadedImageAddress = NULL;
  414. ULONG LoadedImageSize = 0;
  415. //
  416. // Load the file we want to boot into memory.
  417. //
  418. Status = BlOpen( NET_DEVICE_ID,
  419. NextBootFile,
  420. ArcOpenReadOnly,
  421. &BootFileId );
  422. if (Status != ESUCCESS) {
  423. return Status;
  424. }
  425. //
  426. // What memory address did he get loaded into?
  427. //
  428. LoadedImageAddress = BlFileTable[BootFileId].u.NetFileContext.InMemoryCopy;
  429. LoadedImageSize = BlFileTable[BootFileId].u.NetFileContext.FileSize;
  430. //
  431. // BUild a device path to the target file. We'll do this by gathering
  432. // some information about ourselves, knowing that we're about to load/launch
  433. // an image from the server, just like where we came from.
  434. //
  435. //
  436. // Get image information on ourselves.
  437. //
  438. FlipToPhysical();
  439. EfiStatus = EfiST->BootServices->HandleProtocol( EfiImageHandle,
  440. &EfiLoadedImageProtocol,
  441. &OriginalEfiImageInfo );
  442. FlipToVirtual();
  443. if( EFI_ERROR(EfiStatus) ) {
  444. if( BdDebuggerEnabled ) {
  445. DbgPrint( "NetSoftReboot: HandleProtocol_1 failed (%d)\n", EfiStatus );
  446. }
  447. return STATUS_INSUFFICIENT_RESOURCES;
  448. }
  449. //
  450. // Get our DevicePath too.
  451. //
  452. FlipToPhysical();
  453. EfiStatus = EfiST->BootServices->HandleProtocol( OriginalEfiImageInfo->DeviceHandle,
  454. &EfiDevicePathProtocol,
  455. &OriginalEfiDevicePath );
  456. FlipToVirtual();
  457. if( EFI_ERROR(EfiStatus) ) {
  458. if( BdDebuggerEnabled ) {
  459. DbgPrint( "NetSoftReboot: HandleProtocol_2 failed (%d)\n", EfiStatus );
  460. }
  461. return STATUS_INSUFFICIENT_RESOURCES;
  462. }
  463. //
  464. // Now build a device path based on the DeviceHandle of ourselves, along
  465. // with the path to the image we want to load.
  466. //
  467. RtlInitString( &aString, NextBootFile );
  468. uString.MaximumLength = MAX_PATH;
  469. uString.Buffer = WideNextBootFile;
  470. RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
  471. i = wcslen(uString.Buffer);
  472. FlipToPhysical();
  473. EfiStatus = EfiST->BootServices->AllocatePool( EfiLoaderData,
  474. i + sizeof(FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH),
  475. (VOID **) &FilePath );
  476. FlipToVirtual();
  477. if( EFI_ERROR(EfiStatus) ) {
  478. if( BdDebuggerEnabled ) {
  479. DbgPrint( "NetSoftReboot: AllocatePool_1 failed (%d)\n", EfiStatus );
  480. }
  481. return STATUS_NO_MEMORY;
  482. }
  483. FilePath->Header.Type = MEDIA_DEVICE_PATH;
  484. FilePath->Header.SubType = MEDIA_FILEPATH_DP;
  485. SetDevicePathNodeLength (&FilePath->Header, i + sizeof(FILEPATH_DEVICE_PATH));
  486. RtlCopyMemory (FilePath->PathName, uString.Buffer, i);
  487. FlipToPhysical();
  488. Eop = NextDevicePathNode(&FilePath->Header);
  489. SetDevicePathEndNode(Eop);
  490. //
  491. // Append file path to device's device path
  492. //
  493. ldrDevicePath = (EFI_DEVICE_PATH *)FilePath;
  494. ldrDevicePath = AppendDevicePath ( OriginalEfiDevicePath,
  495. ldrDevicePath );
  496. FlipToVirtual();
  497. //
  498. // Load the image, then set its loadoptions in preparation
  499. // for launching it.
  500. //
  501. if( BdDebuggerEnabled ) {
  502. DbgPrint( "NetSoftReboot: About to LoadImage.\n" );
  503. }
  504. FlipToPhysical();
  505. EfiStatus = EfiST->BootServices->LoadImage( FALSE,
  506. EfiImageHandle,
  507. ldrDevicePath,
  508. LoadedImageAddress,
  509. LoadedImageSize,
  510. &ImageHandle );
  511. FlipToVirtual();
  512. if( EFI_ERROR(EfiStatus) ) {
  513. if( BdDebuggerEnabled ) {
  514. DbgPrint( "NetSoftReboot: LoadImage failed (%d)\n", EfiStatus );
  515. }
  516. return STATUS_NO_MEMORY;
  517. } else {
  518. if( BdDebuggerEnabled ) {
  519. DbgPrint( "NetSoftReboot: LoadImage worked (%d)\n", EfiStatus );
  520. }
  521. }
  522. //
  523. // allocate a chunk of memory, then load it up w/ all the boot options.
  524. //
  525. FlipToPhysical();
  526. EfiStatus = EfiST->BootServices->AllocatePool( EfiLoaderData,
  527. sizeof(TFTP_RESTART_BLOCK),
  528. (VOID **) &restartBlock );
  529. FlipToVirtual();
  530. restartBlockV1 = (PTFTP_RESTART_BLOCK_V1)(&restartBlock->RestartBlockV1);
  531. BlSetHeadlessRestartBlock(restartBlock);
  532. if (AdministratorPassword) {
  533. RtlMoveMemory(restartBlock->AdministratorPassword,AdministratorPassword, OSC_ADMIN_PASSWORD_LEN);
  534. }
  535. restartBlockV1->RebootParameter = Param;
  536. if (RebootFile != NULL) {
  537. strcpy(restartBlockV1->RebootFile, RebootFile);
  538. }
  539. if (SifFile != NULL) {
  540. strcpy(restartBlockV1->SifFile, SifFile);
  541. }
  542. if (User != NULL) {
  543. strcpy(restartBlockV1->User, User);
  544. }
  545. if (Domain != NULL) {
  546. strcpy(restartBlockV1->Domain, Domain);
  547. }
  548. if (Password != NULL) {
  549. strcpy(restartBlockV1->Password, Password);
  550. }
  551. //
  552. // Set the tag in the restart block and calculate and store the checksum.
  553. //
  554. restartBlockV1->Tag = 'rtsR';
  555. restartBlockV1->Checksum = CalculateChecksum((PLONG)(restartBlockV1), 128);
  556. //
  557. // For all versions of RIS after NT5.0 we have a new datastructure which is
  558. // more adaptable for the future. For this section we have a different checksum,
  559. // do that now.
  560. //
  561. restartBlock->TftpRestartBlockVersion = TFTP_RESTART_BLOCK_VERSION;
  562. restartBlock->NewCheckSumLength = sizeof(TFTP_RESTART_BLOCK);
  563. restartBlock->NewCheckSum = CalculateChecksum((PLONG)restartBlock,
  564. restartBlock->NewCheckSumLength);
  565. //
  566. // We've got the command-line options all setup. Now we need to
  567. // actually put them into ImageInfo->LoadOptions so they get
  568. // passed to the loaded image.
  569. //
  570. if( BdDebuggerEnabled ) {
  571. DbgPrint( "NetSoftReboot: About to EfiLoadedImageProtocol on the loadedImage.\n" );
  572. }
  573. FlipToPhysical();
  574. EfiStatus = EfiST->BootServices->HandleProtocol( ImageHandle,
  575. &EfiLoadedImageProtocol,
  576. &LoadedEfiImageInfo );
  577. FlipToVirtual();
  578. if( EFI_ERROR(EfiStatus) ) {
  579. if( BdDebuggerEnabled ) {
  580. DbgPrint( "NetSoftReboot: HandleProtocol_3 failed (%d)\n", EfiStatus );
  581. }
  582. return STATUS_INSUFFICIENT_RESOURCES;
  583. }
  584. LoadedEfiImageInfo->LoadOptions = (PVOID)restartBlock;
  585. LoadedEfiImageInfo->LoadOptionsSize = sizeof(TFTP_RESTART_BLOCK);
  586. #if DBG
  587. EfiDumpBuffer(LoadedEfiImageInfo->LoadOptions, sizeof(TFTP_RESTART_BLOCK));
  588. #endif
  589. //
  590. // Since we loaded the image from a memory buffer, he's not
  591. // going to have a DeviceHandle set. We'll fail quickly when
  592. // setupldr.efi starts. We can just set it right here, and
  593. // we know exactly what it is because it's the same as the
  594. // network device handle for Oschoice.efi, wich we have
  595. // readily available.
  596. //
  597. LoadedEfiImageInfo->DeviceHandle = OriginalEfiImageInfo->DeviceHandle;
  598. LoadedEfiImageInfo->FilePath = ldrDevicePath;
  599. if( BdDebuggerEnabled ) {
  600. DbgPrint( "NetSoftReboot: LoadedEfiImageInfo->DeviceHandle: 0x%08lx\n", PtrToUlong(LoadedEfiImageInfo->DeviceHandle) );
  601. DbgPrint( "NetSoftReboot: LoadedEfiImageInfo->FilePath: 0x%08lx\n", PtrToUlong(LoadedEfiImageInfo->FilePath) );
  602. }
  603. //
  604. // We shouldn't return from this call!
  605. //
  606. if( BdDebuggerEnabled ) {
  607. DbgPrint( "NetSoftReboot: StartImage.\n" );
  608. }
  609. FlipToPhysical();
  610. EfiStatus = EfiST->BootServices->StartImage( ImageHandle,
  611. 0,
  612. NULL );
  613. FlipToVirtual();
  614. if( EFI_ERROR(EfiStatus) ) {
  615. if( BdDebuggerEnabled ) {
  616. DbgPrint( "NetSoftReboot: StartImage failed (%d)\n", EfiStatus );
  617. }
  618. return STATUS_INSUFFICIENT_RESOURCES;
  619. }
  620. return Status;
  621. }
  622. VOID
  623. NetGetRebootParameters(
  624. OUT PULONGLONG Param OPTIONAL,
  625. OUT PUCHAR RebootFile OPTIONAL,
  626. OUT PUCHAR SifFile OPTIONAL,
  627. OUT PUCHAR User OPTIONAL,
  628. OUT PUCHAR Domain OPTIONAL,
  629. OUT PUCHAR Password OPTIONAL,
  630. OUT PUCHAR AdministratorPassword OPTIONAL,
  631. BOOLEAN ClearRestartBlock
  632. )
  633. /*++
  634. Routine Description:
  635. This routine reads the reboot parameters from the global TFTP_RESTART_BLOCK
  636. and returns them.
  637. Arguments:
  638. Param - Space for returning the value.
  639. RebootFile - Optional space for storing the file to reboot to when done here. (size >= char[128])
  640. SifFile - Optional space for storing a SIF file passed from whoever
  641. initiated the soft reboot.
  642. User/Domain/Password/AdministratorPassword - Optional space to store credentials passed across
  643. the soft reboot.
  644. ClearRestartBlock - If set to TRUE, it wipes out the memory here - should be done exactly once, at the
  645. last call to this function.
  646. Return Value:
  647. None.
  648. --*/
  649. {
  650. BOOLEAN restartBlockValid = FALSE;
  651. #if DBG
  652. EfiDumpBuffer(&gTFTPRestartBlock, sizeof(TFTP_RESTART_BLOCK));
  653. #endif
  654. //
  655. // See if the block is valid. If it's not, we create a temporary empty
  656. // one so the copy logic below doesn't have to keep checking.
  657. //
  658. if ((gTFTPRestartBlock.RestartBlockV1.Tag == 'rtsR') &&
  659. (CalculateChecksum((PLONG)(&gTFTPRestartBlock.RestartBlockV1), 128) == 0)) {
  660. restartBlockValid = TRUE;
  661. }
  662. //
  663. // Copy out the parameters that were in the original TFTP_RESTART_BLOCK structure.
  664. // These shipped in Win2K.
  665. //
  666. if (Param != NULL) {
  667. *Param = gTFTPRestartBlock.RestartBlockV1.RebootParameter;
  668. }
  669. if (RebootFile != NULL) {
  670. memcpy(RebootFile, gTFTPRestartBlock.RestartBlockV1.RebootFile, sizeof(gTFTPRestartBlock.RestartBlockV1.RebootFile));
  671. }
  672. if (SifFile != NULL) {
  673. memcpy(SifFile, gTFTPRestartBlock.RestartBlockV1.SifFile, sizeof(gTFTPRestartBlock.RestartBlockV1.SifFile));
  674. }
  675. if (User != NULL) {
  676. strcpy(User, gTFTPRestartBlock.RestartBlockV1.User);
  677. }
  678. if (Domain != NULL) {
  679. strcpy(Domain, gTFTPRestartBlock.RestartBlockV1.Domain);
  680. }
  681. if (Password != NULL) {
  682. strcpy(Password, gTFTPRestartBlock.RestartBlockV1.Password);
  683. }
  684. //
  685. // Now do a new check for all versions past Win2K
  686. //
  687. if (restartBlockValid) {
  688. if ((gTFTPRestartBlock.NewCheckSumLength == 0) ||
  689. (CalculateChecksum((PLONG)(&gTFTPRestartBlock), gTFTPRestartBlock.NewCheckSumLength) != 0)) {
  690. //
  691. // A pre-Win2K OsChooser has given us this block. Clear out all fields
  692. // that are post-Win2K and continue.
  693. //
  694. RtlZeroMemory( &gTFTPRestartBlock, sizeof(TFTP_RESTART_BLOCK) );
  695. }
  696. }
  697. //
  698. // Now extract the parameters from the block.
  699. //
  700. if (gTFTPRestartBlock.TftpRestartBlockVersion == TFTP_RESTART_BLOCK_VERSION) {
  701. BlGetHeadlessRestartBlock(&gTFTPRestartBlock, restartBlockValid);
  702. if (AdministratorPassword) {
  703. RtlMoveMemory(AdministratorPassword,gTFTPRestartBlock.AdministratorPassword, OSC_ADMIN_PASSWORD_LEN);
  704. }
  705. }
  706. if (restartBlockValid && ClearRestartBlock) {
  707. RtlZeroMemory(&gTFTPRestartBlock, sizeof(TFTP_RESTART_BLOCK));
  708. }
  709. #if DBG
  710. BlPrint(TEXT("Done getting TFTP_RESTART_BLOCK.\r\n"));
  711. #endif
  712. return;
  713. }
  714. ARC_STATUS
  715. NetFillNetworkLoaderBlock (
  716. PNETWORK_LOADER_BLOCK NetworkLoaderBlock
  717. )
  718. {
  719. SHORT status;
  720. t_PXENV_GET_BINL_INFO gbi;
  721. BOOTPLAYER packet;
  722. //
  723. // Get client IP address, server IP address, default gateway IP address,
  724. // and subnet mask from the DHCP ACK packet.
  725. //
  726. gbi.packet_type = PXENV_PACKET_TYPE_DHCP_ACK;
  727. gbi.buffer_size = sizeof(packet);
  728. gbi.buffer_offset = (USHORT)((ULONG_PTR)&packet & 0x0f);
  729. gbi.buffer_segment = (USHORT)(((ULONG_PTR)&packet >> 4) & 0xffff);
  730. status = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
  731. if ( status != PXENV_EXIT_SUCCESS ) {
  732. DbgPrint("PXENV_GET_BINL_INFO(DHCPACK) failed with %x\n", status);
  733. return ENODEV;
  734. }
  735. NetworkLoaderBlock->DHCPServerACK = BlAllocateHeap(gbi.buffer_size);
  736. if (NetworkLoaderBlock->DHCPServerACK == NULL) {
  737. return ENOMEM;
  738. }
  739. memcpy( NetworkLoaderBlock->DHCPServerACK, &packet, gbi.buffer_size );
  740. NetworkLoaderBlock->DHCPServerACKLength = gbi.buffer_size;
  741. gbi.packet_type = PXENV_PACKET_TYPE_BINL_REPLY;
  742. gbi.buffer_size = sizeof(packet);
  743. gbi.buffer_offset = (USHORT)((ULONG_PTR)&packet & 0x0f);
  744. gbi.buffer_segment = (USHORT)(((ULONG_PTR)&packet >> 4) & 0xffff);
  745. status = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
  746. if ( status != PXENV_EXIT_SUCCESS ) {
  747. DbgPrint("PXENV_GET_BINL_INFO(BINLREPLY) failed with %x\n", status);
  748. } else {
  749. NetworkLoaderBlock->BootServerReplyPacket = BlAllocateHeap(gbi.buffer_size);
  750. if (NetworkLoaderBlock->BootServerReplyPacket == NULL) {
  751. return ENOMEM;
  752. }
  753. memcpy( NetworkLoaderBlock->BootServerReplyPacket, &packet, gbi.buffer_size );
  754. NetworkLoaderBlock->BootServerReplyPacketLength = gbi.buffer_size;
  755. }
  756. return ESUCCESS;
  757. }