2 Boot functions implementation for UefiPxeBc Driver.
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "PxeBcImpl.h"
20 Display the string of the boot item.
22 If the length of the boot item string beyond 70 Char, just display 70 Char.
24 @param[in] Str The pointer to the string.
25 @param[in] Len The length of the string.
29 PxeBcDisplayBootItem (
37 // Cut off the chars behind 70th.
39 Len
= (UINT8
) MIN (PXEBC_DISPLAY_MAX_LINE
, Len
);
42 AsciiPrint ("%a \n", Str
);
45 // Restore the original 70th char.
52 Select and maintain the boot prompt if needed.
54 @param[in] Private Pointer to PxeBc private data.
56 @retval EFI_SUCCESS Selected boot prompt done.
57 @retval EFI_TIMEOUT Selected boot prompt timed out.
58 @retval EFI_NOT_FOUND The proxy offer is not Pxe10.
59 @retval EFI_ABORTED User cancelled the operation.
60 @retval EFI_NOT_READY Reading the input key from the keyboard has not finish.
64 PxeBcSelectBootPrompt (
65 IN PXEBC_PRIVATE_DATA
*Private
68 PXEBC_DHCP_PACKET_CACHE
*Cache
;
69 PXEBC_VENDOR_OPTION
*VendorOpt
;
70 EFI_PXE_BASE_CODE_MODE
*Mode
;
71 EFI_EVENT TimeoutEvent
;
72 EFI_EVENT DescendEvent
;
73 EFI_INPUT_KEY InputKey
;
84 Mode
= Private
->PxeBc
.Mode
;
85 Cache
= Mode
->ProxyOfferReceived
? &Private
->ProxyOffer
: &Private
->DhcpAck
;
86 OfferType
= Mode
->UsingIpv6
? Cache
->Dhcp6
.OfferType
: Cache
->Dhcp4
.OfferType
;
89 // Only ProxyPxe10 offer needs boot prompt.
91 if (OfferType
!= PxeOfferTypeProxyPxe10
) {
96 // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec.
98 ASSERT (!Mode
->UsingIpv6
);
100 VendorOpt
= &Cache
->Dhcp4
.VendorOpt
;
101 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
105 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
106 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
107 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
110 // The valid scope of Timeout refers to PXE2.1 spec.
115 if (Timeout
== 255) {
120 // Create and start a timer as timeout event.
122 Status
= gBS
->CreateEvent (
129 if (EFI_ERROR (Status
)) {
133 Status
= gBS
->SetTimer (
136 Timeout
* TICKS_PER_SECOND
138 if (EFI_ERROR (Status
)) {
143 // Create and start a periodic timer as descend event by second.
145 Status
= gBS
->CreateEvent (
152 if (EFI_ERROR (Status
)) {
156 Status
= gBS
->SetTimer (
161 if (EFI_ERROR (Status
)) {
166 // Display the boot item and cursor on the screen.
168 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
169 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
171 PxeBcDisplayBootItem (Prompt
, PromptLen
);
173 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
174 AsciiPrint ("(%d) ", Timeout
--);
176 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
177 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
178 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
179 AsciiPrint ("(%d) ", Timeout
--);
181 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
182 gBS
->Stall (10 * TICKS_PER_MS
);
186 // Parse the input key by user.
188 if (InputKey
.ScanCode
== 0) {
190 switch (InputKey
.UnicodeChar
) {
193 Status
= EFI_ABORTED
;
199 Status
= EFI_TIMEOUT
;
208 switch (InputKey
.ScanCode
) {
211 Status
= EFI_TIMEOUT
;
215 Status
= EFI_ABORTED
;
227 // Reset the cursor on the screen.
229 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
232 if (DescendEvent
!= NULL
) {
233 gBS
->CloseEvent (DescendEvent
);
235 if (TimeoutEvent
!= NULL
) {
236 gBS
->CloseEvent (TimeoutEvent
);
244 Select the boot menu by user's input.
246 @param[in] Private Pointer to PxeBc private data.
247 @param[out] Type The type of the menu.
248 @param[in] UseDefaultItem Use default item or not.
250 @retval EFI_ABORTED User cancel operation.
251 @retval EFI_SUCCESS Select the boot menu success.
252 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
256 PxeBcSelectBootMenu (
257 IN PXEBC_PRIVATE_DATA
*Private
,
259 IN BOOLEAN UseDefaultItem
262 EFI_PXE_BASE_CODE_MODE
*Mode
;
263 PXEBC_DHCP_PACKET_CACHE
*Cache
;
264 PXEBC_VENDOR_OPTION
*VendorOpt
;
265 EFI_INPUT_KEY InputKey
;
274 CHAR8 Blank
[PXEBC_DISPLAY_MAX_LINE
];
275 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
276 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MENU_MAX_NUM
];
282 Mode
= Private
->PxeBc
.Mode
;
283 Cache
= Mode
->ProxyOfferReceived
? &Private
->ProxyOffer
: &Private
->DhcpAck
;
284 OfferType
= Mode
->UsingIpv6
? Cache
->Dhcp6
.OfferType
: Cache
->Dhcp4
.OfferType
;
287 // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec.
289 ASSERT (!Mode
->UsingIpv6
);
290 ASSERT (OfferType
== PxeOfferTypeProxyPxe10
);
292 VendorOpt
= &Cache
->Dhcp4
.VendorOpt
;
293 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
298 // Display the boot menu on the screen.
300 SetMem (Blank
, sizeof(Blank
), ' ');
302 MenuSize
= VendorOpt
->BootMenuLen
;
303 MenuItem
= VendorOpt
->BootMenu
;
306 return EFI_DEVICE_ERROR
;
309 while (MenuSize
> 0 && Index
< PXEBC_MENU_MAX_NUM
) {
310 ASSERT (MenuItem
!= NULL
);
311 MenuArray
[Index
] = MenuItem
;
312 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
313 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
317 if (UseDefaultItem
) {
318 ASSERT (MenuArray
[0] != NULL
);
319 CopyMem (Type
, &MenuArray
[0]->Type
, sizeof (UINT16
));
320 *Type
= NTOHS (*Type
);
326 for (Index
= 0; Index
< MenuNum
; Index
++) {
327 ASSERT (MenuArray
[Index
] != NULL
);
328 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
331 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
334 // Select the boot item by user in the boot menu.
338 // Highlight selected row.
340 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
341 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
342 ASSERT (Select
< PXEBC_MENU_MAX_NUM
);
343 ASSERT (MenuArray
[Select
] != NULL
);
344 Blank
[MenuArray
[Select
]->DescLen
] = 0;
345 AsciiPrint ("%a\r", Blank
);
346 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
347 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
350 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
351 gBS
->Stall (10 * TICKS_PER_MS
);
354 if (InputKey
.ScanCode
!= 0) {
355 switch (InputKey
.UnicodeChar
) {
357 InputKey
.ScanCode
= SCAN_ESC
;
360 case CTRL ('j'): /* linefeed */
361 case CTRL ('m'): /* return */
365 case CTRL ('i'): /* tab */
369 InputKey
.ScanCode
= SCAN_DOWN
;
372 case CTRL ('h'): /* backspace */
375 InputKey
.ScanCode
= SCAN_UP
;
379 InputKey
.ScanCode
= 0;
383 switch (InputKey
.ScanCode
) {
393 if (++Select
== MenuNum
) {
405 Select
= (UINT16
) (MenuNum
- 1);
413 // Unhighlight the last selected row.
415 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
416 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
417 ASSERT (LastSelect
< PXEBC_MENU_MAX_NUM
);
418 ASSERT (MenuArray
[LastSelect
] != NULL
);
419 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
420 AsciiPrint ("%a\r", Blank
);
421 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
422 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
426 // Swap the byte order.
428 ASSERT (Select
< PXEBC_MENU_MAX_NUM
);
429 ASSERT (MenuArray
[Select
] != NULL
);
430 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
431 *Type
= NTOHS (*Type
);
438 Parse out the boot information from the last Dhcp4 reply packet.
440 @param[in, out] Private Pointer to PxeBc private data.
441 @param[out] BufferSize Size of the boot file to be downloaded.
443 @retval EFI_SUCCESS Successfully parsed out all the boot information.
444 @retval Others Failed to parse out the boot information.
449 IN OUT PXEBC_PRIVATE_DATA
*Private
,
450 OUT UINT64
*BufferSize
453 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
454 EFI_PXE_BASE_CODE_MODE
*Mode
;
456 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
459 PxeBc
= &Private
->PxeBc
;
461 Status
= EFI_SUCCESS
;
465 // Get the last received Dhcp4 reply packet.
467 if (Mode
->PxeReplyReceived
) {
468 Cache4
= &Private
->PxeReply
.Dhcp4
;
469 } else if (Mode
->ProxyOfferReceived
) {
470 Cache4
= &Private
->ProxyOffer
.Dhcp4
;
472 Cache4
= &Private
->DhcpAck
.Dhcp4
;
476 // Parse the boot server Ipv4 address by next server address.
477 // If this field isn't available, use option 54 instead.
481 &Cache4
->Packet
.Offer
.Dhcp4
.Header
.ServerAddr
,
482 sizeof (EFI_IPv4_ADDRESS
)
485 if (Private
->ServerIp
.Addr
[0] == 0) {
488 Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
489 sizeof (EFI_IPv4_ADDRESS
)
494 // Parse the boot file name by option.
496 ASSERT (Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
497 Private
->BootFileName
= Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Data
;
499 if (Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN
] != NULL
) {
501 // Parse the boot file size by option.
503 CopyMem (&Value
, Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN
]->Data
, sizeof (Value
));
504 Value
= NTOHS (Value
);
506 // The field of boot file size is 512 bytes in unit.
508 *BufferSize
= 512 * Value
;
511 // Get the bootfile size by tftp command if no option available.
513 Status
= PxeBc
->Mtftp (
515 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
521 Private
->BootFileName
,
528 // Save the value of boot file size.
530 Private
->BootFileSize
= (UINTN
) *BufferSize
;
533 // Display all the information: boot server address, boot file name and boot file size.
535 AsciiPrint ("\n Server IP address is ");
536 PxeBcShowIp4Addr (&Private
->ServerIp
.v4
);
537 AsciiPrint ("\n NBP filename is %a", Private
->BootFileName
);
538 AsciiPrint ("\n NBP filesize is %d Bytes", Private
->BootFileSize
);
545 Parse out the boot information from the last Dhcp6 reply packet.
547 @param[in, out] Private Pointer to PxeBc private data.
548 @param[out] BufferSize Size of the boot file to be downloaded.
550 @retval EFI_SUCCESS Successfully parsed out all the boot information.
551 @retval EFI_BUFFER_TOO_SMALL
552 @retval Others Failed to parse out the boot information.
557 IN OUT PXEBC_PRIVATE_DATA
*Private
,
558 OUT UINT64
*BufferSize
561 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
562 EFI_PXE_BASE_CODE_MODE
*Mode
;
564 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
567 PxeBc
= &Private
->PxeBc
;
569 Status
= EFI_SUCCESS
;
573 // Get the last received Dhcp6 reply packet.
575 if (Mode
->PxeReplyReceived
) {
576 Cache6
= &Private
->PxeReply
.Dhcp6
;
577 } else if (Mode
->ProxyOfferReceived
) {
578 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
580 Cache6
= &Private
->DhcpAck
.Dhcp6
;
583 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
586 // Parse (m)tftp server ip address and bootfile name.
588 Status
= PxeBcExtractBootFileUrl (
589 &Private
->BootFileName
,
590 &Private
->ServerIp
.v6
,
591 (CHAR8
*) (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
592 NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
594 if (EFI_ERROR (Status
)) {
599 // Parse the value of boot file size.
601 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] != NULL
) {
603 // Parse it out if have the boot file parameter option.
605 Status
= PxeBcExtractBootFileParam ((CHAR8
*) Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
]->Data
, &Value
);
606 if (EFI_ERROR (Status
)) {
610 // The field of boot file size is 512 bytes in unit.
612 *BufferSize
= 512 * Value
;
615 // Send get file size command by tftp if option unavailable.
617 Status
= PxeBc
->Mtftp (
619 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
625 Private
->BootFileName
,
632 // Save the value of boot file size.
634 Private
->BootFileSize
= (UINTN
) *BufferSize
;
637 // Display all the information: boot server address, boot file name and boot file size.
639 AsciiPrint ("\n Server IP address is ");
640 PxeBcShowIp6Addr (&Private
->ServerIp
.v6
);
641 AsciiPrint ("\n NBP filename is %a", Private
->BootFileName
);
642 AsciiPrint ("\n NBP filesize is %d Bytes", Private
->BootFileSize
);
649 Extract the discover information and boot server entry from the
650 cached packets if unspecified.
652 @param[in] Private Pointer to PxeBc private data.
653 @param[in] Type The type of bootstrap to perform.
654 @param[in, out] Info Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO.
655 @param[out] BootEntry Pointer to PXEBC_BOOT_SVR_ENTRY.
656 @param[out] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
658 @retval EFI_SUCCESS Successfully extracted the information.
659 @retval EFI_DEVICE_ERROR Failed to extract the information.
663 PxeBcExtractDiscoverInfo (
664 IN PXEBC_PRIVATE_DATA
*Private
,
666 IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO
*Info
,
667 OUT PXEBC_BOOT_SVR_ENTRY
**BootEntry
,
668 OUT EFI_PXE_BASE_CODE_SRVLIST
**SrvList
671 EFI_PXE_BASE_CODE_MODE
*Mode
;
672 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
673 PXEBC_VENDOR_OPTION
*VendorOpt
;
674 PXEBC_BOOT_SVR_ENTRY
*Entry
;
677 Mode
= Private
->PxeBc
.Mode
;
679 if (Mode
->UsingIpv6
) {
681 Info
->UseUCast
= TRUE
;
683 Info
->SrvList
[0].Type
= Type
;
684 Info
->SrvList
[0].AcceptAnyResponse
= FALSE
;
687 // There is no vendor options specified in DHCPv6, so take BootFileUrl in the last cached packet.
689 CopyMem (&Info
->SrvList
[0].IpAddr
, &Private
->ServerIp
, sizeof (EFI_IP_ADDRESS
));
691 *SrvList
= Info
->SrvList
;
695 Cache4
= (Mode
->ProxyOfferReceived
) ? &Private
->ProxyOffer
.Dhcp4
: &Private
->DhcpAck
.Dhcp4
;
696 VendorOpt
= &Cache4
->VendorOpt
;
698 if (!Mode
->DhcpAckReceived
|| !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt
->BitMap
)) {
700 // Address is not acquired or no discovery options.
702 return EFI_INVALID_PARAMETER
;
706 // Parse the boot server entry from the vendor option in the last cached packet.
708 Info
->UseMCast
= (BOOLEAN
) !IS_DISABLE_MCAST_DISCOVER (VendorOpt
->DiscoverCtrl
);
709 Info
->UseBCast
= (BOOLEAN
) !IS_DISABLE_BCAST_DISCOVER (VendorOpt
->DiscoverCtrl
);
710 Info
->MustUseList
= (BOOLEAN
) IS_ENABLE_USE_SERVER_LIST (VendorOpt
->DiscoverCtrl
);
711 Info
->UseUCast
= Info
->MustUseList
;
713 if (Info
->UseMCast
) {
715 // Get the multicast discover ip address from vendor option if has.
717 CopyMem (&Info
->ServerMCastIp
.v4
, &VendorOpt
->DiscoverMcastIp
, sizeof (EFI_IPv4_ADDRESS
));
722 if (Info
->MustUseList
) {
723 Entry
= VendorOpt
->BootSvr
;
725 while (((UINT8
) (Entry
- VendorOpt
->BootSvr
)) < VendorOpt
->BootSvrLen
) {
726 if (Entry
->Type
== HTONS (Type
)) {
730 Entry
= GET_NEXT_BOOT_SVR_ENTRY (Entry
);
734 return EFI_DEVICE_ERROR
;
737 Info
->IpCnt
= Entry
->IpCnt
;
748 Build the discover packet and send out for boot server.
750 @param[in] Private Pointer to PxeBc private data.
751 @param[in] Type PxeBc option boot item type.
752 @param[in] Layer Pointer to option boot item layer.
753 @param[in] UseBis Use BIS or not.
754 @param[in] DestIp Pointer to the destination address.
755 @param[in] IpCount The count of the server address.
756 @param[in] SrvList Pointer to the server address list.
758 @retval EFI_SUCCESS Successfully discovered boot file.
759 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
760 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
761 @retval Others Failed to discover boot file.
765 PxeBcDiscoverBootServer (
766 IN PXEBC_PRIVATE_DATA
*Private
,
770 IN EFI_IP_ADDRESS
*DestIp
,
772 IN EFI_PXE_BASE_CODE_SRVLIST
*SrvList
775 if (Private
->PxeBc
.Mode
->UsingIpv6
) {
776 return PxeBcDhcp6Discover (
784 return PxeBcDhcp4Discover (
798 Discover all the boot information for boot file.
800 @param[in, out] Private Pointer to PxeBc private data.
801 @param[out] BufferSize Size of the boot file to be downloaded.
803 @retval EFI_SUCCESS Successfully obtained all the boot information .
804 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
805 @retval EFI_ABORTED User cancel current operation.
806 @retval Others Failed to parse out the boot information.
810 PxeBcDiscoverBootFile (
811 IN OUT PXEBC_PRIVATE_DATA
*Private
,
812 OUT UINT64
*BufferSize
815 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
816 EFI_PXE_BASE_CODE_MODE
*Mode
;
822 PxeBc
= &Private
->PxeBc
;
824 Type
= EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
;
825 Layer
= EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL
;
828 // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and
829 // other pxe boot information.
831 Status
= PxeBc
->Dhcp (PxeBc
, TRUE
);
832 if (EFI_ERROR (Status
)) {
837 // Select a boot server from boot server list.
839 Status
= PxeBcSelectBootPrompt (Private
);
841 if (Status
== EFI_SUCCESS
) {
843 // Choose by user's input.
845 Status
= PxeBcSelectBootMenu (Private
, &Type
, TRUE
);
846 } else if (Status
== EFI_TIMEOUT
) {
848 // Choose by default item.
850 Status
= PxeBcSelectBootMenu (Private
, &Type
, FALSE
);
853 if (!EFI_ERROR (Status
)) {
855 if (Type
== EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
) {
857 // Local boot(PXE bootstrap server) need abort
863 // Start to discover the boot server to get (m)tftp server ip address, bootfile
864 // name and bootfile size.
866 UseBis
= (BOOLEAN
) (Mode
->BisSupported
&& Mode
->BisDetected
);
867 Status
= PxeBc
->Discover (PxeBc
, Type
, &Layer
, UseBis
, NULL
);
868 if (EFI_ERROR (Status
)) {
874 // Parse the boot information.
876 if (Mode
->UsingIpv6
) {
877 Status
= PxeBcDhcp6BootInfo (Private
, BufferSize
);
879 Status
= PxeBcDhcp4BootInfo (Private
, BufferSize
);
887 Install PxeBaseCodeCallbackProtocol if not installed before.
889 @param[in, out] Private Pointer to PxeBc private data.
890 @param[out] NewMakeCallback If TRUE, it is a new callback.
891 Otherwise, it is not new callback.
892 @retval EFI_SUCCESS PxeBaseCodeCallbackProtocol installed succesfully.
893 @retval Others Failed to install PxeBaseCodeCallbackProtocol.
897 PxeBcInstallCallback (
898 IN OUT PXEBC_PRIVATE_DATA
*Private
,
899 OUT BOOLEAN
*NewMakeCallback
902 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
906 // Check whether PxeBaseCodeCallbackProtocol already installed.
908 PxeBc
= &Private
->PxeBc
;
909 Status
= gBS
->HandleProtocol (
911 &gEfiPxeBaseCodeCallbackProtocolGuid
,
912 (VOID
**) &Private
->PxeBcCallback
914 if (Status
== EFI_UNSUPPORTED
) {
917 &Private
->LoadFileCallback
,
918 &gPxeBcCallBackTemplate
,
919 sizeof (EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
)
923 // Install a default callback if user didn't offer one.
925 Status
= gBS
->InstallProtocolInterface (
926 &Private
->Controller
,
927 &gEfiPxeBaseCodeCallbackProtocolGuid
,
928 EFI_NATIVE_INTERFACE
,
929 &Private
->LoadFileCallback
932 (*NewMakeCallback
) = (BOOLEAN
) (Status
== EFI_SUCCESS
);
934 Status
= PxeBc
->SetParameters (PxeBc
, NULL
, NULL
, NULL
, NULL
, NewMakeCallback
);
935 if (EFI_ERROR (Status
)) {
946 Uninstall PxeBaseCodeCallbackProtocol.
948 @param[in] Private Pointer to PxeBc private data.
949 @param[in] NewMakeCallback If TRUE, it is a new callback.
950 Otherwise, it is not new callback.
954 PxeBcUninstallCallback (
955 IN PXEBC_PRIVATE_DATA
*Private
,
956 IN BOOLEAN NewMakeCallback
959 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
961 PxeBc
= &Private
->PxeBc
;
963 if (NewMakeCallback
) {
965 NewMakeCallback
= FALSE
;
967 PxeBc
->SetParameters (PxeBc
, NULL
, NULL
, NULL
, NULL
, &NewMakeCallback
);
969 gBS
->UninstallProtocolInterface (
971 &gEfiPxeBaseCodeCallbackProtocolGuid
,
972 &Private
->LoadFileCallback
979 Download one of boot file in the list, and it's special for IPv6.
981 @param[in] Private Pointer to PxeBc private data.
982 @param[in, out] BufferSize Size of user buffer for input;
983 required buffer size for output.
984 @param[in] Buffer Pointer to user buffer.
986 @retval EFI_SUCCESS Read one of boot file in the list successfully.
987 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
988 @retval EFI_NOT_FOUND There is no proper boot file available.
989 @retval Others Failed to download boot file in the list.
993 PxeBcReadBootFileList (
994 IN PXEBC_PRIVATE_DATA
*Private
,
995 IN OUT UINT64
*BufferSize
,
996 IN VOID
*Buffer OPTIONAL
1000 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1002 PxeBc
= &Private
->PxeBc
;
1005 // Try to download the boot file if everything is ready.
1007 if (Buffer
!= NULL
) {
1008 Status
= PxeBc
->Mtftp (
1010 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1014 &Private
->BlockSize
,
1016 Private
->BootFileName
,
1023 Status
= EFI_BUFFER_TOO_SMALL
;
1031 Load boot file into user buffer.
1033 @param[in] Private Pointer to PxeBc private data.
1034 @param[in, out] BufferSize Size of user buffer for input;
1035 required buffer size for output.
1036 @param[in] Buffer Pointer to user buffer.
1038 @retval EFI_SUCCESS Get all the boot information successfully.
1039 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
1040 @retval EFI_ABORTED User cancelled the current operation.
1041 @retval Others Failed to parse out the boot information.
1046 IN PXEBC_PRIVATE_DATA
*Private
,
1047 IN OUT UINTN
*BufferSize
,
1048 IN VOID
*Buffer OPTIONAL
1051 BOOLEAN NewMakeCallback
;
1052 UINT64 RequiredSize
;
1055 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1056 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
1058 NewMakeCallback
= FALSE
;
1059 PxeBc
= &Private
->PxeBc
;
1060 PxeBcMode
= &Private
->Mode
;
1061 CurrentSize
= *BufferSize
;
1065 // Install pxebc callback protocol if hasn't been installed yet.
1067 Status
= PxeBcInstallCallback (Private
, &NewMakeCallback
);
1068 if (EFI_ERROR(Status
)) {
1072 if (Private
->BootFileSize
== 0) {
1074 // Discover the boot information about the bootfile if hasn't.
1076 Status
= PxeBcDiscoverBootFile (Private
, &RequiredSize
);
1078 if (PXEBC_IS_SIZE_OVERFLOWED (RequiredSize
)) {
1080 // It's error if the required buffer size is beyond the system scope.
1082 Status
= EFI_DEVICE_ERROR
;
1084 } else if (RequiredSize
> 0) {
1086 // Get the right buffer size of the bootfile required.
1088 if (CurrentSize
< RequiredSize
|| Buffer
== NULL
) {
1090 // It's buffer too small if the size of user buffer is smaller than the required.
1092 CurrentSize
= RequiredSize
;
1093 Status
= EFI_BUFFER_TOO_SMALL
;
1096 CurrentSize
= RequiredSize
;
1097 } else if (RequiredSize
== 0 && PxeBcMode
->UsingIpv6
) {
1099 // Try to download another bootfile in list if failed to get the filesize of the last one.
1100 // It's special for the case of IPv6.
1102 Status
= PxeBcReadBootFileList (Private
, &CurrentSize
, Buffer
);
1105 } else if (CurrentSize
< Private
->BootFileSize
|| Buffer
== NULL
) {
1107 // It's buffer too small if the size of user buffer is smaller than the required.
1109 CurrentSize
= Private
->BootFileSize
;
1110 Status
= EFI_BUFFER_TOO_SMALL
;
1115 // Begin to download the bootfile if everything is ready.
1117 AsciiPrint ("\n Downloading NBP file...\n");
1118 if (PxeBcMode
->UsingIpv6
) {
1119 Status
= PxeBcReadBootFileList (
1125 Status
= PxeBc
->Mtftp (
1127 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1131 &Private
->BlockSize
,
1133 Private
->BootFileName
,
1140 *BufferSize
= (UINTN
) CurrentSize
;
1141 PxeBcUninstallCallback(Private
, NewMakeCallback
);
1143 if (Status
== EFI_SUCCESS
) {
1144 AsciiPrint ("\n Succeed to download NBP file.\n");
1146 } else if (Status
== EFI_BUFFER_TOO_SMALL
&& Buffer
!= NULL
) {
1147 AsciiPrint ("\n PXE-E05: Buffer size is smaller than the requested file.\n");
1148 } else if (Status
== EFI_DEVICE_ERROR
) {
1149 AsciiPrint ("\n PXE-E07: Network device error.\n");
1150 } else if (Status
== EFI_OUT_OF_RESOURCES
) {
1151 AsciiPrint ("\n PXE-E09: Could not allocate I/O buffers.\n");
1152 } else if (Status
== EFI_NO_MEDIA
) {
1153 AsciiPrint ("\n PXE-E12: Could not detect network connection.\n");
1154 } else if (Status
== EFI_NO_RESPONSE
) {
1155 AsciiPrint ("\n PXE-E16: No offer received.\n");
1156 } else if (Status
== EFI_TIMEOUT
) {
1157 AsciiPrint ("\n PXE-E18: Server response timeout.\n");
1158 } else if (Status
== EFI_ABORTED
) {
1159 AsciiPrint ("\n PXE-E21: Remote boot cancelled.\n");
1160 } else if (Status
== EFI_ICMP_ERROR
) {
1161 AsciiPrint ("\n PXE-E22: Client received ICMP error from server.\n");
1162 } else if (Status
== EFI_TFTP_ERROR
) {
1163 AsciiPrint ("\n PXE-E23: Client received TFTP error from server.\n");
1164 } else if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1165 AsciiPrint ("\n PXE-E99: Unexpected network error.\n");