2 Boot functions implementation for UefiPxeBc Driver.
4 Copyright (c) 2009 - 2013, 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 DhcpPxe10 and ProxyPxe10 offer needs boot prompt.
91 if (OfferType
!= PxeOfferTypeProxyPxe10
&& OfferType
!= PxeOfferTypeDhcpPxe10
) {
96 // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec.
98 ASSERT (!Mode
->UsingIpv6
);
100 VendorOpt
= &Cache
->Dhcp4
.VendorOpt
;
102 // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options,
103 // we must not consider a boot prompt or boot menu if all of the following hold:
104 // - the PXE_DISCOVERY_CONTROL tag(6) is present inside the Vendor Options(43), and has bit 3 set
105 // - a boot file name has been presented in the initial DHCP or ProxyDHCP offer packet.
107 if (IS_DISABLE_PROMPT_MENU (VendorOpt
->DiscoverCtrl
) &&
108 Cache
->Dhcp4
.OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
) {
112 if (!IS_VALID_BOOT_PROMPT (VendorOpt
->BitMap
)) {
116 Timeout
= VendorOpt
->MenuPrompt
->Timeout
;
117 Prompt
= VendorOpt
->MenuPrompt
->Prompt
;
118 PromptLen
= (UINT8
) (VendorOpt
->MenuPromptLen
- 1);
121 // The valid scope of Timeout refers to PXE2.1 spec.
126 if (Timeout
== 255) {
131 // Create and start a timer as timeout event.
133 Status
= gBS
->CreateEvent (
140 if (EFI_ERROR (Status
)) {
144 Status
= gBS
->SetTimer (
147 Timeout
* TICKS_PER_SECOND
149 if (EFI_ERROR (Status
)) {
154 // Create and start a periodic timer as descend event by second.
156 Status
= gBS
->CreateEvent (
163 if (EFI_ERROR (Status
)) {
167 Status
= gBS
->SetTimer (
172 if (EFI_ERROR (Status
)) {
177 // Display the boot item and cursor on the screen.
179 SecCol
= gST
->ConOut
->Mode
->CursorColumn
;
180 SecRow
= gST
->ConOut
->Mode
->CursorRow
;
182 PxeBcDisplayBootItem (Prompt
, PromptLen
);
184 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
185 AsciiPrint ("(%d) ", Timeout
--);
187 Status
= EFI_TIMEOUT
;
188 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
189 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
190 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
191 AsciiPrint ("(%d) ", Timeout
--);
193 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
194 gBS
->Stall (10 * TICKS_PER_MS
);
198 // Parse the input key by user.
199 // If <F8> or <Ctrl> + <M> is pressed, return success to display the boot menu.
201 if (InputKey
.ScanCode
== 0) {
203 switch (InputKey
.UnicodeChar
) {
206 Status
= EFI_ABORTED
;
212 Status
= EFI_SUCCESS
;
221 switch (InputKey
.ScanCode
) {
224 Status
= EFI_SUCCESS
;
228 Status
= EFI_ABORTED
;
240 // Reset the cursor on the screen.
242 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
245 if (DescendEvent
!= NULL
) {
246 gBS
->CloseEvent (DescendEvent
);
248 if (TimeoutEvent
!= NULL
) {
249 gBS
->CloseEvent (TimeoutEvent
);
257 Select the boot menu by user's input.
259 @param[in] Private Pointer to PxeBc private data.
260 @param[out] Type The type of the menu.
261 @param[in] UseDefaultItem Use default item or not.
263 @retval EFI_ABORTED User cancel operation.
264 @retval EFI_SUCCESS Select the boot menu success.
265 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
269 PxeBcSelectBootMenu (
270 IN PXEBC_PRIVATE_DATA
*Private
,
272 IN BOOLEAN UseDefaultItem
275 EFI_PXE_BASE_CODE_MODE
*Mode
;
276 PXEBC_DHCP_PACKET_CACHE
*Cache
;
277 PXEBC_VENDOR_OPTION
*VendorOpt
;
278 EFI_INPUT_KEY InputKey
;
287 CHAR8 Blank
[PXEBC_DISPLAY_MAX_LINE
];
288 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
289 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MENU_MAX_NUM
];
295 Mode
= Private
->PxeBc
.Mode
;
296 Cache
= Mode
->ProxyOfferReceived
? &Private
->ProxyOffer
: &Private
->DhcpAck
;
297 OfferType
= Mode
->UsingIpv6
? Cache
->Dhcp6
.OfferType
: Cache
->Dhcp4
.OfferType
;
300 // There is no specified DhcpPxe10/ProxyPxe10 for IPv6 in PXE and UEFI spec.
302 ASSERT (!Mode
->UsingIpv6
);
303 ASSERT (OfferType
== PxeOfferTypeProxyPxe10
|| OfferType
== PxeOfferTypeDhcpPxe10
);
305 VendorOpt
= &Cache
->Dhcp4
.VendorOpt
;
306 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
311 // Display the boot menu on the screen.
313 SetMem (Blank
, sizeof(Blank
), ' ');
315 MenuSize
= VendorOpt
->BootMenuLen
;
316 MenuItem
= VendorOpt
->BootMenu
;
319 return EFI_DEVICE_ERROR
;
322 while (MenuSize
> 0 && Index
< PXEBC_MENU_MAX_NUM
) {
323 ASSERT (MenuItem
!= NULL
);
324 MenuArray
[Index
] = MenuItem
;
325 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
326 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
330 if (UseDefaultItem
) {
331 ASSERT (MenuArray
[0] != NULL
);
332 CopyMem (Type
, &MenuArray
[0]->Type
, sizeof (UINT16
));
333 *Type
= NTOHS (*Type
);
339 for (Index
= 0; Index
< MenuNum
; Index
++) {
340 ASSERT (MenuArray
[Index
] != NULL
);
341 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
344 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
347 // Select the boot item by user in the boot menu.
351 // Highlight selected row.
353 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
354 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
355 ASSERT (Select
< PXEBC_MENU_MAX_NUM
);
356 ASSERT (MenuArray
[Select
] != NULL
);
357 Blank
[MenuArray
[Select
]->DescLen
] = 0;
358 AsciiPrint ("%a\r", Blank
);
359 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
360 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
363 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
364 gBS
->Stall (10 * TICKS_PER_MS
);
367 if (InputKey
.ScanCode
== 0) {
368 switch (InputKey
.UnicodeChar
) {
370 InputKey
.ScanCode
= SCAN_ESC
;
373 case CTRL ('j'): /* linefeed */
374 case CTRL ('m'): /* return */
378 case CTRL ('i'): /* tab */
382 InputKey
.ScanCode
= SCAN_DOWN
;
385 case CTRL ('h'): /* backspace */
388 InputKey
.ScanCode
= SCAN_UP
;
392 InputKey
.ScanCode
= 0;
396 switch (InputKey
.ScanCode
) {
406 if (++Select
== MenuNum
) {
418 Select
= (UINT16
) (MenuNum
- 1);
426 // Unhighlight the last selected row.
428 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
429 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
430 ASSERT (LastSelect
< PXEBC_MENU_MAX_NUM
);
431 ASSERT (MenuArray
[LastSelect
] != NULL
);
432 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
433 AsciiPrint ("%a\r", Blank
);
434 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
435 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
439 // Swap the byte order.
441 ASSERT (Select
< PXEBC_MENU_MAX_NUM
);
442 ASSERT (MenuArray
[Select
] != NULL
);
443 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
444 *Type
= NTOHS (*Type
);
451 Parse out the boot information from the last Dhcp4 reply packet.
453 @param[in, out] Private Pointer to PxeBc private data.
454 @param[out] BufferSize Size of the boot file to be downloaded.
456 @retval EFI_SUCCESS Successfully parsed out all the boot information.
457 @retval Others Failed to parse out the boot information.
462 IN OUT PXEBC_PRIVATE_DATA
*Private
,
463 OUT UINT64
*BufferSize
466 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
467 EFI_PXE_BASE_CODE_MODE
*Mode
;
469 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
472 PxeBc
= &Private
->PxeBc
;
474 Status
= EFI_SUCCESS
;
478 // Get the last received Dhcp4 reply packet.
480 if (Mode
->PxeReplyReceived
) {
481 Cache4
= &Private
->PxeReply
.Dhcp4
;
482 } else if (Mode
->ProxyOfferReceived
) {
483 Cache4
= &Private
->ProxyOffer
.Dhcp4
;
485 Cache4
= &Private
->DhcpAck
.Dhcp4
;
489 // Parse the boot server Ipv4 address by next server address.
490 // If this field isn't available, use option 54 instead.
494 &Cache4
->Packet
.Offer
.Dhcp4
.Header
.ServerAddr
,
495 sizeof (EFI_IPv4_ADDRESS
)
498 if (Private
->ServerIp
.Addr
[0] == 0) {
501 Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
502 sizeof (EFI_IPv4_ADDRESS
)
507 // Parse the boot file name by option.
509 ASSERT (Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
510 Private
->BootFileName
= Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Data
;
512 if (Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN
] != NULL
) {
514 // Parse the boot file size by option.
516 CopyMem (&Value
, Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN
]->Data
, sizeof (Value
));
517 Value
= NTOHS (Value
);
519 // The field of boot file size is 512 bytes in unit.
521 *BufferSize
= 512 * Value
;
524 // Get the bootfile size by tftp command if no option available.
526 Status
= PxeBc
->Mtftp (
528 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
534 Private
->BootFileName
,
541 // Save the value of boot file size.
543 Private
->BootFileSize
= (UINTN
) *BufferSize
;
546 // Display all the information: boot server address, boot file name and boot file size.
548 AsciiPrint ("\n Server IP address is ");
549 PxeBcShowIp4Addr (&Private
->ServerIp
.v4
);
550 AsciiPrint ("\n NBP filename is %a", Private
->BootFileName
);
551 AsciiPrint ("\n NBP filesize is %d Bytes", Private
->BootFileSize
);
558 Parse out the boot information from the last Dhcp6 reply packet.
560 @param[in, out] Private Pointer to PxeBc private data.
561 @param[out] BufferSize Size of the boot file to be downloaded.
563 @retval EFI_SUCCESS Successfully parsed out all the boot information.
564 @retval EFI_BUFFER_TOO_SMALL
565 @retval Others Failed to parse out the boot information.
570 IN OUT PXEBC_PRIVATE_DATA
*Private
,
571 OUT UINT64
*BufferSize
574 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
575 EFI_PXE_BASE_CODE_MODE
*Mode
;
577 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
580 PxeBc
= &Private
->PxeBc
;
582 Status
= EFI_SUCCESS
;
586 // Get the last received Dhcp6 reply packet.
588 if (Mode
->PxeReplyReceived
) {
589 Cache6
= &Private
->PxeReply
.Dhcp6
;
590 } else if (Mode
->ProxyOfferReceived
) {
591 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
593 Cache6
= &Private
->DhcpAck
.Dhcp6
;
596 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
599 // Parse (m)tftp server ip address and bootfile name.
601 Status
= PxeBcExtractBootFileUrl (
602 &Private
->BootFileName
,
603 &Private
->ServerIp
.v6
,
604 (CHAR8
*) (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
605 NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
607 if (EFI_ERROR (Status
)) {
612 // Parse the value of boot file size.
614 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] != NULL
) {
616 // Parse it out if have the boot file parameter option.
618 Status
= PxeBcExtractBootFileParam ((CHAR8
*) Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
]->Data
, &Value
);
619 if (EFI_ERROR (Status
)) {
623 // The field of boot file size is 512 bytes in unit.
625 *BufferSize
= 512 * Value
;
628 // Send get file size command by tftp if option unavailable.
630 Status
= PxeBc
->Mtftp (
632 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
638 Private
->BootFileName
,
645 // Save the value of boot file size.
647 Private
->BootFileSize
= (UINTN
) *BufferSize
;
650 // Display all the information: boot server address, boot file name and boot file size.
652 AsciiPrint ("\n Server IP address is ");
653 PxeBcShowIp6Addr (&Private
->ServerIp
.v6
);
654 AsciiPrint ("\n NBP filename is %a", Private
->BootFileName
);
655 AsciiPrint ("\n NBP filesize is %d Bytes", Private
->BootFileSize
);
662 Extract the discover information and boot server entry from the
663 cached packets if unspecified.
665 @param[in] Private Pointer to PxeBc private data.
666 @param[in] Type The type of bootstrap to perform.
667 @param[in, out] DiscoverInfo Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO.
668 @param[out] BootEntry Pointer to PXEBC_BOOT_SVR_ENTRY.
669 @param[out] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
671 @retval EFI_SUCCESS Successfully extracted the information.
672 @retval EFI_DEVICE_ERROR Failed to extract the information.
676 PxeBcExtractDiscoverInfo (
677 IN PXEBC_PRIVATE_DATA
*Private
,
679 IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO
**DiscoverInfo
,
680 OUT PXEBC_BOOT_SVR_ENTRY
**BootEntry
,
681 OUT EFI_PXE_BASE_CODE_SRVLIST
**SrvList
684 EFI_PXE_BASE_CODE_MODE
*Mode
;
685 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
686 PXEBC_VENDOR_OPTION
*VendorOpt
;
687 PXEBC_BOOT_SVR_ENTRY
*Entry
;
689 EFI_PXE_BASE_CODE_DISCOVER_INFO
*Info
;
692 Mode
= Private
->PxeBc
.Mode
;
693 Info
= *DiscoverInfo
;
695 if (Mode
->UsingIpv6
) {
697 Info
->UseUCast
= TRUE
;
699 Info
->SrvList
[0].Type
= Type
;
700 Info
->SrvList
[0].AcceptAnyResponse
= FALSE
;
703 // There is no vendor options specified in DHCPv6, so take BootFileUrl in the last cached packet.
705 CopyMem (&Info
->SrvList
[0].IpAddr
, &Private
->ServerIp
, sizeof (EFI_IP_ADDRESS
));
707 *SrvList
= Info
->SrvList
;
711 Cache4
= (Mode
->ProxyOfferReceived
) ? &Private
->ProxyOffer
.Dhcp4
: &Private
->DhcpAck
.Dhcp4
;
712 VendorOpt
= &Cache4
->VendorOpt
;
714 if (!Mode
->DhcpAckReceived
|| !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt
->BitMap
)) {
716 // Address is not acquired or no discovery options.
718 return EFI_INVALID_PARAMETER
;
722 // Parse the boot server entry from the vendor option in the last cached packet.
724 Info
->UseMCast
= (BOOLEAN
) !IS_DISABLE_MCAST_DISCOVER (VendorOpt
->DiscoverCtrl
);
725 Info
->UseBCast
= (BOOLEAN
) !IS_DISABLE_BCAST_DISCOVER (VendorOpt
->DiscoverCtrl
);
726 Info
->MustUseList
= (BOOLEAN
) IS_ENABLE_USE_SERVER_LIST (VendorOpt
->DiscoverCtrl
);
727 Info
->UseUCast
= (BOOLEAN
) IS_VALID_BOOT_SERVERS (VendorOpt
->BitMap
);
729 if (Info
->UseMCast
) {
731 // Get the multicast discover ip address from vendor option if has.
733 CopyMem (&Info
->ServerMCastIp
.v4
, &VendorOpt
->DiscoverMcastIp
, sizeof (EFI_IPv4_ADDRESS
));
738 if (Info
->UseUCast
) {
739 Entry
= VendorOpt
->BootSvr
;
741 while (((UINT8
) (Entry
- VendorOpt
->BootSvr
)) < VendorOpt
->BootSvrLen
) {
742 if (Entry
->Type
== HTONS (Type
)) {
746 Entry
= GET_NEXT_BOOT_SVR_ENTRY (Entry
);
750 return EFI_DEVICE_ERROR
;
753 Info
->IpCnt
= Entry
->IpCnt
;
754 if (Info
->IpCnt
>= 1) {
755 *DiscoverInfo
= AllocatePool (sizeof (*Info
) + (Info
->IpCnt
- 1) * sizeof (**SrvList
));
756 if (*DiscoverInfo
== NULL
) {
757 return EFI_OUT_OF_RESOURCES
;
759 CopyMem (*DiscoverInfo
, Info
, sizeof (*Info
));
760 Info
= *DiscoverInfo
;
763 for (Index
= 0; Index
< Info
->IpCnt
; Index
++) {
764 CopyMem (&Info
->SrvList
[Index
].IpAddr
, &Entry
->IpAddr
[Index
], sizeof (EFI_IPv4_ADDRESS
));
765 Info
->SrvList
[Index
].AcceptAnyResponse
= !Info
->MustUseList
;
766 Info
->SrvList
[Index
].Type
= NTOHS (Entry
->Type
);
771 *SrvList
= Info
->SrvList
;
779 Build the discover packet and send out for boot server.
781 @param[in] Private Pointer to PxeBc private data.
782 @param[in] Type PxeBc option boot item type.
783 @param[in] Layer Pointer to option boot item layer.
784 @param[in] UseBis Use BIS or not.
785 @param[in] DestIp Pointer to the destination address.
786 @param[in] IpCount The count of the server address.
787 @param[in] SrvList Pointer to the server address list.
789 @retval EFI_SUCCESS Successfully discovered boot file.
790 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
791 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
792 @retval Others Failed to discover boot file.
796 PxeBcDiscoverBootServer (
797 IN PXEBC_PRIVATE_DATA
*Private
,
801 IN EFI_IP_ADDRESS
*DestIp
,
803 IN EFI_PXE_BASE_CODE_SRVLIST
*SrvList
806 if (Private
->PxeBc
.Mode
->UsingIpv6
) {
807 return PxeBcDhcp6Discover (
815 return PxeBcDhcp4Discover (
829 Discover all the boot information for boot file.
831 @param[in, out] Private Pointer to PxeBc private data.
832 @param[out] BufferSize Size of the boot file to be downloaded.
834 @retval EFI_SUCCESS Successfully obtained all the boot information .
835 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
836 @retval EFI_ABORTED User cancel current operation.
837 @retval Others Failed to parse out the boot information.
841 PxeBcDiscoverBootFile (
842 IN OUT PXEBC_PRIVATE_DATA
*Private
,
843 OUT UINT64
*BufferSize
846 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
847 EFI_PXE_BASE_CODE_MODE
*Mode
;
853 PxeBc
= &Private
->PxeBc
;
855 Type
= EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
;
856 Layer
= EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL
;
859 // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and
860 // other pxe boot information.
862 Status
= PxeBc
->Dhcp (PxeBc
, TRUE
);
863 if (EFI_ERROR (Status
)) {
868 // Select a boot server from boot server list.
870 Status
= PxeBcSelectBootPrompt (Private
);
872 if (Status
== EFI_SUCCESS
) {
874 // Choose by user's input.
876 Status
= PxeBcSelectBootMenu (Private
, &Type
, FALSE
);
877 } else if (Status
== EFI_TIMEOUT
) {
879 // Choose by default item.
881 Status
= PxeBcSelectBootMenu (Private
, &Type
, TRUE
);
884 if (!EFI_ERROR (Status
)) {
886 if (Type
== EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
) {
888 // Local boot(PXE bootstrap server) need abort
894 // Start to discover the boot server to get (m)tftp server ip address, bootfile
895 // name and bootfile size.
897 UseBis
= (BOOLEAN
) (Mode
->BisSupported
&& Mode
->BisDetected
);
898 Status
= PxeBc
->Discover (PxeBc
, Type
, &Layer
, UseBis
, NULL
);
899 if (EFI_ERROR (Status
)) {
903 if (Mode
->PxeReplyReceived
&& !Mode
->ProxyOfferReceived
) {
905 // Some network boot loader only search the packet in Mode.ProxyOffer to get its server
906 // IP address, so we need to store a copy of Mode.PxeReply packet into Mode.ProxyOffer.
908 if (Mode
->UsingIpv6
) {
910 &Mode
->ProxyOffer
.Dhcpv6
,
911 &Mode
->PxeReply
.Dhcpv6
,
912 Private
->PxeReply
.Dhcp6
.Packet
.Ack
.Length
916 &Mode
->ProxyOffer
.Dhcpv4
,
917 &Mode
->PxeReply
.Dhcpv4
,
918 Private
->PxeReply
.Dhcp4
.Packet
.Ack
.Length
921 Mode
->ProxyOfferReceived
= TRUE
;
926 // Parse the boot information.
928 if (Mode
->UsingIpv6
) {
929 Status
= PxeBcDhcp6BootInfo (Private
, BufferSize
);
931 Status
= PxeBcDhcp4BootInfo (Private
, BufferSize
);
939 Install PxeBaseCodeCallbackProtocol if not installed before.
941 @param[in, out] Private Pointer to PxeBc private data.
942 @param[out] NewMakeCallback If TRUE, it is a new callback.
943 Otherwise, it is not new callback.
944 @retval EFI_SUCCESS PxeBaseCodeCallbackProtocol installed succesfully.
945 @retval Others Failed to install PxeBaseCodeCallbackProtocol.
949 PxeBcInstallCallback (
950 IN OUT PXEBC_PRIVATE_DATA
*Private
,
951 OUT BOOLEAN
*NewMakeCallback
954 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
958 // Check whether PxeBaseCodeCallbackProtocol already installed.
960 PxeBc
= &Private
->PxeBc
;
961 Status
= gBS
->HandleProtocol (
963 &gEfiPxeBaseCodeCallbackProtocolGuid
,
964 (VOID
**) &Private
->PxeBcCallback
966 if (Status
== EFI_UNSUPPORTED
) {
969 &Private
->LoadFileCallback
,
970 &gPxeBcCallBackTemplate
,
971 sizeof (EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
)
975 // Install a default callback if user didn't offer one.
977 Status
= gBS
->InstallProtocolInterface (
978 &Private
->Controller
,
979 &gEfiPxeBaseCodeCallbackProtocolGuid
,
980 EFI_NATIVE_INTERFACE
,
981 &Private
->LoadFileCallback
984 (*NewMakeCallback
) = (BOOLEAN
) (Status
== EFI_SUCCESS
);
986 Status
= PxeBc
->SetParameters (PxeBc
, NULL
, NULL
, NULL
, NULL
, NewMakeCallback
);
987 if (EFI_ERROR (Status
)) {
998 Uninstall PxeBaseCodeCallbackProtocol.
1000 @param[in] Private Pointer to PxeBc private data.
1001 @param[in] NewMakeCallback If TRUE, it is a new callback.
1002 Otherwise, it is not new callback.
1006 PxeBcUninstallCallback (
1007 IN PXEBC_PRIVATE_DATA
*Private
,
1008 IN BOOLEAN NewMakeCallback
1011 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1013 PxeBc
= &Private
->PxeBc
;
1015 if (NewMakeCallback
) {
1017 NewMakeCallback
= FALSE
;
1019 PxeBc
->SetParameters (PxeBc
, NULL
, NULL
, NULL
, NULL
, &NewMakeCallback
);
1021 gBS
->UninstallProtocolInterface (
1022 Private
->Controller
,
1023 &gEfiPxeBaseCodeCallbackProtocolGuid
,
1024 &Private
->LoadFileCallback
1031 Download one of boot file in the list, and it's special for IPv6.
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 Read one of boot file in the list successfully.
1039 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
1040 @retval EFI_NOT_FOUND There is no proper boot file available.
1041 @retval Others Failed to download boot file in the list.
1045 PxeBcReadBootFileList (
1046 IN PXEBC_PRIVATE_DATA
*Private
,
1047 IN OUT UINT64
*BufferSize
,
1048 IN VOID
*Buffer OPTIONAL
1052 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1054 PxeBc
= &Private
->PxeBc
;
1057 // Try to download the boot file if everything is ready.
1059 if (Buffer
!= NULL
) {
1060 Status
= PxeBc
->Mtftp (
1062 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1066 &Private
->BlockSize
,
1068 Private
->BootFileName
,
1075 Status
= EFI_BUFFER_TOO_SMALL
;
1083 Load boot file into user buffer.
1085 @param[in] Private Pointer to PxeBc private data.
1086 @param[in, out] BufferSize Size of user buffer for input;
1087 required buffer size for output.
1088 @param[in] Buffer Pointer to user buffer.
1090 @retval EFI_SUCCESS Get all the boot information successfully.
1091 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
1092 @retval EFI_ABORTED User cancelled the current operation.
1093 @retval Others Failed to parse out the boot information.
1098 IN PXEBC_PRIVATE_DATA
*Private
,
1099 IN OUT UINTN
*BufferSize
,
1100 IN VOID
*Buffer OPTIONAL
1103 BOOLEAN NewMakeCallback
;
1104 UINT64 RequiredSize
;
1107 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1108 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
1110 NewMakeCallback
= FALSE
;
1111 PxeBc
= &Private
->PxeBc
;
1112 PxeBcMode
= &Private
->Mode
;
1113 CurrentSize
= *BufferSize
;
1117 // Install pxebc callback protocol if hasn't been installed yet.
1119 Status
= PxeBcInstallCallback (Private
, &NewMakeCallback
);
1120 if (EFI_ERROR(Status
)) {
1124 if (Private
->BootFileSize
== 0) {
1126 // Discover the boot information about the bootfile if hasn't.
1128 Status
= PxeBcDiscoverBootFile (Private
, &RequiredSize
);
1129 if (EFI_ERROR (Status
)) {
1133 if (PXEBC_IS_SIZE_OVERFLOWED (RequiredSize
)) {
1135 // It's error if the required buffer size is beyond the system scope.
1137 Status
= EFI_DEVICE_ERROR
;
1139 } else if (RequiredSize
> 0) {
1141 // Get the right buffer size of the bootfile required.
1143 if (CurrentSize
< RequiredSize
|| Buffer
== NULL
) {
1145 // It's buffer too small if the size of user buffer is smaller than the required.
1147 CurrentSize
= RequiredSize
;
1148 Status
= EFI_BUFFER_TOO_SMALL
;
1151 CurrentSize
= RequiredSize
;
1152 } else if (RequiredSize
== 0 && PxeBcMode
->UsingIpv6
) {
1154 // Try to download another bootfile in list if failed to get the filesize of the last one.
1155 // It's special for the case of IPv6.
1157 Status
= PxeBcReadBootFileList (Private
, &CurrentSize
, Buffer
);
1160 } else if (CurrentSize
< Private
->BootFileSize
|| Buffer
== NULL
) {
1162 // It's buffer too small if the size of user buffer is smaller than the required.
1164 CurrentSize
= Private
->BootFileSize
;
1165 Status
= EFI_BUFFER_TOO_SMALL
;
1170 // Begin to download the bootfile if everything is ready.
1172 AsciiPrint ("\n Downloading NBP file...\n");
1173 if (PxeBcMode
->UsingIpv6
) {
1174 Status
= PxeBcReadBootFileList (
1180 Status
= PxeBc
->Mtftp (
1182 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1186 &Private
->BlockSize
,
1188 Private
->BootFileName
,
1195 *BufferSize
= (UINTN
) CurrentSize
;
1196 PxeBcUninstallCallback(Private
, NewMakeCallback
);
1198 if (Status
== EFI_SUCCESS
) {
1199 AsciiPrint ("\n Succeed to download NBP file.\n");
1201 } else if (Status
== EFI_BUFFER_TOO_SMALL
&& Buffer
!= NULL
) {
1202 AsciiPrint ("\n PXE-E05: Buffer size is smaller than the requested file.\n");
1203 } else if (Status
== EFI_DEVICE_ERROR
) {
1204 AsciiPrint ("\n PXE-E07: Network device error.\n");
1205 } else if (Status
== EFI_OUT_OF_RESOURCES
) {
1206 AsciiPrint ("\n PXE-E09: Could not allocate I/O buffers.\n");
1207 } else if (Status
== EFI_NO_MEDIA
) {
1208 AsciiPrint ("\n PXE-E12: Could not detect network connection.\n");
1209 } else if (Status
== EFI_NO_RESPONSE
) {
1210 AsciiPrint ("\n PXE-E16: No offer received.\n");
1211 } else if (Status
== EFI_TIMEOUT
) {
1212 AsciiPrint ("\n PXE-E18: Server response timeout.\n");
1213 } else if (Status
== EFI_ABORTED
) {
1214 AsciiPrint ("\n PXE-E21: Remote boot cancelled.\n");
1215 } else if (Status
== EFI_ICMP_ERROR
) {
1216 AsciiPrint ("\n PXE-E22: Client received ICMP error from server.\n");
1217 } else if (Status
== EFI_TFTP_ERROR
) {
1218 AsciiPrint ("\n PXE-E23: Client received TFTP error from server.\n");
1219 } else if (Status
== EFI_NOT_FOUND
) {
1220 AsciiPrint ("\n PXE-E53: No boot filename received.\n");
1221 } else if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1222 AsciiPrint ("\n PXE-E99: Unexpected network error.\n");