3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 An implementation of the load file protocol for network devices.
23 #define DO_MENU (EFI_SUCCESS)
24 #define NO_MENU (DO_MENU + 1)
25 #define LOCAL_BOOT (EFI_ABORTED)
26 #define AUTO_SELECT (NO_MENU)
28 #define NUMBER_ROWS 25 // we set to mode 0
29 #define MAX_MENULIST 23
31 #define Ctl(x) (0x1F & (x))
34 DHCPV4_OP_STRUCT
*OpPtr
;
35 PXE_BOOT_MENU_ENTRY
*CurrentMenuItemPtr
;
36 PXE_OP_DISCOVERY_CONTROL
*DiscCtlOpStr
;
37 PXE_OP_BOOT_MENU
*MenuPtr
;
43 EFI_PXE_BASE_CODE_CALLBACK_STATUS
46 IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
* This
,
47 IN EFI_PXE_BASE_CODE_FUNCTION Function
,
49 IN UINT32 PacketLength
,
50 IN EFI_PXE_BASE_CODE_PACKET
* PacketPtr OPTIONAL
56 PxeBc callback routine for status updates and aborts.
60 This - Pointer to PxeBcCallback interface
61 Function - PxeBc function ID#
62 Received - Receive/transmit flag
63 PacketLength - Length of received packet (0 == idle callback)
64 PacketPtr - Pointer to received packet (NULL == idle callback)
68 EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE -
69 EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT -
73 STATIC UINTN Propeller
;
81 // Resolve Warning 4 unreferenced parameter problem
86 // Check for user abort.
88 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
) == EFI_SUCCESS
) {
90 if (Key
.UnicodeChar
== Ctl ('c')) {
91 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT
;
93 } else if (Key
.ScanCode
== SCAN_ESC
) {
94 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT
;
98 // Do nothing if this is a receive.
101 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
;
104 // The display code is only for these functions.
107 case EFI_PXE_BASE_CODE_FUNCTION_MTFTP
:
109 // If this is a transmit and not a M/TFTP open request,
110 // return now. Do not print a dot for each M/TFTP packet
111 // that is sent, only for the open packets.
113 if (PacketLength
!= 0 && PacketPtr
!= NULL
) {
114 if (PacketPtr
->Raw
[0x1C] != 0x00 || PacketPtr
->Raw
[0x1D] != 0x01) {
115 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
;
121 case EFI_PXE_BASE_CODE_FUNCTION_DHCP
:
122 case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER
:
126 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
;
131 if (PacketLength
!= 0 && PacketPtr
!= NULL
) {
133 // Display a '.' when a packet is transmitted.
136 } else if (PacketLength
== 0 && PacketPtr
== NULL
) {
138 // Display a propeller when waiting for packets if at
139 // least 200 ms have passed.
141 Row
= gST
->ConOut
->Mode
->CursorRow
;
142 Col
= gST
->ConOut
->Mode
->CursorColumn
;
144 AsciiPrint ("%c", "/-\\|"[Propeller
]);
145 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Col
, Row
);
147 Propeller
= (Propeller
+ 1) & 3;
150 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
;
153 STATIC EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL _bc_callback
= {
154 EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION
,
167 Display an IPv4 address in dot notation.
171 Ptr - Pointer to IPv4 address.
180 AsciiPrint ("%d.%d.%d.%d", Ptr
[0], Ptr
[1], Ptr
[2], Ptr
[3]);
187 IN PXE_BASECODE_DEVICE
*Private
193 Display client and server IP information.
197 Private - Pointer to PxeBc interface
205 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
209 // Do nothing if a NULL pointer is passed in.
211 if (Private
== NULL
) {
215 // Get pointer to PXE BaseCode mode structure
217 PxeBcMode
= Private
->EfiBc
.Mode
;
220 // Display client IP address
222 AsciiPrint ("\rCLIENT IP: ");
223 PrintIpv4 (PxeBcMode
->StationIp
.v4
.Addr
);
226 // Display subnet mask
228 AsciiPrint (" MASK: ");
229 PrintIpv4 (PxeBcMode
->SubnetMask
.v4
.Addr
);
232 // Display DHCP and proxyDHCP IP addresses
234 if (PxeBcMode
->ProxyOfferReceived
) {
235 AsciiPrint ("\nDHCP IP: ");
236 PrintIpv4 (((DHCPV4_OP_SERVER_IP
*) DHCPV4_ACK_BUFFER
.OpAdds
.PktOptAdds
[OP_DHCP_SERVER_IP_IX
- 1])->Ip
.Addr
);
238 AsciiPrint (" PROXY IP: ");
239 PrintIpv4 (((DHCPV4_OP_SERVER_IP
*) PXE_OFFER_BUFFER
.OpAdds
.PktOptAdds
[OP_DHCP_SERVER_IP_IX
- 1])->Ip
.Addr
);
241 AsciiPrint (" DHCP IP: ");
242 PrintIpv4 (((DHCPV4_OP_SERVER_IP
*) DHCPV4_ACK_BUFFER
.OpAdds
.PktOptAdds
[OP_DHCP_SERVER_IP_IX
- 1])->Ip
.Addr
);
245 // Display gateway IP addresses
247 for (Index
= 0; Index
< PxeBcMode
->RouteTableEntries
; ++Index
) {
248 if ((Index
% 3) == 0) {
249 AsciiPrint ("\r\nGATEWAY IP:");
253 PrintIpv4 (PxeBcMode
->RouteTable
[Index
].GwAddr
.v4
.Addr
);
263 PXE_BASECODE_DEVICE
*Private
,
264 PXE_OP_BOOT_PROMPT
*BootPromptPtr
270 Display prompt and wait for input.
274 Private - Pointer to PxeBc interface
275 BootPromptPtr - Pointer to PXE boot prompt option
287 EFI_EVENT TimeoutEvent
;
288 EFI_EVENT SecondsEvent
;
295 // if auto select, just get right to it
297 if (BootPromptPtr
->Timeout
== PXE_BOOT_PROMPT_AUTO_SELECT
) {
301 // if no timeout, go directly to display of menu
303 if (BootPromptPtr
->Timeout
== PXE_BOOT_PROMPT_NO_TIMEOUT
) {
309 Status
= gBS
->CreateEvent (
317 if (EFI_ERROR (Status
)) {
321 Status
= gBS
->SetTimer (
324 BootPromptPtr
->Timeout
* 10000000 + 100000
327 if (EFI_ERROR (Status
)) {
328 gBS
->CloseEvent (TimeoutEvent
);
334 Status
= gBS
->CreateEvent (
342 if (EFI_ERROR (Status
)) {
343 gBS
->CloseEvent (TimeoutEvent
);
347 Status
= gBS
->SetTimer (
353 if (EFI_ERROR (Status
)) {
354 gBS
->CloseEvent (SecondsEvent
);
355 gBS
->CloseEvent (TimeoutEvent
);
359 // display the prompt
360 // IMPORTANT! This prompt is an ASCII character string that may
361 // not be terminated with a NULL byte.
363 SaveChar
= BootPromptPtr
->Prompt
[BootPromptPtr
->Header
.Length
- 1];
364 BootPromptPtr
->Prompt
[BootPromptPtr
->Header
.Length
- 1] = 0;
366 AsciiPrint ("%a ", BootPromptPtr
->Prompt
);
367 BootPromptPtr
->Prompt
[BootPromptPtr
->Header
.Length
- 1] = SaveChar
;
370 // wait until time expires or selection made - menu or local
372 SecColumn
= gST
->ConOut
->Mode
->CursorColumn
;
373 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
374 SecsLeft
= BootPromptPtr
->Timeout
;
376 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecColumn
, SecRow
);
377 AsciiPrint ("(%d) ", SecsLeft
);
380 // set the default action to be AUTO_SELECT
382 Status
= AUTO_SELECT
;
384 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
387 if (!EFI_ERROR (gBS
->CheckEvent (SecondsEvent
))) {
389 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecColumn
, SecRow
);
390 AsciiPrint ("(%d) ", SecsLeft
);
393 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
) == EFI_NOT_READY
) {
398 BufferSize
= sizeof Buffer
;
400 Status
= Private
->EfiBc
.UdpRead (
402 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
|
403 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
|
404 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT
,
406 NULL
, /* dest port */
418 if (Key
.ScanCode
== 0) {
419 switch (Key
.UnicodeChar
) {
434 switch (Key
.ScanCode
) {
451 gBS
->CloseEvent (SecondsEvent
);
452 gBS
->CloseEvent (TimeoutEvent
);
454 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecColumn
, SecRow
);
463 PXE_BOOT_MENU_ENTRY
*MenuItemPtr
469 Display one menu item.
473 MenuItemPtr - Pointer to PXE menu item option.
484 Length
= (UINT8
) EFI_MIN (70, MenuItemPtr
->DataLen
);
485 SaveChar
= MenuItemPtr
->Data
[Length
];
487 MenuItemPtr
->Data
[Length
] = 0;
488 AsciiPrint (" %a\n", MenuItemPtr
->Data
);
489 MenuItemPtr
->Data
[Length
] = SaveChar
;
495 PXE_BASECODE_DEVICE
*Private
,
496 DHCP_RECEIVE_BUFFER
*RxBufferPtr
502 Display and process menu.
506 Private - Pointer to PxeBc interface
507 RxBufferPtr - Pointer to receive buffer
516 PXE_OP_DISCOVERY_CONTROL
*DiscoveryControlPtr
;
517 PXE_BOOT_MENU_ENTRY
*MenuItemPtrs
[MAX_MENULIST
];
534 DEBUG ((EFI_D_WARN
, "\nDoMenu() Enter."));
536 /* see if we have a menu/prompt */
537 if (!(RxBufferPtr
->OpAdds
.Status
& DISCOVER_TYPE
)) {
540 "\nDoMenu() No menu/prompt info. OpAdds.Status == %xh ",
541 RxBufferPtr
->OpAdds
.Status
)
547 DiscoveryControlPtr
= (PXE_OP_DISCOVERY_CONTROL
*) RxBufferPtr
->OpAdds
.PxeOptAdds
[VEND_PXE_DISCOVERY_CONTROL_IX
- 1];
550 // if not USE_BOOTFILE or no bootfile given, must have menu stuff
552 if ((DiscoveryControlPtr
->ControlBits
& USE_BOOTFILE
) && RxBufferPtr
->OpAdds
.PktOptAdds
[OP_DHCP_BOOTFILE_IX
- 1]) {
553 DEBUG ((EFI_D_WARN
, "\nDoMenu() DHCP w/ bootfile. "));
557 // do prompt & menu if necessary
559 Status
= DoPrompt (Private
, (PXE_OP_BOOT_PROMPT
*) RxBufferPtr
->OpAdds
.PxeOptAdds
[VEND_PXE_BOOT_PROMPT_IX
- 1]);
561 if (Status
== LOCAL_BOOT
) {
562 DEBUG ((EFI_D_WARN
, "\nDoMenu() DoPrompt() returned LOCAL_BOOT. "));
567 Ptr
.BytePtr
= (UINT8
*) RxBufferPtr
->OpAdds
.PxeOptAdds
[VEND_PXE_BOOT_MENU_IX
- 1];
569 MenuLth
= Ptr
.MenuPtr
->Header
.Length
;
570 Ptr
.CurrentMenuItemPtr
= Ptr
.MenuPtr
->MenuItem
;
573 // build menu items array
575 for (Longest
= NumMenuItems
= Index
= 0; Index
< MenuLth
&& NumMenuItems
<= MAX_MENULIST
;) {
578 lth
= Ptr
.CurrentMenuItemPtr
->DataLen
+ sizeof (*Ptr
.CurrentMenuItemPtr
) - sizeof (Ptr
.CurrentMenuItemPtr
->Data
);
580 MenuItemPtrs
[NumMenuItems
++] = Ptr
.CurrentMenuItemPtr
;
586 if ((Longest
= lth
) > 70 + (sizeof (*Ptr
.CurrentMenuItemPtr
) - sizeof (Ptr
.CurrentMenuItemPtr
->Data
))) {
587 Longest
= 70 + (sizeof (*Ptr
.CurrentMenuItemPtr
) - sizeof (Ptr
.CurrentMenuItemPtr
->Data
));
595 if (Status
!= AUTO_SELECT
) {
598 SetMem (BlankBuf
, sizeof BlankBuf
, ' ');
599 BlankBuf
[Longest
+ 5 - (sizeof (*Ptr
.CurrentMenuItemPtr
) - sizeof (Ptr
.CurrentMenuItemPtr
->Data
))] = 0;
605 for (Index
= 0; Index
< NumMenuItems
; ++Index
) {
606 PrintMenuItem (MenuItemPtrs
[Index
]);
609 TopRow
= gST
->ConOut
->Mode
->CursorRow
- NumMenuItems
;
612 // now wait for a selection
617 // highlight selection
622 NewSelected
= Selected
;
625 // highlight selected row
627 gST
->ConOut
->SetAttribute (
629 EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
)
631 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Selected
);
633 AsciiPrint (" --->%a\r", BlankBuf
);
635 PrintMenuItem (MenuItemPtrs
[Selected
]);
636 gST
->ConOut
->SetAttribute (
638 EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
)
640 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ NumMenuItems
);
643 // wait for a keystroke
645 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
) == EFI_NOT_READY
) {
649 TmpBufLen
= sizeof TmpBuf
;
651 Private
->EfiBc
.UdpRead (
653 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP
|
654 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT
|
655 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT
,
657 NULL
, /* dest port */
668 switch (Key
.UnicodeChar
) {
670 Key
.ScanCode
= SCAN_ESC
;
673 case Ctl ('j'): /* linefeed */
674 case Ctl ('m'): /* return */
678 case Ctl ('i'): /* tab */
682 Key
.ScanCode
= SCAN_DOWN
;
685 case Ctl ('h'): /* backspace */
688 Key
.ScanCode
= SCAN_UP
;
696 switch (Key
.ScanCode
) {
707 if (++NewSelected
== NumMenuItems
) {
720 NewSelected
= NumMenuItems
- 1;
727 /* unhighlight last selected row */
728 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 5, TopRow
+ Selected
);
730 AsciiPrint ("%a\r", BlankBuf
);
732 PrintMenuItem (MenuItemPtrs
[Selected
]);
734 Selected
= NewSelected
;
738 SaveNumRte
= Private
->EfiBc
.Mode
->RouteTableEntries
;
740 Type
= NTOHS (MenuItemPtrs
[Selected
]->Type
);
743 DEBUG ((EFI_D_WARN
, "\nDoMenu() Local boot selected. "));
747 AsciiPrint ("Discover");
749 Status
= Private
->EfiBc
.Discover (
753 (BOOLEAN
) (Private
->EfiBc
.Mode
->BisSupported
&& Private
->EfiBc
.Mode
->BisDetected
),
757 if (EFI_ERROR (Status
)) {
758 AsciiPrint ("\r \r");
762 "\nDoMenu() Return w/ %xh (%r).",
770 AsciiPrint ("\rBOOT_SERVER_IP: ");
771 PrintIpv4 ((UINT8
*) &Private
->ServerIp
);
773 for (Index
= SaveNumRte
; Index
< Private
->EfiBc
.Mode
->RouteTableEntries
; ++Index
) {
774 if ((Index
% 3) == 0) {
775 AsciiPrint ("\r\nGATEWAY IP:");
779 PrintIpv4 ((UINT8
*) &Private
->EfiBc
.Mode
->RouteTable
[Index
].GwAddr
);
785 DEBUG ((EFI_D_WARN
, "\nDoMenu() Return w/ EFI_SUCCESS. "));
793 DHCPV4_OP_STRUCT
*OpPtr
799 Get value 8- or 16-bit value from DHCP option.
803 OpPtr - Pointer to DHCP option
807 Value from DHCP option
811 if (OpPtr
->Header
.Length
== 1) {
812 return OpPtr
->Data
[0];
814 return NTOHS (OpPtr
->Data
);
829 Locate opcode in buffer.
833 BufferPtr - Pointer to buffer
834 BufferLen - Length of buffer
835 OpCode - Option number
839 Pointer to opcode, may be NULL
843 if (BufferPtr
== NULL
) {
847 while (BufferLen
!= 0) {
848 if (*BufferPtr
== OpCode
) {
852 switch (*BufferPtr
) {
862 if ((UINTN
) BufferLen
<= (UINTN
) 2 + BufferPtr
[1]) {
866 BufferLen
-= 2 + BufferPtr
[1];
867 BufferPtr
+= 2 + BufferPtr
[1];
875 EFI_PXE_BASE_CODE_PACKET
*PacketPtr
,
882 Find option in packet
886 PacketPtr - Pointer to packet
887 OpCode - option number
891 Pointer to option in packet
897 UINT8
*OptionBufferPtr
;
906 // Figure size of DHCP option space.
908 OptionBufferPtr
= _PxeBcFindOpt (
909 PacketPtr
->Dhcpv4
.DhcpOptions
,
911 OP_DHCP_MAX_MESSAGE_SZ
914 if (OptionBufferPtr
!= NULL
) {
915 if (OptionBufferPtr
[1] == 2) {
918 CopyMem (&n
, &OptionBufferPtr
[2], 2);
919 PacketLen
= HTONS (n
);
921 if (PacketLen
< sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET
)) {
924 PacketLen
-= (PacketPtr
->Dhcpv4
.DhcpOptions
- &PacketPtr
->Dhcpv4
.BootpOpcode
) + 28;
929 // Look for option overloading.
931 OptionBufferPtr
= _PxeBcFindOpt (
932 PacketPtr
->Dhcpv4
.DhcpOptions
,
934 OP_DHCP_OPTION_OVERLOAD
937 if (OptionBufferPtr
!= NULL
) {
938 if (OptionBufferPtr
[1] == 1) {
939 Overload
= OptionBufferPtr
[2];
943 // Look for caller's option.
945 OptionBufferPtr
= _PxeBcFindOpt (
946 PacketPtr
->Dhcpv4
.DhcpOptions
,
951 if (OptionBufferPtr
!= NULL
) {
952 return OptionBufferPtr
;
955 if (Overload
& OVLD_FILE
) {
956 OptionBufferPtr
= _PxeBcFindOpt (PacketPtr
->Dhcpv4
.BootpBootFile
, 128, OpCode
);
958 if (OptionBufferPtr
!= NULL
) {
959 return OptionBufferPtr
;
963 if (Overload
& OVLD_SRVR_NAME
) {
964 OptionBufferPtr
= _PxeBcFindOpt (PacketPtr
->Dhcpv4
.BootpSrvName
, 64, OpCode
);
966 if (OptionBufferPtr
!= NULL
) {
967 return OptionBufferPtr
;
977 IN PXE_BASECODE_DEVICE
*Private
,
978 IN OUT UINT64
*BufferSize
,
985 Download file into buffer
989 Private - Pointer to PxeBc interface
990 BufferSize - pointer to size of download buffer
991 Buffer - Pointer to buffer
995 EFI_BUFFER_TOO_SMALL -
1001 EFI_PXE_BASE_CODE_MTFTP_INFO MtftpInfo
;
1002 EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode
;
1003 DHCP_RECEIVE_BUFFER
*RxBuf
;
1007 RxBuf
= (DHCP_RECEIVE_BUFFER
*) Private
->BootServerReceiveBuffer
;
1010 DEBUG ((EFI_D_WARN
, "\nDownloadFile() Enter."));
1012 if (Buffer
== NULL
|| *BufferSize
== 0 || *BufferSize
< Private
->FileSize
) {
1013 if (Private
->FileSize
!= 0) {
1014 *BufferSize
= Private
->FileSize
;
1015 return EFI_BUFFER_TOO_SMALL
;
1018 AsciiPrint ("\nTSize");
1020 OpCode
= EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
;
1021 } else if (RxBuf
->OpAdds
.Status
& WfM11a_TYPE
) {
1022 OpCode
= EFI_PXE_BASE_CODE_MTFTP_READ_FILE
;
1024 ZeroMem (&MtftpInfo
, sizeof MtftpInfo
);
1026 *(IPV4_ADDR
*) &MtftpInfo
.MCastIp
= *(IPV4_ADDR
*) RxBuf
->OpAdds
.PxeOptAdds
[VEND_PXE_MTFTP_IP
- 1]->Data
;
1030 RxBuf
->OpAdds
.PxeOptAdds
[VEND_PXE_MTFTP_CPORT
- 1]->Data
,
1031 sizeof MtftpInfo
.CPort
1036 RxBuf
->OpAdds
.PxeOptAdds
[VEND_PXE_MTFTP_SPORT
- 1]->Data
,
1037 sizeof MtftpInfo
.SPort
1040 MtftpInfo
.ListenTimeout
= GetValue (RxBuf
->OpAdds
.PxeOptAdds
[VEND_PXE_MTFTP_TMOUT
- 1]);
1042 MtftpInfo
.TransmitTimeout
= GetValue (RxBuf
->OpAdds
.PxeOptAdds
[VEND_PXE_MTFTP_DELAY
- 1]);
1044 AsciiPrint ("\nMTFTP");
1046 AsciiPrint ("\nTFTP");
1048 OpCode
= EFI_PXE_BASE_CODE_TFTP_READ_FILE
;
1051 Private
->FileSize
= 0;
1053 RxBuf
->OpAdds
.PktOptAdds
[OP_DHCP_BOOTFILE_IX
- 1]->Data
[RxBuf
->OpAdds
.PktOptAdds
[OP_DHCP_BOOTFILE_IX
- 1]->Header
.Length
] = 0;
1055 Status
= Private
->EfiBc
.Mtftp (
1063 (UINT8
*) RxBuf
->OpAdds
.PktOptAdds
[OP_DHCP_BOOTFILE_IX
- 1]->Data
,
1068 if (Status
!= EFI_SUCCESS
&& Status
!= EFI_BUFFER_TOO_SMALL
) {
1069 DEBUG ((EFI_D_WARN
, "\nDownloadFile() Exit #1 %Xh", Status
));
1073 if (sizeof (UINTN
) < sizeof (UINT64
) && *BufferSize
> 0xFFFFFFFF) {
1074 Private
->FileSize
= 0xFFFFFFFF;
1076 Private
->FileSize
= (UINTN
) *BufferSize
;
1079 if (OpCode
== EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
) {
1080 DEBUG ((EFI_D_WARN
, "\nDownloadFile() Exit #2"));
1081 return EFI_BUFFER_TOO_SMALL
;
1084 if (EFI_ERROR (Status
)) {
1085 DEBUG ((EFI_D_WARN
, "\nDownloadFile() Exit #3 %Xh", Status
));
1089 if (Private
->EfiBc
.Mode
->BisSupported
&& Private
->EfiBc
.Mode
->BisDetected
&& Private
->EfiBc
.Mode
->PxeBisReplyReceived
) {
1090 UINT64 CredentialLen
;
1092 UINT8 CredentialFilename
[256];
1094 VOID
*CredentialBuffer
;
1097 // Get name of credential file. It may be in the BOOTP
1098 // bootfile field or a DHCP option.
1100 ZeroMem (CredentialFilename
, sizeof CredentialFilename
);
1102 op
= PxeBcFindDhcpOpt (&Private
->EfiBc
.Mode
->PxeBisReply
, OP_DHCP_BOOTFILE
);
1106 /* No credential filename */
1107 return EFI_NOT_FOUND
;
1110 CopyMem (CredentialFilename
, &op
[2], op
[1]);
1112 if (Private
->EfiBc
.Mode
->PxeBisReply
.Dhcpv4
.BootpBootFile
[0] == 0) {
1113 /* No credential filename */
1114 return EFI_NOT_FOUND
;
1117 CopyMem (CredentialFilename
, &op
[2], 128);
1120 // Get size of credential file. It may be available as a
1121 // DHCP option. If not, use the TFTP get file size.
1125 op
= PxeBcFindDhcpOpt (&Private
->EfiBc
.Mode
->PxeBisReply
, OP_BOOT_FILE_SZ
);
1129 * This is actually the size of the credential file
1130 * buffer. The actual credential file size will be
1131 * returned when we download the file.
1136 CopyMem (&n
, &op
[2], 2);
1137 CredentialLen
= HTONS (n
) * 512;
1141 if (CredentialLen
== 0) {
1144 Status
= Private
->EfiBc
.Mtftp (
1146 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
1157 if (EFI_ERROR (Status
)) {
1161 if (CredentialLen
== 0) {
1163 // %%TBD -- EFI error for invalid credential
1166 return EFI_PROTOCOL_ERROR
;
1170 // Allocate credential file buffer.
1172 Status
= gBS
->AllocatePool (
1173 EfiBootServicesData
,
1174 (UINTN
) CredentialLen
,
1178 if (EFI_ERROR (Status
)) {
1182 // Download credential file.
1186 Status
= Private
->EfiBc
.Mtftp (
1188 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1199 if (EFI_ERROR (Status
)) {
1200 gBS
->FreePool (CredentialBuffer
);
1204 // Verify credentials.
1206 if (PxebcBisVerify (Private
, Buffer
, Private
->FileSize
, CredentialBuffer
, (UINTN
) CredentialLen
)) {
1207 Status
= EFI_SUCCESS
;
1210 // %%TBD -- An EFI error code for failing credential verification.
1212 Status
= EFI_PROTOCOL_ERROR
;
1215 gBS
->FreePool (CredentialBuffer
);
1224 IN PXE_BASECODE_DEVICE
*Private
,
1225 IN OUT UINT64
*BufferSize
,
1230 Routine Description:
1232 Start PXE DHCP. Get DHCP and proxyDHCP information.
1233 Display remote boot menu and prompt. Select item from menu.
1237 Private - Pointer to PxeBc interface
1238 BufferSize - Pointer to download buffer size
1239 Buffer - Pointer to download buffer
1248 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
1249 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
1250 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
1254 DEBUG ((EFI_D_WARN
, "\nLoadfileStart() Enter."));
1257 // Try to start BaseCode, for now only IPv4 is supported
1258 // so don't try to start using IPv6.
1260 Status
= Private
->EfiBc
.Start (&Private
->EfiBc
, FALSE
);
1262 if (EFI_ERROR (Status
)) {
1263 if (Status
!= EFI_ALREADY_STARTED
) {
1264 DEBUG ((EFI_D_NET
, "\nLoadfileStart() Exit BC.Start() == %xh", Status
));
1269 // Get pointers to PXE mode structure, SNP protocol structure
1270 // and SNP mode structure.
1272 PxeBcMode
= Private
->EfiBc
.Mode
;
1273 Snp
= Private
->SimpleNetwork
;
1274 SnpMode
= Snp
->Mode
;
1277 // Display client MAC address, like 16-bit PXE ROMs
1279 AsciiPrint ("\nCLIENT MAC ADDR: ");
1285 hlen
= SnpMode
->HwAddressSize
;
1287 for (Index
= 0; Index
< hlen
; ++Index
) {
1288 AsciiPrint ("%02x ", SnpMode
->CurrentAddress
.Addr
[Index
]);
1292 AsciiPrint ("\nDHCP");
1294 Status
= Private
->EfiBc
.Dhcp (&Private
->EfiBc
, TRUE
);
1296 if (EFI_ERROR (Status
)) {
1297 DEBUG ((EFI_D_WARN
, "\nLoadfileStart() Exit BC.Dhcp() == %Xh", Status
));
1298 AsciiPrint ("\r \r");
1302 ShowMyInfo (Private
);
1304 RxBuf
= PxeBcMode
->ProxyOfferReceived
? &PXE_OFFER_BUFFER
: &DHCPV4_ACK_BUFFER
;
1305 #define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)
1307 Status
= DoMenu (Private
, RxBufferPtr
);
1309 if (Status
== EFI_SUCCESS
) {
1311 // did a discovery - take info from discovery packet
1313 RxBuf
= &PXE_ACK_BUFFER
;
1314 } else if (Status
== NO_MENU
) {
1316 // did not do a discovery - take info from rxbuf
1318 Private
->ServerIp
.Addr
[0] = RxBufferPtr
->u
.Dhcpv4
.siaddr
;
1320 if (!(Private
->ServerIp
.Addr
[0])) {
1321 *(IPV4_ADDR
*) &Private
->ServerIp
= *(IPV4_ADDR
*) RxBufferPtr
->OpAdds
.PktOptAdds
[OP_DHCP_SERVER_IP_IX
- 1]->Data
;
1324 DEBUG ((EFI_D_WARN
, "\nLoadfileStart() Exit DoMenu() == %Xh", Status
));
1328 if (!RxBufferPtr
->OpAdds
.PktOptAdds
[OP_DHCP_BOOTFILE_IX
- 1]) {
1329 DEBUG ((EFI_D_WARN
, "\nLoadfileStart() Exit Not ready?"));
1330 return EFI_NOT_READY
;
1333 // check for file size option sent
1335 if (RxBufferPtr
->OpAdds
.PktOptAdds
[OP_BOOT_FILE_SZ_IX
- 1]) {
1336 Private
->FileSize
= 512 * NTOHS (RxBufferPtr
->OpAdds
.PktOptAdds
[OP_BOOT_FILE_SZ_IX
- 1]->Data
);
1339 Private
->BootServerReceiveBuffer
= RxBufferPtr
;
1341 Status
= DownloadFile (Private
, BufferSize
, Buffer
);
1345 "\nLoadfileStart() Exit. DownloadFile() = %Xh",
1355 IN EFI_LOAD_FILE_PROTOCOL
*This
,
1356 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1357 IN BOOLEAN BootPolicy
,
1358 IN OUT UINTN
*BufferSize
,
1363 Routine Description:
1365 Loadfile interface for PxeBc interface
1369 This - Pointer to Loadfile interface
1370 FilePath - Not used and not checked
1371 BootPolicy - Must be TRUE
1372 BufferSize - Pointer to buffer size
1373 Buffer - Pointer to download buffer or NULL
1377 EFI_INVALID_PARAMETER -
1380 EFI_BUFFER_TOO_SMALL -
1384 LOADFILE_DEVICE
*LoadfilePtr
;
1387 INT32 OrigAttribute
;
1388 BOOLEAN RemoveCallback
;
1389 BOOLEAN NewMakeCallback
;
1391 EFI_STATUS TempStatus
;
1395 OrigMode
= gST
->ConOut
->Mode
->Mode
;
1396 OrigAttribute
= gST
->ConOut
->Mode
->Attribute
;
1397 RemoveCallback
= FALSE
;
1399 AsciiPrint ("Running LoadFile()\n");
1402 // Resolve Warning 4 unreferenced parameter problem
1407 // If either if these parameters are NULL, we cannot continue.
1409 if (This
== NULL
|| BufferSize
== NULL
) {
1410 DEBUG ((EFI_D_WARN
, "\nLoadFile() This or BufferSize == NULL"));
1411 return EFI_INVALID_PARAMETER
;
1414 // We only support BootPolicy == TRUE
1417 DEBUG ((EFI_D_WARN
, "\nLoadFile() BootPolicy == FALSE"));
1418 return EFI_UNSUPPORTED
;
1421 // Get pointer to LoadFile protocol structure.
1423 LoadfilePtr
= CR (This
, LOADFILE_DEVICE
, LoadFile
, LOADFILE_DEVICE_SIGNATURE
);
1425 if (LoadfilePtr
== NULL
) {
1428 "\nLoadFile() Could not get pointer to LoadFile structure")
1430 return EFI_INVALID_PARAMETER
;
1435 EfiAcquireLock (&LoadfilePtr
->Lock
);
1438 // Set console output mode and display attribute
1440 if (OrigMode
!= 0) {
1441 gST
->ConOut
->SetMode (gST
->ConOut
, 0);
1444 gST
->ConOut
->SetAttribute (
1446 EFI_TEXT_ATTR (EFI_LIGHTGRAY
,EFI_BLACK
)
1450 // See if BaseCode already has a Callback protocol attached.
1451 // If there is none, attach our own Callback protocol.
1453 Status
= gBS
->HandleProtocol (
1454 LoadfilePtr
->Private
->Handle
,
1455 &gEfiPxeBaseCodeCallbackProtocolGuid
,
1456 (VOID
*) &LoadfilePtr
->Private
->CallbackProtocolPtr
1462 // There is already a callback routine. Do nothing.
1464 DEBUG ((EFI_D_WARN
, "\nLoadFile() BC callback exists."));
1467 case EFI_UNSUPPORTED
:
1469 // No BaseCode Callback protocol found. Add our own.
1471 Status
= gBS
->InstallProtocolInterface (
1472 &LoadfilePtr
->Private
->Handle
,
1473 &gEfiPxeBaseCodeCallbackProtocolGuid
,
1474 EFI_NATIVE_INTERFACE
,
1478 DEBUG ((EFI_D_WARN
, "\nLoadFile() Callback install status == %xh", Status
));
1480 RemoveCallback
= (BOOLEAN
) (Status
== EFI_SUCCESS
);
1482 if (LoadfilePtr
->Private
->EfiBc
.Mode
!= NULL
&& LoadfilePtr
->Private
->EfiBc
.Mode
->Started
) {
1483 NewMakeCallback
= TRUE
;
1484 LoadfilePtr
->Private
->EfiBc
.SetParameters (
1485 &LoadfilePtr
->Private
->EfiBc
,
1497 DEBUG ((EFI_D_WARN
, "\nLoadFile() Callback check status == %xh", Status
));
1500 // Check for starting or for continuing after already getting
1503 if (LoadfilePtr
->Private
->FileSize
== 0) {
1505 Status
= LoadfileStart (LoadfilePtr
->Private
, &TmpBufSz
, Buffer
);
1507 if (sizeof (UINTN
) < sizeof (UINT64
) && TmpBufSz
> 0xFFFFFFFF) {
1508 *BufferSize
= 0xFFFFFFFF;
1510 *BufferSize
= (UINTN
) TmpBufSz
;
1513 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1515 // This is done so loadfile will work even if the boot manager
1516 // did not make the first call with Buffer == NULL.
1520 } else if (Buffer
== NULL
) {
1521 DEBUG ((EFI_D_WARN
, "\nLoadfile() Get buffer size"));
1524 // Continuing from previous LoadFile request. Make sure there
1525 // is a buffer and that it is big enough.
1527 *BufferSize
= LoadfilePtr
->Private
->FileSize
;
1528 Status
= EFI_BUFFER_TOO_SMALL
;
1530 DEBUG ((EFI_D_WARN
, "\nLoadFile() Download file"));
1533 // Everything looks good, try to download the file.
1535 TmpBufSz
= *BufferSize
;
1536 Status
= DownloadFile (LoadfilePtr
->Private
, &TmpBufSz
, Buffer
);
1539 // Next call to loadfile will start DHCP process again.
1541 LoadfilePtr
->Private
->FileSize
= 0;
1544 // If we added a callback protocol, now is the time to remove it.
1546 if (RemoveCallback
) {
1547 NewMakeCallback
= FALSE
;
1548 TempStatus
= LoadfilePtr
->Private
->EfiBc
.SetParameters (
1549 &LoadfilePtr
->Private
->EfiBc
,
1557 if (TempStatus
== EFI_SUCCESS
) {
1558 gBS
->UninstallProtocolInterface (
1559 LoadfilePtr
->Private
->Handle
,
1560 &gEfiPxeBaseCodeCallbackProtocolGuid
,
1566 // Restore display mode and attribute
1568 if (OrigMode
!= 0) {
1569 gST
->ConOut
->SetMode (gST
->ConOut
, OrigMode
);
1572 gST
->ConOut
->SetAttribute (gST
->ConOut
, OrigAttribute
);
1577 EfiReleaseLock (&LoadfilePtr
->Lock
);
1579 DEBUG ((EFI_D_WARN
, "\nBC.Loadfile() Status == %xh\n", Status
));
1582 case EFI_SUCCESS
: /* 0 */
1585 case EFI_BUFFER_TOO_SMALL
: /* 5 */
1587 // Error is only displayed when we are actually trying to
1588 // download the boot image.
1590 if (Buffer
== NULL
) {
1591 return EFI_BUFFER_TOO_SMALL
;
1594 AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n");
1597 case EFI_DEVICE_ERROR
: /* 7 */
1598 AsciiPrint ("\nPXE-E07: Network device error. Check network connection.\n");
1601 case EFI_OUT_OF_RESOURCES
: /* 9 */
1602 AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n");
1605 case EFI_NO_MEDIA
: /* 12 */
1606 AsciiPrint ("\nPXE-E12: Could not detect network connection. Check cable.\n");
1609 case EFI_NO_RESPONSE
: /* 16 */
1610 AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n");
1613 case EFI_TIMEOUT
: /* 18 */
1614 AsciiPrint ("\nPXE-E18: Timeout. Server did not respond.\n");
1617 case EFI_ABORTED
: /* 21 */
1618 AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n");
1621 case EFI_ICMP_ERROR
: /* 22 */
1622 AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n");
1624 if (LoadfilePtr
->Private
->EfiBc
.Mode
== NULL
) {
1628 if (!LoadfilePtr
->Private
->EfiBc
.Mode
->IcmpErrorReceived
) {
1633 "PXE-E98: Type: %xh Code: %xh ",
1634 LoadfilePtr
->Private
->EfiBc
.Mode
->IcmpError
.Type
,
1635 LoadfilePtr
->Private
->EfiBc
.Mode
->IcmpError
.Code
1638 switch (LoadfilePtr
->Private
->EfiBc
.Mode
->IcmpError
.Type
) {
1640 switch (LoadfilePtr
->Private
->EfiBc
.Mode
->IcmpError
.Code
) {
1641 case 0x00: /* net unreachable */
1642 AsciiPrint ("Net unreachable");
1645 case 0x01: /* host unreachable */
1646 AsciiPrint ("Host unreachable");
1649 case 0x02: /* protocol unreachable */
1650 AsciiPrint ("Protocol unreachable");
1653 case 0x03: /* port unreachable */
1654 AsciiPrint ("Port unreachable");
1657 case 0x04: /* Fragmentation needed */
1658 AsciiPrint ("Fragmentation needed");
1661 case 0x05: /* Source route failed */
1662 AsciiPrint ("Source route failed");
1673 case EFI_TFTP_ERROR
: /* 23 */
1674 AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n");
1676 if (LoadfilePtr
->Private
->EfiBc
.Mode
== NULL
) {
1680 if (LoadfilePtr
->Private
->EfiBc
.Mode
->TftpErrorReceived
) {
1682 "PXE-E98: Code: %xh %a\n",
1683 LoadfilePtr
->Private
->EfiBc
.Mode
->TftpError
.ErrorCode
,
1684 LoadfilePtr
->Private
->EfiBc
.Mode
->TftpError
.ErrorString
1691 AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status
);
1694 LoadfilePtr
->Private
->EfiBc
.Stop (&LoadfilePtr
->Private
->EfiBc
);