2 Boot functions implementation for UefiPxeBc Driver.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "PxeBcImpl.h"
15 Display the string of the boot item.
17 If the length of the boot item string beyond 70 Char, just display 70 Char.
19 @param[in] Str The pointer to the string.
20 @param[in] Len The length of the string.
24 PxeBcDisplayBootItem (
32 // Cut off the chars behind 70th.
34 Len
= (UINT8
) MIN (PXEBC_DISPLAY_MAX_LINE
, Len
);
37 AsciiPrint ("%a \n", Str
);
40 // Restore the original 70th char.
47 Select and maintain the boot prompt if needed.
49 @param[in] Private Pointer to PxeBc private data.
51 @retval EFI_SUCCESS Selected boot prompt done.
52 @retval EFI_TIMEOUT Selected boot prompt timed out.
53 @retval EFI_NOT_FOUND The proxy offer is not Pxe10.
54 @retval EFI_ABORTED User cancelled the operation.
55 @retval EFI_NOT_READY Reading the input key from the keyboard has not finish.
59 PxeBcSelectBootPrompt (
60 IN PXEBC_PRIVATE_DATA
*Private
63 PXEBC_DHCP_PACKET_CACHE
*Cache
;
64 PXEBC_VENDOR_OPTION
*VendorOpt
;
65 EFI_PXE_BASE_CODE_MODE
*Mode
;
66 EFI_EVENT TimeoutEvent
;
67 EFI_EVENT DescendEvent
;
68 EFI_INPUT_KEY InputKey
;
79 Mode
= Private
->PxeBc
.Mode
;
80 Cache
= Mode
->ProxyOfferReceived
? &Private
->ProxyOffer
: &Private
->DhcpAck
;
81 OfferType
= Mode
->UsingIpv6
? Cache
->Dhcp6
.OfferType
: Cache
->Dhcp4
.OfferType
;
84 // Only DhcpPxe10 and ProxyPxe10 offer needs boot prompt.
86 if (OfferType
!= PxeOfferTypeProxyPxe10
&& OfferType
!= PxeOfferTypeDhcpPxe10
) {
91 // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec.
93 ASSERT (!Mode
->UsingIpv6
);
95 VendorOpt
= &Cache
->Dhcp4
.VendorOpt
;
97 // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options,
98 // we must not consider a boot prompt or boot menu if all of the following hold:
99 // - the PXE_DISCOVERY_CONTROL tag(6) is present inside the Vendor Options(43), and has bit 3 set
100 // - a boot file name has been presented in the initial DHCP or ProxyDHCP offer packet.
102 if (IS_DISABLE_PROMPT_MENU (VendorOpt
->DiscoverCtrl
) &&
103 Cache
->Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
107 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
111 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
112 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
113 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
116 // The valid scope of Timeout refers to PXE2.1 spec.
121 if (Timeout
== 255) {
126 // Create and start a timer as timeout event.
128 Status
= gBS
->CreateEvent (
135 if (EFI_ERROR (Status
)) {
139 Status
= gBS
->SetTimer (
142 MultU64x32 (Timeout
, TICKS_PER_SECOND
)
144 if (EFI_ERROR (Status
)) {
149 // Create and start a periodic timer as descend event by second.
151 Status
= gBS
->CreateEvent (
158 if (EFI_ERROR (Status
)) {
162 Status
= gBS
->SetTimer (
167 if (EFI_ERROR (Status
)) {
172 // Display the boot item and cursor on the screen.
174 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
175 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
177 PxeBcDisplayBootItem (Prompt
, PromptLen
);
179 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
180 AsciiPrint ("(%d) ", Timeout
--);
182 Status
= EFI_TIMEOUT
;
183 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
184 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
185 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
186 AsciiPrint ("(%d) ", Timeout
--);
188 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
189 gBS
->Stall (10 * TICKS_PER_MS
);
193 // Parse the input key by user.
194 // If <F8> or <Ctrl> + <M> is pressed, return success to display the boot menu.
196 if (InputKey
.ScanCode
== 0) {
198 switch (InputKey
.UnicodeChar
) {
201 Status
= EFI_ABORTED
;
207 Status
= EFI_SUCCESS
;
216 switch (InputKey
.ScanCode
) {
219 Status
= EFI_SUCCESS
;
223 Status
= EFI_ABORTED
;
235 // Reset the cursor on the screen.
237 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
240 if (DescendEvent
!= NULL
) {
241 gBS
->CloseEvent (DescendEvent
);
243 if (TimeoutEvent
!= NULL
) {
244 gBS
->CloseEvent (TimeoutEvent
);
252 Select the boot menu by user's input.
254 @param[in] Private Pointer to PxeBc private data.
255 @param[out] Type The type of the menu.
256 @param[in] UseDefaultItem Use default item or not.
258 @retval EFI_ABORTED User cancel operation.
259 @retval EFI_SUCCESS Select the boot menu success.
260 @retval EFI_NOT_READY Read the input key from the keyboard has not finish.
264 PxeBcSelectBootMenu (
265 IN PXEBC_PRIVATE_DATA
*Private
,
267 IN BOOLEAN UseDefaultItem
270 EFI_PXE_BASE_CODE_MODE
*Mode
;
271 PXEBC_DHCP_PACKET_CACHE
*Cache
;
272 PXEBC_VENDOR_OPTION
*VendorOpt
;
273 EFI_INPUT_KEY InputKey
;
282 CHAR8 Blank
[PXEBC_DISPLAY_MAX_LINE
];
283 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
284 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MENU_MAX_NUM
];
290 Mode
= Private
->PxeBc
.Mode
;
291 Cache
= Mode
->ProxyOfferReceived
? &Private
->ProxyOffer
: &Private
->DhcpAck
;
292 OfferType
= Mode
->UsingIpv6
? Cache
->Dhcp6
.OfferType
: Cache
->Dhcp4
.OfferType
;
295 // There is no specified DhcpPxe10/ProxyPxe10 for IPv6 in PXE and UEFI spec.
297 ASSERT (!Mode
->UsingIpv6
);
298 ASSERT (OfferType
== PxeOfferTypeProxyPxe10
|| OfferType
== PxeOfferTypeDhcpPxe10
);
300 VendorOpt
= &Cache
->Dhcp4
.VendorOpt
;
301 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
306 // Display the boot menu on the screen.
308 SetMem (Blank
, sizeof(Blank
), ' ');
310 MenuSize
= VendorOpt
->BootMenuLen
;
311 MenuItem
= VendorOpt
->BootMenu
;
314 return EFI_DEVICE_ERROR
;
317 while (MenuSize
> 0 && Index
< PXEBC_MENU_MAX_NUM
) {
318 ASSERT (MenuItem
!= NULL
);
319 MenuArray
[Index
] = MenuItem
;
320 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
321 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
325 if (UseDefaultItem
) {
326 ASSERT (MenuArray
[0] != NULL
);
327 CopyMem (Type
, &MenuArray
[0]->Type
, sizeof (UINT16
));
328 *Type
= NTOHS (*Type
);
334 for (Index
= 0; Index
< MenuNum
; Index
++) {
335 ASSERT (MenuArray
[Index
] != NULL
);
336 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
339 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
342 // Select the boot item by user in the boot menu.
346 // Highlight selected row.
348 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
349 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
350 ASSERT (Select
< PXEBC_MENU_MAX_NUM
);
351 ASSERT (MenuArray
[Select
] != NULL
);
352 Blank
[MenuArray
[Select
]->DescLen
] = 0;
353 AsciiPrint ("%a\r", Blank
);
354 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
355 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
358 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
359 gBS
->Stall (10 * TICKS_PER_MS
);
362 if (InputKey
.ScanCode
== 0) {
363 switch (InputKey
.UnicodeChar
) {
365 InputKey
.ScanCode
= SCAN_ESC
;
368 case CTRL ('j'): /* linefeed */
369 case CTRL ('m'): /* return */
373 case CTRL ('i'): /* tab */
377 InputKey
.ScanCode
= SCAN_DOWN
;
380 case CTRL ('h'): /* backspace */
383 InputKey
.ScanCode
= SCAN_UP
;
387 InputKey
.ScanCode
= 0;
391 switch (InputKey
.ScanCode
) {
401 if (++Select
== MenuNum
) {
413 Select
= (UINT16
) (MenuNum
- 1);
421 // Unhighlight the last selected row.
423 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
424 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
425 ASSERT (LastSelect
< PXEBC_MENU_MAX_NUM
);
426 ASSERT (MenuArray
[LastSelect
] != NULL
);
427 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
428 AsciiPrint ("%a\r", Blank
);
429 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
430 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
434 // Swap the byte order.
436 ASSERT (Select
< PXEBC_MENU_MAX_NUM
);
437 ASSERT (MenuArray
[Select
] != NULL
);
438 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
439 *Type
= NTOHS (*Type
);
446 Parse out the boot information from the last Dhcp4 reply packet.
448 @param[in, out] Private Pointer to PxeBc private data.
449 @param[out] BufferSize Size of the boot file to be downloaded.
451 @retval EFI_SUCCESS Successfully parsed out all the boot information.
452 @retval Others Failed to parse out the boot information.
457 IN OUT PXEBC_PRIVATE_DATA
*Private
,
458 OUT UINT64
*BufferSize
461 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
462 EFI_PXE_BASE_CODE_MODE
*Mode
;
464 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
466 PXEBC_VENDOR_OPTION
*VendorOpt
;
467 PXEBC_BOOT_SVR_ENTRY
*Entry
;
469 PxeBc
= &Private
->PxeBc
;
471 Status
= EFI_SUCCESS
;
475 // Get the last received Dhcp4 reply packet.
477 if (Mode
->PxeReplyReceived
) {
478 Cache4
= &Private
->PxeReply
.Dhcp4
;
479 } else if (Mode
->ProxyOfferReceived
) {
480 Cache4
= &Private
->ProxyOffer
.Dhcp4
;
482 Cache4
= &Private
->DhcpAck
.Dhcp4
;
485 ASSERT (Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
488 // Parse the boot server address.
489 // If prompt/discover is disabled, get the first boot server from the boot servers list.
490 // Otherwise, parse the boot server Ipv4 address from next server address field in DHCP header.
491 // If all these fields are not available, use option 54 instead.
493 VendorOpt
= &Cache4
->VendorOpt
;
494 if (IS_DISABLE_PROMPT_MENU (VendorOpt
->DiscoverCtrl
) && IS_VALID_BOOT_SERVERS (VendorOpt
->BitMap
)) {
495 Entry
= VendorOpt
->BootSvr
;
496 if (VendorOpt
->BootSvrLen
>= sizeof (PXEBC_BOOT_SVR_ENTRY
) && Entry
->IpCnt
> 0) {
500 sizeof (EFI_IPv4_ADDRESS
)
504 if (Private
->ServerIp
.Addr
[0] == 0) {
506 // ServerIp.Addr[0] equals zero means we failed to get IP address from boot server list.
507 // Try to use next server address field.
511 &Cache4
->Packet
.Offer
.Dhcp4
.Header
.ServerAddr
,
512 sizeof (EFI_IPv4_ADDRESS
)
515 if (Private
->ServerIp
.Addr
[0] == 0) {
517 // Still failed , use the IP address from option 54.
521 Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
522 sizeof (EFI_IPv4_ADDRESS
)
527 // Parse the boot file name by option.
529 Private
->BootFileName
= Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Data
;
531 if (Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN
] != NULL
) {
533 // Parse the boot file size by option.
535 CopyMem (&Value
, Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN
]->Data
, sizeof (Value
));
536 Value
= NTOHS (Value
);
538 // The field of boot file size is 512 bytes in unit.
540 *BufferSize
= 512 * Value
;
543 // Get the bootfile size by tftp command if no option available.
545 Status
= PxeBc
->Mtftp (
547 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
553 Private
->BootFileName
,
560 // Save the value of boot file size.
562 Private
->BootFileSize
= (UINTN
) *BufferSize
;
565 // Display all the information: boot server address, boot file name and boot file size.
567 AsciiPrint ("\n Server IP address is ");
568 PxeBcShowIp4Addr (&Private
->ServerIp
.v4
);
569 AsciiPrint ("\n NBP filename is %a", Private
->BootFileName
);
570 AsciiPrint ("\n NBP filesize is %d Bytes", Private
->BootFileSize
);
577 Parse out the boot information from the last Dhcp6 reply packet.
579 @param[in, out] Private Pointer to PxeBc private data.
580 @param[out] BufferSize Size of the boot file to be downloaded.
582 @retval EFI_SUCCESS Successfully parsed out all the boot information.
583 @retval EFI_BUFFER_TOO_SMALL
584 @retval Others Failed to parse out the boot information.
589 IN OUT PXEBC_PRIVATE_DATA
*Private
,
590 OUT UINT64
*BufferSize
593 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
594 EFI_PXE_BASE_CODE_MODE
*Mode
;
596 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
599 PxeBc
= &Private
->PxeBc
;
601 Status
= EFI_SUCCESS
;
605 // Get the last received Dhcp6 reply packet.
607 if (Mode
->PxeReplyReceived
) {
608 Cache6
= &Private
->PxeReply
.Dhcp6
;
609 } else if (Mode
->ProxyOfferReceived
) {
610 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
612 Cache6
= &Private
->DhcpAck
.Dhcp6
;
615 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
618 // Set the station address to IP layer.
620 Status
= PxeBcSetIp6Address (Private
);
621 if (EFI_ERROR (Status
)) {
627 // Parse (m)tftp server ip address and bootfile name.
629 Status
= PxeBcExtractBootFileUrl (
631 &Private
->BootFileName
,
632 &Private
->ServerIp
.v6
,
633 (CHAR8
*) (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
634 NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
636 if (EFI_ERROR (Status
)) {
641 // Parse the value of boot file size.
643 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] != NULL
) {
645 // Parse it out if have the boot file parameter option.
647 Status
= PxeBcExtractBootFileParam ((CHAR8
*) Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
]->Data
, &Value
);
648 if (EFI_ERROR (Status
)) {
652 // The field of boot file size is 512 bytes in unit.
654 *BufferSize
= 512 * Value
;
657 // Send get file size command by tftp if option unavailable.
659 Status
= PxeBc
->Mtftp (
661 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
667 Private
->BootFileName
,
674 // Save the value of boot file size.
676 Private
->BootFileSize
= (UINTN
) *BufferSize
;
679 // Display all the information: boot server address, boot file name and boot file size.
681 AsciiPrint ("\n Server IP address is ");
682 PxeBcShowIp6Addr (&Private
->ServerIp
.v6
);
683 AsciiPrint ("\n NBP filename is %a", Private
->BootFileName
);
684 AsciiPrint ("\n NBP filesize is %d Bytes", Private
->BootFileSize
);
691 Extract the discover information and boot server entry from the
692 cached packets if unspecified.
694 @param[in] Private Pointer to PxeBc private data.
695 @param[in] Type The type of bootstrap to perform.
696 @param[in, out] DiscoverInfo Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO.
697 @param[out] BootEntry Pointer to PXEBC_BOOT_SVR_ENTRY.
698 @param[out] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
700 @retval EFI_SUCCESS Successfully extracted the information.
701 @retval EFI_DEVICE_ERROR Failed to extract the information.
705 PxeBcExtractDiscoverInfo (
706 IN PXEBC_PRIVATE_DATA
*Private
,
708 IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO
**DiscoverInfo
,
709 OUT PXEBC_BOOT_SVR_ENTRY
**BootEntry
,
710 OUT EFI_PXE_BASE_CODE_SRVLIST
**SrvList
713 EFI_PXE_BASE_CODE_MODE
*Mode
;
714 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
715 PXEBC_VENDOR_OPTION
*VendorOpt
;
716 PXEBC_BOOT_SVR_ENTRY
*Entry
;
718 EFI_PXE_BASE_CODE_DISCOVER_INFO
*Info
;
721 Mode
= Private
->PxeBc
.Mode
;
722 Info
= *DiscoverInfo
;
724 if (Mode
->UsingIpv6
) {
726 Info
->UseUCast
= TRUE
;
728 Info
->SrvList
[0].Type
= Type
;
729 Info
->SrvList
[0].AcceptAnyResponse
= FALSE
;
732 // There is no vendor options specified in DHCPv6, so take BootFileUrl in the last cached packet.
734 CopyMem (&Info
->SrvList
[0].IpAddr
, &Private
->ServerIp
, sizeof (EFI_IP_ADDRESS
));
736 *SrvList
= Info
->SrvList
;
740 Cache4
= (Mode
->ProxyOfferReceived
) ? &Private
->ProxyOffer
.Dhcp4
: &Private
->DhcpAck
.Dhcp4
;
741 VendorOpt
= &Cache4
->VendorOpt
;
743 if (!Mode
->DhcpAckReceived
|| !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt
->BitMap
)) {
745 // Address is not acquired or no discovery options.
747 return EFI_INVALID_PARAMETER
;
751 // Parse the boot server entry from the vendor option in the last cached packet.
753 Info
->UseMCast
= (BOOLEAN
) !IS_DISABLE_MCAST_DISCOVER (VendorOpt
->DiscoverCtrl
);
754 Info
->UseBCast
= (BOOLEAN
) !IS_DISABLE_BCAST_DISCOVER (VendorOpt
->DiscoverCtrl
);
755 Info
->MustUseList
= (BOOLEAN
) IS_ENABLE_USE_SERVER_LIST (VendorOpt
->DiscoverCtrl
);
756 Info
->UseUCast
= (BOOLEAN
) IS_VALID_BOOT_SERVERS (VendorOpt
->BitMap
);
758 if (Info
->UseMCast
) {
760 // Get the multicast discover ip address from vendor option if has.
762 CopyMem (&Info
->ServerMCastIp
.v4
, &VendorOpt
->DiscoverMcastIp
, sizeof (EFI_IPv4_ADDRESS
));
767 if (Info
->UseUCast
) {
768 Entry
= VendorOpt
->BootSvr
;
770 while (((UINT8
) (Entry
- VendorOpt
->BootSvr
)) < VendorOpt
->BootSvrLen
) {
771 if (Entry
->Type
== HTONS (Type
)) {
775 Entry
= GET_NEXT_BOOT_SVR_ENTRY (Entry
);
779 return EFI_DEVICE_ERROR
;
782 Info
->IpCnt
= Entry
->IpCnt
;
783 if (Info
->IpCnt
>= 1) {
784 *DiscoverInfo
= AllocatePool (sizeof (*Info
) + (Info
->IpCnt
- 1) * sizeof (**SrvList
));
785 if (*DiscoverInfo
== NULL
) {
786 return EFI_OUT_OF_RESOURCES
;
788 CopyMem (*DiscoverInfo
, Info
, sizeof (*Info
));
789 Info
= *DiscoverInfo
;
792 for (Index
= 0; Index
< Info
->IpCnt
; Index
++) {
793 CopyMem (&Info
->SrvList
[Index
].IpAddr
, &Entry
->IpAddr
[Index
], sizeof (EFI_IPv4_ADDRESS
));
794 Info
->SrvList
[Index
].AcceptAnyResponse
= !Info
->MustUseList
;
795 Info
->SrvList
[Index
].Type
= NTOHS (Entry
->Type
);
800 *SrvList
= Info
->SrvList
;
808 Build the discover packet and send out for boot server.
810 @param[in] Private Pointer to PxeBc private data.
811 @param[in] Type PxeBc option boot item type.
812 @param[in] Layer Pointer to option boot item layer.
813 @param[in] UseBis Use BIS or not.
814 @param[in] DestIp Pointer to the destination address.
815 @param[in] IpCount The count of the server address.
816 @param[in] SrvList Pointer to the server address list.
818 @retval EFI_SUCCESS Successfully discovered boot file.
819 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
820 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
821 @retval Others Failed to discover boot file.
825 PxeBcDiscoverBootServer (
826 IN PXEBC_PRIVATE_DATA
*Private
,
830 IN EFI_IP_ADDRESS
*DestIp
,
832 IN EFI_PXE_BASE_CODE_SRVLIST
*SrvList
835 if (Private
->PxeBc
.Mode
->UsingIpv6
) {
836 return PxeBcDhcp6Discover (
844 return PxeBcDhcp4Discover (
858 Discover all the boot information for boot file.
860 @param[in, out] Private Pointer to PxeBc private data.
861 @param[out] BufferSize Size of the boot file to be downloaded.
863 @retval EFI_SUCCESS Successfully obtained all the boot information .
864 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
865 @retval EFI_ABORTED User cancel current operation.
866 @retval Others Failed to parse out the boot information.
870 PxeBcDiscoverBootFile (
871 IN OUT PXEBC_PRIVATE_DATA
*Private
,
872 OUT UINT64
*BufferSize
875 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
876 EFI_PXE_BASE_CODE_MODE
*Mode
;
882 PxeBc
= &Private
->PxeBc
;
884 Type
= EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
;
885 Layer
= EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL
;
888 // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and
889 // other pxe boot information.
891 Status
= PxeBc
->Dhcp (PxeBc
, TRUE
);
892 if (EFI_ERROR (Status
)) {
897 // Select a boot server from boot server list.
899 Status
= PxeBcSelectBootPrompt (Private
);
901 if (Status
== EFI_SUCCESS
) {
903 // Choose by user's input.
905 Status
= PxeBcSelectBootMenu (Private
, &Type
, FALSE
);
906 } else if (Status
== EFI_TIMEOUT
) {
908 // Choose by default item.
910 Status
= PxeBcSelectBootMenu (Private
, &Type
, TRUE
);
913 if (!EFI_ERROR (Status
)) {
915 if (Type
== EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
) {
917 // Local boot(PXE bootstrap server) need abort
923 // Start to discover the boot server to get (m)tftp server ip address, bootfile
924 // name and bootfile size.
926 UseBis
= (BOOLEAN
) (Mode
->BisSupported
&& Mode
->BisDetected
);
927 Status
= PxeBc
->Discover (PxeBc
, Type
, &Layer
, UseBis
, NULL
);
928 if (EFI_ERROR (Status
)) {
932 if (Mode
->PxeReplyReceived
&& !Mode
->ProxyOfferReceived
) {
934 // Some network boot loader only search the packet in Mode.ProxyOffer to get its server
935 // IP address, so we need to store a copy of Mode.PxeReply packet into Mode.ProxyOffer.
937 if (Mode
->UsingIpv6
) {
939 &Mode
->ProxyOffer
.Dhcpv6
,
940 &Mode
->PxeReply
.Dhcpv6
,
941 Private
->PxeReply
.Dhcp6
.Packet
.Ack
.Length
945 &Mode
->ProxyOffer
.Dhcpv4
,
946 &Mode
->PxeReply
.Dhcpv4
,
947 Private
->PxeReply
.Dhcp4
.Packet
.Ack
.Length
950 Mode
->ProxyOfferReceived
= TRUE
;
955 // Parse the boot information.
957 if (Mode
->UsingIpv6
) {
958 Status
= PxeBcDhcp6BootInfo (Private
, BufferSize
);
960 Status
= PxeBcDhcp4BootInfo (Private
, BufferSize
);
968 Install PxeBaseCodeCallbackProtocol if not installed before.
970 @param[in, out] Private Pointer to PxeBc private data.
971 @param[out] NewMakeCallback If TRUE, it is a new callback.
972 Otherwise, it is not new callback.
973 @retval EFI_SUCCESS PxeBaseCodeCallbackProtocol installed successfully.
974 @retval Others Failed to install PxeBaseCodeCallbackProtocol.
978 PxeBcInstallCallback (
979 IN OUT PXEBC_PRIVATE_DATA
*Private
,
980 OUT BOOLEAN
*NewMakeCallback
983 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
987 // Check whether PxeBaseCodeCallbackProtocol already installed.
989 PxeBc
= &Private
->PxeBc
;
990 Status
= gBS
->HandleProtocol (
991 Private
->Mode
.UsingIpv6
? Private
->Ip6Nic
->Controller
: Private
->Ip4Nic
->Controller
,
992 &gEfiPxeBaseCodeCallbackProtocolGuid
,
993 (VOID
**) &Private
->PxeBcCallback
995 if (Status
== EFI_UNSUPPORTED
) {
998 &Private
->LoadFileCallback
,
999 &gPxeBcCallBackTemplate
,
1000 sizeof (EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
)
1004 // Install a default callback if user didn't offer one.
1006 Status
= gBS
->InstallProtocolInterface (
1007 Private
->Mode
.UsingIpv6
? &Private
->Ip6Nic
->Controller
: &Private
->Ip4Nic
->Controller
,
1008 &gEfiPxeBaseCodeCallbackProtocolGuid
,
1009 EFI_NATIVE_INTERFACE
,
1010 &Private
->LoadFileCallback
1013 (*NewMakeCallback
) = (BOOLEAN
) (Status
== EFI_SUCCESS
);
1015 Status
= PxeBc
->SetParameters (PxeBc
, NULL
, NULL
, NULL
, NULL
, NewMakeCallback
);
1016 if (EFI_ERROR (Status
)) {
1017 PxeBc
->Stop (PxeBc
);
1027 Uninstall PxeBaseCodeCallbackProtocol.
1029 @param[in] Private Pointer to PxeBc private data.
1030 @param[in] NewMakeCallback If TRUE, it is a new callback.
1031 Otherwise, it is not new callback.
1035 PxeBcUninstallCallback (
1036 IN PXEBC_PRIVATE_DATA
*Private
,
1037 IN BOOLEAN NewMakeCallback
1040 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1042 PxeBc
= &Private
->PxeBc
;
1044 if (NewMakeCallback
) {
1046 NewMakeCallback
= FALSE
;
1048 PxeBc
->SetParameters (PxeBc
, NULL
, NULL
, NULL
, NULL
, &NewMakeCallback
);
1050 gBS
->UninstallProtocolInterface (
1051 Private
->Mode
.UsingIpv6
? Private
->Ip6Nic
->Controller
: Private
->Ip4Nic
->Controller
,
1052 &gEfiPxeBaseCodeCallbackProtocolGuid
,
1053 &Private
->LoadFileCallback
1060 Download one of boot file in the list, and it's special for IPv6.
1062 @param[in] Private Pointer to PxeBc private data.
1063 @param[in, out] BufferSize Size of user buffer for input;
1064 required buffer size for output.
1065 @param[in] Buffer Pointer to user buffer.
1067 @retval EFI_SUCCESS Read one of boot file in the list successfully.
1068 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
1069 @retval EFI_NOT_FOUND There is no proper boot file available.
1070 @retval Others Failed to download boot file in the list.
1074 PxeBcReadBootFileList (
1075 IN PXEBC_PRIVATE_DATA
*Private
,
1076 IN OUT UINT64
*BufferSize
,
1077 IN VOID
*Buffer OPTIONAL
1081 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1083 PxeBc
= &Private
->PxeBc
;
1086 // Try to download the boot file if everything is ready.
1088 if (Buffer
!= NULL
) {
1089 Status
= PxeBc
->Mtftp (
1091 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1095 &Private
->BlockSize
,
1097 Private
->BootFileName
,
1104 Status
= EFI_BUFFER_TOO_SMALL
;
1112 Load boot file into user buffer.
1114 @param[in] Private Pointer to PxeBc private data.
1115 @param[in, out] BufferSize Size of user buffer for input;
1116 required buffer size for output.
1117 @param[in] Buffer Pointer to user buffer.
1119 @retval EFI_SUCCESS Get all the boot information successfully.
1120 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
1121 @retval EFI_ABORTED User cancelled the current operation.
1122 @retval Others Failed to parse out the boot information.
1127 IN PXEBC_PRIVATE_DATA
*Private
,
1128 IN OUT UINTN
*BufferSize
,
1129 IN VOID
*Buffer OPTIONAL
1132 BOOLEAN NewMakeCallback
;
1133 UINT64 RequiredSize
;
1136 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1137 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
1139 NewMakeCallback
= FALSE
;
1140 PxeBc
= &Private
->PxeBc
;
1141 PxeBcMode
= &Private
->Mode
;
1142 CurrentSize
= *BufferSize
;
1146 // Install pxebc callback protocol if hasn't been installed yet.
1148 Status
= PxeBcInstallCallback (Private
, &NewMakeCallback
);
1149 if (EFI_ERROR(Status
)) {
1153 if (Private
->BootFileSize
== 0) {
1155 // Discover the boot information about the bootfile if hasn't.
1157 Status
= PxeBcDiscoverBootFile (Private
, &RequiredSize
);
1158 if (EFI_ERROR (Status
)) {
1162 if (PXEBC_IS_SIZE_OVERFLOWED (RequiredSize
)) {
1164 // It's error if the required buffer size is beyond the system scope.
1166 Status
= EFI_DEVICE_ERROR
;
1168 } else if (RequiredSize
> 0) {
1170 // Get the right buffer size of the bootfile required.
1172 if (CurrentSize
< RequiredSize
|| Buffer
== NULL
) {
1174 // It's buffer too small if the size of user buffer is smaller than the required.
1176 CurrentSize
= RequiredSize
;
1177 Status
= EFI_BUFFER_TOO_SMALL
;
1180 CurrentSize
= RequiredSize
;
1181 } else if (RequiredSize
== 0 && PxeBcMode
->UsingIpv6
) {
1183 // Try to download another bootfile in list if failed to get the filesize of the last one.
1184 // It's special for the case of IPv6.
1186 Status
= PxeBcReadBootFileList (Private
, &CurrentSize
, Buffer
);
1189 } else if (CurrentSize
< Private
->BootFileSize
|| Buffer
== NULL
) {
1191 // It's buffer too small if the size of user buffer is smaller than the required.
1193 CurrentSize
= Private
->BootFileSize
;
1194 Status
= EFI_BUFFER_TOO_SMALL
;
1199 // Begin to download the bootfile if everything is ready.
1201 AsciiPrint ("\n Downloading NBP file...\n");
1202 if (PxeBcMode
->UsingIpv6
) {
1203 Status
= PxeBcReadBootFileList (
1209 Status
= PxeBc
->Mtftp (
1211 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1215 &Private
->BlockSize
,
1217 Private
->BootFileName
,
1224 *BufferSize
= (UINTN
) CurrentSize
;
1225 PxeBcUninstallCallback(Private
, NewMakeCallback
);
1227 if (Status
== EFI_SUCCESS
) {
1228 AsciiPrint ("\n NBP file downloaded successfully.\n");
1230 } else if (Status
== EFI_BUFFER_TOO_SMALL
&& Buffer
!= NULL
) {
1231 AsciiPrint ("\n PXE-E05: Buffer size is smaller than the requested file.\n");
1232 } else if (Status
== EFI_DEVICE_ERROR
) {
1233 AsciiPrint ("\n PXE-E07: Network device error.\n");
1234 } else if (Status
== EFI_OUT_OF_RESOURCES
) {
1235 AsciiPrint ("\n PXE-E09: Could not allocate I/O buffers.\n");
1236 } else if (Status
== EFI_NO_MEDIA
) {
1237 AsciiPrint ("\n PXE-E12: Could not detect network connection.\n");
1238 } else if (Status
== EFI_NO_RESPONSE
) {
1239 AsciiPrint ("\n PXE-E16: No valid offer received.\n");
1240 } else if (Status
== EFI_TIMEOUT
) {
1241 AsciiPrint ("\n PXE-E18: Server response timeout.\n");
1242 } else if (Status
== EFI_ABORTED
) {
1243 AsciiPrint ("\n PXE-E21: Remote boot cancelled.\n");
1244 } else if (Status
== EFI_ICMP_ERROR
) {
1245 AsciiPrint ("\n PXE-E22: Client received ICMP error from server.\n");
1246 } else if (Status
== EFI_TFTP_ERROR
) {
1247 AsciiPrint ("\n PXE-E23: Client received TFTP error from server.\n");
1248 } else if (Status
== EFI_NOT_FOUND
) {
1249 AsciiPrint ("\n PXE-E53: No boot filename received.\n");
1250 } else if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1251 AsciiPrint ("\n PXE-E99: Unexpected network error.\n");