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.

1305 lines
35 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. ULONG NetLocalIpAddress;
  55. ULONG NetLocalSubnetMask;
  56. ULONG NetServerIpAddress;
  57. ULONG NetGatewayIpAddress;
  58. UCHAR NetLocalHardwareAddress[16];
  59. UCHAR MyGuid[16];
  60. ULONG MyGuidLength = sizeof(MyGuid);
  61. BOOLEAN MyGuidValid = FALSE;
  62. TFTP_RESTART_BLOCK gTFTPRestartBlock;
  63. VOID
  64. EfiDumpBuffer(
  65. PVOID Buffer,
  66. ULONG BufferSize
  67. )
  68. /*++
  69. Routine Description:
  70. Dumps the buffer content on to the debugger output.
  71. Arguments:
  72. Buffer: buffer pointer.
  73. BufferSize: size of the buffer.
  74. Return Value:
  75. none
  76. --*/
  77. {
  78. #define NUM_CHARS 16
  79. ULONG i, limit;
  80. CHAR TextBuffer[NUM_CHARS + 1];
  81. PUCHAR BufferPtr = Buffer;
  82. BlPrint(TEXT("------------------------------------\r\n"));
  83. //
  84. // Hex dump of the bytes
  85. //
  86. limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
  87. for (i = 0; i < limit; i++) {
  88. if (i < BufferSize) {
  89. BlPrint(TEXT("%x "), (UCHAR)BufferPtr[i]);
  90. if (BufferPtr[i] < 31 ) {
  91. TextBuffer[i % NUM_CHARS] = '.';
  92. } else if (BufferPtr[i] == '\0') {
  93. TextBuffer[i % NUM_CHARS] = ' ';
  94. } else {
  95. TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i];
  96. }
  97. } else {
  98. BlPrint(TEXT(" "));
  99. TextBuffer[i % NUM_CHARS] = ' ';
  100. }
  101. if ((i + 1) % NUM_CHARS == 0) {
  102. TextBuffer[NUM_CHARS] = 0;
  103. BlPrint(TEXT(" %s\r\n"), TextBuffer);
  104. }
  105. }
  106. BlPrint(TEXT("------------------------------------\r\n"));
  107. #if 0
  108. //
  109. // enable this to make it pause after dumping the buffer.
  110. //
  111. DBG_EFI_PAUSE();
  112. #endif
  113. }
  114. EFI_STATUS
  115. EfiGetPxeClient(
  116. VOID
  117. )
  118. /*++
  119. Routine Description:
  120. Obtains the global pointer to the PXE device
  121. booted from in a RIS scenario.
  122. Arguments:
  123. none
  124. Return Value:
  125. ESUCCESS when successful, otherwise failure
  126. --*/
  127. {
  128. EFI_STATUS Status = EFI_UNSUPPORTED;
  129. EFI_GUID PXEGuid = EFI_PXE_BASE_CODE_PROTOCOL;
  130. EFI_LOADED_IMAGE *EfiImageInfo;
  131. EFI_DEVICE_PATH *PXEDevicePath;
  132. EFI_HANDLE PXEHandle;
  133. if (PXEClient) {
  134. //
  135. // already have a pointer to the device
  136. // no more work needed
  137. //
  138. return ESUCCESS;
  139. }
  140. //
  141. // get the correct PXE Handle by looking at the loaded
  142. // image for oschooser
  143. //
  144. //
  145. // get the image info for oschooser
  146. //
  147. FlipToPhysical();
  148. Status = EfiST->BootServices->HandleProtocol (EfiImageHandle,
  149. &EfiLoadedImageProtocol,
  150. &EfiImageInfo);
  151. FlipToVirtual();
  152. if (Status != EFI_SUCCESS) {
  153. if( BdDebuggerEnabled ) {
  154. DbgPrint( "EfiGetPxeClient: HandleProtocol failed -LoadedImageProtocol (%d)\n", Status);
  155. }
  156. return Status;
  157. }
  158. //
  159. // get the device path to the image
  160. //
  161. FlipToPhysical();
  162. Status = EfiST->BootServices->HandleProtocol (EfiImageInfo->DeviceHandle,
  163. &EfiDevicePathProtocol,
  164. &PXEDevicePath);
  165. FlipToVirtual();
  166. if (Status != EFI_SUCCESS) {
  167. if( BdDebuggerEnabled ) {
  168. DbgPrint( "EfiGetPxeClient: HandleProtocol failed -DevicePathProtocol (%d)\n", Status);
  169. }
  170. return Status;
  171. }
  172. //
  173. // get the PXE_BASE_CODE_PROTOCOL interface from returned handle
  174. //
  175. FlipToPhysical();
  176. Status = EfiST->BootServices->LocateDevicePath(&PXEGuid,
  177. &PXEDevicePath,
  178. &PXEHandle);
  179. FlipToVirtual();
  180. if (Status != EFI_SUCCESS)
  181. {
  182. if( BdDebuggerEnabled ) {
  183. DbgPrint( "EfiGetPxeClient: LocateDevicePath failed (%d)\n", Status);
  184. }
  185. return Status;
  186. }
  187. // get the pxebc interface from PXEHandle
  188. FlipToPhysical();
  189. Status = EfiST->BootServices->HandleProtocol(PXEHandle,
  190. &PXEGuid,
  191. &PXEClient);
  192. FlipToVirtual();
  193. if (Status != EFI_SUCCESS)
  194. {
  195. if( BdDebuggerEnabled ) {
  196. DbgPrint( "EfiGetPxeClient: HandleProtocol failed -PXEBCP interface (%d)\n", Status);
  197. }
  198. return Status;
  199. }
  200. return EFI_SUCCESS;
  201. }
  202. ARC_STATUS
  203. FindDhcpOption(
  204. IN EFI_PXE_BASE_CODE_PACKET Packet,
  205. IN UCHAR Option,
  206. IN ULONG MaximumLength,
  207. OUT PUCHAR OptionData,
  208. OUT PULONG Length OPTIONAL,
  209. IN ULONG Instance OPTIONAL
  210. )
  211. /*++
  212. Routine Description:
  213. Searches a dhcp packet for a given option.
  214. Arguments:
  215. Packet - pointer to the dhcp packet. Caller is responsible for assuring
  216. that the packet is a valid dhcp packet.
  217. Option - the dhcp option we're searching for.
  218. MaximumLength - size in bytes of OptionData buffer.
  219. OptionData - buffer to receive the option.
  220. Length - if specified, receives the actual length of option copied.
  221. Instance - specifies which instance of the option you are searching for.
  222. If not specified (zero), then we just grab the first instance of the tag.
  223. Return Value:
  224. ARC_STATUS indicating outcome.
  225. --*/
  226. {
  227. PUCHAR curOption;
  228. ULONG copyLength;
  229. ULONG i = 0;
  230. if (MaximumLength == 0) {
  231. return EINVAL;
  232. }
  233. RtlZeroMemory(OptionData, MaximumLength);
  234. //
  235. // Parse the DHCP options looking for a specific one.
  236. //
  237. curOption = (PUCHAR)&Packet.Dhcpv4.DhcpOptions;
  238. while ((curOption - (PUCHAR)&Packet.Dhcpv4) < sizeof(EFI_PXE_BASE_CODE_DHCPV4_PACKET) &&
  239. *curOption != 0xff) {
  240. if (*curOption == DHCP_PAD) {
  241. //
  242. // just walk past any pad options
  243. // these will not have any length
  244. //
  245. curOption++;
  246. }
  247. else {
  248. if (*curOption == Option) {
  249. //
  250. // Found it, copy and leave.
  251. //
  252. if ( i == Instance ) {
  253. if (sizeof(EFI_PXE_BASE_CODE_DHCPV4_PACKET) <= curOption + 2 - (PUCHAR)&Packet.Dhcpv4 ||
  254. sizeof(EFI_PXE_BASE_CODE_DHCPV4_PACKET) <= curOption + 2 + curOption[1] - (PUCHAR)&Packet.Dhcpv4 ) {
  255. //
  256. // invalid option. it walked past the end of the packet
  257. //
  258. break;
  259. }
  260. if (curOption[1] > MaximumLength) {
  261. copyLength = MaximumLength;
  262. } else {
  263. copyLength = curOption[1];
  264. }
  265. RtlCopyMemory(OptionData,
  266. curOption+2,
  267. copyLength);
  268. if (ARGUMENT_PRESENT(Length)) {
  269. *Length = copyLength;
  270. }
  271. return ESUCCESS;
  272. }
  273. i++;
  274. }
  275. curOption = curOption + 2 + curOption[1];
  276. }
  277. }
  278. return EINVAL;
  279. }
  280. BOOLEAN
  281. IsIpv4AddressNonZero(
  282. EFI_IPv4_ADDRESS *pAddress
  283. )
  284. {
  285. if (pAddress->Addr[0] != 0 ||
  286. pAddress->Addr[1] != 0 ||
  287. pAddress->Addr[2] != 0 ||
  288. pAddress->Addr[3] != 0) {
  289. return(TRUE);
  290. }
  291. return(FALSE);
  292. }
  293. ARC_STATUS
  294. GetParametersFromRom (
  295. VOID
  296. )
  297. {
  298. UINTN Count = 0;
  299. EFI_STATUS Status = EFI_UNSUPPORTED;
  300. PUCHAR p;
  301. UCHAR temp[4];
  302. //
  303. // obtain a pointer to the PXE device we booted from
  304. //
  305. Status = EfiGetPxeClient();
  306. if (Status != EFI_SUCCESS) {
  307. return (ARC_STATUS) Status;
  308. }
  309. //
  310. // Our IP address is down in:
  311. // PXEClient->Mode->StationIp.v4
  312. //
  313. // The server's IP address is down in:
  314. // PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr
  315. //
  316. // Our NIC's GUID should be down in:
  317. // PXEClient->Mode->ProxyOffer.Dhcpv4.BootpHwAddr
  318. //
  319. // Our Subnetmask is down in:
  320. // PXEClient->Mode->SubnetMask.v4
  321. //
  322. NetServerIpAddress = 0;
  323. NetLocalIpAddress = 0;
  324. NetLocalSubnetMask = 0;
  325. NetGatewayIpAddress = 0;
  326. for( Count = 0; Count < 4; Count++ ) {
  327. NetServerIpAddress = (NetServerIpAddress << 8) + PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr[Count];
  328. NetLocalIpAddress = (NetLocalIpAddress << 8) + PXEClient->Mode->StationIp.v4.Addr[Count];
  329. NetLocalSubnetMask = (NetLocalSubnetMask << 8) + PXEClient->Mode->SubnetMask.v4.Addr[Count];
  330. }
  331. //
  332. // Our gateway address is either in the dhcp ack or the proxy offer packet.
  333. // proxy offer overrides the dhcp ack.
  334. // first look for the dhcp router option, then look in the packet itself.
  335. //
  336. //
  337. if (FindDhcpOption(PXEClient->Mode->DhcpAck, DHCP_ROUTER, sizeof(temp), (PUCHAR)temp, NULL, 0) == ESUCCESS) {
  338. NetGatewayIpAddress = (temp[0] << 24) +
  339. (temp[1] << 16) +
  340. (temp[2] << 8) +
  341. temp[3];
  342. } else if (IsIpv4AddressNonZero((EFI_IPv4_ADDRESS *)&PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[0])) {
  343. NetGatewayIpAddress = (PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[0] << 24) +
  344. (PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[1] << 16) +
  345. (PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[2] << 8) +
  346. PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[3];
  347. }
  348. if (FindDhcpOption(PXEClient->Mode->ProxyOffer, DHCP_ROUTER, sizeof(temp), (PUCHAR)temp, NULL, 0) == ESUCCESS) {
  349. NetGatewayIpAddress = (temp[0] << 24) +
  350. (temp[1] << 16) +
  351. (temp[2] << 8) +
  352. temp[3];
  353. } else if (IsIpv4AddressNonZero((EFI_IPv4_ADDRESS *)&PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[0])) {
  354. NetGatewayIpAddress = (PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[0] << 24) +
  355. (PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[1] << 16) +
  356. (PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[2] << 8) +
  357. PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[3];
  358. }
  359. memcpy( NetLocalHardwareAddress, PXEClient->Mode->ProxyOffer.Dhcpv4.BootpHwAddr, sizeof(NetLocalHardwareAddress) );
  360. //
  361. // Get the path where we were launched from. We what to remove the
  362. // actual file name (oschoice.efi in this case), but leave that trailing
  363. // '\'.
  364. //
  365. strncpy( NetBootPath, (PCHAR)PXEClient->Mode->ProxyOffer.Dhcpv4.BootpBootFile, sizeof(NetBootPath) );
  366. NetBootPath[sizeof(NetBootPath)-1] = '\0';
  367. p = (PUCHAR)strrchr( NetBootPath, '\\' );
  368. if( p ) {
  369. p++;
  370. *p = '\0';
  371. } else {
  372. NetBootPath[0] = '\0'; // no path
  373. }
  374. return ESUCCESS;
  375. }
  376. VOID
  377. EfiNetTerminate(
  378. VOID
  379. )
  380. {
  381. FlipToPhysical();
  382. PXEClient->Stop( PXEClient );
  383. FlipToVirtual();
  384. }
  385. ARC_STATUS
  386. GetGuid(
  387. OUT PUCHAR *Guid,
  388. OUT PULONG GuidLength
  389. )
  390. /*++
  391. Routine Description:
  392. This routine returns the Guid of this machine.
  393. Arguments:
  394. Guid - Place to store pointer to the guid.
  395. GuidLength - Place to store the length in bytes of the guid.
  396. Return Value:
  397. ARC code indicating outcome.
  398. --*/
  399. {
  400. PSMBIOS_SYSTEM_INFORMATION_STRUCT SystemInfoHeader = NULL;
  401. *Guid = NULL;
  402. *GuidLength = 0;
  403. SystemInfoHeader = (PSMBIOS_SYSTEM_INFORMATION_STRUCT)FindSMBIOSTable( SMBIOS_SYSTEM_INFORMATION );
  404. if( SystemInfoHeader ) {
  405. *Guid = (PUCHAR)BlAllocateHeap( SYSID_UUID_DATA_SIZE );
  406. if( *Guid ) {
  407. *GuidLength = SYSID_UUID_DATA_SIZE;
  408. RtlCopyMemory( *Guid,
  409. SystemInfoHeader->Uuid,
  410. SYSID_UUID_DATA_SIZE );
  411. return ESUCCESS;
  412. } else {
  413. if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed Alloc.\r\n" ); }
  414. *GuidLength = 0;
  415. return ENOMEM;
  416. }
  417. } else {
  418. if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed to find a SMBIOS_SYSTEM_INFORMATION table.\n" ); }
  419. }
  420. return ENODEV;
  421. }
  422. ULONG
  423. CalculateChecksum(
  424. IN PLONG Block,
  425. IN ULONG Length
  426. )
  427. /*++
  428. Routine Description:
  429. This routine calculates a simple two's-complement checksum of a block of
  430. memory. If the returned value is stored in the block (in a word that was
  431. zero during the calculation), then new checksum of the block will be zero.
  432. Arguments:
  433. Block - Address of a block of data. Must be 4-byte aligned.
  434. Length - Length of the block. Must be a multiple of 4.
  435. Return Value:
  436. ULONG - Two's complement additive checksum of the input block.
  437. --*/
  438. {
  439. LONG checksum = 0;
  440. ASSERT( ((ULONG_PTR)Block & 3) == 0 );
  441. ASSERT( (Length & 3) == 0 );
  442. for ( ; Length != 0; Length -= 4 ) {
  443. checksum += *Block;
  444. Block++;
  445. }
  446. return -checksum;
  447. }
  448. UINTN
  449. DevicePathSize (
  450. IN EFI_DEVICE_PATH *DevPath
  451. )
  452. {
  453. EFI_DEVICE_PATH *Start;
  454. /*
  455. * Search for the end of the device path structure
  456. * */
  457. Start = DevPath;
  458. while (!IsDevicePathEnd(DevPath)) {
  459. DevPath = NextDevicePathNode(DevPath);
  460. }
  461. /*
  462. * Compute the size
  463. */
  464. return ((UINTN) DevPath - (UINTN) Start) + sizeof(EFI_DEVICE_PATH);
  465. }
  466. EFI_DEVICE_PATH *
  467. DevicePathInstance (
  468. IN OUT EFI_DEVICE_PATH **DevicePath,
  469. OUT UINTN *Size
  470. )
  471. {
  472. EFI_DEVICE_PATH *Start, *Next, *DevPath;
  473. UINTN Count;
  474. DevPath = *DevicePath;
  475. Start = DevPath;
  476. if (!DevPath) {
  477. return NULL;
  478. }
  479. /*
  480. * Check for end of device path type
  481. * */
  482. for (Count = 0; ; Count++) {
  483. Next = NextDevicePathNode(DevPath);
  484. if (IsDevicePathEndType(DevPath)) {
  485. break;
  486. }
  487. if (Count > 01000) {
  488. break;
  489. }
  490. DevPath = Next;
  491. }
  492. ASSERT (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE ||
  493. DevicePathSubType(DevPath) == END_INSTANCE_DEVICE_PATH_SUBTYPE);
  494. /*
  495. * Set next position
  496. */
  497. if (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
  498. Next = NULL;
  499. }
  500. *DevicePath = Next;
  501. /*
  502. * Return size and start of device path instance
  503. */
  504. *Size = ((UINT8 *) DevPath) - ((UINT8 *) Start);
  505. return Start;
  506. }
  507. UINTN
  508. DevicePathInstanceCount (
  509. IN EFI_DEVICE_PATH *DevicePath
  510. )
  511. {
  512. UINTN Count, Size;
  513. Count = 0;
  514. while (DevicePathInstance(&DevicePath, &Size)) {
  515. Count += 1;
  516. }
  517. return Count;
  518. }
  519. EFI_DEVICE_PATH *
  520. AppendDevicePath (
  521. IN EFI_DEVICE_PATH *Src1,
  522. IN EFI_DEVICE_PATH *Src2
  523. )
  524. /* Src1 may have multiple "instances" and each instance is appended
  525. * Src2 is appended to each instance is Src1. (E.g., it's possible
  526. * to append a new instance to the complete device path by passing
  527. * it in Src2) */
  528. {
  529. UINTN Src1Size, Src1Inst, Src2Size, Size;
  530. EFI_DEVICE_PATH *Dst, *Inst;
  531. UINT8 *DstPos;
  532. EFI_DEVICE_PATH EndInstanceDevicePath[] = { END_DEVICE_PATH_TYPE,
  533. END_INSTANCE_DEVICE_PATH_SUBTYPE,
  534. END_DEVICE_PATH_LENGTH,
  535. 0 };
  536. EFI_DEVICE_PATH EndDevicePath[] = { END_DEVICE_PATH_TYPE,
  537. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  538. END_DEVICE_PATH_LENGTH,
  539. 0 };
  540. Src1Size = DevicePathSize(Src1);
  541. Src1Inst = DevicePathInstanceCount(Src1);
  542. Src2Size = DevicePathSize(Src2);
  543. Size = Src1Size * Src1Inst + Src2Size;
  544. EfiAllocateAndZeroMemory( EfiLoaderData,
  545. Size,
  546. (VOID **) &Dst );
  547. if (Dst) {
  548. DstPos = (UINT8 *) Dst;
  549. /*
  550. * Copy all device path instances
  551. */
  552. while ((Inst = DevicePathInstance (&Src1, &Size)) != 0) {
  553. RtlCopyMemory(DstPos, Inst, Size);
  554. DstPos += Size;
  555. RtlCopyMemory(DstPos, Src2, Src2Size);
  556. DstPos += Src2Size;
  557. RtlCopyMemory(DstPos, EndInstanceDevicePath, sizeof(EFI_DEVICE_PATH));
  558. DstPos += sizeof(EFI_DEVICE_PATH);
  559. }
  560. /* Change last end marker */
  561. DstPos -= sizeof(EFI_DEVICE_PATH);
  562. RtlCopyMemory(DstPos, EndDevicePath, sizeof(EFI_DEVICE_PATH));
  563. }
  564. return Dst;
  565. }
  566. NTSTATUS
  567. NetSoftReboot(
  568. IN PUCHAR NextBootFile,
  569. IN ULONGLONG Param,
  570. IN PUCHAR RebootFile OPTIONAL,
  571. IN PUCHAR SifFile OPTIONAL,
  572. IN PUCHAR User OPTIONAL,
  573. IN PUCHAR Domain OPTIONAL,
  574. IN PUCHAR Password OPTIONAL,
  575. IN PUCHAR AdministratorPassword OPTIONAL
  576. )
  577. /*++
  578. Routine Description:
  579. This routine will load the specified file, build a parameter
  580. list and transfer control to the loaded file.
  581. Arguments:
  582. NextBootFile - Fully qualified path name of the file to download.
  583. Param - Reboot parameter to set.
  584. RebootFile - String identifying the file to reboot to when after the current reboot is done.
  585. SifFile - Optional SIF file to pass to the next loader.
  586. User/Domain/Password/AdministratorPassword - Optional credentials to pass to the next loader.
  587. Return Value:
  588. Should not return if successful.
  589. --*/
  590. {
  591. NTSTATUS Status = STATUS_SUCCESS;
  592. EFI_DEVICE_PATH *ldrDevicePath = NULL, *Eop = NULL;
  593. EFI_HANDLE ImageHandle = NULL;
  594. UINTN i = 0;
  595. EFI_STATUS EfiStatus = EFI_SUCCESS;
  596. WCHAR WideNextBootFile[MAX_PATH];
  597. FILEPATH_DEVICE_PATH *FilePath = NULL;
  598. UNICODE_STRING uString;
  599. ANSI_STRING aString;
  600. EFI_LOADED_IMAGE *OriginalEfiImageInfo = NULL;
  601. EFI_LOADED_IMAGE *LoadedEfiImageInfo = NULL;
  602. EFI_DEVICE_PATH *OriginalEfiDevicePath = NULL;
  603. PTFTP_RESTART_BLOCK restartBlock = NULL;
  604. PTFTP_RESTART_BLOCK_V1 restartBlockV1 = NULL;
  605. ULONG BootFileId = 0;
  606. PUCHAR LoadedImageAddress = NULL;
  607. ULONG LoadedImageSize = 0;
  608. //
  609. // Load the file we want to boot into memory.
  610. //
  611. Status = BlOpen( NET_DEVICE_ID,
  612. (PCHAR)NextBootFile,
  613. ArcOpenReadOnly,
  614. &BootFileId );
  615. if (Status != ESUCCESS) {
  616. return Status;
  617. }
  618. //
  619. // What memory address did he get loaded into?
  620. //
  621. // make sure we have the physical address
  622. //
  623. LoadedImageAddress = (PUCHAR)((ULONGLONG)(BlFileTable[BootFileId].u.NetFileContext.InMemoryCopy) & ~KSEG0_BASE);
  624. LoadedImageSize = BlFileTable[BootFileId].u.NetFileContext.FileSize;
  625. //
  626. // BUild a device path to the target file. We'll do this by gathering
  627. // some information about ourselves, knowing that we're about to load/launch
  628. // an image from the server, just like where we came from.
  629. //
  630. //
  631. // Get image information on ourselves.
  632. //
  633. FlipToPhysical();
  634. EfiStatus = EfiST->BootServices->HandleProtocol( EfiImageHandle,
  635. &EfiLoadedImageProtocol,
  636. &OriginalEfiImageInfo );
  637. FlipToVirtual();
  638. if( EFI_ERROR(EfiStatus) ) {
  639. if( BdDebuggerEnabled ) {
  640. DbgPrint( "NetSoftReboot: HandleProtocol_1 failed (%d)\n", EfiStatus );
  641. }
  642. return STATUS_INSUFFICIENT_RESOURCES;
  643. }
  644. //
  645. // Get our DevicePath too.
  646. //
  647. FlipToPhysical();
  648. EfiStatus = EfiST->BootServices->HandleProtocol( OriginalEfiImageInfo->DeviceHandle,
  649. &EfiDevicePathProtocol,
  650. &OriginalEfiDevicePath );
  651. FlipToVirtual();
  652. if( EFI_ERROR(EfiStatus) ) {
  653. if( BdDebuggerEnabled ) {
  654. DbgPrint( "NetSoftReboot: HandleProtocol_2 failed (%d)\n", EfiStatus );
  655. }
  656. return STATUS_INSUFFICIENT_RESOURCES;
  657. }
  658. //
  659. // Now build a device path based on the DeviceHandle of ourselves, along
  660. // with the path to the image we want to load.
  661. //
  662. RtlInitString( &aString, (PCHAR)NextBootFile );
  663. uString.MaximumLength = MAX_PATH;
  664. uString.Buffer = WideNextBootFile;
  665. RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
  666. i = wcslen(uString.Buffer);
  667. EfiStatus = EfiAllocateAndZeroMemory( EfiLoaderData,
  668. i + sizeof(FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH),
  669. (VOID **) &FilePath );
  670. if( EFI_ERROR(EfiStatus) ) {
  671. if( BdDebuggerEnabled ) {
  672. DbgPrint( "NetSoftReboot: AllocatePool_1 failed (%d)\n", EfiStatus );
  673. }
  674. return STATUS_NO_MEMORY;
  675. }
  676. FilePath->Header.Type = MEDIA_DEVICE_PATH;
  677. FilePath->Header.SubType = MEDIA_FILEPATH_DP;
  678. SetDevicePathNodeLength (&FilePath->Header, i + sizeof(FILEPATH_DEVICE_PATH));
  679. RtlCopyMemory (FilePath->PathName, uString.Buffer, i);
  680. FlipToPhysical();
  681. Eop = NextDevicePathNode(&FilePath->Header);
  682. SetDevicePathEndNode(Eop);
  683. //
  684. // Append file path to device's device path
  685. //
  686. ldrDevicePath = (EFI_DEVICE_PATH *)FilePath;
  687. ldrDevicePath = AppendDevicePath ( OriginalEfiDevicePath,
  688. ldrDevicePath );
  689. FlipToVirtual();
  690. //
  691. // Load the image, then set its loadoptions in preparation
  692. // for launching it.
  693. //
  694. if( BdDebuggerEnabled ) {
  695. DbgPrint( "NetSoftReboot: About to LoadImage.\n" );
  696. }
  697. FlipToPhysical();
  698. EfiStatus = EfiST->BootServices->LoadImage( FALSE,
  699. EfiImageHandle,
  700. ldrDevicePath,
  701. LoadedImageAddress,
  702. LoadedImageSize,
  703. &ImageHandle );
  704. FlipToVirtual();
  705. if( EFI_ERROR(EfiStatus) ) {
  706. if( BdDebuggerEnabled ) {
  707. DbgPrint( "NetSoftReboot: LoadImage failed (%d)\n", EfiStatus );
  708. }
  709. return STATUS_NO_MEMORY;
  710. } else {
  711. if( BdDebuggerEnabled ) {
  712. DbgPrint( "NetSoftReboot: LoadImage worked (%d)\n", EfiStatus );
  713. }
  714. }
  715. //
  716. // allocate a chunk of memory, then load it up w/ all the boot options.
  717. //
  718. EfiStatus = EfiAllocateAndZeroMemory( EfiLoaderData,
  719. sizeof(TFTP_RESTART_BLOCK),
  720. (VOID **) &restartBlock );
  721. if( EFI_ERROR(EfiStatus) ) {
  722. if( BdDebuggerEnabled ) {
  723. DbgPrint( "NetSoftReboot: Failed to allocate memory for restartBlock (%d)\n", EfiStatus );
  724. }
  725. return STATUS_NO_MEMORY;
  726. }
  727. restartBlockV1 = (PTFTP_RESTART_BLOCK_V1)(&restartBlock->RestartBlockV1);
  728. //
  729. // There's no need to pass the headless settings through the restart block.
  730. // The only way to get headless settings on EFI is to get them from firmware
  731. // and we'll be checking for formware settings when we reboot back into
  732. // setupldr anyway. -matth (2/2002)
  733. //
  734. // BlSetHeadlessRestartBlock(restartBlock);
  735. if (AdministratorPassword) {
  736. RtlMoveMemory(restartBlock->AdministratorPassword,AdministratorPassword, OSC_ADMIN_PASSWORD_LEN);
  737. }
  738. restartBlockV1->RebootParameter = Param;
  739. if (RebootFile != NULL) {
  740. strncpy(restartBlockV1->RebootFile, (PCHAR)RebootFile, sizeof(restartBlockV1->RebootFile));
  741. restartBlockV1->RebootFile[sizeof(restartBlockV1->RebootFile)-1] = '\0';
  742. }
  743. if (SifFile != NULL) {
  744. strncpy(restartBlockV1->SifFile, (PCHAR)SifFile, sizeof(restartBlockV1->SifFile));
  745. restartBlockV1->SifFile[sizeof(restartBlockV1->SifFile)-1] = '\0';
  746. }
  747. if (User != NULL) {
  748. strncpy(restartBlockV1->User, (PCHAR)User, sizeof(restartBlockV1->User));
  749. restartBlockV1->User[sizeof(restartBlockV1->User)-1] = '\0';
  750. }
  751. if (Domain != NULL) {
  752. strncpy(restartBlockV1->Domain, (PCHAR)Domain, sizeof(restartBlockV1->Domain));
  753. restartBlockV1->Domain[sizeof(restartBlockV1->Domain)-1] = '\0';
  754. }
  755. if (Password != NULL) {
  756. strncpy(restartBlockV1->Password, (PCHAR)Password, sizeof(restartBlockV1->Password));
  757. restartBlockV1->Password[sizeof(restartBlockV1->Password)-1] = '\0';
  758. }
  759. //
  760. // Set the tag in the restart block and calculate and store the checksum.
  761. //
  762. restartBlockV1->Tag = 'rtsR';
  763. restartBlockV1->Checksum = CalculateChecksum((PLONG)(restartBlockV1), 128);
  764. //
  765. // For all versions of RIS after NT5.0 we have a new datastructure which is
  766. // more adaptable for the future. For this section we have a different checksum,
  767. // do that now.
  768. //
  769. restartBlock->TftpRestartBlockVersion = TFTP_RESTART_BLOCK_VERSION;
  770. restartBlock->NewCheckSumLength = sizeof(TFTP_RESTART_BLOCK);
  771. restartBlock->NewCheckSum = CalculateChecksum((PLONG)restartBlock,
  772. restartBlock->NewCheckSumLength);
  773. //
  774. // We've got the command-line options all setup. Now we need to
  775. // actually put them into ImageInfo->LoadOptions so they get
  776. // passed to the loaded image.
  777. //
  778. if( BdDebuggerEnabled ) {
  779. DbgPrint( "NetSoftReboot: About to EfiLoadedImageProtocol on the loadedImage.\n" );
  780. }
  781. FlipToPhysical();
  782. EfiStatus = EfiST->BootServices->HandleProtocol( ImageHandle,
  783. &EfiLoadedImageProtocol,
  784. &LoadedEfiImageInfo );
  785. FlipToVirtual();
  786. if( EFI_ERROR(EfiStatus) ) {
  787. if( BdDebuggerEnabled ) {
  788. DbgPrint( "NetSoftReboot: HandleProtocol_3 failed (%d)\n", EfiStatus );
  789. }
  790. return STATUS_INSUFFICIENT_RESOURCES;
  791. }
  792. LoadedEfiImageInfo->LoadOptions = (PVOID)restartBlock;
  793. LoadedEfiImageInfo->LoadOptionsSize = sizeof(TFTP_RESTART_BLOCK);
  794. #if DBG
  795. EfiDumpBuffer(LoadedEfiImageInfo->LoadOptions, sizeof(TFTP_RESTART_BLOCK));
  796. #endif
  797. //
  798. // Since we loaded the image from a memory buffer, he's not
  799. // going to have a DeviceHandle set. We'll fail quickly when
  800. // setupldr.efi starts. We can just set it right here, and
  801. // we know exactly what it is because it's the same as the
  802. // network device handle for Oschoice.efi, wich we have
  803. // readily available.
  804. //
  805. LoadedEfiImageInfo->DeviceHandle = OriginalEfiImageInfo->DeviceHandle;
  806. LoadedEfiImageInfo->FilePath = ldrDevicePath;
  807. if( BdDebuggerEnabled ) {
  808. DbgPrint( "NetSoftReboot: LoadedEfiImageInfo->DeviceHandle: 0x%08lx\n", PtrToUlong(LoadedEfiImageInfo->DeviceHandle) );
  809. DbgPrint( "NetSoftReboot: LoadedEfiImageInfo->FilePath: 0x%08lx\n", PtrToUlong(LoadedEfiImageInfo->FilePath) );
  810. }
  811. //
  812. // We shouldn't return from this call!
  813. //
  814. if( BdDebuggerEnabled ) {
  815. DbgPrint( "NetSoftReboot: StartImage.\n" );
  816. }
  817. FlipToPhysical();
  818. EfiStatus = EfiST->BootServices->StartImage( ImageHandle,
  819. 0,
  820. NULL );
  821. FlipToVirtual();
  822. if( EFI_ERROR(EfiStatus) ) {
  823. if( BdDebuggerEnabled ) {
  824. DbgPrint( "NetSoftReboot: StartImage failed (%d)\n", EfiStatus );
  825. }
  826. return STATUS_INSUFFICIENT_RESOURCES;
  827. }
  828. return Status;
  829. }
  830. VOID
  831. NetGetRebootParameters(
  832. OUT PULONGLONG Param OPTIONAL,
  833. OUT PUCHAR RebootFile OPTIONAL,
  834. OUT PUCHAR SifFile OPTIONAL,
  835. OUT PUCHAR User OPTIONAL,
  836. OUT PUCHAR Domain OPTIONAL,
  837. OUT PUCHAR Password OPTIONAL,
  838. OUT PUCHAR AdministratorPassword OPTIONAL,
  839. BOOLEAN ClearRestartBlock
  840. )
  841. /*++
  842. Routine Description:
  843. This routine reads the reboot parameters from the global TFTP_RESTART_BLOCK
  844. and returns them.
  845. Arguments:
  846. Param - Space for returning the value.
  847. RebootFile - Optional space for storing the file to reboot to when done here. (size >= char[128])
  848. SifFile - Optional space for storing a SIF file passed from whoever
  849. initiated the soft reboot.
  850. User/Domain/Password/AdministratorPassword - Optional space to store credentials passed across
  851. the soft reboot.
  852. ClearRestartBlock - If set to TRUE, it wipes out the memory here - should be done exactly once, at the
  853. last call to this function.
  854. Return Value:
  855. None.
  856. --*/
  857. {
  858. BOOLEAN restartBlockValid = FALSE;
  859. #if DBG
  860. EfiDumpBuffer(&gTFTPRestartBlock, sizeof(TFTP_RESTART_BLOCK));
  861. #endif
  862. //
  863. // See if the block is valid. If it's not, we create a temporary empty
  864. // one so the copy logic below doesn't have to keep checking.
  865. //
  866. if ((gTFTPRestartBlock.RestartBlockV1.Tag == 'rtsR') &&
  867. (CalculateChecksum((PLONG)(&gTFTPRestartBlock.RestartBlockV1), 128) == 0)) {
  868. restartBlockValid = TRUE;
  869. }
  870. //
  871. // Copy out the parameters that were in the original TFTP_RESTART_BLOCK structure.
  872. // These shipped in Win2K.
  873. //
  874. //
  875. // Unfortunetly we do not know the size of the parameters passed to us.
  876. // Assume they are no smaller than the fields in the restart block
  877. //
  878. if (Param != NULL) {
  879. *Param = gTFTPRestartBlock.RestartBlockV1.RebootParameter;
  880. }
  881. if (RebootFile != NULL) {
  882. memcpy(RebootFile, gTFTPRestartBlock.RestartBlockV1.RebootFile, sizeof(gTFTPRestartBlock.RestartBlockV1.RebootFile));
  883. }
  884. if (SifFile != NULL) {
  885. memcpy(SifFile, gTFTPRestartBlock.RestartBlockV1.SifFile, sizeof(gTFTPRestartBlock.RestartBlockV1.SifFile));
  886. }
  887. if (User != NULL) {
  888. strncpy((PCHAR)User, gTFTPRestartBlock.RestartBlockV1.User, sizeof(gTFTPRestartBlock.RestartBlockV1.User));
  889. User[sizeof(gTFTPRestartBlock.RestartBlockV1.User)-1] = '\0';
  890. }
  891. if (Domain != NULL) {
  892. strncpy((PCHAR)Domain, gTFTPRestartBlock.RestartBlockV1.Domain,sizeof(gTFTPRestartBlock.RestartBlockV1.Domain));
  893. Domain[sizeof(gTFTPRestartBlock.RestartBlockV1.Domain)-1] = '\0';
  894. }
  895. if (Password != NULL) {
  896. strncpy((PCHAR)Password, gTFTPRestartBlock.RestartBlockV1.Password, sizeof(gTFTPRestartBlock.RestartBlockV1.Password));
  897. Password[sizeof(gTFTPRestartBlock.RestartBlockV1.Password)-1] = '\0';
  898. }
  899. //
  900. // Now do a new check for all versions past Win2K
  901. //
  902. if (restartBlockValid) {
  903. if ((gTFTPRestartBlock.NewCheckSumLength == 0) ||
  904. (CalculateChecksum((PLONG)(&gTFTPRestartBlock), gTFTPRestartBlock.NewCheckSumLength) != 0)) {
  905. //
  906. // A pre-Win2K OsChooser has given us this block. Clear out all fields
  907. // that are post-Win2K and continue.
  908. //
  909. RtlZeroMemory( &gTFTPRestartBlock, sizeof(TFTP_RESTART_BLOCK) );
  910. }
  911. }
  912. //
  913. // Now extract the parameters from the block.
  914. //
  915. if (gTFTPRestartBlock.TftpRestartBlockVersion == TFTP_RESTART_BLOCK_VERSION) {
  916. //
  917. // Don't load these here. Rather get the headless settings from firmware.
  918. // -matth (2/2002)
  919. //
  920. // BlGetHeadlessRestartBlock(&gTFTPRestartBlock, restartBlockValid);
  921. if (AdministratorPassword) {
  922. RtlMoveMemory(AdministratorPassword,gTFTPRestartBlock.AdministratorPassword, OSC_ADMIN_PASSWORD_LEN);
  923. }
  924. }
  925. if (restartBlockValid && ClearRestartBlock) {
  926. RtlZeroMemory(&gTFTPRestartBlock, sizeof(TFTP_RESTART_BLOCK));
  927. }
  928. #if DBG
  929. BlPrint(TEXT("Done getting TFTP_RESTART_BLOCK.\r\n"));
  930. #endif
  931. return;
  932. }
  933. ARC_STATUS
  934. NetFillNetworkLoaderBlock (
  935. PNETWORK_LOADER_BLOCK NetworkLoaderBlock
  936. )
  937. {
  938. EFI_STATUS Status;
  939. ARC_STATUS ArcStatus;
  940. //
  941. // get a pointer to the PXE client code.
  942. //
  943. Status = EfiGetPxeClient();
  944. if (Status != EFI_SUCCESS) {
  945. ArcStatus = EIO;
  946. goto cleanup;
  947. }
  948. //
  949. // save off the DHCPServerACK packet
  950. //
  951. NetworkLoaderBlock->DHCPServerACK = BlAllocateHeap(sizeof(EFI_PXE_BASE_CODE_PACKET));
  952. if (NetworkLoaderBlock->DHCPServerACK == NULL) {
  953. ArcStatus = ENOMEM;
  954. goto cleanup;
  955. }
  956. memcpy(
  957. NetworkLoaderBlock->DHCPServerACK,
  958. &PXEClient->Mode->DhcpAck,
  959. sizeof(EFI_PXE_BASE_CODE_PACKET) );
  960. NetworkLoaderBlock->DHCPServerACKLength = sizeof(EFI_PXE_BASE_CODE_PACKET);
  961. //
  962. // save off the BINL reply packet
  963. //
  964. NetworkLoaderBlock->BootServerReplyPacket = BlAllocateHeap(sizeof(EFI_PXE_BASE_CODE_PACKET));
  965. if (NetworkLoaderBlock->BootServerReplyPacket == NULL) {
  966. ArcStatus = ENOMEM;
  967. goto cleanup;
  968. }
  969. memcpy(
  970. NetworkLoaderBlock->BootServerReplyPacket,
  971. &PXEClient->Mode->ProxyOffer,
  972. sizeof(EFI_PXE_BASE_CODE_PACKET) );
  973. NetworkLoaderBlock->BootServerReplyPacketLength = sizeof(EFI_PXE_BASE_CODE_PACKET);
  974. //
  975. // we succeeded, mark success
  976. //
  977. ArcStatus = ESUCCESS;
  978. cleanup:
  979. return(ArcStatus);
  980. }