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
;
28 LIST_ENTRY mPlatformBootDescriptionHandlers
= INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers
);
31 /// This GUID is used for an EFI Variable that stores the front device pathes
32 /// for a partial device path that starts with the HD node.
34 EFI_GUID mBmHardDriveBootVariableGuid
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
35 EFI_GUID mBmAutoCreateBootOptionGuid
= { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
38 The function registers the legacy boot support capabilities.
40 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
41 @param LegacyBoot The function pointer to boot the legacy boot option.
45 EfiBootManagerRegisterLegacyBootSupport (
46 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption
,
47 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
50 mBmRefreshLegacyBootOption
= RefreshLegacyBootOption
;
51 mBmLegacyBoot
= LegacyBoot
;
55 For a bootable Device path, return its boot type.
57 @param DevicePath The bootable device Path to check
59 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
60 which HID is floppy device.
61 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
62 and its last device path node's subtype is MSG_ATAPI_DP.
63 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
64 and its last device path node's subtype is MSG_SATA_DP.
65 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
66 and its last device path node's subtype is MSG_SCSI_DP.
67 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
68 and its last device path node's subtype is MSG_USB_DP.
69 @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
70 and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
71 MSG_IPv4_DP or MSG_IPv6_DP.
72 @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.
77 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
80 EFI_DEVICE_PATH_PROTOCOL
*Node
;
81 EFI_DEVICE_PATH_PROTOCOL
*NextNode
;
83 ASSERT (DevicePath
!= NULL
);
85 for (Node
= DevicePath
; !IsDevicePathEndType (Node
); Node
= NextDevicePathNode (Node
)) {
86 switch (DevicePathType (Node
)) {
88 case ACPI_DEVICE_PATH
:
89 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH
*) Node
)->HID
) == 0x0604) {
90 return BmAcpiFloppyBoot
;
94 case HARDWARE_DEVICE_PATH
:
95 if (DevicePathSubType (Node
) == HW_CONTROLLER_DP
) {
96 return BmHardwareDeviceBoot
;
100 case MESSAGING_DEVICE_PATH
:
102 // Skip LUN device node
106 NextNode
= NextDevicePathNode (NextNode
);
108 (DevicePathType (NextNode
) == MESSAGING_DEVICE_PATH
) &&
109 (DevicePathSubType(NextNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
)
113 // If the device path not only point to driver device, it is not a messaging device path,
115 if (!IsDevicePathEndType (NextNode
)) {
119 switch (DevicePathSubType (Node
)) {
121 return BmMessageAtapiBoot
;
125 return BmMessageSataBoot
;
129 return BmMessageUsbBoot
;
133 return BmMessageScsiBoot
;
136 case MSG_MAC_ADDR_DP
:
140 return BmMessageNetworkBoot
;
150 Find the boot option in the NV storage and return the option number.
152 @param OptionToFind Boot option to be checked.
154 @return The option number of the found boot option.
158 BmFindBootOptionInVariable (
159 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
163 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
165 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
166 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
167 UINTN BootOptionCount
;
170 OptionNumber
= LoadOptionNumberUnassigned
;
173 // Try to match the variable exactly if the option number is assigned
175 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
177 OptionName
, sizeof (OptionName
), L
"%s%04x",
178 mBmLoadOptionName
[OptionToFind
->OptionType
], OptionToFind
->OptionNumber
180 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
182 if (!EFI_ERROR (Status
)) {
183 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
184 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
185 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
186 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
187 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
188 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
190 OptionNumber
= OptionToFind
->OptionNumber
;
192 EfiBootManagerFreeLoadOption (&BootOption
);
197 // The option number assigned is either incorrect or unassigned.
199 if (OptionNumber
== LoadOptionNumberUnassigned
) {
200 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
202 Index
= BmFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
204 OptionNumber
= BootOptions
[Index
].OptionNumber
;
207 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
214 Get the file buffer using a Memory Mapped Device Path.
216 FV address may change across reboot. This routine promises the FV file device path is right.
218 @param DevicePath The Memory Mapped Device Path to get the file buffer.
219 @param FullPath Receive the updated FV Device Path pointint to the file.
220 @param FileSize Receive the file buffer size.
222 @return The file buffer.
225 BmGetFileBufferByMemmapFv (
226 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
227 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
233 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
235 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
236 UINT32 AuthenticationStatus
;
238 EFI_HANDLE
*FvHandles
;
239 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
242 FvFileNode
= DevicePath
;
243 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
244 if (!EFI_ERROR (Status
)) {
245 FileBuffer
= GetFileBufferByFilePath (TRUE
, DevicePath
, FileSize
, &AuthenticationStatus
);
246 if (FileBuffer
!= NULL
) {
247 *FullPath
= DuplicateDevicePath (DevicePath
);
252 FvFileNode
= NextDevicePathNode (DevicePath
);
255 // Firstly find the FV file in current FV
257 gBS
->HandleProtocol (
259 &gEfiLoadedImageProtocolGuid
,
260 (VOID
**) &LoadedImage
262 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
263 FileBuffer
= BmGetFileBufferByMemmapFv (NewDevicePath
, FullPath
, FileSize
);
264 FreePool (NewDevicePath
);
266 if (FileBuffer
!= NULL
) {
271 // Secondly find the FV file in all other FVs
273 gBS
->LocateHandleBuffer (
275 &gEfiFirmwareVolume2ProtocolGuid
,
280 for (Index
= 0; (Index
< FvHandleCount
) && (FileBuffer
== NULL
); Index
++) {
281 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
287 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
288 FileBuffer
= BmGetFileBufferByMemmapFv (NewDevicePath
, FullPath
, FileSize
);
289 FreePool (NewDevicePath
);
292 if (FvHandles
!= NULL
) {
293 FreePool (FvHandles
);
299 Check if it's a Memory Mapped FV Device Path.
301 The function doesn't garentee the device path points to existing FV file.
303 @param DevicePath Input device path.
305 @retval TRUE The device path is a Memory Mapped FV Device Path.
306 @retval FALSE The device path is NOT a Memory Mapped FV Device Path.
309 BmIsMemmapFvFilePath (
310 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
313 EFI_DEVICE_PATH_PROTOCOL
*FileNode
;
315 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
316 FileNode
= NextDevicePathNode (DevicePath
);
317 if ((DevicePathType (FileNode
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (FileNode
) == MEDIA_PIWG_FW_FILE_DP
)) {
318 return IsDevicePathEnd (NextDevicePathNode (FileNode
));
326 Check whether a USB device match the specified USB Class device path. This
327 function follows "Load Option Processing" behavior in UEFI specification.
329 @param UsbIo USB I/O protocol associated with the USB device.
330 @param UsbClass The USB Class device path to match.
332 @retval TRUE The USB device match the USB Class device path.
333 @retval FALSE The USB device does not match the USB Class device path.
338 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
339 IN USB_CLASS_DEVICE_PATH
*UsbClass
343 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
344 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
346 UINT8 DeviceSubClass
;
347 UINT8 DeviceProtocol
;
349 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
350 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
355 // Check Vendor Id and Product Id.
357 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
358 if (EFI_ERROR (Status
)) {
362 if ((UsbClass
->VendorId
!= 0xffff) &&
363 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
367 if ((UsbClass
->ProductId
!= 0xffff) &&
368 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
372 DeviceClass
= DevDesc
.DeviceClass
;
373 DeviceSubClass
= DevDesc
.DeviceSubClass
;
374 DeviceProtocol
= DevDesc
.DeviceProtocol
;
375 if (DeviceClass
== 0) {
377 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
378 // Protocol in Interface Descriptor instead.
380 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
381 if (EFI_ERROR (Status
)) {
385 DeviceClass
= IfDesc
.InterfaceClass
;
386 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
387 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
391 // Check Class, SubClass and Protocol.
393 if ((UsbClass
->DeviceClass
!= 0xff) &&
394 (UsbClass
->DeviceClass
!= DeviceClass
)) {
398 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
399 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
403 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
404 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
412 Eliminate the extra spaces in the Str to one space.
414 @param Str Input string info.
417 BmEliminateExtraSpaces (
424 for (Index
= 0, ActualIndex
= 0; Str
[Index
] != L
'\0'; Index
++) {
425 if ((Str
[Index
] != L
' ') || ((ActualIndex
> 0) && (Str
[ActualIndex
- 1] != L
' '))) {
426 Str
[ActualIndex
++] = Str
[Index
];
429 Str
[ActualIndex
] = L
'\0';
433 Try to get the controller's ATA/ATAPI description.
435 @param Handle Controller handle.
437 @return The description string.
440 BmGetDescriptionFromDiskInfo (
446 EFI_DISK_INFO_PROTOCOL
*DiskInfo
;
448 EFI_ATAPI_IDENTIFY_DATA IdentifyData
;
449 EFI_SCSI_INQUIRY_DATA InquiryData
;
452 CONST UINTN ModelNameLength
= 40;
453 CONST UINTN SerialNumberLength
= 20;
459 Status
= gBS
->HandleProtocol (
461 &gEfiDiskInfoProtocolGuid
,
464 if (EFI_ERROR (Status
)) {
468 if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoAhciInterfaceGuid
) ||
469 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoIdeInterfaceGuid
)) {
470 BufferSize
= sizeof (EFI_ATAPI_IDENTIFY_DATA
);
471 Status
= DiskInfo
->Identify (
476 if (!EFI_ERROR (Status
)) {
477 Description
= AllocateZeroPool ((ModelNameLength
+ SerialNumberLength
+ 2) * sizeof (CHAR16
));
478 ASSERT (Description
!= NULL
);
479 for (Index
= 0; Index
+ 1 < ModelNameLength
; Index
+= 2) {
480 Description
[Index
] = (CHAR16
) IdentifyData
.ModelName
[Index
+ 1];
481 Description
[Index
+ 1] = (CHAR16
) IdentifyData
.ModelName
[Index
];
485 Description
[Length
++] = L
' ';
487 for (Index
= 0; Index
+ 1 < SerialNumberLength
; Index
+= 2) {
488 Description
[Length
+ Index
] = (CHAR16
) IdentifyData
.SerialNo
[Index
+ 1];
489 Description
[Length
+ Index
+ 1] = (CHAR16
) IdentifyData
.SerialNo
[Index
];
492 Description
[Length
++] = L
'\0';
493 ASSERT (Length
== ModelNameLength
+ SerialNumberLength
+ 2);
495 BmEliminateExtraSpaces (Description
);
497 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
498 BufferSize
= sizeof (EFI_SCSI_INQUIRY_DATA
);
499 Status
= DiskInfo
->Inquiry (
504 if (!EFI_ERROR (Status
)) {
505 Description
= AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2) * sizeof (CHAR16
));
506 ASSERT (Description
!= NULL
);
509 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
510 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
511 // Here combine the vendor identification and product identification to the description.
513 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
]);
514 Temp
= StrPtr
[VENDOR_IDENTIFICATION_LENGTH
];
515 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = '\0';
516 AsciiStrToUnicodeStr (StrPtr
, Description
);
517 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = Temp
;
520 // Add one space at the middle of vendor information and product information.
522 Description
[VENDOR_IDENTIFICATION_LENGTH
] = L
' ';
524 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
]);
525 StrPtr
[PRODUCT_IDENTIFICATION_LENGTH
] = '\0';
526 AsciiStrToUnicodeStr (StrPtr
, Description
+ VENDOR_IDENTIFICATION_LENGTH
+ 1);
528 BmEliminateExtraSpaces (Description
);
536 Try to get the controller's USB description.
538 @param Handle Controller handle.
540 @return The description string.
543 BmGetUsbDescription (
548 EFI_USB_IO_PROTOCOL
*UsbIo
;
550 CHAR16
*Manufacturer
;
552 CHAR16
*SerialNumber
;
554 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
556 Status
= gBS
->HandleProtocol (
558 &gEfiUsbIoProtocolGuid
,
561 if (EFI_ERROR (Status
)) {
567 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
568 if (EFI_ERROR (Status
)) {
572 Status
= UsbIo
->UsbGetStringDescriptor (
575 DevDesc
.StrManufacturer
,
578 if (EFI_ERROR (Status
)) {
579 Manufacturer
= &NullChar
;
582 Status
= UsbIo
->UsbGetStringDescriptor (
588 if (EFI_ERROR (Status
)) {
592 Status
= UsbIo
->UsbGetStringDescriptor (
595 DevDesc
.StrSerialNumber
,
598 if (EFI_ERROR (Status
)) {
599 SerialNumber
= &NullChar
;
602 if ((Manufacturer
== &NullChar
) &&
603 (Product
== &NullChar
) &&
604 (SerialNumber
== &NullChar
)
609 Description
= AllocateZeroPool (StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
));
610 ASSERT (Description
!= NULL
);
611 StrCat (Description
, Manufacturer
);
612 StrCat (Description
, L
" ");
614 StrCat (Description
, Product
);
615 StrCat (Description
, L
" ");
617 StrCat (Description
, SerialNumber
);
619 if (Manufacturer
!= &NullChar
) {
620 FreePool (Manufacturer
);
622 if (Product
!= &NullChar
) {
625 if (SerialNumber
!= &NullChar
) {
626 FreePool (SerialNumber
);
629 BmEliminateExtraSpaces (Description
);
635 Return the boot description for the controller based on the type.
637 @param Handle Controller handle.
639 @return The description string.
642 BmGetMiscDescription (
648 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
649 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
651 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
652 case BmAcpiFloppyBoot
:
653 Description
= L
"Floppy";
656 case BmMessageAtapiBoot
:
657 case BmMessageSataBoot
:
658 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
659 ASSERT_EFI_ERROR (Status
);
661 // Assume a removable SATA device should be the DVD/CD device
663 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
666 case BmMessageUsbBoot
:
667 Description
= L
"USB Device";
670 case BmMessageScsiBoot
:
671 Description
= L
"SCSI Device";
674 case BmHardwareDeviceBoot
:
675 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
676 if (!EFI_ERROR (Status
)) {
677 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
679 Description
= L
"Misc Device";
683 case BmMessageNetworkBoot
:
684 Description
= L
"Network";
688 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**) &Fs
);
689 if (!EFI_ERROR (Status
)) {
690 Description
= L
"Non-Block Boot Device";
692 Description
= L
"Misc Device";
697 return AllocateCopyPool (StrSize (Description
), Description
);
701 Register the platform provided boot description handler.
703 @param Handler The platform provided boot description handler
705 @retval EFI_SUCCESS The handler was registered successfully.
706 @retval EFI_ALREADY_STARTED The handler was already registered.
707 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
711 EfiBootManagerRegisterBootDescriptionHandler (
712 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
716 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
718 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
719 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
720 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
722 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
723 if (Entry
->Handler
== Handler
) {
724 return EFI_ALREADY_STARTED
;
728 Entry
= AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY
));
730 return EFI_OUT_OF_RESOURCES
;
733 Entry
->Signature
= BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
;
734 Entry
->Handler
= Handler
;
735 InsertTailList (&mPlatformBootDescriptionHandlers
, &Entry
->Link
);
739 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers
[] = {
741 BmGetDescriptionFromDiskInfo
,
746 Return the boot description for the controller.
748 @param Handle Controller handle.
750 @return The description string.
753 BmGetBootDescription (
758 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
760 CHAR16
*DefaultDescription
;
765 // Firstly get the default boot description
767 DefaultDescription
= NULL
;
768 for (Index
= 0; Index
< sizeof (mBmBootDescriptionHandlers
) / sizeof (mBmBootDescriptionHandlers
[0]); Index
++) {
769 DefaultDescription
= mBmBootDescriptionHandlers
[Index
] (Handle
);
770 if (DefaultDescription
!= NULL
) {
772 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
773 // ONLY for core provided boot description handler.
775 Temp
= AllocatePool (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
));
776 ASSERT (Temp
!= NULL
);
777 StrCpy (Temp
, mBmUefiPrefix
);
778 StrCat (Temp
, DefaultDescription
);
779 FreePool (DefaultDescription
);
780 DefaultDescription
= Temp
;
784 ASSERT (DefaultDescription
!= NULL
);
787 // Secondly query platform for the better boot description
789 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
790 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
791 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
793 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
794 Description
= Entry
->Handler (Handle
, DefaultDescription
);
795 if (Description
!= NULL
) {
796 FreePool (DefaultDescription
);
801 return DefaultDescription
;
805 Check whether a USB device match the specified USB WWID device path. This
806 function follows "Load Option Processing" behavior in UEFI specification.
808 @param UsbIo USB I/O protocol associated with the USB device.
809 @param UsbWwid The USB WWID device path to match.
811 @retval TRUE The USB device match the USB WWID device path.
812 @retval FALSE The USB device does not match the USB WWID device path.
817 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
818 IN USB_WWID_DEVICE_PATH
*UsbWwid
822 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
823 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
829 CHAR16
*SerialNumberStr
;
832 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
833 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
838 // Check Vendor Id and Product Id.
840 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
841 if (EFI_ERROR (Status
)) {
844 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
845 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
850 // Check Interface Number.
852 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
853 if (EFI_ERROR (Status
)) {
856 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
861 // Check Serial Number.
863 if (DevDesc
.StrSerialNumber
== 0) {
868 // Get all supported languages.
872 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
873 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
878 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
880 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
881 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
882 if (CompareStr
[CompareLen
- 1] == L
'\0') {
887 // Compare serial number in each supported language.
889 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
890 SerialNumberStr
= NULL
;
891 Status
= UsbIo
->UsbGetStringDescriptor (
894 DevDesc
.StrSerialNumber
,
897 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
901 Length
= StrLen (SerialNumberStr
);
902 if ((Length
>= CompareLen
) &&
903 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
904 FreePool (SerialNumberStr
);
908 FreePool (SerialNumberStr
);
915 Find a USB device which match the specified short-form device path start with
916 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
917 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
918 this function will only search in its child devices.
920 @param DevicePath The device path that contains USB Class or USB WWID device path.
921 @param ParentDevicePathSize The length of the device path before the USB Class or
922 USB WWID device path.
923 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
925 @retval NULL The matched USB IO handles cannot be found.
926 @retval other The matched USB IO handles.
931 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
932 IN UINTN ParentDevicePathSize
,
933 OUT UINTN
*UsbIoHandleCount
937 EFI_HANDLE
*UsbIoHandles
;
938 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
939 EFI_USB_IO_PROTOCOL
*UsbIo
;
941 UINTN UsbIoDevicePathSize
;
944 ASSERT (UsbIoHandleCount
!= NULL
);
947 // Get all UsbIo Handles.
949 Status
= gBS
->LocateHandleBuffer (
951 &gEfiUsbIoProtocolGuid
,
956 if (EFI_ERROR (Status
)) {
957 *UsbIoHandleCount
= 0;
961 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
963 // Get the Usb IO interface.
965 Status
= gBS
->HandleProtocol(
967 &gEfiUsbIoProtocolGuid
,
970 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
972 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
973 UsbIoDevicePathSize
= GetDevicePathSize (UsbIoDevicePath
) - END_DEVICE_PATH_LENGTH
;
976 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
978 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
979 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
980 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
987 (*UsbIoHandleCount
) --;
988 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
998 Expand USB Class or USB WWID device path node to be full device path of a USB
1001 This function support following 4 cases:
1002 1) Boot Option device path starts with a USB Class or USB WWID device path,
1003 and there is no Media FilePath device path in the end.
1004 In this case, it will follow Removable Media Boot Behavior.
1005 2) Boot Option device path starts with a USB Class or USB WWID device path,
1006 and ended with Media FilePath device path.
1007 3) Boot Option device path starts with a full device path to a USB Host Controller,
1008 contains a USB Class or USB WWID device path node, while not ended with Media
1009 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
1010 4) Boot Option device path starts with a full device path to a USB Host Controller,
1011 contains a USB Class or USB WWID device path node, and ended with Media
1012 FilePath device path.
1014 @param FilePath The device path pointing to a load option.
1015 It could be a short-form device path.
1016 @param FullPath Return the full device path of the load option after
1017 short-form device path expanding.
1018 Caller is responsible to free it.
1019 @param FileSize Return the load option size.
1020 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
1022 @return The load option buffer. Caller is responsible to free the memory.
1025 BmExpandUsbDevicePath (
1026 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1027 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1028 OUT UINTN
*FileSize
,
1029 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
1032 UINTN ParentDevicePathSize
;
1033 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
1034 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
1035 EFI_HANDLE
*Handles
;
1040 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
1041 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
1043 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
1045 for (Index
= 0; (Index
< HandleCount
) && (FileBuffer
== NULL
); Index
++) {
1046 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
1047 FileBuffer
= BmGetLoadOptionBuffer (FullDevicePath
, FullPath
, FileSize
);
1048 FreePool (FullDevicePath
);
1051 if (Handles
!= NULL
) {
1059 Save the partition DevicePath to the CachedDevicePath as the first instance.
1061 @param CachedDevicePath The device path cache.
1062 @param DevicePath The partition device path to be cached.
1065 BmCachePartitionDevicePath (
1066 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
1067 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1070 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1073 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
1074 TempDevicePath
= *CachedDevicePath
;
1075 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
1076 FreePool (TempDevicePath
);
1079 if (*CachedDevicePath
== NULL
) {
1080 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
1084 TempDevicePath
= *CachedDevicePath
;
1085 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
1086 if (TempDevicePath
!= NULL
) {
1087 FreePool (TempDevicePath
);
1091 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
1092 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
1095 TempDevicePath
= *CachedDevicePath
;
1096 while (!IsDevicePathEnd (TempDevicePath
)) {
1097 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1099 // Parse one instance
1101 while (!IsDevicePathEndType (TempDevicePath
)) {
1102 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1106 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
1109 SetDevicePathEndNode (TempDevicePath
);
1116 Expand a device path that starts with a hard drive media device path node to be a
1117 full device path that includes the full hardware path to the device. We need
1118 to do this so it can be booted. As an optimization the front match (the part point
1119 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
1120 so a connect all is not required on every boot. All successful history device path
1121 which point to partition node (the front part) will be saved.
1123 @param FilePath The device path pointing to a load option.
1124 It could be a short-form device path.
1125 @param FullPath Return the full device path of the load option after
1126 short-form device path expanding.
1127 Caller is responsible to free it.
1128 @param FileSize Return the load option size.
1130 @return The load option buffer. Caller is responsible to free the memory.
1133 BmExpandPartitionDevicePath (
1134 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1135 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1140 UINTN BlockIoHandleCount
;
1141 EFI_HANDLE
*BlockIoBuffer
;
1143 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
1145 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
1146 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
1147 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1148 UINTN CachedDevicePathSize
;
1150 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1155 // Check if there is prestore 'HDDP' variable.
1156 // If exist, search the front path which point to partition node in the variable instants.
1157 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
1159 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
1162 // Delete the invalid 'HDDP' variable.
1164 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
1165 FreePool (CachedDevicePath
);
1166 CachedDevicePath
= NULL
;
1167 Status
= gRT
->SetVariable (
1169 &mBmHardDriveBootVariableGuid
,
1174 ASSERT_EFI_ERROR (Status
);
1177 if (CachedDevicePath
!= NULL
) {
1178 TempNewDevicePath
= CachedDevicePath
;
1182 // Check every instance of the variable
1183 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
1184 // partial partition boot option. Second, check whether the instance could be connected.
1186 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
1187 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1189 // Connect the device path instance, the device path point to hard drive media device path node
1190 // e.g. ACPI() /PCI()/ATA()/Partition()
1192 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
1193 if (!EFI_ERROR (Status
)) {
1194 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
1195 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1196 FreePool (TempDevicePath
);
1198 if (FileBuffer
!= NULL
) {
1200 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
1203 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
1205 // Save the matching Device Path so we don't need to do a connect all next time
1206 // Failing to save only impacts performance next time expanding the short-form device path
1208 Status
= gRT
->SetVariable (
1210 &mBmHardDriveBootVariableGuid
,
1211 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1212 GetDevicePathSize (CachedDevicePath
),
1217 FreePool (Instance
);
1218 FreePool (CachedDevicePath
);
1224 // Come here means the first instance is not matched
1228 } while (TempNewDevicePath
!= NULL
);
1232 // If we get here we fail to find or 'HDDP' not exist, and now we need
1233 // to search all devices in the system for a matched partition
1235 EfiBootManagerConnectAll ();
1236 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
1237 if (EFI_ERROR (Status
)) {
1238 BlockIoHandleCount
= 0;
1239 BlockIoBuffer
= NULL
;
1242 // Loop through all the device handles that support the BLOCK_IO Protocol
1244 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
1245 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
1246 if (BlockIoDevicePath
== NULL
) {
1250 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1252 // Find the matched partition device path
1254 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
1255 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1256 FreePool (TempDevicePath
);
1258 if (FileBuffer
!= NULL
) {
1259 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
1262 // Save the matching Device Path so we don't need to do a connect all next time
1263 // Failing to save only impacts performance next time expanding the short-form device path
1265 Status
= gRT
->SetVariable (
1267 &mBmHardDriveBootVariableGuid
,
1268 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1269 GetDevicePathSize (CachedDevicePath
),
1278 if (CachedDevicePath
!= NULL
) {
1279 FreePool (CachedDevicePath
);
1281 if (BlockIoBuffer
!= NULL
) {
1282 FreePool (BlockIoBuffer
);
1288 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
1289 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1291 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1292 @param FullPath Return the full device path pointing to the load option.
1293 @param FileSize Return the size of the load option.
1295 @return The load option buffer.
1298 BmExpandMediaDevicePath (
1299 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1300 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1306 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1308 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1311 EFI_HANDLE
*SimpleFileSystemHandles
;
1312 UINTN NumberSimpleFileSystemHandles
;
1315 UINT32 AuthenticationStatus
;
1318 // Check whether the device is connected
1320 TempDevicePath
= DevicePath
;
1321 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1322 if (!EFI_ERROR (Status
)) {
1323 ASSERT (IsDevicePathEnd (TempDevicePath
));
1325 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1326 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1327 if (FileBuffer
== NULL
) {
1328 FreePool (TempDevicePath
);
1329 TempDevicePath
= NULL
;
1331 *FullPath
= TempDevicePath
;
1336 // For device boot option only pointing to the removable device handle,
1337 // should make sure all its children handles (its child partion or media handles) are created and connected.
1339 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1342 // Issue a dummy read to the device to check for media change.
1343 // When the removable media is changed, any Block IO read/write will
1344 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1345 // returned. After the Block IO protocol is reinstalled, subsequent
1346 // Block IO read/write will success.
1348 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1349 ASSERT_EFI_ERROR (Status
);
1350 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1351 ASSERT_EFI_ERROR (Status
);
1352 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1353 if (Buffer
!= NULL
) {
1354 BlockIo
->ReadBlocks (
1356 BlockIo
->Media
->MediaId
,
1358 BlockIo
->Media
->BlockSize
,
1365 // Detect the the default boot file from removable Media
1369 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1370 gBS
->LocateHandleBuffer (
1372 &gEfiSimpleFileSystemProtocolGuid
,
1374 &NumberSimpleFileSystemHandles
,
1375 &SimpleFileSystemHandles
1377 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1379 // Get the device path size of SimpleFileSystem handle
1381 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1382 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1384 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1386 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1387 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1388 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1389 if (FileBuffer
!= NULL
) {
1390 *FullPath
= TempDevicePath
;
1393 FreePool (TempDevicePath
);
1397 if (SimpleFileSystemHandles
!= NULL
) {
1398 FreePool (SimpleFileSystemHandles
);
1405 Get the load option by its device path.
1407 @param FilePath The device path pointing to a load option.
1408 It could be a short-form device path.
1409 @param FullPath Return the full device path of the load option after
1410 short-form device path expanding.
1411 Caller is responsible to free it.
1412 @param FileSize Return the load option size.
1414 @return The load option buffer. Caller is responsible to free the memory.
1417 BmGetLoadOptionBuffer (
1418 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1419 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1425 UINT32 AuthenticationStatus
;
1426 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1429 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1431 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1438 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1441 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1442 if (EFI_ERROR (Status
)) {
1443 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1446 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1447 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1451 // Expand the short-form device path to full device path
1453 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1454 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1456 // Expand the Harddrive device path
1458 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1460 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1461 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1462 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1467 if (!IsDevicePathEnd (Node
)) {
1469 // Expand the USB WWID/Class device path
1471 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1472 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1474 // Boot Option device path starts with USB Class or USB WWID device path.
1475 // For Boot Option device path which doesn't begin with the USB Class or
1476 // USB WWID device path, it's not needed to connect again here.
1478 BmConnectUsbShortFormDevicePath (FilePath
);
1479 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1486 // Fix up the boot option path if it points to a FV in memory map style of device path
1488 if (BmIsMemmapFvFilePath (FilePath
)) {
1489 return BmGetFileBufferByMemmapFv (FilePath
, FullPath
, FileSize
);
1493 // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),
1494 // or it directly points to a file in simple file system instance.
1496 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1497 if (FileBuffer
!= NULL
) {
1498 *FullPath
= DuplicateDevicePath (FilePath
);
1505 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1506 also signals the EFI ready to boot event. If the device path for the option
1507 starts with a BBS device path a legacy boot is attempted via the registered
1508 gLegacyBoot function. Short form device paths are also supported via this
1509 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1510 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1511 If the BootOption Device Path fails the removable media boot algorithm
1512 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1513 is tried per processor type)
1515 @param BootOption Boot Option to try and boot.
1516 On return, BootOption->Status contains the boot status.
1517 EFI_SUCCESS BootOption was booted
1518 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1519 registered via EfiBootManagerInitialize().
1520 EFI_NOT_FOUND The BootOption was not found on the system
1521 !EFI_SUCCESS BootOption failed with this error status
1526 EfiBootManagerBoot (
1527 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1531 EFI_HANDLE ImageHandle
;
1532 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1535 UINTN OriginalOptionNumber
;
1536 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1537 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1538 EFI_HANDLE FvHandle
;
1541 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1542 EFI_EVENT LegacyBootEvent
;
1544 if (BootOption
== NULL
) {
1548 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1549 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1554 // 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")
1556 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1557 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1558 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1559 if (!EFI_ERROR (Status
)) {
1561 // Save the BootOption->OptionNumber to restore later
1563 OptionNumber
= Uint16
;
1564 OriginalOptionNumber
= BootOption
->OptionNumber
;
1565 BootOption
->OptionNumber
= OptionNumber
;
1566 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1567 BootOption
->OptionNumber
= OriginalOptionNumber
;
1570 if (EFI_ERROR (Status
)) {
1571 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1572 BootOption
->Status
= Status
;
1578 // 2. Set BootCurrent
1580 Uint16
= (UINT16
) OptionNumber
;
1581 BmSetVariableAndReportStatusCodeOnError (
1583 &gEfiGlobalVariableGuid
,
1584 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1590 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1593 Node
= BootOption
->FilePath
;
1594 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1595 if (!EFI_ERROR (Status
) && CompareGuid (
1596 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1597 PcdGetPtr (PcdBootManagerMenuFile
)
1599 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1600 BmStopHotkeyService (NULL
, NULL
);
1602 EfiSignalEventReadyToBoot();
1604 // Report Status Code to indicate ReadyToBoot was signalled
1606 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1608 // 4. Repair system through DriverHealth protocol
1610 BmRepairAllControllers ();
1613 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1616 // 5. Load EFI boot option to ImageHandle
1619 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1620 Status
= EFI_NOT_FOUND
;
1621 FileBuffer
= BmGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1623 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1624 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1625 BmPrintDp (BootOption
->FilePath
);
1626 DEBUG ((EFI_D_INFO
, " -> "));
1627 BmPrintDp (FilePath
);
1628 DEBUG ((EFI_D_INFO
, "\n"));
1631 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1632 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1633 Status
= gBS
->LoadImage (
1642 if (FileBuffer
!= NULL
) {
1643 FreePool (FileBuffer
);
1645 if (FilePath
!= NULL
) {
1646 FreePool (FilePath
);
1649 if (EFI_ERROR (Status
)) {
1651 // Report Status Code to indicate that the failure to load boot option
1653 REPORT_STATUS_CODE (
1654 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1655 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1657 BootOption
->Status
= Status
;
1663 // 6. Adjust the different type memory page number just before booting
1664 // and save the updated info into the variable for next boot to use
1666 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
) {
1667 if (PcdGetBool (PcdResetOnMemoryTypeInformationChange
)) {
1668 BmSetMemoryTypeInformationVariable ();
1673 if (BootOption
->Description
== NULL
) {
1674 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1676 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1681 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1682 // Write boot to OS performance data for Legacy boot
1684 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1685 if (mBmLegacyBoot
!= NULL
) {
1687 // Write boot to OS performance data for legacy boot.
1691 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1693 Status
= EfiCreateEventLegacyBootEx(
1695 BmWriteBootToOsPerformanceData
,
1699 ASSERT_EFI_ERROR (Status
);
1702 mBmLegacyBoot (BootOption
);
1704 BootOption
->Status
= EFI_UNSUPPORTED
;
1707 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1712 // Provide the image with its load options
1714 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1715 ASSERT_EFI_ERROR (Status
);
1717 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1718 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1721 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1723 ImageInfo
->ParentHandle
= NULL
;
1726 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1728 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1731 // Write boot to OS performance data for UEFI boot
1734 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1737 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1739 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1740 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1741 BootOption
->Status
= Status
;
1742 if (EFI_ERROR (Status
)) {
1744 // Report Status Code to indicate that boot failure
1746 REPORT_STATUS_CODE (
1747 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1748 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1751 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1754 // Clear the Watchdog Timer after the image returns
1756 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1759 // Set Logo status invalid after trying one boot option
1762 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1763 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1764 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1765 ASSERT_EFI_ERROR (Status
);
1769 // Clear Boot Current
1771 Status
= gRT
->SetVariable (
1773 &gEfiGlobalVariableGuid
,
1779 // Deleting variable with current variable implementation shouldn't fail.
1780 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1781 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1783 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1787 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1788 instances, has the same partition node with HardDriveDevicePath device path
1790 @param BlockIoDevicePath Multi device path instances which need to check
1791 @param HardDriveDevicePath A device path which starts with a hard drive media
1794 @retval TRUE There is a matched device path instance.
1795 @retval FALSE There is no matched device path instance.
1799 BmMatchPartitionDevicePathNode (
1800 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1801 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1804 HARDDRIVE_DEVICE_PATH
*Node
;
1806 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1811 // find the partition device path node
1813 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1814 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1815 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1820 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1823 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1828 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1830 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1833 // Match Signature and PartitionNumber.
1834 // Unused bytes in Signature are initiaized with zeros.
1837 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1838 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1839 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1840 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1845 Emuerate all possible bootable medias in the following order:
1846 1. Removable BlockIo - The boot option only points to the removable media
1847 device, like USB key, DVD, Floppy etc.
1848 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1850 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1851 SimpleFileSystem Protocol, but not supporting BlockIo
1853 4. LoadFile - The boot option points to the media supporting
1855 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1857 @param BootOptionCount Return the boot option count which has been found.
1859 @retval Pointer to the boot option array.
1861 EFI_BOOT_MANAGER_LOAD_OPTION
*
1862 BmEnumerateBootOptions (
1863 UINTN
*BootOptionCount
1867 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1869 EFI_HANDLE
*Handles
;
1870 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
1873 CHAR16
*Description
;
1875 ASSERT (BootOptionCount
!= NULL
);
1877 *BootOptionCount
= 0;
1881 // Parse removable block io followed by fixed block io
1883 gBS
->LocateHandleBuffer (
1885 &gEfiBlockIoProtocolGuid
,
1891 for (Removable
= 0; Removable
< 2; Removable
++) {
1892 for (Index
= 0; Index
< HandleCount
; Index
++) {
1893 Status
= gBS
->HandleProtocol (
1895 &gEfiBlockIoProtocolGuid
,
1898 if (EFI_ERROR (Status
)) {
1903 // Skip the logical partitions
1905 if (BlkIo
->Media
->LogicalPartition
) {
1910 // Skip the fixed block io then the removable block io
1912 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
1916 Description
= BmGetBootDescription (Handles
[Index
]);
1917 BootOptions
= ReallocatePool (
1918 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1919 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1922 ASSERT (BootOptions
!= NULL
);
1924 Status
= EfiBootManagerInitializeLoadOption (
1925 &BootOptions
[(*BootOptionCount
)++],
1926 LoadOptionNumberUnassigned
,
1930 DevicePathFromHandle (Handles
[Index
]),
1934 ASSERT_EFI_ERROR (Status
);
1936 FreePool (Description
);
1940 if (HandleCount
!= 0) {
1945 // Parse simple file system not based on block io
1947 gBS
->LocateHandleBuffer (
1949 &gEfiSimpleFileSystemProtocolGuid
,
1954 for (Index
= 0; Index
< HandleCount
; Index
++) {
1955 Status
= gBS
->HandleProtocol (
1957 &gEfiBlockIoProtocolGuid
,
1960 if (!EFI_ERROR (Status
)) {
1962 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
1966 Description
= BmGetBootDescription (Handles
[Index
]);
1967 BootOptions
= ReallocatePool (
1968 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1969 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1972 ASSERT (BootOptions
!= NULL
);
1974 Status
= EfiBootManagerInitializeLoadOption (
1975 &BootOptions
[(*BootOptionCount
)++],
1976 LoadOptionNumberUnassigned
,
1980 DevicePathFromHandle (Handles
[Index
]),
1984 ASSERT_EFI_ERROR (Status
);
1985 FreePool (Description
);
1988 if (HandleCount
!= 0) {
1993 // Parse load file, assuming UEFI Network boot option
1995 gBS
->LocateHandleBuffer (
1997 &gEfiLoadFileProtocolGuid
,
2002 for (Index
= 0; Index
< HandleCount
; Index
++) {
2004 Description
= BmGetBootDescription (Handles
[Index
]);
2005 BootOptions
= ReallocatePool (
2006 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2007 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2010 ASSERT (BootOptions
!= NULL
);
2012 Status
= EfiBootManagerInitializeLoadOption (
2013 &BootOptions
[(*BootOptionCount
)++],
2014 LoadOptionNumberUnassigned
,
2018 DevicePathFromHandle (Handles
[Index
]),
2022 ASSERT_EFI_ERROR (Status
);
2023 FreePool (Description
);
2026 if (HandleCount
!= 0) {
2034 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2038 EfiBootManagerRefreshAllBootOption (
2043 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2044 UINTN NvBootOptionCount
;
2045 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2046 UINTN BootOptionCount
;
2050 // Optionally refresh the legacy boot option
2052 if (mBmRefreshLegacyBootOption
!= NULL
) {
2053 mBmRefreshLegacyBootOption ();
2056 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2057 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2060 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2062 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2063 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2064 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2068 // Remove invalid EFI boot options from NV
2070 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2071 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2072 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2074 (NvBootOptions
[Index
].OptionalDataSize
== sizeof (EFI_GUID
)) &&
2075 CompareGuid ((EFI_GUID
*) NvBootOptions
[Index
].OptionalData
, &mBmAutoCreateBootOptionGuid
)
2078 // Only check those added by BDS
2079 // so that the boot options added by end-user or OS installer won't be deleted
2081 if (BmFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
2082 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2084 // Deleting variable with current variable implementation shouldn't fail.
2086 ASSERT_EFI_ERROR (Status
);
2092 // Add new EFI boot options to NV
2094 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2095 if (BmFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
2096 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2098 // Try best to add the boot options so continue upon failure.
2103 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2104 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2108 This function is called to create the boot option for the Boot Manager Menu.
2110 The Boot Manager Menu is shown after successfully booting a boot option.
2111 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2113 @param BootOption Return the boot option of the Boot Manager Menu
2115 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2116 @retval Status Return status of gRT->SetVariable (). BootOption still points
2117 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2120 BmRegisterBootManagerMenu (
2121 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2125 CHAR16
*Description
;
2126 UINTN DescriptionLength
;
2127 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2128 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2129 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2131 Status
= GetSectionFromFv (
2132 PcdGetPtr (PcdBootManagerMenuFile
),
2133 EFI_SECTION_USER_INTERFACE
,
2135 (VOID
**) &Description
,
2138 if (EFI_ERROR (Status
)) {
2142 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2143 Status
= gBS
->HandleProtocol (
2145 &gEfiLoadedImageProtocolGuid
,
2146 (VOID
**) &LoadedImage
2148 ASSERT_EFI_ERROR (Status
);
2149 DevicePath
= AppendDevicePathNode (
2150 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2151 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2153 ASSERT (DevicePath
!= NULL
);
2155 Status
= EfiBootManagerInitializeLoadOption (
2157 LoadOptionNumberUnassigned
,
2159 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2160 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2165 ASSERT_EFI_ERROR (Status
);
2166 FreePool (DevicePath
);
2167 if (Description
!= NULL
) {
2168 FreePool (Description
);
2172 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2173 UINTN BootOptionCount
;
2175 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2176 ASSERT (BmFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2177 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2180 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2184 Return the boot option corresponding to the Boot Manager Menu.
2185 It may automatically create one if the boot option hasn't been created yet.
2187 @param BootOption Return the Boot Manager Menu.
2189 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2190 @retval Status Return status of gRT->SetVariable (). BootOption still points
2191 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2195 EfiBootManagerGetBootManagerMenu (
2196 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2200 UINTN BootOptionCount
;
2201 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2203 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2204 EFI_HANDLE FvHandle
;
2206 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2208 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2209 Node
= BootOptions
[Index
].FilePath
;
2210 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2211 if (!EFI_ERROR (Status
)) {
2213 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2214 PcdGetPtr (PcdBootManagerMenuFile
)
2217 Status
= EfiBootManagerInitializeLoadOption (
2219 BootOptions
[Index
].OptionNumber
,
2220 BootOptions
[Index
].OptionType
,
2221 BootOptions
[Index
].Attributes
,
2222 BootOptions
[Index
].Description
,
2223 BootOptions
[Index
].FilePath
,
2224 BootOptions
[Index
].OptionalData
,
2225 BootOptions
[Index
].OptionalDataSize
2227 ASSERT_EFI_ERROR (Status
);
2233 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2236 // Automatically create the Boot#### for Boot Manager Menu when not found.
2238 if (Index
== BootOptionCount
) {
2239 return BmRegisterBootManagerMenu (BootOption
);