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 MessageHttpBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
73 and its last device path node's subtype is MSG_URI_DP.
74 @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.
79 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
82 EFI_DEVICE_PATH_PROTOCOL
*Node
;
83 EFI_DEVICE_PATH_PROTOCOL
*NextNode
;
85 ASSERT (DevicePath
!= NULL
);
87 for (Node
= DevicePath
; !IsDevicePathEndType (Node
); Node
= NextDevicePathNode (Node
)) {
88 switch (DevicePathType (Node
)) {
90 case ACPI_DEVICE_PATH
:
91 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH
*) Node
)->HID
) == 0x0604) {
92 return BmAcpiFloppyBoot
;
96 case HARDWARE_DEVICE_PATH
:
97 if (DevicePathSubType (Node
) == HW_CONTROLLER_DP
) {
98 return BmHardwareDeviceBoot
;
102 case MESSAGING_DEVICE_PATH
:
104 // Skip LUN device node
108 NextNode
= NextDevicePathNode (NextNode
);
110 (DevicePathType (NextNode
) == MESSAGING_DEVICE_PATH
) &&
111 (DevicePathSubType(NextNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
)
115 // If the device path not only point to driver device, it is not a messaging device path,
117 if (!IsDevicePathEndType (NextNode
)) {
121 switch (DevicePathSubType (Node
)) {
123 return BmMessageAtapiBoot
;
127 return BmMessageSataBoot
;
131 return BmMessageUsbBoot
;
135 return BmMessageScsiBoot
;
138 case MSG_MAC_ADDR_DP
:
142 return BmMessageNetworkBoot
;
146 return BmMessageHttpBoot
;
156 Find the boot option in the NV storage and return the option number.
158 @param OptionToFind Boot option to be checked.
160 @return The option number of the found boot option.
164 BmFindBootOptionInVariable (
165 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
169 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
171 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
172 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
173 UINTN BootOptionCount
;
176 OptionNumber
= LoadOptionNumberUnassigned
;
179 // Try to match the variable exactly if the option number is assigned
181 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
183 OptionName
, sizeof (OptionName
), L
"%s%04x",
184 mBmLoadOptionName
[OptionToFind
->OptionType
], OptionToFind
->OptionNumber
186 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
188 if (!EFI_ERROR (Status
)) {
189 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
190 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
191 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
192 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
193 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
194 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
196 OptionNumber
= OptionToFind
->OptionNumber
;
198 EfiBootManagerFreeLoadOption (&BootOption
);
203 // The option number assigned is either incorrect or unassigned.
205 if (OptionNumber
== LoadOptionNumberUnassigned
) {
206 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
208 Index
= BmFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
210 OptionNumber
= BootOptions
[Index
].OptionNumber
;
213 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
220 Get the file buffer using a Memory Mapped Device Path.
222 FV address may change across reboot. This routine promises the FV file device path is right.
224 @param DevicePath The Memory Mapped Device Path to get the file buffer.
225 @param FullPath Receive the updated FV Device Path pointint to the file.
226 @param FileSize Receive the file buffer size.
228 @return The file buffer.
231 BmGetFileBufferByMemmapFv (
232 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
233 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
239 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
241 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
242 UINT32 AuthenticationStatus
;
244 EFI_HANDLE
*FvHandles
;
245 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
248 FvFileNode
= DevicePath
;
249 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
250 if (!EFI_ERROR (Status
)) {
251 FileBuffer
= GetFileBufferByFilePath (TRUE
, DevicePath
, FileSize
, &AuthenticationStatus
);
252 if (FileBuffer
!= NULL
) {
253 *FullPath
= DuplicateDevicePath (DevicePath
);
258 FvFileNode
= NextDevicePathNode (DevicePath
);
261 // Firstly find the FV file in current FV
263 gBS
->HandleProtocol (
265 &gEfiLoadedImageProtocolGuid
,
266 (VOID
**) &LoadedImage
268 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
269 FileBuffer
= BmGetFileBufferByMemmapFv (NewDevicePath
, FullPath
, FileSize
);
270 FreePool (NewDevicePath
);
272 if (FileBuffer
!= NULL
) {
277 // Secondly find the FV file in all other FVs
279 gBS
->LocateHandleBuffer (
281 &gEfiFirmwareVolume2ProtocolGuid
,
286 for (Index
= 0; (Index
< FvHandleCount
) && (FileBuffer
== NULL
); Index
++) {
287 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
293 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
294 FileBuffer
= BmGetFileBufferByMemmapFv (NewDevicePath
, FullPath
, FileSize
);
295 FreePool (NewDevicePath
);
298 if (FvHandles
!= NULL
) {
299 FreePool (FvHandles
);
305 Check if it's a Memory Mapped FV Device Path.
307 The function doesn't garentee the device path points to existing FV file.
309 @param DevicePath Input device path.
311 @retval TRUE The device path is a Memory Mapped FV Device Path.
312 @retval FALSE The device path is NOT a Memory Mapped FV Device Path.
315 BmIsMemmapFvFilePath (
316 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
319 EFI_DEVICE_PATH_PROTOCOL
*FileNode
;
321 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
322 FileNode
= NextDevicePathNode (DevicePath
);
323 if ((DevicePathType (FileNode
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (FileNode
) == MEDIA_PIWG_FW_FILE_DP
)) {
324 return IsDevicePathEnd (NextDevicePathNode (FileNode
));
332 Check whether a USB device match the specified USB Class device path. This
333 function follows "Load Option Processing" behavior in UEFI specification.
335 @param UsbIo USB I/O protocol associated with the USB device.
336 @param UsbClass The USB Class device path to match.
338 @retval TRUE The USB device match the USB Class device path.
339 @retval FALSE The USB device does not match the USB Class device path.
344 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
345 IN USB_CLASS_DEVICE_PATH
*UsbClass
349 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
350 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
352 UINT8 DeviceSubClass
;
353 UINT8 DeviceProtocol
;
355 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
356 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
361 // Check Vendor Id and Product Id.
363 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
364 if (EFI_ERROR (Status
)) {
368 if ((UsbClass
->VendorId
!= 0xffff) &&
369 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
373 if ((UsbClass
->ProductId
!= 0xffff) &&
374 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
378 DeviceClass
= DevDesc
.DeviceClass
;
379 DeviceSubClass
= DevDesc
.DeviceSubClass
;
380 DeviceProtocol
= DevDesc
.DeviceProtocol
;
381 if (DeviceClass
== 0) {
383 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
384 // Protocol in Interface Descriptor instead.
386 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
387 if (EFI_ERROR (Status
)) {
391 DeviceClass
= IfDesc
.InterfaceClass
;
392 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
393 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
397 // Check Class, SubClass and Protocol.
399 if ((UsbClass
->DeviceClass
!= 0xff) &&
400 (UsbClass
->DeviceClass
!= DeviceClass
)) {
404 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
405 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
409 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
410 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
418 Eliminate the extra spaces in the Str to one space.
420 @param Str Input string info.
423 BmEliminateExtraSpaces (
430 for (Index
= 0, ActualIndex
= 0; Str
[Index
] != L
'\0'; Index
++) {
431 if ((Str
[Index
] != L
' ') || ((ActualIndex
> 0) && (Str
[ActualIndex
- 1] != L
' '))) {
432 Str
[ActualIndex
++] = Str
[Index
];
435 Str
[ActualIndex
] = L
'\0';
439 Try to get the controller's ATA/ATAPI description.
441 @param Handle Controller handle.
443 @return The description string.
446 BmGetDescriptionFromDiskInfo (
452 EFI_DISK_INFO_PROTOCOL
*DiskInfo
;
454 EFI_ATAPI_IDENTIFY_DATA IdentifyData
;
455 EFI_SCSI_INQUIRY_DATA InquiryData
;
458 CONST UINTN ModelNameLength
= 40;
459 CONST UINTN SerialNumberLength
= 20;
465 Status
= gBS
->HandleProtocol (
467 &gEfiDiskInfoProtocolGuid
,
470 if (EFI_ERROR (Status
)) {
474 if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoAhciInterfaceGuid
) ||
475 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoIdeInterfaceGuid
)) {
476 BufferSize
= sizeof (EFI_ATAPI_IDENTIFY_DATA
);
477 Status
= DiskInfo
->Identify (
482 if (!EFI_ERROR (Status
)) {
483 Description
= AllocateZeroPool ((ModelNameLength
+ SerialNumberLength
+ 2) * sizeof (CHAR16
));
484 ASSERT (Description
!= NULL
);
485 for (Index
= 0; Index
+ 1 < ModelNameLength
; Index
+= 2) {
486 Description
[Index
] = (CHAR16
) IdentifyData
.ModelName
[Index
+ 1];
487 Description
[Index
+ 1] = (CHAR16
) IdentifyData
.ModelName
[Index
];
491 Description
[Length
++] = L
' ';
493 for (Index
= 0; Index
+ 1 < SerialNumberLength
; Index
+= 2) {
494 Description
[Length
+ Index
] = (CHAR16
) IdentifyData
.SerialNo
[Index
+ 1];
495 Description
[Length
+ Index
+ 1] = (CHAR16
) IdentifyData
.SerialNo
[Index
];
498 Description
[Length
++] = L
'\0';
499 ASSERT (Length
== ModelNameLength
+ SerialNumberLength
+ 2);
501 BmEliminateExtraSpaces (Description
);
503 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
504 BufferSize
= sizeof (EFI_SCSI_INQUIRY_DATA
);
505 Status
= DiskInfo
->Inquiry (
510 if (!EFI_ERROR (Status
)) {
511 Description
= AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2) * sizeof (CHAR16
));
512 ASSERT (Description
!= NULL
);
515 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
516 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
517 // Here combine the vendor identification and product identification to the description.
519 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
]);
520 Temp
= StrPtr
[VENDOR_IDENTIFICATION_LENGTH
];
521 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = '\0';
522 AsciiStrToUnicodeStr (StrPtr
, Description
);
523 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = Temp
;
526 // Add one space at the middle of vendor information and product information.
528 Description
[VENDOR_IDENTIFICATION_LENGTH
] = L
' ';
530 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
]);
531 StrPtr
[PRODUCT_IDENTIFICATION_LENGTH
] = '\0';
532 AsciiStrToUnicodeStr (StrPtr
, Description
+ VENDOR_IDENTIFICATION_LENGTH
+ 1);
534 BmEliminateExtraSpaces (Description
);
542 Try to get the controller's USB description.
544 @param Handle Controller handle.
546 @return The description string.
549 BmGetUsbDescription (
554 EFI_USB_IO_PROTOCOL
*UsbIo
;
556 CHAR16
*Manufacturer
;
558 CHAR16
*SerialNumber
;
560 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
563 Status
= gBS
->HandleProtocol (
565 &gEfiUsbIoProtocolGuid
,
568 if (EFI_ERROR (Status
)) {
574 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
575 if (EFI_ERROR (Status
)) {
579 Status
= UsbIo
->UsbGetStringDescriptor (
582 DevDesc
.StrManufacturer
,
585 if (EFI_ERROR (Status
)) {
586 Manufacturer
= &NullChar
;
589 Status
= UsbIo
->UsbGetStringDescriptor (
595 if (EFI_ERROR (Status
)) {
599 Status
= UsbIo
->UsbGetStringDescriptor (
602 DevDesc
.StrSerialNumber
,
605 if (EFI_ERROR (Status
)) {
606 SerialNumber
= &NullChar
;
609 if ((Manufacturer
== &NullChar
) &&
610 (Product
== &NullChar
) &&
611 (SerialNumber
== &NullChar
)
616 DescMaxSize
= StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
);
617 Description
= AllocateZeroPool (DescMaxSize
);
618 ASSERT (Description
!= NULL
);
619 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Manufacturer
);
620 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
622 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Product
);
623 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
625 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), SerialNumber
);
627 if (Manufacturer
!= &NullChar
) {
628 FreePool (Manufacturer
);
630 if (Product
!= &NullChar
) {
633 if (SerialNumber
!= &NullChar
) {
634 FreePool (SerialNumber
);
637 BmEliminateExtraSpaces (Description
);
643 Return the boot description for the controller based on the type.
645 @param Handle Controller handle.
647 @return The description string.
650 BmGetMiscDescription (
656 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
657 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
659 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
660 case BmAcpiFloppyBoot
:
661 Description
= L
"Floppy";
664 case BmMessageAtapiBoot
:
665 case BmMessageSataBoot
:
666 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
667 ASSERT_EFI_ERROR (Status
);
669 // Assume a removable SATA device should be the DVD/CD device
671 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
674 case BmMessageUsbBoot
:
675 Description
= L
"USB Device";
678 case BmMessageScsiBoot
:
679 Description
= L
"SCSI Device";
682 case BmHardwareDeviceBoot
:
683 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
684 if (!EFI_ERROR (Status
)) {
685 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
687 Description
= L
"Misc Device";
691 case BmMessageNetworkBoot
:
692 Description
= L
"Network";
695 case BmMessageHttpBoot
:
696 Description
= L
"Http";
700 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**) &Fs
);
701 if (!EFI_ERROR (Status
)) {
702 Description
= L
"Non-Block Boot Device";
704 Description
= L
"Misc Device";
709 return AllocateCopyPool (StrSize (Description
), Description
);
713 Register the platform provided boot description handler.
715 @param Handler The platform provided boot description handler
717 @retval EFI_SUCCESS The handler was registered successfully.
718 @retval EFI_ALREADY_STARTED The handler was already registered.
719 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
723 EfiBootManagerRegisterBootDescriptionHandler (
724 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
728 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
730 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
731 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
732 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
734 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
735 if (Entry
->Handler
== Handler
) {
736 return EFI_ALREADY_STARTED
;
740 Entry
= AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY
));
742 return EFI_OUT_OF_RESOURCES
;
745 Entry
->Signature
= BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
;
746 Entry
->Handler
= Handler
;
747 InsertTailList (&mPlatformBootDescriptionHandlers
, &Entry
->Link
);
751 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers
[] = {
753 BmGetDescriptionFromDiskInfo
,
758 Return the boot description for the controller.
760 @param Handle Controller handle.
762 @return The description string.
765 BmGetBootDescription (
770 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
772 CHAR16
*DefaultDescription
;
777 // Firstly get the default boot description
779 DefaultDescription
= NULL
;
780 for (Index
= 0; Index
< sizeof (mBmBootDescriptionHandlers
) / sizeof (mBmBootDescriptionHandlers
[0]); Index
++) {
781 DefaultDescription
= mBmBootDescriptionHandlers
[Index
] (Handle
);
782 if (DefaultDescription
!= NULL
) {
784 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
785 // ONLY for core provided boot description handler.
787 Temp
= AllocatePool (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
));
788 ASSERT (Temp
!= NULL
);
790 (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
))/sizeof(CHAR16
),
794 (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
))/sizeof(CHAR16
),
797 FreePool (DefaultDescription
);
798 DefaultDescription
= Temp
;
802 ASSERT (DefaultDescription
!= NULL
);
805 // Secondly query platform for the better boot description
807 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
808 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
809 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
811 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
812 Description
= Entry
->Handler (Handle
, DefaultDescription
);
813 if (Description
!= NULL
) {
814 FreePool (DefaultDescription
);
819 return DefaultDescription
;
823 Check whether a USB device match the specified USB WWID device path. This
824 function follows "Load Option Processing" behavior in UEFI specification.
826 @param UsbIo USB I/O protocol associated with the USB device.
827 @param UsbWwid The USB WWID device path to match.
829 @retval TRUE The USB device match the USB WWID device path.
830 @retval FALSE The USB device does not match the USB WWID device path.
835 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
836 IN USB_WWID_DEVICE_PATH
*UsbWwid
840 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
841 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
847 CHAR16
*SerialNumberStr
;
850 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
851 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
856 // Check Vendor Id and Product Id.
858 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
859 if (EFI_ERROR (Status
)) {
862 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
863 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
868 // Check Interface Number.
870 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
871 if (EFI_ERROR (Status
)) {
874 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
879 // Check Serial Number.
881 if (DevDesc
.StrSerialNumber
== 0) {
886 // Get all supported languages.
890 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
891 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
896 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
898 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
899 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
900 if (CompareStr
[CompareLen
- 1] == L
'\0') {
905 // Compare serial number in each supported language.
907 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
908 SerialNumberStr
= NULL
;
909 Status
= UsbIo
->UsbGetStringDescriptor (
912 DevDesc
.StrSerialNumber
,
915 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
919 Length
= StrLen (SerialNumberStr
);
920 if ((Length
>= CompareLen
) &&
921 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
922 FreePool (SerialNumberStr
);
926 FreePool (SerialNumberStr
);
933 Find a USB device which match the specified short-form device path start with
934 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
935 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
936 this function will only search in its child devices.
938 @param DevicePath The device path that contains USB Class or USB WWID device path.
939 @param ParentDevicePathSize The length of the device path before the USB Class or
940 USB WWID device path.
941 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
943 @retval NULL The matched USB IO handles cannot be found.
944 @retval other The matched USB IO handles.
949 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
950 IN UINTN ParentDevicePathSize
,
951 OUT UINTN
*UsbIoHandleCount
955 EFI_HANDLE
*UsbIoHandles
;
956 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
957 EFI_USB_IO_PROTOCOL
*UsbIo
;
959 UINTN UsbIoDevicePathSize
;
962 ASSERT (UsbIoHandleCount
!= NULL
);
965 // Get all UsbIo Handles.
967 Status
= gBS
->LocateHandleBuffer (
969 &gEfiUsbIoProtocolGuid
,
974 if (EFI_ERROR (Status
)) {
975 *UsbIoHandleCount
= 0;
979 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
981 // Get the Usb IO interface.
983 Status
= gBS
->HandleProtocol(
985 &gEfiUsbIoProtocolGuid
,
988 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
990 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
991 UsbIoDevicePathSize
= GetDevicePathSize (UsbIoDevicePath
) - END_DEVICE_PATH_LENGTH
;
994 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
996 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
997 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
998 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
1005 (*UsbIoHandleCount
) --;
1006 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
1012 return UsbIoHandles
;
1016 Expand USB Class or USB WWID device path node to be full device path of a USB
1019 This function support following 4 cases:
1020 1) Boot Option device path starts with a USB Class or USB WWID device path,
1021 and there is no Media FilePath device path in the end.
1022 In this case, it will follow Removable Media Boot Behavior.
1023 2) Boot Option device path starts with a USB Class or USB WWID device path,
1024 and ended with Media FilePath device path.
1025 3) Boot Option device path starts with a full device path to a USB Host Controller,
1026 contains a USB Class or USB WWID device path node, while not ended with Media
1027 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
1028 4) Boot Option device path starts with a full device path to a USB Host Controller,
1029 contains a USB Class or USB WWID device path node, and ended with Media
1030 FilePath device path.
1032 @param FilePath The device path pointing to a load option.
1033 It could be a short-form device path.
1034 @param FullPath Return the full device path of the load option after
1035 short-form device path expanding.
1036 Caller is responsible to free it.
1037 @param FileSize Return the load option size.
1038 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
1040 @return The load option buffer. Caller is responsible to free the memory.
1043 BmExpandUsbDevicePath (
1044 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1045 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1046 OUT UINTN
*FileSize
,
1047 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
1050 UINTN ParentDevicePathSize
;
1051 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
1052 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
1053 EFI_HANDLE
*Handles
;
1058 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
1059 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
1061 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
1063 for (Index
= 0; (Index
< HandleCount
) && (FileBuffer
== NULL
); Index
++) {
1064 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
1065 FileBuffer
= BmGetLoadOptionBuffer (FullDevicePath
, FullPath
, FileSize
);
1066 FreePool (FullDevicePath
);
1069 if (Handles
!= NULL
) {
1077 Save the partition DevicePath to the CachedDevicePath as the first instance.
1079 @param CachedDevicePath The device path cache.
1080 @param DevicePath The partition device path to be cached.
1083 BmCachePartitionDevicePath (
1084 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
1085 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1088 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1091 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
1092 TempDevicePath
= *CachedDevicePath
;
1093 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
1094 FreePool (TempDevicePath
);
1097 if (*CachedDevicePath
== NULL
) {
1098 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
1102 TempDevicePath
= *CachedDevicePath
;
1103 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
1104 if (TempDevicePath
!= NULL
) {
1105 FreePool (TempDevicePath
);
1109 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
1110 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
1113 TempDevicePath
= *CachedDevicePath
;
1114 while (!IsDevicePathEnd (TempDevicePath
)) {
1115 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1117 // Parse one instance
1119 while (!IsDevicePathEndType (TempDevicePath
)) {
1120 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1124 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
1127 SetDevicePathEndNode (TempDevicePath
);
1134 Expand a device path that starts with a hard drive media device path node to be a
1135 full device path that includes the full hardware path to the device. We need
1136 to do this so it can be booted. As an optimization the front match (the part point
1137 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
1138 so a connect all is not required on every boot. All successful history device path
1139 which point to partition node (the front part) will be saved.
1141 @param FilePath The device path pointing to a load option.
1142 It could be a short-form device path.
1143 @param FullPath Return the full device path of the load option after
1144 short-form device path expanding.
1145 Caller is responsible to free it.
1146 @param FileSize Return the load option size.
1148 @return The load option buffer. Caller is responsible to free the memory.
1151 BmExpandPartitionDevicePath (
1152 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1153 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1158 UINTN BlockIoHandleCount
;
1159 EFI_HANDLE
*BlockIoBuffer
;
1161 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
1163 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
1164 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
1165 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1166 UINTN CachedDevicePathSize
;
1168 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1173 // Check if there is prestore 'HDDP' variable.
1174 // If exist, search the front path which point to partition node in the variable instants.
1175 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
1177 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
1180 // Delete the invalid 'HDDP' variable.
1182 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
1183 FreePool (CachedDevicePath
);
1184 CachedDevicePath
= NULL
;
1185 Status
= gRT
->SetVariable (
1187 &mBmHardDriveBootVariableGuid
,
1192 ASSERT_EFI_ERROR (Status
);
1195 if (CachedDevicePath
!= NULL
) {
1196 TempNewDevicePath
= CachedDevicePath
;
1200 // Check every instance of the variable
1201 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
1202 // partial partition boot option. Second, check whether the instance could be connected.
1204 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
1205 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1207 // Connect the device path instance, the device path point to hard drive media device path node
1208 // e.g. ACPI() /PCI()/ATA()/Partition()
1210 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
1211 if (!EFI_ERROR (Status
)) {
1212 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
1213 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1214 FreePool (TempDevicePath
);
1216 if (FileBuffer
!= NULL
) {
1218 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
1221 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
1223 // Save the matching Device Path so we don't need to do a connect all next time
1224 // Failing to save only impacts performance next time expanding the short-form device path
1226 Status
= gRT
->SetVariable (
1228 &mBmHardDriveBootVariableGuid
,
1229 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1230 GetDevicePathSize (CachedDevicePath
),
1235 FreePool (Instance
);
1236 FreePool (CachedDevicePath
);
1242 // Come here means the first instance is not matched
1246 } while (TempNewDevicePath
!= NULL
);
1250 // If we get here we fail to find or 'HDDP' not exist, and now we need
1251 // to search all devices in the system for a matched partition
1253 EfiBootManagerConnectAll ();
1254 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
1255 if (EFI_ERROR (Status
)) {
1256 BlockIoHandleCount
= 0;
1257 BlockIoBuffer
= NULL
;
1260 // Loop through all the device handles that support the BLOCK_IO Protocol
1262 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
1263 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
1264 if (BlockIoDevicePath
== NULL
) {
1268 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1270 // Find the matched partition device path
1272 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
1273 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1274 FreePool (TempDevicePath
);
1276 if (FileBuffer
!= NULL
) {
1277 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
1280 // Save the matching Device Path so we don't need to do a connect all next time
1281 // Failing to save only impacts performance next time expanding the short-form device path
1283 Status
= gRT
->SetVariable (
1285 &mBmHardDriveBootVariableGuid
,
1286 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1287 GetDevicePathSize (CachedDevicePath
),
1296 if (CachedDevicePath
!= NULL
) {
1297 FreePool (CachedDevicePath
);
1299 if (BlockIoBuffer
!= NULL
) {
1300 FreePool (BlockIoBuffer
);
1306 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
1307 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1309 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1310 @param FullPath Return the full device path pointing to the load option.
1311 @param FileSize Return the size of the load option.
1313 @return The load option buffer.
1316 BmExpandMediaDevicePath (
1317 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1318 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1324 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1326 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1329 EFI_HANDLE
*SimpleFileSystemHandles
;
1330 UINTN NumberSimpleFileSystemHandles
;
1333 UINT32 AuthenticationStatus
;
1336 // Check whether the device is connected
1338 TempDevicePath
= DevicePath
;
1339 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1340 if (!EFI_ERROR (Status
)) {
1341 ASSERT (IsDevicePathEnd (TempDevicePath
));
1343 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1344 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1345 if (FileBuffer
== NULL
) {
1346 FreePool (TempDevicePath
);
1347 TempDevicePath
= NULL
;
1349 *FullPath
= TempDevicePath
;
1354 // For device boot option only pointing to the removable device handle,
1355 // should make sure all its children handles (its child partion or media handles) are created and connected.
1357 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1360 // Issue a dummy read to the device to check for media change.
1361 // When the removable media is changed, any Block IO read/write will
1362 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1363 // returned. After the Block IO protocol is reinstalled, subsequent
1364 // Block IO read/write will success.
1366 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1367 ASSERT_EFI_ERROR (Status
);
1368 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1369 ASSERT_EFI_ERROR (Status
);
1370 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1371 if (Buffer
!= NULL
) {
1372 BlockIo
->ReadBlocks (
1374 BlockIo
->Media
->MediaId
,
1376 BlockIo
->Media
->BlockSize
,
1383 // Detect the the default boot file from removable Media
1387 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1388 gBS
->LocateHandleBuffer (
1390 &gEfiSimpleFileSystemProtocolGuid
,
1392 &NumberSimpleFileSystemHandles
,
1393 &SimpleFileSystemHandles
1395 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1397 // Get the device path size of SimpleFileSystem handle
1399 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1400 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1402 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1404 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1405 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1406 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1407 if (FileBuffer
!= NULL
) {
1408 *FullPath
= TempDevicePath
;
1411 FreePool (TempDevicePath
);
1415 if (SimpleFileSystemHandles
!= NULL
) {
1416 FreePool (SimpleFileSystemHandles
);
1423 Get the load option by its device path.
1425 @param FilePath The device path pointing to a load option.
1426 It could be a short-form device path.
1427 @param FullPath Return the full device path of the load option after
1428 short-form device path expanding.
1429 Caller is responsible to free it.
1430 @param FileSize Return the load option size.
1432 @return The load option buffer. Caller is responsible to free the memory.
1435 BmGetLoadOptionBuffer (
1436 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1437 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1443 UINT32 AuthenticationStatus
;
1444 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1447 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1449 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1456 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1459 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1460 if (EFI_ERROR (Status
)) {
1461 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1464 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1465 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1469 // Expand the short-form device path to full device path
1471 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1472 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1474 // Expand the Harddrive device path
1476 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1478 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1479 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1480 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1485 if (!IsDevicePathEnd (Node
)) {
1487 // Expand the USB WWID/Class device path
1489 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1490 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1492 // Boot Option device path starts with USB Class or USB WWID device path.
1493 // For Boot Option device path which doesn't begin with the USB Class or
1494 // USB WWID device path, it's not needed to connect again here.
1496 BmConnectUsbShortFormDevicePath (FilePath
);
1497 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1504 // Fix up the boot option path if it points to a FV in memory map style of device path
1506 if (BmIsMemmapFvFilePath (FilePath
)) {
1507 return BmGetFileBufferByMemmapFv (FilePath
, FullPath
, FileSize
);
1511 // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),
1512 // or it directly points to a file in simple file system instance.
1515 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1516 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1517 if (FileBuffer
!= NULL
) {
1518 if (EFI_ERROR (Status
)) {
1519 *FullPath
= DuplicateDevicePath (FilePath
);
1522 // LoadFile () may cause the device path of the Handle be updated.
1524 *FullPath
= AppendDevicePath (DevicePathFromHandle (Handle
), Node
);
1532 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1533 also signals the EFI ready to boot event. If the device path for the option
1534 starts with a BBS device path a legacy boot is attempted via the registered
1535 gLegacyBoot function. Short form device paths are also supported via this
1536 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1537 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1538 If the BootOption Device Path fails the removable media boot algorithm
1539 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1540 is tried per processor type)
1542 @param BootOption Boot Option to try and boot.
1543 On return, BootOption->Status contains the boot status.
1544 EFI_SUCCESS BootOption was booted
1545 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1546 registered via EfiBootManagerInitialize().
1547 EFI_NOT_FOUND The BootOption was not found on the system
1548 !EFI_SUCCESS BootOption failed with this error status
1553 EfiBootManagerBoot (
1554 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1558 EFI_HANDLE ImageHandle
;
1559 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1562 UINTN OriginalOptionNumber
;
1563 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1564 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1565 EFI_HANDLE FvHandle
;
1568 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1569 EFI_EVENT LegacyBootEvent
;
1571 if (BootOption
== NULL
) {
1575 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1576 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1581 // 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")
1583 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1584 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1585 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1586 if (!EFI_ERROR (Status
)) {
1588 // Save the BootOption->OptionNumber to restore later
1590 OptionNumber
= Uint16
;
1591 OriginalOptionNumber
= BootOption
->OptionNumber
;
1592 BootOption
->OptionNumber
= OptionNumber
;
1593 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1594 BootOption
->OptionNumber
= OriginalOptionNumber
;
1597 if (EFI_ERROR (Status
)) {
1598 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1599 BootOption
->Status
= Status
;
1605 // 2. Set BootCurrent
1607 Uint16
= (UINT16
) OptionNumber
;
1608 BmSetVariableAndReportStatusCodeOnError (
1610 &gEfiGlobalVariableGuid
,
1611 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1617 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1620 Node
= BootOption
->FilePath
;
1621 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1622 if (!EFI_ERROR (Status
) && CompareGuid (
1623 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1624 PcdGetPtr (PcdBootManagerMenuFile
)
1626 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1627 BmStopHotkeyService (NULL
, NULL
);
1629 EfiSignalEventReadyToBoot();
1631 // Report Status Code to indicate ReadyToBoot was signalled
1633 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1635 // 4. Repair system through DriverHealth protocol
1637 BmRepairAllControllers ();
1640 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1643 // 5. Load EFI boot option to ImageHandle
1646 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1647 Status
= EFI_NOT_FOUND
;
1648 FileBuffer
= BmGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1650 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1651 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1652 BmPrintDp (BootOption
->FilePath
);
1653 DEBUG ((EFI_D_INFO
, " -> "));
1654 BmPrintDp (FilePath
);
1655 DEBUG ((EFI_D_INFO
, "\n"));
1658 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1659 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1660 Status
= gBS
->LoadImage (
1669 if (FileBuffer
!= NULL
) {
1670 FreePool (FileBuffer
);
1672 if (FilePath
!= NULL
) {
1673 FreePool (FilePath
);
1676 if (EFI_ERROR (Status
)) {
1678 // Report Status Code to indicate that the failure to load boot option
1680 REPORT_STATUS_CODE (
1681 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1682 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1684 BootOption
->Status
= Status
;
1690 // 6. Adjust the different type memory page number just before booting
1691 // and save the updated info into the variable for next boot to use
1693 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
) {
1694 if (PcdGetBool (PcdResetOnMemoryTypeInformationChange
)) {
1695 BmSetMemoryTypeInformationVariable ();
1700 if (BootOption
->Description
== NULL
) {
1701 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1703 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1708 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1709 // Write boot to OS performance data for Legacy boot
1711 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1712 if (mBmLegacyBoot
!= NULL
) {
1714 // Write boot to OS performance data for legacy boot.
1718 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1720 Status
= EfiCreateEventLegacyBootEx(
1722 BmWriteBootToOsPerformanceData
,
1726 ASSERT_EFI_ERROR (Status
);
1729 mBmLegacyBoot (BootOption
);
1731 BootOption
->Status
= EFI_UNSUPPORTED
;
1734 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1739 // Provide the image with its load options
1741 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1742 ASSERT_EFI_ERROR (Status
);
1744 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1745 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1748 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1750 ImageInfo
->ParentHandle
= NULL
;
1753 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1755 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1758 // Write boot to OS performance data for UEFI boot
1761 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1764 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1766 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1767 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1768 BootOption
->Status
= Status
;
1769 if (EFI_ERROR (Status
)) {
1771 // Report Status Code to indicate that boot failure
1773 REPORT_STATUS_CODE (
1774 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1775 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1778 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1781 // Clear the Watchdog Timer after the image returns
1783 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1786 // Set Logo status invalid after trying one boot option
1789 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1790 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1791 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1792 ASSERT_EFI_ERROR (Status
);
1796 // Clear Boot Current
1798 Status
= gRT
->SetVariable (
1800 &gEfiGlobalVariableGuid
,
1806 // Deleting variable with current variable implementation shouldn't fail.
1807 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1808 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1810 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1814 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1815 instances, has the same partition node with HardDriveDevicePath device path
1817 @param BlockIoDevicePath Multi device path instances which need to check
1818 @param HardDriveDevicePath A device path which starts with a hard drive media
1821 @retval TRUE There is a matched device path instance.
1822 @retval FALSE There is no matched device path instance.
1826 BmMatchPartitionDevicePathNode (
1827 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1828 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1831 HARDDRIVE_DEVICE_PATH
*Node
;
1833 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1838 // find the partition device path node
1840 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1841 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1842 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1847 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1850 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1855 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1857 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1860 // Match Signature and PartitionNumber.
1861 // Unused bytes in Signature are initiaized with zeros.
1864 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1865 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1866 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1867 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1872 Emuerate all possible bootable medias in the following order:
1873 1. Removable BlockIo - The boot option only points to the removable media
1874 device, like USB key, DVD, Floppy etc.
1875 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1877 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1878 SimpleFileSystem Protocol, but not supporting BlockIo
1880 4. LoadFile - The boot option points to the media supporting
1882 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1884 @param BootOptionCount Return the boot option count which has been found.
1886 @retval Pointer to the boot option array.
1888 EFI_BOOT_MANAGER_LOAD_OPTION
*
1889 BmEnumerateBootOptions (
1890 UINTN
*BootOptionCount
1894 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1896 EFI_HANDLE
*Handles
;
1897 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
1900 CHAR16
*Description
;
1902 ASSERT (BootOptionCount
!= NULL
);
1904 *BootOptionCount
= 0;
1908 // Parse removable block io followed by fixed block io
1910 gBS
->LocateHandleBuffer (
1912 &gEfiBlockIoProtocolGuid
,
1918 for (Removable
= 0; Removable
< 2; Removable
++) {
1919 for (Index
= 0; Index
< HandleCount
; Index
++) {
1920 Status
= gBS
->HandleProtocol (
1922 &gEfiBlockIoProtocolGuid
,
1925 if (EFI_ERROR (Status
)) {
1930 // Skip the logical partitions
1932 if (BlkIo
->Media
->LogicalPartition
) {
1937 // Skip the fixed block io then the removable block io
1939 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
1943 Description
= BmGetBootDescription (Handles
[Index
]);
1944 BootOptions
= ReallocatePool (
1945 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1946 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1949 ASSERT (BootOptions
!= NULL
);
1951 Status
= EfiBootManagerInitializeLoadOption (
1952 &BootOptions
[(*BootOptionCount
)++],
1953 LoadOptionNumberUnassigned
,
1957 DevicePathFromHandle (Handles
[Index
]),
1961 ASSERT_EFI_ERROR (Status
);
1963 FreePool (Description
);
1967 if (HandleCount
!= 0) {
1972 // Parse simple file system not based on block io
1974 gBS
->LocateHandleBuffer (
1976 &gEfiSimpleFileSystemProtocolGuid
,
1981 for (Index
= 0; Index
< HandleCount
; Index
++) {
1982 Status
= gBS
->HandleProtocol (
1984 &gEfiBlockIoProtocolGuid
,
1987 if (!EFI_ERROR (Status
)) {
1989 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
1993 Description
= BmGetBootDescription (Handles
[Index
]);
1994 BootOptions
= ReallocatePool (
1995 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1996 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1999 ASSERT (BootOptions
!= NULL
);
2001 Status
= EfiBootManagerInitializeLoadOption (
2002 &BootOptions
[(*BootOptionCount
)++],
2003 LoadOptionNumberUnassigned
,
2007 DevicePathFromHandle (Handles
[Index
]),
2011 ASSERT_EFI_ERROR (Status
);
2012 FreePool (Description
);
2015 if (HandleCount
!= 0) {
2020 // Parse load file, assuming UEFI Network boot option
2022 gBS
->LocateHandleBuffer (
2024 &gEfiLoadFileProtocolGuid
,
2029 for (Index
= 0; Index
< HandleCount
; Index
++) {
2031 Description
= BmGetBootDescription (Handles
[Index
]);
2032 BootOptions
= ReallocatePool (
2033 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2034 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2037 ASSERT (BootOptions
!= NULL
);
2039 Status
= EfiBootManagerInitializeLoadOption (
2040 &BootOptions
[(*BootOptionCount
)++],
2041 LoadOptionNumberUnassigned
,
2045 DevicePathFromHandle (Handles
[Index
]),
2049 ASSERT_EFI_ERROR (Status
);
2050 FreePool (Description
);
2053 if (HandleCount
!= 0) {
2061 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2065 EfiBootManagerRefreshAllBootOption (
2070 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2071 UINTN NvBootOptionCount
;
2072 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2073 UINTN BootOptionCount
;
2077 // Optionally refresh the legacy boot option
2079 if (mBmRefreshLegacyBootOption
!= NULL
) {
2080 mBmRefreshLegacyBootOption ();
2083 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2084 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2087 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2089 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2090 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2091 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2095 // Remove invalid EFI boot options from NV
2097 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2098 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2099 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2101 (NvBootOptions
[Index
].OptionalDataSize
== sizeof (EFI_GUID
)) &&
2102 CompareGuid ((EFI_GUID
*) NvBootOptions
[Index
].OptionalData
, &mBmAutoCreateBootOptionGuid
)
2105 // Only check those added by BDS
2106 // so that the boot options added by end-user or OS installer won't be deleted
2108 if (BmFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
2109 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2111 // Deleting variable with current variable implementation shouldn't fail.
2113 ASSERT_EFI_ERROR (Status
);
2119 // Add new EFI boot options to NV
2121 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2122 if (BmFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
2123 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2125 // Try best to add the boot options so continue upon failure.
2130 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2131 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2135 This function is called to create the boot option for the Boot Manager Menu.
2137 The Boot Manager Menu is shown after successfully booting a boot option.
2138 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2140 @param BootOption Return the boot option of the Boot Manager Menu
2142 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2143 @retval Status Return status of gRT->SetVariable (). BootOption still points
2144 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2147 BmRegisterBootManagerMenu (
2148 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2152 CHAR16
*Description
;
2153 UINTN DescriptionLength
;
2154 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2155 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2156 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2158 Status
= GetSectionFromFv (
2159 PcdGetPtr (PcdBootManagerMenuFile
),
2160 EFI_SECTION_USER_INTERFACE
,
2162 (VOID
**) &Description
,
2165 if (EFI_ERROR (Status
)) {
2169 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2170 Status
= gBS
->HandleProtocol (
2172 &gEfiLoadedImageProtocolGuid
,
2173 (VOID
**) &LoadedImage
2175 ASSERT_EFI_ERROR (Status
);
2176 DevicePath
= AppendDevicePathNode (
2177 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2178 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2180 ASSERT (DevicePath
!= NULL
);
2182 Status
= EfiBootManagerInitializeLoadOption (
2184 LoadOptionNumberUnassigned
,
2186 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2187 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2192 ASSERT_EFI_ERROR (Status
);
2193 FreePool (DevicePath
);
2194 if (Description
!= NULL
) {
2195 FreePool (Description
);
2199 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2200 UINTN BootOptionCount
;
2202 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2203 ASSERT (BmFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2204 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2207 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2211 Return the boot option corresponding to the Boot Manager Menu.
2212 It may automatically create one if the boot option hasn't been created yet.
2214 @param BootOption Return the Boot Manager Menu.
2216 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2217 @retval Status Return status of gRT->SetVariable (). BootOption still points
2218 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2222 EfiBootManagerGetBootManagerMenu (
2223 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2227 UINTN BootOptionCount
;
2228 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2230 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2231 EFI_HANDLE FvHandle
;
2233 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2235 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2236 Node
= BootOptions
[Index
].FilePath
;
2237 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2238 if (!EFI_ERROR (Status
)) {
2240 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2241 PcdGetPtr (PcdBootManagerMenuFile
)
2244 Status
= EfiBootManagerInitializeLoadOption (
2246 BootOptions
[Index
].OptionNumber
,
2247 BootOptions
[Index
].OptionType
,
2248 BootOptions
[Index
].Attributes
,
2249 BootOptions
[Index
].Description
,
2250 BootOptions
[Index
].FilePath
,
2251 BootOptions
[Index
].OptionalData
,
2252 BootOptions
[Index
].OptionalDataSize
2254 ASSERT_EFI_ERROR (Status
);
2260 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2263 // Automatically create the Boot#### for Boot Manager Menu when not found.
2265 if (Index
== BootOptionCount
) {
2266 return BmRegisterBootManagerMenu (BootOption
);