2 Boot functions implementation for UefiPxeBc Driver.
4 Copyright (c) 2009 - 2012, 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
;
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 Status
= EFI_TIMEOUT
;
177 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
178 if (!EFI_ERROR (gBS
->CheckEvent (DescendEvent
))) {
179 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, SecCol
+ PromptLen
, SecRow
);
180 AsciiPrint ("(%d) ", Timeout
--);
182 if (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
183 gBS
->Stall (10 * TICKS_PER_MS
);
187 // Parse the input key by user.
188 // If <F8> or <Ctrl> + <M> is pressed, return success to display the boot menu.
190 if (InputKey
.ScanCode
== 0) {
192 switch (InputKey
.UnicodeChar
) {
195 Status
= EFI_ABORTED
;
201 Status
= EFI_SUCCESS
;
210 switch (InputKey
.ScanCode
) {
213 Status
= EFI_SUCCESS
;
217 Status
= EFI_ABORTED
;
229 // Reset the cursor on the screen.
231 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0 , SecRow
+ 1);
234 if (DescendEvent
!= NULL
) {
235 gBS
->CloseEvent (DescendEvent
);
237 if (TimeoutEvent
!= NULL
) {
238 gBS
->CloseEvent (TimeoutEvent
);
246 Select the boot menu by user's input.
248 @param[in] Private Pointer to PxeBc private data.
249 @param[out] Type The type of the menu.
250 @param[in] UseDefaultItem Use default item or not.
252 @retval EFI_ABORTED User cancel operation.
253 @retval EFI_SUCCESS Select the boot menu success.
254 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
258 PxeBcSelectBootMenu (
259 IN PXEBC_PRIVATE_DATA
*Private
,
261 IN BOOLEAN UseDefaultItem
264 EFI_PXE_BASE_CODE_MODE
*Mode
;
265 PXEBC_DHCP_PACKET_CACHE
*Cache
;
266 PXEBC_VENDOR_OPTION
*VendorOpt
;
267 EFI_INPUT_KEY InputKey
;
276 CHAR8 Blank
[PXEBC_DISPLAY_MAX_LINE
];
277 PXEBC_BOOT_MENU_ENTRY
*MenuItem
;
278 PXEBC_BOOT_MENU_ENTRY
*MenuArray
[PXEBC_MENU_MAX_NUM
];
284 Mode
= Private
->PxeBc
.Mode
;
285 Cache
= Mode
->ProxyOfferReceived
? &Private
->ProxyOffer
: &Private
->DhcpAck
;
286 OfferType
= Mode
->UsingIpv6
? Cache
->Dhcp6
.OfferType
: Cache
->Dhcp4
.OfferType
;
289 // There is no specified DhcpPxe10/ProxyPxe10 for IPv6 in PXE and UEFI spec.
291 ASSERT (!Mode
->UsingIpv6
);
292 ASSERT (OfferType
== PxeOfferTypeProxyPxe10
|| OfferType
== PxeOfferTypeDhcpPxe10
);
294 VendorOpt
= &Cache
->Dhcp4
.VendorOpt
;
295 if (!IS_VALID_BOOT_MENU (VendorOpt
->BitMap
)) {
300 // Display the boot menu on the screen.
302 SetMem (Blank
, sizeof(Blank
), ' ');
304 MenuSize
= VendorOpt
->BootMenuLen
;
305 MenuItem
= VendorOpt
->BootMenu
;
308 return EFI_DEVICE_ERROR
;
311 while (MenuSize
> 0 && Index
< PXEBC_MENU_MAX_NUM
) {
312 ASSERT (MenuItem
!= NULL
);
313 MenuArray
[Index
] = MenuItem
;
314 MenuSize
= (UINT8
) (MenuSize
- (MenuItem
->DescLen
+ 3));
315 MenuItem
= (PXEBC_BOOT_MENU_ENTRY
*) ((UINT8
*) MenuItem
+ MenuItem
->DescLen
+ 3);
319 if (UseDefaultItem
) {
320 ASSERT (MenuArray
[0] != NULL
);
321 CopyMem (Type
, &MenuArray
[0]->Type
, sizeof (UINT16
));
322 *Type
= NTOHS (*Type
);
328 for (Index
= 0; Index
< MenuNum
; Index
++) {
329 ASSERT (MenuArray
[Index
] != NULL
);
330 PxeBcDisplayBootItem (MenuArray
[Index
]->DescStr
, MenuArray
[Index
]->DescLen
);
333 TopRow
= gST
->ConOut
->Mode
->CursorRow
- MenuNum
;
336 // Select the boot item by user in the boot menu.
340 // Highlight selected row.
342 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
343 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ Select
);
344 ASSERT (Select
< PXEBC_MENU_MAX_NUM
);
345 ASSERT (MenuArray
[Select
] != NULL
);
346 Blank
[MenuArray
[Select
]->DescLen
] = 0;
347 AsciiPrint ("%a\r", Blank
);
348 PxeBcDisplayBootItem (MenuArray
[Select
]->DescStr
, MenuArray
[Select
]->DescLen
);
349 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
352 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &InputKey
) == EFI_NOT_READY
) {
353 gBS
->Stall (10 * TICKS_PER_MS
);
356 if (InputKey
.ScanCode
== 0) {
357 switch (InputKey
.UnicodeChar
) {
359 InputKey
.ScanCode
= SCAN_ESC
;
362 case CTRL ('j'): /* linefeed */
363 case CTRL ('m'): /* return */
367 case CTRL ('i'): /* tab */
371 InputKey
.ScanCode
= SCAN_DOWN
;
374 case CTRL ('h'): /* backspace */
377 InputKey
.ScanCode
= SCAN_UP
;
381 InputKey
.ScanCode
= 0;
385 switch (InputKey
.ScanCode
) {
395 if (++Select
== MenuNum
) {
407 Select
= (UINT16
) (MenuNum
- 1);
415 // Unhighlight the last selected row.
417 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
418 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ LastSelect
);
419 ASSERT (LastSelect
< PXEBC_MENU_MAX_NUM
);
420 ASSERT (MenuArray
[LastSelect
] != NULL
);
421 Blank
[MenuArray
[LastSelect
]->DescLen
] = 0;
422 AsciiPrint ("%a\r", Blank
);
423 PxeBcDisplayBootItem (MenuArray
[LastSelect
]->DescStr
, MenuArray
[LastSelect
]->DescLen
);
424 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, TopRow
+ MenuNum
);
428 // Swap the byte order.
430 ASSERT (Select
< PXEBC_MENU_MAX_NUM
);
431 ASSERT (MenuArray
[Select
] != NULL
);
432 CopyMem (Type
, &MenuArray
[Select
]->Type
, sizeof (UINT16
));
433 *Type
= NTOHS (*Type
);
440 Parse out the boot information from the last Dhcp4 reply packet.
442 @param[in, out] Private Pointer to PxeBc private data.
443 @param[out] BufferSize Size of the boot file to be downloaded.
445 @retval EFI_SUCCESS Successfully parsed out all the boot information.
446 @retval Others Failed to parse out the boot information.
451 IN OUT PXEBC_PRIVATE_DATA
*Private
,
452 OUT UINT64
*BufferSize
455 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
456 EFI_PXE_BASE_CODE_MODE
*Mode
;
458 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
461 PxeBc
= &Private
->PxeBc
;
463 Status
= EFI_SUCCESS
;
467 // Get the last received Dhcp4 reply packet.
469 if (Mode
->PxeReplyReceived
) {
470 Cache4
= &Private
->PxeReply
.Dhcp4
;
471 } else if (Mode
->ProxyOfferReceived
) {
472 Cache4
= &Private
->ProxyOffer
.Dhcp4
;
474 Cache4
= &Private
->DhcpAck
.Dhcp4
;
478 // Parse the boot server Ipv4 address by next server address.
479 // If this field isn't available, use option 54 instead.
483 &Cache4
->Packet
.Offer
.Dhcp4
.Header
.ServerAddr
,
484 sizeof (EFI_IPv4_ADDRESS
)
487 if (Private
->ServerIp
.Addr
[0] == 0) {
490 Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_SERVER_ID
]->Data
,
491 sizeof (EFI_IPv4_ADDRESS
)
496 // Parse the boot file name by option.
498 ASSERT (Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
] != NULL
);
499 Private
->BootFileName
= Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE
]->Data
;
501 if (Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN
] != NULL
) {
503 // Parse the boot file size by option.
505 CopyMem (&Value
, Cache4
->OptList
[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN
]->Data
, sizeof (Value
));
506 Value
= NTOHS (Value
);
508 // The field of boot file size is 512 bytes in unit.
510 *BufferSize
= 512 * Value
;
513 // Get the bootfile size by tftp command if no option available.
515 Status
= PxeBc
->Mtftp (
517 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
523 Private
->BootFileName
,
530 // Save the value of boot file size.
532 Private
->BootFileSize
= (UINTN
) *BufferSize
;
535 // Display all the information: boot server address, boot file name and boot file size.
537 AsciiPrint ("\n Server IP address is ");
538 PxeBcShowIp4Addr (&Private
->ServerIp
.v4
);
539 AsciiPrint ("\n NBP filename is %a", Private
->BootFileName
);
540 AsciiPrint ("\n NBP filesize is %d Bytes", Private
->BootFileSize
);
547 Parse out the boot information from the last Dhcp6 reply packet.
549 @param[in, out] Private Pointer to PxeBc private data.
550 @param[out] BufferSize Size of the boot file to be downloaded.
552 @retval EFI_SUCCESS Successfully parsed out all the boot information.
553 @retval EFI_BUFFER_TOO_SMALL
554 @retval Others Failed to parse out the boot information.
559 IN OUT PXEBC_PRIVATE_DATA
*Private
,
560 OUT UINT64
*BufferSize
563 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
564 EFI_PXE_BASE_CODE_MODE
*Mode
;
566 PXEBC_DHCP6_PACKET_CACHE
*Cache6
;
569 PxeBc
= &Private
->PxeBc
;
571 Status
= EFI_SUCCESS
;
575 // Get the last received Dhcp6 reply packet.
577 if (Mode
->PxeReplyReceived
) {
578 Cache6
= &Private
->PxeReply
.Dhcp6
;
579 } else if (Mode
->ProxyOfferReceived
) {
580 Cache6
= &Private
->ProxyOffer
.Dhcp6
;
582 Cache6
= &Private
->DhcpAck
.Dhcp6
;
585 ASSERT (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
] != NULL
);
588 // Parse (m)tftp server ip address and bootfile name.
590 Status
= PxeBcExtractBootFileUrl (
591 &Private
->BootFileName
,
592 &Private
->ServerIp
.v6
,
593 (CHAR8
*) (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->Data
),
594 NTOHS (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_URL
]->OpLen
)
596 if (EFI_ERROR (Status
)) {
601 // Parse the value of boot file size.
603 if (Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
] != NULL
) {
605 // Parse it out if have the boot file parameter option.
607 Status
= PxeBcExtractBootFileParam ((CHAR8
*) Cache6
->OptList
[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM
]->Data
, &Value
);
608 if (EFI_ERROR (Status
)) {
612 // The field of boot file size is 512 bytes in unit.
614 *BufferSize
= 512 * Value
;
617 // Send get file size command by tftp if option unavailable.
619 Status
= PxeBc
->Mtftp (
621 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
627 Private
->BootFileName
,
634 // Save the value of boot file size.
636 Private
->BootFileSize
= (UINTN
) *BufferSize
;
639 // Display all the information: boot server address, boot file name and boot file size.
641 AsciiPrint ("\n Server IP address is ");
642 PxeBcShowIp6Addr (&Private
->ServerIp
.v6
);
643 AsciiPrint ("\n NBP filename is %a", Private
->BootFileName
);
644 AsciiPrint ("\n NBP filesize is %d Bytes", Private
->BootFileSize
);
651 Extract the discover information and boot server entry from the
652 cached packets if unspecified.
654 @param[in] Private Pointer to PxeBc private data.
655 @param[in] Type The type of bootstrap to perform.
656 @param[in, out] DiscoverInfo Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO.
657 @param[out] BootEntry Pointer to PXEBC_BOOT_SVR_ENTRY.
658 @param[out] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
660 @retval EFI_SUCCESS Successfully extracted the information.
661 @retval EFI_DEVICE_ERROR Failed to extract the information.
665 PxeBcExtractDiscoverInfo (
666 IN PXEBC_PRIVATE_DATA
*Private
,
668 IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO
**DiscoverInfo
,
669 OUT PXEBC_BOOT_SVR_ENTRY
**BootEntry
,
670 OUT EFI_PXE_BASE_CODE_SRVLIST
**SrvList
673 EFI_PXE_BASE_CODE_MODE
*Mode
;
674 PXEBC_DHCP4_PACKET_CACHE
*Cache4
;
675 PXEBC_VENDOR_OPTION
*VendorOpt
;
676 PXEBC_BOOT_SVR_ENTRY
*Entry
;
678 EFI_PXE_BASE_CODE_DISCOVER_INFO
*Info
;
681 Mode
= Private
->PxeBc
.Mode
;
682 Info
= *DiscoverInfo
;
684 if (Mode
->UsingIpv6
) {
686 Info
->UseUCast
= TRUE
;
688 Info
->SrvList
[0].Type
= Type
;
689 Info
->SrvList
[0].AcceptAnyResponse
= FALSE
;
692 // There is no vendor options specified in DHCPv6, so take BootFileUrl in the last cached packet.
694 CopyMem (&Info
->SrvList
[0].IpAddr
, &Private
->ServerIp
, sizeof (EFI_IP_ADDRESS
));
696 *SrvList
= Info
->SrvList
;
700 Cache4
= (Mode
->ProxyOfferReceived
) ? &Private
->ProxyOffer
.Dhcp4
: &Private
->DhcpAck
.Dhcp4
;
701 VendorOpt
= &Cache4
->VendorOpt
;
703 if (!Mode
->DhcpAckReceived
|| !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt
->BitMap
)) {
705 // Address is not acquired or no discovery options.
707 return EFI_INVALID_PARAMETER
;
711 // Parse the boot server entry from the vendor option in the last cached packet.
713 Info
->UseMCast
= (BOOLEAN
) !IS_DISABLE_MCAST_DISCOVER (VendorOpt
->DiscoverCtrl
);
714 Info
->UseBCast
= (BOOLEAN
) !IS_DISABLE_BCAST_DISCOVER (VendorOpt
->DiscoverCtrl
);
715 Info
->MustUseList
= (BOOLEAN
) IS_ENABLE_USE_SERVER_LIST (VendorOpt
->DiscoverCtrl
);
716 Info
->UseUCast
= (BOOLEAN
) IS_VALID_BOOT_SERVERS (VendorOpt
->BitMap
);
718 if (Info
->UseMCast
) {
720 // Get the multicast discover ip address from vendor option if has.
722 CopyMem (&Info
->ServerMCastIp
.v4
, &VendorOpt
->DiscoverMcastIp
, sizeof (EFI_IPv4_ADDRESS
));
727 if (Info
->UseUCast
) {
728 Entry
= VendorOpt
->BootSvr
;
730 while (((UINT8
) (Entry
- VendorOpt
->BootSvr
)) < VendorOpt
->BootSvrLen
) {
731 if (Entry
->Type
== HTONS (Type
)) {
735 Entry
= GET_NEXT_BOOT_SVR_ENTRY (Entry
);
739 return EFI_DEVICE_ERROR
;
742 Info
->IpCnt
= Entry
->IpCnt
;
743 if (Info
->IpCnt
>= 1) {
744 *DiscoverInfo
= AllocatePool (sizeof (*Info
) + (Info
->IpCnt
- 1) * sizeof (**SrvList
));
745 if (*DiscoverInfo
== NULL
) {
746 return EFI_OUT_OF_RESOURCES
;
748 CopyMem (*DiscoverInfo
, Info
, sizeof (*Info
));
749 Info
= *DiscoverInfo
;
752 for (Index
= 0; Index
< Info
->IpCnt
; Index
++) {
753 CopyMem (&Info
->SrvList
[Index
].IpAddr
, &Entry
->IpAddr
[Index
], sizeof (EFI_IPv4_ADDRESS
));
754 Info
->SrvList
[Index
].AcceptAnyResponse
= !Info
->MustUseList
;
755 Info
->SrvList
[Index
].Type
= NTOHS (Entry
->Type
);
760 *SrvList
= Info
->SrvList
;
768 Build the discover packet and send out for boot server.
770 @param[in] Private Pointer to PxeBc private data.
771 @param[in] Type PxeBc option boot item type.
772 @param[in] Layer Pointer to option boot item layer.
773 @param[in] UseBis Use BIS or not.
774 @param[in] DestIp Pointer to the destination address.
775 @param[in] IpCount The count of the server address.
776 @param[in] SrvList Pointer to the server address list.
778 @retval EFI_SUCCESS Successfully discovered boot file.
779 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
780 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
781 @retval Others Failed to discover boot file.
785 PxeBcDiscoverBootServer (
786 IN PXEBC_PRIVATE_DATA
*Private
,
790 IN EFI_IP_ADDRESS
*DestIp
,
792 IN EFI_PXE_BASE_CODE_SRVLIST
*SrvList
795 if (Private
->PxeBc
.Mode
->UsingIpv6
) {
796 return PxeBcDhcp6Discover (
804 return PxeBcDhcp4Discover (
818 Discover all the boot information for boot file.
820 @param[in, out] Private Pointer to PxeBc private data.
821 @param[out] BufferSize Size of the boot file to be downloaded.
823 @retval EFI_SUCCESS Successfully obtained all the boot information .
824 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
825 @retval EFI_ABORTED User cancel current operation.
826 @retval Others Failed to parse out the boot information.
830 PxeBcDiscoverBootFile (
831 IN OUT PXEBC_PRIVATE_DATA
*Private
,
832 OUT UINT64
*BufferSize
835 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
836 EFI_PXE_BASE_CODE_MODE
*Mode
;
842 PxeBc
= &Private
->PxeBc
;
844 Type
= EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
;
845 Layer
= EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL
;
848 // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and
849 // other pxe boot information.
851 Status
= PxeBc
->Dhcp (PxeBc
, TRUE
);
852 if (EFI_ERROR (Status
)) {
857 // Select a boot server from boot server list.
859 Status
= PxeBcSelectBootPrompt (Private
);
861 if (Status
== EFI_SUCCESS
) {
863 // Choose by user's input.
865 Status
= PxeBcSelectBootMenu (Private
, &Type
, FALSE
);
866 } else if (Status
== EFI_TIMEOUT
) {
868 // Choose by default item.
870 Status
= PxeBcSelectBootMenu (Private
, &Type
, TRUE
);
873 if (!EFI_ERROR (Status
)) {
875 if (Type
== EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
) {
877 // Local boot(PXE bootstrap server) need abort
883 // Start to discover the boot server to get (m)tftp server ip address, bootfile
884 // name and bootfile size.
886 UseBis
= (BOOLEAN
) (Mode
->BisSupported
&& Mode
->BisDetected
);
887 Status
= PxeBc
->Discover (PxeBc
, Type
, &Layer
, UseBis
, NULL
);
888 if (EFI_ERROR (Status
)) {
892 if (Mode
->PxeReplyReceived
&& !Mode
->ProxyOfferReceived
) {
894 // Some network boot loader only search the packet in Mode.ProxyOffer to get its server
895 // IP address, so we need to store a copy of Mode.PxeReply packet into Mode.ProxyOffer.
897 if (Mode
->UsingIpv6
) {
899 &Mode
->ProxyOffer
.Dhcpv6
,
900 &Mode
->PxeReply
.Dhcpv6
,
901 Private
->PxeReply
.Dhcp6
.Packet
.Ack
.Length
905 &Mode
->ProxyOffer
.Dhcpv4
,
906 &Mode
->PxeReply
.Dhcpv4
,
907 Private
->PxeReply
.Dhcp4
.Packet
.Ack
.Length
910 Mode
->ProxyOfferReceived
= TRUE
;
915 // Parse the boot information.
917 if (Mode
->UsingIpv6
) {
918 Status
= PxeBcDhcp6BootInfo (Private
, BufferSize
);
920 Status
= PxeBcDhcp4BootInfo (Private
, BufferSize
);
928 Install PxeBaseCodeCallbackProtocol if not installed before.
930 @param[in, out] Private Pointer to PxeBc private data.
931 @param[out] NewMakeCallback If TRUE, it is a new callback.
932 Otherwise, it is not new callback.
933 @retval EFI_SUCCESS PxeBaseCodeCallbackProtocol installed succesfully.
934 @retval Others Failed to install PxeBaseCodeCallbackProtocol.
938 PxeBcInstallCallback (
939 IN OUT PXEBC_PRIVATE_DATA
*Private
,
940 OUT BOOLEAN
*NewMakeCallback
943 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
947 // Check whether PxeBaseCodeCallbackProtocol already installed.
949 PxeBc
= &Private
->PxeBc
;
950 Status
= gBS
->HandleProtocol (
952 &gEfiPxeBaseCodeCallbackProtocolGuid
,
953 (VOID
**) &Private
->PxeBcCallback
955 if (Status
== EFI_UNSUPPORTED
) {
958 &Private
->LoadFileCallback
,
959 &gPxeBcCallBackTemplate
,
960 sizeof (EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL
)
964 // Install a default callback if user didn't offer one.
966 Status
= gBS
->InstallProtocolInterface (
967 &Private
->Controller
,
968 &gEfiPxeBaseCodeCallbackProtocolGuid
,
969 EFI_NATIVE_INTERFACE
,
970 &Private
->LoadFileCallback
973 (*NewMakeCallback
) = (BOOLEAN
) (Status
== EFI_SUCCESS
);
975 Status
= PxeBc
->SetParameters (PxeBc
, NULL
, NULL
, NULL
, NULL
, NewMakeCallback
);
976 if (EFI_ERROR (Status
)) {
987 Uninstall PxeBaseCodeCallbackProtocol.
989 @param[in] Private Pointer to PxeBc private data.
990 @param[in] NewMakeCallback If TRUE, it is a new callback.
991 Otherwise, it is not new callback.
995 PxeBcUninstallCallback (
996 IN PXEBC_PRIVATE_DATA
*Private
,
997 IN BOOLEAN NewMakeCallback
1000 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1002 PxeBc
= &Private
->PxeBc
;
1004 if (NewMakeCallback
) {
1006 NewMakeCallback
= FALSE
;
1008 PxeBc
->SetParameters (PxeBc
, NULL
, NULL
, NULL
, NULL
, &NewMakeCallback
);
1010 gBS
->UninstallProtocolInterface (
1011 Private
->Controller
,
1012 &gEfiPxeBaseCodeCallbackProtocolGuid
,
1013 &Private
->LoadFileCallback
1020 Download one of boot file in the list, and it's special for IPv6.
1022 @param[in] Private Pointer to PxeBc private data.
1023 @param[in, out] BufferSize Size of user buffer for input;
1024 required buffer size for output.
1025 @param[in] Buffer Pointer to user buffer.
1027 @retval EFI_SUCCESS Read one of boot file in the list successfully.
1028 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
1029 @retval EFI_NOT_FOUND There is no proper boot file available.
1030 @retval Others Failed to download boot file in the list.
1034 PxeBcReadBootFileList (
1035 IN PXEBC_PRIVATE_DATA
*Private
,
1036 IN OUT UINT64
*BufferSize
,
1037 IN VOID
*Buffer OPTIONAL
1041 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1043 PxeBc
= &Private
->PxeBc
;
1046 // Try to download the boot file if everything is ready.
1048 if (Buffer
!= NULL
) {
1049 Status
= PxeBc
->Mtftp (
1051 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1055 &Private
->BlockSize
,
1057 Private
->BootFileName
,
1064 Status
= EFI_BUFFER_TOO_SMALL
;
1072 Load boot file into user buffer.
1074 @param[in] Private Pointer to PxeBc private data.
1075 @param[in, out] BufferSize Size of user buffer for input;
1076 required buffer size for output.
1077 @param[in] Buffer Pointer to user buffer.
1079 @retval EFI_SUCCESS Get all the boot information successfully.
1080 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
1081 @retval EFI_ABORTED User cancelled the current operation.
1082 @retval Others Failed to parse out the boot information.
1087 IN PXEBC_PRIVATE_DATA
*Private
,
1088 IN OUT UINTN
*BufferSize
,
1089 IN VOID
*Buffer OPTIONAL
1092 BOOLEAN NewMakeCallback
;
1093 UINT64 RequiredSize
;
1096 EFI_PXE_BASE_CODE_PROTOCOL
*PxeBc
;
1097 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
1099 NewMakeCallback
= FALSE
;
1100 PxeBc
= &Private
->PxeBc
;
1101 PxeBcMode
= &Private
->Mode
;
1102 CurrentSize
= *BufferSize
;
1106 // Install pxebc callback protocol if hasn't been installed yet.
1108 Status
= PxeBcInstallCallback (Private
, &NewMakeCallback
);
1109 if (EFI_ERROR(Status
)) {
1113 if (Private
->BootFileSize
== 0) {
1115 // Discover the boot information about the bootfile if hasn't.
1117 Status
= PxeBcDiscoverBootFile (Private
, &RequiredSize
);
1118 if (EFI_ERROR (Status
)) {
1122 if (PXEBC_IS_SIZE_OVERFLOWED (RequiredSize
)) {
1124 // It's error if the required buffer size is beyond the system scope.
1126 Status
= EFI_DEVICE_ERROR
;
1128 } else if (RequiredSize
> 0) {
1130 // Get the right buffer size of the bootfile required.
1132 if (CurrentSize
< RequiredSize
|| Buffer
== NULL
) {
1134 // It's buffer too small if the size of user buffer is smaller than the required.
1136 CurrentSize
= RequiredSize
;
1137 Status
= EFI_BUFFER_TOO_SMALL
;
1140 CurrentSize
= RequiredSize
;
1141 } else if (RequiredSize
== 0 && PxeBcMode
->UsingIpv6
) {
1143 // Try to download another bootfile in list if failed to get the filesize of the last one.
1144 // It's special for the case of IPv6.
1146 Status
= PxeBcReadBootFileList (Private
, &CurrentSize
, Buffer
);
1149 } else if (CurrentSize
< Private
->BootFileSize
|| Buffer
== NULL
) {
1151 // It's buffer too small if the size of user buffer is smaller than the required.
1153 CurrentSize
= Private
->BootFileSize
;
1154 Status
= EFI_BUFFER_TOO_SMALL
;
1159 // Begin to download the bootfile if everything is ready.
1161 AsciiPrint ("\n Downloading NBP file...\n");
1162 if (PxeBcMode
->UsingIpv6
) {
1163 Status
= PxeBcReadBootFileList (
1169 Status
= PxeBc
->Mtftp (
1171 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1175 &Private
->BlockSize
,
1177 Private
->BootFileName
,
1184 *BufferSize
= (UINTN
) CurrentSize
;
1185 PxeBcUninstallCallback(Private
, NewMakeCallback
);
1187 if (Status
== EFI_SUCCESS
) {
1188 AsciiPrint ("\n Succeed to download NBP file.\n");
1190 } else if (Status
== EFI_BUFFER_TOO_SMALL
&& Buffer
!= NULL
) {
1191 AsciiPrint ("\n PXE-E05: Buffer size is smaller than the requested file.\n");
1192 } else if (Status
== EFI_DEVICE_ERROR
) {
1193 AsciiPrint ("\n PXE-E07: Network device error.\n");
1194 } else if (Status
== EFI_OUT_OF_RESOURCES
) {
1195 AsciiPrint ("\n PXE-E09: Could not allocate I/O buffers.\n");
1196 } else if (Status
== EFI_NO_MEDIA
) {
1197 AsciiPrint ("\n PXE-E12: Could not detect network connection.\n");
1198 } else if (Status
== EFI_NO_RESPONSE
) {
1199 AsciiPrint ("\n PXE-E16: No offer received.\n");
1200 } else if (Status
== EFI_TIMEOUT
) {
1201 AsciiPrint ("\n PXE-E18: Server response timeout.\n");
1202 } else if (Status
== EFI_ABORTED
) {
1203 AsciiPrint ("\n PXE-E21: Remote boot cancelled.\n");
1204 } else if (Status
== EFI_ICMP_ERROR
) {
1205 AsciiPrint ("\n PXE-E22: Client received ICMP error from server.\n");
1206 } else if (Status
== EFI_TFTP_ERROR
) {
1207 AsciiPrint ("\n PXE-E23: Client received TFTP error from server.\n");
1208 } else if (Status
== EFI_NOT_FOUND
) {
1209 AsciiPrint ("\n PXE-E53: No boot filename received.\n");
1210 } else if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1211 AsciiPrint ("\n PXE-E99: Unexpected network error.\n");