2 Library functions which relates with booting.
4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "InternalBm.h"
17 #define VENDOR_IDENTIFICATION_OFFSET 3
18 #define VENDOR_IDENTIFICATION_LENGTH 8
19 #define PRODUCT_IDENTIFICATION_OFFSET 11
20 #define PRODUCT_IDENTIFICATION_LENGTH 16
22 CONST UINT16 mBmUsbLangId
= 0x0409; // English
23 CHAR16 mBmUefiPrefix
[] = L
"UEFI ";
25 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption
= NULL
;
26 EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot
= NULL
;
29 /// This GUID is used for an EFI Variable that stores the front device pathes
30 /// for a partial device path that starts with the HD node.
32 EFI_GUID mBmHardDriveBootVariableGuid
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
33 EFI_GUID mBmAutoCreateBootOptionGuid
= { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
36 The function registers the legacy boot support capabilities.
38 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
39 @param LegacyBoot The function pointer to boot the legacy boot option.
43 EfiBootManagerRegisterLegacyBootSupport (
44 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption
,
45 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
48 mBmRefreshLegacyBootOption
= RefreshLegacyBootOption
;
49 mBmLegacyBoot
= LegacyBoot
;
53 For a bootable Device path, return its boot type.
55 @param DevicePath The bootable device Path to check
57 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
58 which HID is floppy device.
59 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
60 and its last device path node's subtype is MSG_ATAPI_DP.
61 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
62 and its last device path node's subtype is MSG_SATA_DP.
63 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
64 and its last device path node's subtype is MSG_SCSI_DP.
65 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
66 and its last device path node's subtype is MSG_USB_DP.
67 @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
68 and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
69 MSG_IPv4_DP or MSG_IPv6_DP.
70 @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.
74 BmBootTypeFromDevicePath (
75 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
78 EFI_DEVICE_PATH_PROTOCOL
*Node
;
79 EFI_DEVICE_PATH_PROTOCOL
*NextNode
;
81 ASSERT (DevicePath
!= NULL
);
83 for (Node
= DevicePath
; !IsDevicePathEndType (Node
); Node
= NextDevicePathNode (Node
)) {
84 switch (DevicePathType (Node
)) {
86 case ACPI_DEVICE_PATH
:
87 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH
*) Node
)->HID
) == 0x0604) {
88 return BmAcpiFloppyBoot
;
92 case HARDWARE_DEVICE_PATH
:
93 if (DevicePathSubType (Node
) == HW_CONTROLLER_DP
) {
94 return BmHardwareDeviceBoot
;
98 case MESSAGING_DEVICE_PATH
:
100 // Skip LUN device node
104 NextNode
= NextDevicePathNode (NextNode
);
106 (DevicePathType (NextNode
) == MESSAGING_DEVICE_PATH
) &&
107 (DevicePathSubType(NextNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
)
111 // If the device path not only point to driver device, it is not a messaging device path,
113 if (!IsDevicePathEndType (NextNode
)) {
117 switch (DevicePathSubType (Node
)) {
119 return BmMessageAtapiBoot
;
123 return BmMessageSataBoot
;
127 return BmMessageUsbBoot
;
131 return BmMessageScsiBoot
;
134 case MSG_MAC_ADDR_DP
:
138 return BmMessageNetworkBoot
;
148 Free old buffer and reuse the pointer to return new buffer.
150 @param Orig Pointer to the old buffer.
151 @param New Pointer to the new buffer.
164 Find the boot option in the NV storage and return the option number.
166 @param OptionToFind Boot option to be checked.
168 @return The option number of the found boot option.
172 BmFindBootOptionInVariable (
173 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
177 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
179 CHAR16 OptionName
[sizeof ("Boot####")];
180 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
181 UINTN BootOptionCount
;
184 OptionNumber
= LoadOptionNumberUnassigned
;
187 // Try to match the variable exactly if the option number is assigned
189 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
190 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Boot%04x", OptionToFind
->OptionNumber
);
191 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
193 if (!EFI_ERROR (Status
)) {
194 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
195 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
196 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
197 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
198 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
199 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
201 OptionNumber
= OptionToFind
->OptionNumber
;
203 EfiBootManagerFreeLoadOption (&BootOption
);
208 // The option number assigned is either incorrect or unassigned.
210 if (OptionNumber
== LoadOptionNumberUnassigned
) {
211 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
213 Index
= BmFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
215 OptionNumber
= BootOptions
[Index
].OptionNumber
;
218 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
225 According to a file guild, check a Fv file device path is valid. If it is invalid,
226 try to return the valid device path.
227 FV address maybe changes for memory layout adjust from time to time, use this function
228 could promise the Fv file device path is right.
230 @param DevicePath The Fv file device path to be fixed up.
234 BmFixupMemmapFvFilePath (
235 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
240 EFI_DEVICE_PATH_PROTOCOL
*Node
;
242 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
243 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
245 EFI_FV_FILETYPE Type
;
246 EFI_FV_FILE_ATTRIBUTES Attributes
;
247 UINT32 AuthenticationStatus
;
249 EFI_HANDLE
*FvHandleBuffer
;
250 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
253 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
254 if (!EFI_ERROR (Status
)) {
255 Status
= gBS
->HandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**) &Fv
);
256 ASSERT_EFI_ERROR (Status
);
258 Status
= Fv
->ReadFile (
260 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
265 &AuthenticationStatus
267 if (EFI_ERROR (Status
)) {
268 BmFreeAndSet ((VOID
**) DevicePath
, NULL
);
274 Node
= NextDevicePathNode (DevicePath
);
277 // Firstly find the FV file in current FV
279 gBS
->HandleProtocol (
281 &gEfiLoadedImageProtocolGuid
,
282 (VOID
**) &LoadedImage
284 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), Node
);
285 BmFixupMemmapFvFilePath (&NewDevicePath
);
287 if (NewDevicePath
!= NULL
) {
288 BmFreeAndSet ((VOID
**) DevicePath
, NewDevicePath
);
293 // Secondly find the FV file in all other FVs
295 gBS
->LocateHandleBuffer (
297 &gEfiFirmwareVolume2ProtocolGuid
,
302 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
303 if (FvHandleBuffer
[Index
] == LoadedImage
->DeviceHandle
) {
309 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandleBuffer
[Index
]), Node
);
310 BmFixupMemmapFvFilePath (&NewDevicePath
);
312 if (NewDevicePath
!= NULL
) {
313 BmFreeAndSet ((VOID
**) DevicePath
, NewDevicePath
);
320 Check if it's of Fv file device path type.
322 The function doesn't garentee the device path points to existing Fv file.
324 @param DevicePath Input device path info.
326 @retval TRUE The device path is of Fv file device path type.
327 @retval FALSE The device path isn't of Fv file device path type.
330 BmIsMemmapFvFilePath (
331 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
334 EFI_DEVICE_PATH_PROTOCOL
*FileNode
;
336 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
337 FileNode
= NextDevicePathNode (DevicePath
);
338 if ((DevicePathType (FileNode
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (FileNode
) == MEDIA_PIWG_FW_FILE_DP
)) {
339 return IsDevicePathEnd (NextDevicePathNode (FileNode
));
347 Check whether a USB device match the specified USB Class device path. This
348 function follows "Load Option Processing" behavior in UEFI specification.
350 @param UsbIo USB I/O protocol associated with the USB device.
351 @param UsbClass The USB Class device path to match.
353 @retval TRUE The USB device match the USB Class device path.
354 @retval FALSE The USB device does not match the USB Class device path.
359 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
360 IN USB_CLASS_DEVICE_PATH
*UsbClass
364 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
365 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
367 UINT8 DeviceSubClass
;
368 UINT8 DeviceProtocol
;
370 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
371 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
376 // Check Vendor Id and Product Id.
378 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
379 if (EFI_ERROR (Status
)) {
383 if ((UsbClass
->VendorId
!= 0xffff) &&
384 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
388 if ((UsbClass
->ProductId
!= 0xffff) &&
389 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
393 DeviceClass
= DevDesc
.DeviceClass
;
394 DeviceSubClass
= DevDesc
.DeviceSubClass
;
395 DeviceProtocol
= DevDesc
.DeviceProtocol
;
396 if (DeviceClass
== 0) {
398 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
399 // Protocol in Interface Descriptor instead.
401 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
402 if (EFI_ERROR (Status
)) {
406 DeviceClass
= IfDesc
.InterfaceClass
;
407 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
408 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
412 // Check Class, SubClass and Protocol.
414 if ((UsbClass
->DeviceClass
!= 0xff) &&
415 (UsbClass
->DeviceClass
!= DeviceClass
)) {
419 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
420 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
424 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
425 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
433 Eliminate the extra spaces in the Str to one space.
435 @param Str Input string info.
438 BmEliminateExtraSpaces (
445 for (Index
= 0, ActualIndex
= 0; Str
[Index
] != L
'\0'; Index
++) {
446 if ((Str
[Index
] != L
' ') || ((ActualIndex
> 0) && (Str
[ActualIndex
- 1] != L
' '))) {
447 Str
[ActualIndex
++] = Str
[Index
];
450 Str
[ActualIndex
] = L
'\0';
454 Try to get the controller's ATA/ATAPI description.
456 @param Handle Controller handle.
458 @return The description string.
461 BmGetDescriptionFromDiskInfo (
467 EFI_DISK_INFO_PROTOCOL
*DiskInfo
;
469 EFI_ATAPI_IDENTIFY_DATA IdentifyData
;
470 EFI_SCSI_INQUIRY_DATA InquiryData
;
473 CONST UINTN ModelNameLength
= 40;
474 CONST UINTN SerialNumberLength
= 20;
480 Status
= gBS
->HandleProtocol (
482 &gEfiDiskInfoProtocolGuid
,
485 if (EFI_ERROR (Status
)) {
489 if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoAhciInterfaceGuid
) ||
490 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoIdeInterfaceGuid
)) {
491 BufferSize
= sizeof (EFI_ATAPI_IDENTIFY_DATA
);
492 Status
= DiskInfo
->Identify (
497 if (!EFI_ERROR (Status
)) {
498 Description
= AllocateZeroPool ((ModelNameLength
+ SerialNumberLength
+ 2) * sizeof (CHAR16
));
499 ASSERT (Description
!= NULL
);
500 for (Index
= 0; Index
+ 1 < ModelNameLength
; Index
+= 2) {
501 Description
[Index
] = (CHAR16
) IdentifyData
.ModelName
[Index
+ 1];
502 Description
[Index
+ 1] = (CHAR16
) IdentifyData
.ModelName
[Index
];
506 Description
[Length
++] = L
' ';
508 for (Index
= 0; Index
+ 1 < SerialNumberLength
; Index
+= 2) {
509 Description
[Length
+ Index
] = (CHAR16
) IdentifyData
.SerialNo
[Index
+ 1];
510 Description
[Length
+ Index
+ 1] = (CHAR16
) IdentifyData
.SerialNo
[Index
];
513 Description
[Length
++] = L
'\0';
514 ASSERT (Length
== ModelNameLength
+ SerialNumberLength
+ 2);
516 BmEliminateExtraSpaces (Description
);
518 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
519 BufferSize
= sizeof (EFI_SCSI_INQUIRY_DATA
);
520 Status
= DiskInfo
->Inquiry (
525 if (!EFI_ERROR (Status
)) {
526 Description
= AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2) * sizeof (CHAR16
));
527 ASSERT (Description
!= NULL
);
530 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
531 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
532 // Here combine the vendor identification and product identification to the description.
534 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
]);
535 Temp
= StrPtr
[VENDOR_IDENTIFICATION_LENGTH
];
536 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = '\0';
537 AsciiStrToUnicodeStr (StrPtr
, Description
);
538 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = Temp
;
541 // Add one space at the middle of vendor information and product information.
543 Description
[VENDOR_IDENTIFICATION_LENGTH
] = L
' ';
545 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
]);
546 StrPtr
[PRODUCT_IDENTIFICATION_LENGTH
] = '\0';
547 AsciiStrToUnicodeStr (StrPtr
, Description
+ VENDOR_IDENTIFICATION_LENGTH
+ 1);
549 BmEliminateExtraSpaces (Description
);
557 Try to get the controller's USB description.
559 @param Handle Controller handle.
561 @return The description string.
564 BmGetUsbDescription (
569 EFI_USB_IO_PROTOCOL
*UsbIo
;
571 CHAR16
*Manufacturer
;
573 CHAR16
*SerialNumber
;
575 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
577 Status
= gBS
->HandleProtocol (
579 &gEfiUsbIoProtocolGuid
,
582 if (EFI_ERROR (Status
)) {
588 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
589 if (EFI_ERROR (Status
)) {
593 Status
= UsbIo
->UsbGetStringDescriptor (
596 DevDesc
.StrManufacturer
,
599 if (EFI_ERROR (Status
)) {
600 Manufacturer
= &NullChar
;
603 Status
= UsbIo
->UsbGetStringDescriptor (
609 if (EFI_ERROR (Status
)) {
613 Status
= UsbIo
->UsbGetStringDescriptor (
616 DevDesc
.StrSerialNumber
,
619 if (EFI_ERROR (Status
)) {
620 SerialNumber
= &NullChar
;
623 if ((Manufacturer
== &NullChar
) &&
624 (Product
== &NullChar
) &&
625 (SerialNumber
== &NullChar
)
630 Description
= AllocateZeroPool (StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
));
631 ASSERT (Description
!= NULL
);
632 StrCat (Description
, Manufacturer
);
633 StrCat (Description
, L
" ");
635 StrCat (Description
, Product
);
636 StrCat (Description
, L
" ");
638 StrCat (Description
, SerialNumber
);
640 if (Manufacturer
!= &NullChar
) {
641 FreePool (Manufacturer
);
643 if (Product
!= &NullChar
) {
646 if (SerialNumber
!= &NullChar
) {
647 FreePool (SerialNumber
);
650 BmEliminateExtraSpaces (Description
);
656 Return the boot description for the controller based on the type.
658 @param Handle Controller handle.
660 @return The description string.
663 BmGetMiscDescription (
669 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
671 switch (BmBootTypeFromDevicePath (DevicePathFromHandle (Handle
))) {
672 case BmAcpiFloppyBoot
:
673 Description
= L
"Floppy";
676 case BmMessageAtapiBoot
:
677 case BmMessageSataBoot
:
678 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
679 ASSERT_EFI_ERROR (Status
);
681 // Assume a removable SATA device should be the DVD/CD device
683 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
686 case BmMessageUsbBoot
:
687 Description
= L
"USB Device";
690 case BmMessageScsiBoot
:
691 Description
= L
"SCSI Device";
694 case BmHardwareDeviceBoot
:
695 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
696 if (!EFI_ERROR (Status
)) {
697 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
699 Description
= L
"Misc Device";
704 Description
= L
"Misc Device";
708 return AllocateCopyPool (StrSize (Description
), Description
);
711 BM_GET_BOOT_DESCRIPTION mBmGetBootDescription
[] = {
713 BmGetDescriptionFromDiskInfo
,
718 Check whether a USB device match the specified USB WWID device path. This
719 function follows "Load Option Processing" behavior in UEFI specification.
721 @param UsbIo USB I/O protocol associated with the USB device.
722 @param UsbWwid The USB WWID device path to match.
724 @retval TRUE The USB device match the USB WWID device path.
725 @retval FALSE The USB device does not match the USB WWID device path.
730 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
731 IN USB_WWID_DEVICE_PATH
*UsbWwid
735 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
736 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
742 CHAR16
*SerialNumberStr
;
745 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
746 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
751 // Check Vendor Id and Product Id.
753 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
754 if (EFI_ERROR (Status
)) {
757 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
758 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
763 // Check Interface Number.
765 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
766 if (EFI_ERROR (Status
)) {
769 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
774 // Check Serial Number.
776 if (DevDesc
.StrSerialNumber
== 0) {
781 // Get all supported languages.
785 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
786 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
791 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
793 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
794 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
795 if (CompareStr
[CompareLen
- 1] == L
'\0') {
800 // Compare serial number in each supported language.
802 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
803 SerialNumberStr
= NULL
;
804 Status
= UsbIo
->UsbGetStringDescriptor (
807 DevDesc
.StrSerialNumber
,
810 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
814 Length
= StrLen (SerialNumberStr
);
815 if ((Length
>= CompareLen
) &&
816 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
817 FreePool (SerialNumberStr
);
821 FreePool (SerialNumberStr
);
828 Print the device path info.
830 @param DevicePath The device path need to print.
835 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
840 Str
= ConvertDevicePathToText (DevicePath
, FALSE
, FALSE
);
841 DEBUG ((EFI_D_INFO
, "%s", Str
));
848 Find a USB device which match the specified short-form device path start with
849 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
850 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
851 this function will only search in its child devices.
853 @param DevicePath The device path that contains USB Class or USB WWID device path.
854 @param ParentDevicePathSize The length of the device path before the USB Class or
855 USB WWID device path.
856 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
858 @retval NULL The matched USB IO handles cannot be found.
859 @retval other The matched USB IO handles.
864 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
865 IN UINTN ParentDevicePathSize
,
866 OUT UINTN
*UsbIoHandleCount
870 EFI_HANDLE
*UsbIoHandles
;
871 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
872 EFI_USB_IO_PROTOCOL
*UsbIo
;
874 UINTN UsbIoDevicePathSize
;
877 ASSERT (UsbIoHandleCount
!= NULL
);
880 // Get all UsbIo Handles.
882 Status
= gBS
->LocateHandleBuffer (
884 &gEfiUsbIoProtocolGuid
,
889 if (EFI_ERROR (Status
)) {
890 *UsbIoHandleCount
= 0;
894 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
896 // Get the Usb IO interface.
898 Status
= gBS
->HandleProtocol(
900 &gEfiUsbIoProtocolGuid
,
903 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
905 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
906 UsbIoDevicePathSize
= GetDevicePathSize (UsbIoDevicePath
) - END_DEVICE_PATH_LENGTH
;
909 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
911 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
912 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
913 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
920 (*UsbIoHandleCount
) --;
921 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
931 Expand USB Class or USB WWID device path node to be full device path of a USB
934 This function support following 4 cases:
935 1) Boot Option device path starts with a USB Class or USB WWID device path,
936 and there is no Media FilePath device path in the end.
937 In this case, it will follow Removable Media Boot Behavior.
938 2) Boot Option device path starts with a USB Class or USB WWID device path,
939 and ended with Media FilePath device path.
940 3) Boot Option device path starts with a full device path to a USB Host Controller,
941 contains a USB Class or USB WWID device path node, while not ended with Media
942 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
943 4) Boot Option device path starts with a full device path to a USB Host Controller,
944 contains a USB Class or USB WWID device path node, and ended with Media
945 FilePath device path.
947 @param DevicePath On input, a pointer to an allocated buffer that contains the
949 On output, a pointer to an reallocated buffer that contains
950 the expanded device path. It would point to NULL if the file
953 @param FileSize A pointer to the file size.
955 @retval !NULL The file buffer.
956 @retval NULL The input device path doesn't point to a valid file.
959 BmExpandUsbShortFormDevicePath (
960 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
,
964 UINTN ParentDevicePathSize
;
965 EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
;
966 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
967 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
968 EFI_HANDLE
*UsbIoHandles
;
969 UINTN UsbIoHandleCount
;
974 // Search for USB Class or USB WWID device path node.
976 for ( ShortformNode
= *DevicePath
977 ; !IsDevicePathEnd (ShortformNode
)
978 ; ShortformNode
= NextDevicePathNode (ShortformNode
)
980 if ((DevicePathType (ShortformNode
) == MESSAGING_DEVICE_PATH
) &&
981 ((DevicePathSubType (ShortformNode
) == MSG_USB_CLASS_DP
) ||
982 (DevicePathSubType (ShortformNode
) == MSG_USB_WWID_DP
))) {
986 ASSERT (!IsDevicePathEnd (ShortformNode
));
988 FullDevicePath
= NULL
;
989 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) *DevicePath
;
990 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
992 UsbIoHandles
= BmFindUsbDevice (*DevicePath
, ParentDevicePathSize
, &UsbIoHandleCount
);
994 for (Index
= 0; Index
< UsbIoHandleCount
; Index
++) {
995 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (UsbIoHandles
[Index
]), RemainingDevicePath
);
996 DEBUG ((EFI_D_INFO
, "[Bds] FullDp1[%d]:", Index
)); DEBUG_CODE (BmPrintDp (FullDevicePath
); ); DEBUG ((EFI_D_INFO
, "\n"));
997 FileBuffer
= BmLoadEfiBootOption (&FullDevicePath
, FileSize
);
998 if (FileBuffer
!= NULL
) {
999 DEBUG ((EFI_D_INFO
, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath
); ); DEBUG ((EFI_D_INFO
, FileBuffer
!= NULL
? " - Found\n" : "\n"));
1004 if (UsbIoHandles
!= NULL
) {
1005 FreePool (UsbIoHandles
);
1008 if (FileBuffer
== NULL
) {
1010 // Boot Option device path starts with USB Class or USB WWID device path.
1011 // For Boot Option device path which doesn't begin with the USB Class or
1012 // USB WWID device path, it's not needed to connect again here.
1014 if ((DevicePathType (*DevicePath
) == MESSAGING_DEVICE_PATH
) &&
1015 ((DevicePathSubType (*DevicePath
) == MSG_USB_CLASS_DP
) ||
1016 (DevicePathSubType (*DevicePath
) == MSG_USB_WWID_DP
))) {
1017 BmConnectUsbShortFormDevicePath (*DevicePath
);
1019 UsbIoHandles
= BmFindUsbDevice (*DevicePath
, ParentDevicePathSize
, &UsbIoHandleCount
);
1020 for (Index
= 0; Index
< UsbIoHandleCount
; Index
++) {
1021 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (UsbIoHandles
[Index
]), RemainingDevicePath
);
1022 DEBUG ((EFI_D_INFO
, "[Bds] FullDp2[%d]:", Index
)); DEBUG_CODE (BmPrintDp (FullDevicePath
); ); DEBUG ((EFI_D_INFO
, "\n"));
1023 FileBuffer
= BmLoadEfiBootOption (&FullDevicePath
, FileSize
);
1024 if (FileBuffer
!= NULL
) {
1025 DEBUG ((EFI_D_INFO
, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath
); ); DEBUG ((EFI_D_INFO
, FileBuffer
!= NULL
? " - Found\n" : "\n"));
1030 if (UsbIoHandles
!= NULL
) {
1031 FreePool (UsbIoHandles
);
1036 BmFreeAndSet ((VOID
**) DevicePath
, FullDevicePath
);
1041 Expand a device path that starts with a hard drive media device path node to be a
1042 full device path that includes the full hardware path to the device. We need
1043 to do this so it can be booted. As an optimization the front match (the part point
1044 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
1045 so a connect all is not required on every boot. All successful history device path
1046 which point to partition node (the front part) will be saved.
1048 @param DevicePath On input, a pointer to an allocated buffer that contains the
1050 On output, a pointer to an reallocated buffer that contains
1051 the expanded device path. It would point to NULL if the file
1056 BmExpandPartitionShortFormDevicePath (
1057 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
1061 UINTN BlockIoHandleCount
;
1062 EFI_HANDLE
*BlockIoBuffer
;
1063 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
1064 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
1067 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
1068 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
1069 UINTN CachedDevicePathSize
;
1070 BOOLEAN DeviceExist
;
1072 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1075 FullDevicePath
= NULL
;
1077 // Check if there is prestore 'HDDP' variable.
1078 // If exist, search the front path which point to partition node in the variable instants.
1079 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
1081 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
1084 // Delete the invalid 'HDDP' variable.
1086 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
1087 FreePool (CachedDevicePath
);
1088 CachedDevicePath
= NULL
;
1089 Status
= gRT
->SetVariable (
1091 &mBmHardDriveBootVariableGuid
,
1096 ASSERT_EFI_ERROR (Status
);
1099 if (CachedDevicePath
!= NULL
) {
1100 TempNewDevicePath
= CachedDevicePath
;
1101 DeviceExist
= FALSE
;
1105 // Check every instance of the variable
1106 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
1107 // partial partition boot option. Second, check whether the instance could be connected.
1109 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
1110 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) *DevicePath
)) {
1112 // Connect the device path instance, the device path point to hard drive media device path node
1113 // e.g. ACPI() /PCI()/ATA()/Partition()
1115 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
1116 if (!EFI_ERROR (Status
)) {
1122 // Come here means the first instance is not matched
1126 } while (TempNewDevicePath
!= NULL
);
1130 // Find the matched device path.
1131 // Append the file path information from the boot option and return the fully expanded device path.
1133 FullDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (*DevicePath
));
1136 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
1140 // First delete the matched instance.
1142 TempNewDevicePath
= CachedDevicePath
;
1143 CachedDevicePath
= BmDelPartMatchInstance (CachedDevicePath
, Instance
);
1144 FreePool (TempNewDevicePath
);
1147 // Second, append the remaining path after the matched instance
1149 TempNewDevicePath
= CachedDevicePath
;
1150 CachedDevicePath
= AppendDevicePathInstance (Instance
, CachedDevicePath
);
1151 FreePool (TempNewDevicePath
);
1153 // Save the matching Device Path so we don't need to do a connect all next time
1154 // Failing to save only impacts performance next time expanding the short-form device path
1156 Status
= gRT
->SetVariable (
1158 &mBmHardDriveBootVariableGuid
,
1159 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1160 GetDevicePathSize (CachedDevicePath
),
1165 FreePool (Instance
);
1166 FreePool (CachedDevicePath
);
1167 FreePool (*DevicePath
);
1168 *DevicePath
= FullDevicePath
;
1174 // If we get here we fail to find or 'HDDP' not exist, and now we need
1175 // to search all devices in the system for a matched partition
1177 EfiBootManagerConnectAll ();
1178 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
1179 if (EFI_ERROR (Status
)) {
1180 BlockIoHandleCount
= 0;
1181 BlockIoBuffer
= NULL
;
1184 // Loop through all the device handles that support the BLOCK_IO Protocol
1186 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
1188 Status
= gBS
->HandleProtocol (BlockIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*) &BlockIoDevicePath
);
1189 if (EFI_ERROR (Status
) || BlockIoDevicePath
== NULL
) {
1193 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) *DevicePath
)) {
1195 // Find the matched partition device path
1197 FullDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (*DevicePath
));
1200 // Save the matched partition device path in 'HDDP' variable
1202 if (CachedDevicePath
!= NULL
) {
1204 // Save the matched partition device path as first instance of 'HDDP' variable
1206 if (BmMatchDevicePaths (CachedDevicePath
, BlockIoDevicePath
)) {
1207 TempNewDevicePath
= CachedDevicePath
;
1208 CachedDevicePath
= BmDelPartMatchInstance (CachedDevicePath
, BlockIoDevicePath
);
1209 FreePool(TempNewDevicePath
);
1212 if (CachedDevicePath
!= NULL
) {
1213 TempNewDevicePath
= CachedDevicePath
;
1214 CachedDevicePath
= AppendDevicePathInstance (BlockIoDevicePath
, CachedDevicePath
);
1215 FreePool(TempNewDevicePath
);
1217 CachedDevicePath
= DuplicateDevicePath (BlockIoDevicePath
);
1221 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
1222 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
1225 ASSERT (CachedDevicePath
!= NULL
);
1226 TempNewDevicePath
= CachedDevicePath
;
1227 while (!IsDevicePathEnd (TempNewDevicePath
)) {
1228 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
1230 // Parse one instance
1232 while (!IsDevicePathEndType (TempNewDevicePath
)) {
1233 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
1237 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
1239 if (InstanceNum
>= 12) {
1240 SetDevicePathEndNode (TempNewDevicePath
);
1245 CachedDevicePath
= DuplicateDevicePath (BlockIoDevicePath
);
1249 // Save the matching Device Path so we don't need to do a connect all next time
1250 // Failing to save only impacts performance next time expanding the short-form device path
1252 Status
= gRT
->SetVariable (
1254 &mBmHardDriveBootVariableGuid
,
1255 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1256 GetDevicePathSize (CachedDevicePath
),
1264 if (CachedDevicePath
!= NULL
) {
1265 FreePool (CachedDevicePath
);
1267 if (BlockIoBuffer
!= NULL
) {
1268 FreePool (BlockIoBuffer
);
1270 BmFreeAndSet ((VOID
**) DevicePath
, FullDevicePath
);
1274 Algorithm follows the UEFI Spec chapter 3.4 Boot Mechanisms.
1276 @param DevicePath Device Path to a bootable device
1278 @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
1282 BmGetBootableDeviceHandle (
1283 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1287 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
1289 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1291 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1294 EFI_HANDLE ReturnHandle
;
1295 EFI_HANDLE
*SimpleFileSystemHandles
;
1296 UINTN NumberSimpleFileSystemHandles
;
1298 EFI_IMAGE_DOS_HEADER DosHeader
;
1299 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
1300 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1302 ReturnHandle
= NULL
;
1303 UpdatedDevicePath
= DevicePath
;
1306 // Check whether the device is connected
1308 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1309 if (EFI_ERROR (Status
)) {
1311 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
1313 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1314 if (EFI_ERROR (Status
)) {
1316 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
1318 UpdatedDevicePath
= DevicePath
;
1319 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1320 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1324 // For removable device boot option, its contained device path only point to the removable device handle,
1325 // should make sure all its children handles (its child partion or media handles) are created and connected.
1327 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1329 // Get BlockIo protocol and check removable attribute
1331 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
1333 // Issue a dummy read to the device to check for media change.
1334 // When the removable media is changed, any Block IO read/write will
1335 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1336 // returned. After the Block IO protocol is reinstalled, subsequent
1337 // Block IO read/write will success.
1339 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1340 if (Buffer
!= NULL
) {
1341 BlockIo
->ReadBlocks (
1343 BlockIo
->Media
->MediaId
,
1345 BlockIo
->Media
->BlockSize
,
1353 // Detect the the default boot file from removable Media
1355 Size
= GetDevicePathSize(DevicePath
) - END_DEVICE_PATH_LENGTH
;
1356 gBS
->LocateHandleBuffer (
1358 &gEfiSimpleFileSystemProtocolGuid
,
1360 &NumberSimpleFileSystemHandles
,
1361 &SimpleFileSystemHandles
1363 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1365 // Get the device path size of SimpleFileSystem handle
1367 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1368 TempSize
= GetDevicePathSize (TempDevicePath
)- END_DEVICE_PATH_LENGTH
;
1370 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1372 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1374 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
1375 // machinename is ia32, ia64, x64, ...
1377 Hdr
.Union
= &HdrData
;
1378 Status
= BmGetImageHeader (
1379 SimpleFileSystemHandles
[Index
],
1380 EFI_REMOVABLE_MEDIA_FILE_NAME
,
1384 if (!EFI_ERROR (Status
) && EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
1385 (Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
)
1387 ReturnHandle
= SimpleFileSystemHandles
[Index
];
1393 if (SimpleFileSystemHandles
!= NULL
) {
1394 FreePool(SimpleFileSystemHandles
);
1397 return ReturnHandle
;
1401 Get the image file buffer data and buffer size by its device path.
1403 @param FilePath On input, a pointer to an allocated buffer that contains the
1405 On output the device path pointer could be modified to point to
1406 a new allocated buffer that contains the full device path.
1407 It could be caused by either short-form device path expanding,
1408 or default boot file path appending.
1409 @param FileSize A pointer to the size of the file buffer.
1411 @retval NULL The file can't be found.
1412 @retval other The file buffer. The caller is responsible to free memory.
1415 BmLoadEfiBootOption (
1416 IN OUT EFI_DEVICE_PATH_PROTOCOL
**FilePath
,
1422 UINT32 AuthenticationStatus
;
1423 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1425 ASSERT ((FilePath
!= NULL
) && (*FilePath
!= NULL
) && (FileSize
!= NULL
));
1427 EfiBootManagerConnectDevicePath (*FilePath
, NULL
);
1432 // Expand the short-form device path to full device path
1434 if ((DevicePathType (*FilePath
) == MEDIA_DEVICE_PATH
) &&
1435 (DevicePathSubType (*FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1437 // Expand the Harddrive device path
1439 BmExpandPartitionShortFormDevicePath (FilePath
);
1440 if (*FilePath
== NULL
) {
1445 for (Node
= *FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1446 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1447 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) ||
1448 (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1453 if (!IsDevicePathEnd (Node
)) {
1455 // Expand the USB WWID/Class device path
1457 FileBuffer
= BmExpandUsbShortFormDevicePath (FilePath
, FileSize
);
1458 if (FileBuffer
== NULL
) {
1465 // Fix up the boot option path if it points to a FV in memory map style of device path
1467 if (BmIsMemmapFvFilePath (*FilePath
)) {
1468 BmFixupMemmapFvFilePath (FilePath
);
1469 if (*FilePath
== NULL
) {
1474 if (FileBuffer
== NULL
) {
1475 FileBuffer
= GetFileBufferByFilePath (TRUE
, *FilePath
, FileSize
, &AuthenticationStatus
);
1479 // If we didn't find an image directly, we need to try as if it is a removable device boot option
1480 // and load the image according to the default boot behavior.
1482 if (FileBuffer
== NULL
) {
1484 // check if there is a bootable media could be found in this device path,
1485 // and get the bootable media handle
1487 Handle
= BmGetBootableDeviceHandle (*FilePath
);
1488 if (Handle
!= NULL
) {
1490 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from the media
1491 // machinename is ia32, ia64, x64, ...
1493 BmFreeAndSet ((VOID
**) FilePath
, FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
));
1494 ASSERT (*FilePath
!= NULL
);
1495 FileBuffer
= GetFileBufferByFilePath (TRUE
, *FilePath
, FileSize
, &AuthenticationStatus
);
1499 if (FileBuffer
== NULL
) {
1500 BmFreeAndSet ((VOID
**) FilePath
, NULL
);
1507 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1508 also signals the EFI ready to boot event. If the device path for the option
1509 starts with a BBS device path a legacy boot is attempted via the registered
1510 gLegacyBoot function. Short form device paths are also supported via this
1511 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1512 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1513 If the BootOption Device Path fails the removable media boot algorithm
1514 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1515 is tried per processor type)
1517 @param BootOption Boot Option to try and boot.
1518 On return, BootOption->Status contains the boot status.
1519 EFI_SUCCESS BootOption was booted
1520 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1521 registered via EfiBootManagerInitialize().
1522 EFI_NOT_FOUND The BootOption was not found on the system
1523 !EFI_SUCCESS BootOption failed with this error status
1528 EfiBootManagerBoot (
1529 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1533 EFI_HANDLE ImageHandle
;
1534 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1537 UINTN OriginalOptionNumber
;
1538 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1539 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1540 EFI_HANDLE FvHandle
;
1543 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1544 EFI_EVENT LegacyBootEvent
;
1546 if (BootOption
== NULL
) {
1550 if (BootOption
->FilePath
== NULL
) {
1551 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1556 // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")
1558 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1559 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1560 Status
= BmGetFreeOptionNumber (L
"BootOrder", &Uint16
);
1561 if (!EFI_ERROR (Status
)) {
1563 // Save the BootOption->OptionNumber to restore later
1565 OptionNumber
= Uint16
;
1566 OriginalOptionNumber
= BootOption
->OptionNumber
;
1567 BootOption
->OptionNumber
= OptionNumber
;
1568 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1569 BootOption
->OptionNumber
= OriginalOptionNumber
;
1572 if (EFI_ERROR (Status
)) {
1573 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1574 BootOption
->Status
= Status
;
1580 // 2. Set BootCurrent
1582 Uint16
= (UINT16
) OptionNumber
;
1583 BmSetVariableAndReportStatusCodeOnError (
1585 &gEfiGlobalVariableGuid
,
1586 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1592 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1595 Node
= BootOption
->FilePath
;
1596 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1597 if (!EFI_ERROR (Status
) && CompareGuid (
1598 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1599 PcdGetPtr (PcdBootManagerMenuFile
)
1601 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1602 BmStopHotkeyService (NULL
, NULL
);
1604 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1605 EfiSignalEventReadyToBoot();
1607 // 4. Repair system through DriverHealth protocol
1609 BmRepairAllControllers ();
1612 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1615 // 5. Load EFI boot option to ImageHandle
1618 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1619 Status
= EFI_NOT_FOUND
;
1620 FilePath
= DuplicateDevicePath (BootOption
->FilePath
);
1621 FileBuffer
= BmLoadEfiBootOption (&FilePath
, &FileSize
);
1622 if (FileBuffer
!= NULL
) {
1624 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1626 Status
= gBS
->LoadImage (
1634 FreePool (FileBuffer
);
1635 FreePool (FilePath
);
1638 if (EFI_ERROR (Status
)) {
1640 // Report Status Code to indicate that the failure to load boot option
1642 REPORT_STATUS_CODE (
1643 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1644 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1646 BootOption
->Status
= Status
;
1652 // 6. Adjust the different type memory page number just before booting
1653 // and save the updated info into the variable for next boot to use
1655 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
) {
1656 if (PcdGetBool (PcdResetOnMemoryTypeInformationChange
)) {
1657 BmSetMemoryTypeInformationVariable ();
1662 if (BootOption
->Description
== NULL
) {
1663 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1665 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1670 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1671 // Write boot to OS performance data for Legacy boot
1673 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1674 if (mBmLegacyBoot
!= NULL
) {
1676 // Write boot to OS performance data for legacy boot.
1680 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1682 Status
= EfiCreateEventLegacyBootEx(
1684 BmWriteBootToOsPerformanceData
,
1688 ASSERT_EFI_ERROR (Status
);
1691 mBmLegacyBoot (BootOption
);
1693 BootOption
->Status
= EFI_UNSUPPORTED
;
1696 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1701 // Provide the image with its load options
1703 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1704 ASSERT_EFI_ERROR (Status
);
1706 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1707 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1710 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1712 ImageInfo
->ParentHandle
= NULL
;
1715 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1717 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1720 // Write boot to OS performance data for UEFI boot
1723 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1726 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1728 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1729 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1730 BootOption
->Status
= Status
;
1731 if (EFI_ERROR (Status
)) {
1733 // Report Status Code to indicate that boot failure
1735 REPORT_STATUS_CODE (
1736 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1737 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1740 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1743 // Clear the Watchdog Timer after the image returns
1745 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1748 // Set Logo status invalid after trying one boot option
1751 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1752 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1753 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1754 ASSERT_EFI_ERROR (Status
);
1758 // Clear Boot Current
1760 Status
= gRT
->SetVariable (
1762 &gEfiGlobalVariableGuid
,
1768 // Deleting variable with current variable implementation shouldn't fail.
1769 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1770 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1772 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1776 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1777 instances, has the same partition node with HardDriveDevicePath device path
1779 @param BlockIoDevicePath Multi device path instances which need to check
1780 @param HardDriveDevicePath A device path which starts with a hard drive media
1783 @retval TRUE There is a matched device path instance.
1784 @retval FALSE There is no matched device path instance.
1788 BmMatchPartitionDevicePathNode (
1789 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1790 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1793 HARDDRIVE_DEVICE_PATH
*TmpHdPath
;
1794 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1796 EFI_DEVICE_PATH_PROTOCOL
*BlockIoHdDevicePathNode
;
1798 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1803 // Make PreviousDevicePath == the device path node before the end node
1805 DevicePath
= BlockIoDevicePath
;
1806 BlockIoHdDevicePathNode
= NULL
;
1809 // find the partition device path node
1811 while (!IsDevicePathEnd (DevicePath
)) {
1812 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
1813 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)
1815 BlockIoHdDevicePathNode
= DevicePath
;
1819 DevicePath
= NextDevicePathNode (DevicePath
);
1822 if (BlockIoHdDevicePathNode
== NULL
) {
1826 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1828 TmpHdPath
= (HARDDRIVE_DEVICE_PATH
*) BlockIoHdDevicePathNode
;
1832 // Check for the match
1834 if ((TmpHdPath
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1835 (TmpHdPath
->SignatureType
== HardDriveDevicePath
->SignatureType
)) {
1836 switch (TmpHdPath
->SignatureType
) {
1837 case SIGNATURE_TYPE_GUID
:
1838 Match
= CompareGuid ((EFI_GUID
*)TmpHdPath
->Signature
, (EFI_GUID
*)HardDriveDevicePath
->Signature
);
1840 case SIGNATURE_TYPE_MBR
:
1841 Match
= (BOOLEAN
) (*((UINT32
*) (&(TmpHdPath
->Signature
[0]))) == ReadUnaligned32((UINT32
*)(&(HardDriveDevicePath
->Signature
[0]))));
1853 Emuerate all possible bootable medias in the following order:
1854 1. Removable BlockIo - The boot option only points to the removable media
1855 device, like USB key, DVD, Floppy etc.
1856 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1858 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1859 SimpleFileSystem Protocol, but not supporting BlockIo
1861 4. LoadFile - The boot option points to the media supporting
1863 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1865 @param BootOptionCount Return the boot option count which has been found.
1867 @retval Pointer to the boot option array.
1869 EFI_BOOT_MANAGER_LOAD_OPTION
*
1870 BmEnumerateBootOptions (
1871 UINTN
*BootOptionCount
1875 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1876 UINT16 NonBlockNumber
;
1878 EFI_HANDLE
*Handles
;
1879 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
1882 UINTN FunctionIndex
;
1884 CHAR16
*DescriptionPtr
;
1885 CHAR16 Description
[30];
1887 ASSERT (BootOptionCount
!= NULL
);
1889 *BootOptionCount
= 0;
1893 // Parse removable block io followed by fixed block io
1895 gBS
->LocateHandleBuffer (
1897 &gEfiBlockIoProtocolGuid
,
1903 for (Removable
= 0; Removable
< 2; Removable
++) {
1904 for (Index
= 0; Index
< HandleCount
; Index
++) {
1905 Status
= gBS
->HandleProtocol (
1907 &gEfiBlockIoProtocolGuid
,
1910 if (EFI_ERROR (Status
)) {
1915 // Skip the logical partitions
1917 if (BlkIo
->Media
->LogicalPartition
) {
1922 // Skip the fixed block io then the removable block io
1924 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
1928 DescriptionPtr
= NULL
;
1929 for (FunctionIndex
= 0; FunctionIndex
< sizeof (mBmGetBootDescription
) / sizeof (mBmGetBootDescription
[0]); FunctionIndex
++) {
1930 DescriptionPtr
= mBmGetBootDescription
[FunctionIndex
] (Handles
[Index
]);
1931 if (DescriptionPtr
!= NULL
) {
1936 if (DescriptionPtr
== NULL
) {
1941 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
1943 Temp
= AllocatePool (StrSize (DescriptionPtr
) + sizeof (mBmUefiPrefix
));
1944 ASSERT (Temp
!= NULL
);
1945 StrCpy (Temp
, mBmUefiPrefix
);
1946 StrCat (Temp
, DescriptionPtr
);
1947 FreePool (DescriptionPtr
);
1948 DescriptionPtr
= Temp
;
1950 BootOptions
= ReallocatePool (
1951 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1952 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1955 ASSERT (BootOptions
!= NULL
);
1957 Status
= EfiBootManagerInitializeLoadOption (
1958 &BootOptions
[(*BootOptionCount
)++],
1959 LoadOptionNumberUnassigned
,
1963 DevicePathFromHandle (Handles
[Index
]),
1967 ASSERT_EFI_ERROR (Status
);
1969 FreePool (DescriptionPtr
);
1973 if (HandleCount
!= 0) {
1978 // Parse simple file system not based on block io
1981 gBS
->LocateHandleBuffer (
1983 &gEfiSimpleFileSystemProtocolGuid
,
1988 for (Index
= 0; Index
< HandleCount
; Index
++) {
1989 Status
= gBS
->HandleProtocol (
1991 &gEfiBlockIoProtocolGuid
,
1994 if (!EFI_ERROR (Status
)) {
1996 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2000 UnicodeSPrint (Description
, sizeof (Description
), NonBlockNumber
> 0 ? L
"%s %d" : L
"%s", L
"UEFI Non-Block Boot Device", NonBlockNumber
);
2002 BootOptions
= ReallocatePool (
2003 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2004 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2007 ASSERT (BootOptions
!= NULL
);
2009 Status
= EfiBootManagerInitializeLoadOption (
2010 &BootOptions
[(*BootOptionCount
)++],
2011 LoadOptionNumberUnassigned
,
2015 DevicePathFromHandle (Handles
[Index
]),
2019 ASSERT_EFI_ERROR (Status
);
2022 if (HandleCount
!= 0) {
2027 // Parse load file, assuming UEFI Network boot option
2029 gBS
->LocateHandleBuffer (
2031 &gEfiLoadFileProtocolGuid
,
2036 for (Index
= 0; Index
< HandleCount
; Index
++) {
2038 UnicodeSPrint (Description
, sizeof (Description
), Index
> 0 ? L
"%s %d" : L
"%s", L
"UEFI Network", Index
);
2040 BootOptions
= ReallocatePool (
2041 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2042 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2045 ASSERT (BootOptions
!= NULL
);
2047 Status
= EfiBootManagerInitializeLoadOption (
2048 &BootOptions
[(*BootOptionCount
)++],
2049 LoadOptionNumberUnassigned
,
2053 DevicePathFromHandle (Handles
[Index
]),
2057 ASSERT_EFI_ERROR (Status
);
2060 if (HandleCount
!= 0) {
2068 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2072 EfiBootManagerRefreshAllBootOption (
2077 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2078 UINTN NvBootOptionCount
;
2079 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2080 UINTN BootOptionCount
;
2084 // Optionally refresh the legacy boot option
2086 if (mBmRefreshLegacyBootOption
!= NULL
) {
2087 mBmRefreshLegacyBootOption ();
2090 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2091 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2094 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2096 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2097 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2098 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2102 // Remove invalid EFI boot options from NV
2104 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2105 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2106 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2108 (NvBootOptions
[Index
].OptionalDataSize
== sizeof (EFI_GUID
)) &&
2109 CompareGuid ((EFI_GUID
*) NvBootOptions
[Index
].OptionalData
, &mBmAutoCreateBootOptionGuid
)
2112 // Only check those added by BDS
2113 // so that the boot options added by end-user or OS installer won't be deleted
2115 if (BmFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
2116 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2118 // Deleting variable with current variable implementation shouldn't fail.
2120 ASSERT_EFI_ERROR (Status
);
2126 // Add new EFI boot options to NV
2128 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2129 if (BmFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
2130 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2132 // Try best to add the boot options so continue upon failure.
2137 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2138 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2142 This function is called to create the boot option for the Boot Manager Menu.
2144 The Boot Manager Menu is shown after successfully booting a boot option.
2145 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2147 @param BootOption Return the boot option of the Boot Manager Menu
2149 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2150 @retval Status Return status of gRT->SetVariable (). BootOption still points
2151 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2154 BmRegisterBootManagerMenu (
2155 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2159 CHAR16
*Description
;
2160 UINTN DescriptionLength
;
2161 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2162 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2163 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2165 Status
= GetSectionFromFv (
2166 PcdGetPtr (PcdBootManagerMenuFile
),
2167 EFI_SECTION_USER_INTERFACE
,
2169 (VOID
**) &Description
,
2172 if (EFI_ERROR (Status
)) {
2176 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2177 Status
= gBS
->HandleProtocol (
2179 &gEfiLoadedImageProtocolGuid
,
2180 (VOID
**) &LoadedImage
2182 ASSERT_EFI_ERROR (Status
);
2183 DevicePath
= AppendDevicePathNode (
2184 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2185 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2187 ASSERT (DevicePath
!= NULL
);
2189 Status
= EfiBootManagerInitializeLoadOption (
2191 LoadOptionNumberUnassigned
,
2193 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2194 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2199 ASSERT_EFI_ERROR (Status
);
2200 FreePool (DevicePath
);
2201 if (Description
!= NULL
) {
2202 FreePool (Description
);
2206 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2207 UINTN BootOptionCount
;
2209 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2210 ASSERT (BmFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2211 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2214 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2218 Return the boot option corresponding to the Boot Manager Menu.
2219 It may automatically create one if the boot option hasn't been created yet.
2221 @param BootOption Return the Boot Manager Menu.
2223 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2224 @retval Status Return status of gRT->SetVariable (). BootOption still points
2225 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2229 EfiBootManagerGetBootManagerMenu (
2230 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2234 UINTN BootOptionCount
;
2235 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2237 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2238 EFI_HANDLE FvHandle
;
2240 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2242 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2243 Node
= BootOptions
[Index
].FilePath
;
2244 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2245 if (!EFI_ERROR (Status
)) {
2247 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2248 PcdGetPtr (PcdBootManagerMenuFile
)
2251 Status
= EfiBootManagerInitializeLoadOption (
2253 BootOptions
[Index
].OptionNumber
,
2254 BootOptions
[Index
].OptionType
,
2255 BootOptions
[Index
].Attributes
,
2256 BootOptions
[Index
].Description
,
2257 BootOptions
[Index
].FilePath
,
2258 BootOptions
[Index
].OptionalData
,
2259 BootOptions
[Index
].OptionalDataSize
2261 ASSERT_EFI_ERROR (Status
);
2267 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2270 // Automatically create the Boot#### for Boot Manager Menu when not found.
2272 if (Index
== BootOptionCount
) {
2273 return BmRegisterBootManagerMenu (BootOption
);