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
;
557 Status
= gBS
->HandleProtocol (
559 &gEfiUsbIoProtocolGuid
,
562 if (EFI_ERROR (Status
)) {
568 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
569 if (EFI_ERROR (Status
)) {
573 Status
= UsbIo
->UsbGetStringDescriptor (
576 DevDesc
.StrManufacturer
,
579 if (EFI_ERROR (Status
)) {
580 Manufacturer
= &NullChar
;
583 Status
= UsbIo
->UsbGetStringDescriptor (
589 if (EFI_ERROR (Status
)) {
593 Status
= UsbIo
->UsbGetStringDescriptor (
596 DevDesc
.StrSerialNumber
,
599 if (EFI_ERROR (Status
)) {
600 SerialNumber
= &NullChar
;
603 if ((Manufacturer
== &NullChar
) &&
604 (Product
== &NullChar
) &&
605 (SerialNumber
== &NullChar
)
610 DescMaxSize
= StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
);
611 Description
= AllocateZeroPool (DescMaxSize
);
612 ASSERT (Description
!= NULL
);
613 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Manufacturer
);
614 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
616 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Product
);
617 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
619 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), SerialNumber
);
621 if (Manufacturer
!= &NullChar
) {
622 FreePool (Manufacturer
);
624 if (Product
!= &NullChar
) {
627 if (SerialNumber
!= &NullChar
) {
628 FreePool (SerialNumber
);
631 BmEliminateExtraSpaces (Description
);
637 Return the boot description for the controller based on the type.
639 @param Handle Controller handle.
641 @return The description string.
644 BmGetMiscDescription (
650 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
651 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
653 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
654 case BmAcpiFloppyBoot
:
655 Description
= L
"Floppy";
658 case BmMessageAtapiBoot
:
659 case BmMessageSataBoot
:
660 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
661 ASSERT_EFI_ERROR (Status
);
663 // Assume a removable SATA device should be the DVD/CD device
665 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
668 case BmMessageUsbBoot
:
669 Description
= L
"USB Device";
672 case BmMessageScsiBoot
:
673 Description
= L
"SCSI Device";
676 case BmHardwareDeviceBoot
:
677 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
678 if (!EFI_ERROR (Status
)) {
679 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
681 Description
= L
"Misc Device";
685 case BmMessageNetworkBoot
:
686 Description
= L
"Network";
690 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**) &Fs
);
691 if (!EFI_ERROR (Status
)) {
692 Description
= L
"Non-Block Boot Device";
694 Description
= L
"Misc Device";
699 return AllocateCopyPool (StrSize (Description
), Description
);
703 Register the platform provided boot description handler.
705 @param Handler The platform provided boot description handler
707 @retval EFI_SUCCESS The handler was registered successfully.
708 @retval EFI_ALREADY_STARTED The handler was already registered.
709 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
713 EfiBootManagerRegisterBootDescriptionHandler (
714 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
718 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
720 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
721 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
722 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
724 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
725 if (Entry
->Handler
== Handler
) {
726 return EFI_ALREADY_STARTED
;
730 Entry
= AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY
));
732 return EFI_OUT_OF_RESOURCES
;
735 Entry
->Signature
= BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
;
736 Entry
->Handler
= Handler
;
737 InsertTailList (&mPlatformBootDescriptionHandlers
, &Entry
->Link
);
741 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers
[] = {
743 BmGetDescriptionFromDiskInfo
,
748 Return the boot description for the controller.
750 @param Handle Controller handle.
752 @return The description string.
755 BmGetBootDescription (
760 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
762 CHAR16
*DefaultDescription
;
767 // Firstly get the default boot description
769 DefaultDescription
= NULL
;
770 for (Index
= 0; Index
< sizeof (mBmBootDescriptionHandlers
) / sizeof (mBmBootDescriptionHandlers
[0]); Index
++) {
771 DefaultDescription
= mBmBootDescriptionHandlers
[Index
] (Handle
);
772 if (DefaultDescription
!= NULL
) {
774 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
775 // ONLY for core provided boot description handler.
777 Temp
= AllocatePool (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
));
778 ASSERT (Temp
!= NULL
);
780 (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
))/sizeof(CHAR16
),
784 (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
))/sizeof(CHAR16
),
787 FreePool (DefaultDescription
);
788 DefaultDescription
= Temp
;
792 ASSERT (DefaultDescription
!= NULL
);
795 // Secondly query platform for the better boot description
797 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
798 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
799 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
801 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
802 Description
= Entry
->Handler (Handle
, DefaultDescription
);
803 if (Description
!= NULL
) {
804 FreePool (DefaultDescription
);
809 return DefaultDescription
;
813 Check whether a USB device match the specified USB WWID device path. This
814 function follows "Load Option Processing" behavior in UEFI specification.
816 @param UsbIo USB I/O protocol associated with the USB device.
817 @param UsbWwid The USB WWID device path to match.
819 @retval TRUE The USB device match the USB WWID device path.
820 @retval FALSE The USB device does not match the USB WWID device path.
825 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
826 IN USB_WWID_DEVICE_PATH
*UsbWwid
830 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
831 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
837 CHAR16
*SerialNumberStr
;
840 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
841 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
846 // Check Vendor Id and Product Id.
848 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
849 if (EFI_ERROR (Status
)) {
852 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
853 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
858 // Check Interface Number.
860 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
861 if (EFI_ERROR (Status
)) {
864 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
869 // Check Serial Number.
871 if (DevDesc
.StrSerialNumber
== 0) {
876 // Get all supported languages.
880 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
881 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
886 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
888 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
889 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
890 if (CompareStr
[CompareLen
- 1] == L
'\0') {
895 // Compare serial number in each supported language.
897 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
898 SerialNumberStr
= NULL
;
899 Status
= UsbIo
->UsbGetStringDescriptor (
902 DevDesc
.StrSerialNumber
,
905 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
909 Length
= StrLen (SerialNumberStr
);
910 if ((Length
>= CompareLen
) &&
911 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
912 FreePool (SerialNumberStr
);
916 FreePool (SerialNumberStr
);
923 Find a USB device which match the specified short-form device path start with
924 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
925 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
926 this function will only search in its child devices.
928 @param DevicePath The device path that contains USB Class or USB WWID device path.
929 @param ParentDevicePathSize The length of the device path before the USB Class or
930 USB WWID device path.
931 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
933 @retval NULL The matched USB IO handles cannot be found.
934 @retval other The matched USB IO handles.
939 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
940 IN UINTN ParentDevicePathSize
,
941 OUT UINTN
*UsbIoHandleCount
945 EFI_HANDLE
*UsbIoHandles
;
946 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
947 EFI_USB_IO_PROTOCOL
*UsbIo
;
949 UINTN UsbIoDevicePathSize
;
952 ASSERT (UsbIoHandleCount
!= NULL
);
955 // Get all UsbIo Handles.
957 Status
= gBS
->LocateHandleBuffer (
959 &gEfiUsbIoProtocolGuid
,
964 if (EFI_ERROR (Status
)) {
965 *UsbIoHandleCount
= 0;
969 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
971 // Get the Usb IO interface.
973 Status
= gBS
->HandleProtocol(
975 &gEfiUsbIoProtocolGuid
,
978 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
980 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
981 UsbIoDevicePathSize
= GetDevicePathSize (UsbIoDevicePath
) - END_DEVICE_PATH_LENGTH
;
984 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
986 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
987 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
988 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
995 (*UsbIoHandleCount
) --;
996 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
1002 return UsbIoHandles
;
1006 Expand USB Class or USB WWID device path node to be full device path of a USB
1009 This function support following 4 cases:
1010 1) Boot Option device path starts with a USB Class or USB WWID device path,
1011 and there is no Media FilePath device path in the end.
1012 In this case, it will follow Removable Media Boot Behavior.
1013 2) Boot Option device path starts with a USB Class or USB WWID device path,
1014 and ended with Media FilePath device path.
1015 3) Boot Option device path starts with a full device path to a USB Host Controller,
1016 contains a USB Class or USB WWID device path node, while not ended with Media
1017 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
1018 4) Boot Option device path starts with a full device path to a USB Host Controller,
1019 contains a USB Class or USB WWID device path node, and ended with Media
1020 FilePath device path.
1022 @param FilePath The device path pointing to a load option.
1023 It could be a short-form device path.
1024 @param FullPath Return the full device path of the load option after
1025 short-form device path expanding.
1026 Caller is responsible to free it.
1027 @param FileSize Return the load option size.
1028 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
1030 @return The load option buffer. Caller is responsible to free the memory.
1033 BmExpandUsbDevicePath (
1034 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1035 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1036 OUT UINTN
*FileSize
,
1037 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
1040 UINTN ParentDevicePathSize
;
1041 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
1042 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
1043 EFI_HANDLE
*Handles
;
1048 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
1049 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
1051 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
1053 for (Index
= 0; (Index
< HandleCount
) && (FileBuffer
== NULL
); Index
++) {
1054 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
1055 FileBuffer
= BmGetLoadOptionBuffer (FullDevicePath
, FullPath
, FileSize
);
1056 FreePool (FullDevicePath
);
1059 if (Handles
!= NULL
) {
1067 Save the partition DevicePath to the CachedDevicePath as the first instance.
1069 @param CachedDevicePath The device path cache.
1070 @param DevicePath The partition device path to be cached.
1073 BmCachePartitionDevicePath (
1074 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
1075 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1078 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1081 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
1082 TempDevicePath
= *CachedDevicePath
;
1083 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
1084 FreePool (TempDevicePath
);
1087 if (*CachedDevicePath
== NULL
) {
1088 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
1092 TempDevicePath
= *CachedDevicePath
;
1093 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
1094 if (TempDevicePath
!= NULL
) {
1095 FreePool (TempDevicePath
);
1099 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
1100 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
1103 TempDevicePath
= *CachedDevicePath
;
1104 while (!IsDevicePathEnd (TempDevicePath
)) {
1105 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1107 // Parse one instance
1109 while (!IsDevicePathEndType (TempDevicePath
)) {
1110 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1114 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
1117 SetDevicePathEndNode (TempDevicePath
);
1124 Expand a device path that starts with a hard drive media device path node to be a
1125 full device path that includes the full hardware path to the device. We need
1126 to do this so it can be booted. As an optimization the front match (the part point
1127 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
1128 so a connect all is not required on every boot. All successful history device path
1129 which point to partition node (the front part) will be saved.
1131 @param FilePath The device path pointing to a load option.
1132 It could be a short-form device path.
1133 @param FullPath Return the full device path of the load option after
1134 short-form device path expanding.
1135 Caller is responsible to free it.
1136 @param FileSize Return the load option size.
1138 @return The load option buffer. Caller is responsible to free the memory.
1141 BmExpandPartitionDevicePath (
1142 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1143 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1148 UINTN BlockIoHandleCount
;
1149 EFI_HANDLE
*BlockIoBuffer
;
1151 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
1153 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
1154 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
1155 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1156 UINTN CachedDevicePathSize
;
1158 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1163 // Check if there is prestore 'HDDP' variable.
1164 // If exist, search the front path which point to partition node in the variable instants.
1165 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
1167 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
1170 // Delete the invalid 'HDDP' variable.
1172 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
1173 FreePool (CachedDevicePath
);
1174 CachedDevicePath
= NULL
;
1175 Status
= gRT
->SetVariable (
1177 &mBmHardDriveBootVariableGuid
,
1182 ASSERT_EFI_ERROR (Status
);
1185 if (CachedDevicePath
!= NULL
) {
1186 TempNewDevicePath
= CachedDevicePath
;
1190 // Check every instance of the variable
1191 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
1192 // partial partition boot option. Second, check whether the instance could be connected.
1194 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
1195 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1197 // Connect the device path instance, the device path point to hard drive media device path node
1198 // e.g. ACPI() /PCI()/ATA()/Partition()
1200 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
1201 if (!EFI_ERROR (Status
)) {
1202 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
1203 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1204 FreePool (TempDevicePath
);
1206 if (FileBuffer
!= NULL
) {
1208 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
1211 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
1213 // Save the matching Device Path so we don't need to do a connect all next time
1214 // Failing to save only impacts performance next time expanding the short-form device path
1216 Status
= gRT
->SetVariable (
1218 &mBmHardDriveBootVariableGuid
,
1219 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1220 GetDevicePathSize (CachedDevicePath
),
1225 FreePool (Instance
);
1226 FreePool (CachedDevicePath
);
1232 // Come here means the first instance is not matched
1236 } while (TempNewDevicePath
!= NULL
);
1240 // If we get here we fail to find or 'HDDP' not exist, and now we need
1241 // to search all devices in the system for a matched partition
1243 EfiBootManagerConnectAll ();
1244 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
1245 if (EFI_ERROR (Status
)) {
1246 BlockIoHandleCount
= 0;
1247 BlockIoBuffer
= NULL
;
1250 // Loop through all the device handles that support the BLOCK_IO Protocol
1252 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
1253 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
1254 if (BlockIoDevicePath
== NULL
) {
1258 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1260 // Find the matched partition device path
1262 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
1263 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1264 FreePool (TempDevicePath
);
1266 if (FileBuffer
!= NULL
) {
1267 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
1270 // Save the matching Device Path so we don't need to do a connect all next time
1271 // Failing to save only impacts performance next time expanding the short-form device path
1273 Status
= gRT
->SetVariable (
1275 &mBmHardDriveBootVariableGuid
,
1276 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1277 GetDevicePathSize (CachedDevicePath
),
1286 if (CachedDevicePath
!= NULL
) {
1287 FreePool (CachedDevicePath
);
1289 if (BlockIoBuffer
!= NULL
) {
1290 FreePool (BlockIoBuffer
);
1296 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
1297 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1299 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1300 @param FullPath Return the full device path pointing to the load option.
1301 @param FileSize Return the size of the load option.
1303 @return The load option buffer.
1306 BmExpandMediaDevicePath (
1307 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1308 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1314 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1316 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1319 EFI_HANDLE
*SimpleFileSystemHandles
;
1320 UINTN NumberSimpleFileSystemHandles
;
1323 UINT32 AuthenticationStatus
;
1326 // Check whether the device is connected
1328 TempDevicePath
= DevicePath
;
1329 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1330 if (!EFI_ERROR (Status
)) {
1331 ASSERT (IsDevicePathEnd (TempDevicePath
));
1333 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1334 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1335 if (FileBuffer
== NULL
) {
1336 FreePool (TempDevicePath
);
1337 TempDevicePath
= NULL
;
1339 *FullPath
= TempDevicePath
;
1344 // For device boot option only pointing to the removable device handle,
1345 // should make sure all its children handles (its child partion or media handles) are created and connected.
1347 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1350 // Issue a dummy read to the device to check for media change.
1351 // When the removable media is changed, any Block IO read/write will
1352 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1353 // returned. After the Block IO protocol is reinstalled, subsequent
1354 // Block IO read/write will success.
1356 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1357 ASSERT_EFI_ERROR (Status
);
1358 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1359 ASSERT_EFI_ERROR (Status
);
1360 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1361 if (Buffer
!= NULL
) {
1362 BlockIo
->ReadBlocks (
1364 BlockIo
->Media
->MediaId
,
1366 BlockIo
->Media
->BlockSize
,
1373 // Detect the the default boot file from removable Media
1377 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1378 gBS
->LocateHandleBuffer (
1380 &gEfiSimpleFileSystemProtocolGuid
,
1382 &NumberSimpleFileSystemHandles
,
1383 &SimpleFileSystemHandles
1385 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1387 // Get the device path size of SimpleFileSystem handle
1389 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1390 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1392 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1394 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1395 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1396 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1397 if (FileBuffer
!= NULL
) {
1398 *FullPath
= TempDevicePath
;
1401 FreePool (TempDevicePath
);
1405 if (SimpleFileSystemHandles
!= NULL
) {
1406 FreePool (SimpleFileSystemHandles
);
1413 Get the load option by its device path.
1415 @param FilePath The device path pointing to a load option.
1416 It could be a short-form device path.
1417 @param FullPath Return the full device path of the load option after
1418 short-form device path expanding.
1419 Caller is responsible to free it.
1420 @param FileSize Return the load option size.
1422 @return The load option buffer. Caller is responsible to free the memory.
1425 BmGetLoadOptionBuffer (
1426 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1427 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1433 UINT32 AuthenticationStatus
;
1434 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1437 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1439 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1446 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1449 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1450 if (EFI_ERROR (Status
)) {
1451 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1454 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1455 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1459 // Expand the short-form device path to full device path
1461 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1462 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1464 // Expand the Harddrive device path
1466 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1468 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1469 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1470 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1475 if (!IsDevicePathEnd (Node
)) {
1477 // Expand the USB WWID/Class device path
1479 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1480 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1482 // Boot Option device path starts with USB Class or USB WWID device path.
1483 // For Boot Option device path which doesn't begin with the USB Class or
1484 // USB WWID device path, it's not needed to connect again here.
1486 BmConnectUsbShortFormDevicePath (FilePath
);
1487 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1494 // Fix up the boot option path if it points to a FV in memory map style of device path
1496 if (BmIsMemmapFvFilePath (FilePath
)) {
1497 return BmGetFileBufferByMemmapFv (FilePath
, FullPath
, FileSize
);
1501 // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),
1502 // or it directly points to a file in simple file system instance.
1505 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1506 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1507 if (FileBuffer
!= NULL
) {
1508 if (EFI_ERROR (Status
)) {
1509 *FullPath
= DuplicateDevicePath (FilePath
);
1512 // LoadFile () may cause the device path of the Handle be updated.
1514 *FullPath
= AppendDevicePath (DevicePathFromHandle (Handle
), Node
);
1522 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1523 also signals the EFI ready to boot event. If the device path for the option
1524 starts with a BBS device path a legacy boot is attempted via the registered
1525 gLegacyBoot function. Short form device paths are also supported via this
1526 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1527 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1528 If the BootOption Device Path fails the removable media boot algorithm
1529 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1530 is tried per processor type)
1532 @param BootOption Boot Option to try and boot.
1533 On return, BootOption->Status contains the boot status.
1534 EFI_SUCCESS BootOption was booted
1535 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1536 registered via EfiBootManagerInitialize().
1537 EFI_NOT_FOUND The BootOption was not found on the system
1538 !EFI_SUCCESS BootOption failed with this error status
1543 EfiBootManagerBoot (
1544 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1548 EFI_HANDLE ImageHandle
;
1549 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1552 UINTN OriginalOptionNumber
;
1553 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1554 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1555 EFI_HANDLE FvHandle
;
1558 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1559 EFI_EVENT LegacyBootEvent
;
1561 if (BootOption
== NULL
) {
1565 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1566 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1571 // 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")
1573 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1574 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1575 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1576 if (!EFI_ERROR (Status
)) {
1578 // Save the BootOption->OptionNumber to restore later
1580 OptionNumber
= Uint16
;
1581 OriginalOptionNumber
= BootOption
->OptionNumber
;
1582 BootOption
->OptionNumber
= OptionNumber
;
1583 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1584 BootOption
->OptionNumber
= OriginalOptionNumber
;
1587 if (EFI_ERROR (Status
)) {
1588 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1589 BootOption
->Status
= Status
;
1595 // 2. Set BootCurrent
1597 Uint16
= (UINT16
) OptionNumber
;
1598 BmSetVariableAndReportStatusCodeOnError (
1600 &gEfiGlobalVariableGuid
,
1601 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1607 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1610 Node
= BootOption
->FilePath
;
1611 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1612 if (!EFI_ERROR (Status
) && CompareGuid (
1613 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1614 PcdGetPtr (PcdBootManagerMenuFile
)
1616 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1617 BmStopHotkeyService (NULL
, NULL
);
1619 EfiSignalEventReadyToBoot();
1621 // Report Status Code to indicate ReadyToBoot was signalled
1623 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1625 // 4. Repair system through DriverHealth protocol
1627 BmRepairAllControllers ();
1630 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1633 // 5. Load EFI boot option to ImageHandle
1636 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1637 Status
= EFI_NOT_FOUND
;
1638 FileBuffer
= BmGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1640 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1641 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1642 BmPrintDp (BootOption
->FilePath
);
1643 DEBUG ((EFI_D_INFO
, " -> "));
1644 BmPrintDp (FilePath
);
1645 DEBUG ((EFI_D_INFO
, "\n"));
1648 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1649 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1650 Status
= gBS
->LoadImage (
1659 if (FileBuffer
!= NULL
) {
1660 FreePool (FileBuffer
);
1662 if (FilePath
!= NULL
) {
1663 FreePool (FilePath
);
1666 if (EFI_ERROR (Status
)) {
1668 // Report Status Code to indicate that the failure to load boot option
1670 REPORT_STATUS_CODE (
1671 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1672 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1674 BootOption
->Status
= Status
;
1680 // 6. Adjust the different type memory page number just before booting
1681 // and save the updated info into the variable for next boot to use
1683 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
) {
1684 if (PcdGetBool (PcdResetOnMemoryTypeInformationChange
)) {
1685 BmSetMemoryTypeInformationVariable ();
1690 if (BootOption
->Description
== NULL
) {
1691 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1693 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1698 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1699 // Write boot to OS performance data for Legacy boot
1701 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1702 if (mBmLegacyBoot
!= NULL
) {
1704 // Write boot to OS performance data for legacy boot.
1708 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1710 Status
= EfiCreateEventLegacyBootEx(
1712 BmWriteBootToOsPerformanceData
,
1716 ASSERT_EFI_ERROR (Status
);
1719 mBmLegacyBoot (BootOption
);
1721 BootOption
->Status
= EFI_UNSUPPORTED
;
1724 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1729 // Provide the image with its load options
1731 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1732 ASSERT_EFI_ERROR (Status
);
1734 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1735 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1738 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1740 ImageInfo
->ParentHandle
= NULL
;
1743 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1745 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1748 // Write boot to OS performance data for UEFI boot
1751 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1754 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1756 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1757 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1758 BootOption
->Status
= Status
;
1759 if (EFI_ERROR (Status
)) {
1761 // Report Status Code to indicate that boot failure
1763 REPORT_STATUS_CODE (
1764 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1765 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1768 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1771 // Clear the Watchdog Timer after the image returns
1773 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1776 // Set Logo status invalid after trying one boot option
1779 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1780 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1781 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1782 ASSERT_EFI_ERROR (Status
);
1786 // Clear Boot Current
1788 Status
= gRT
->SetVariable (
1790 &gEfiGlobalVariableGuid
,
1796 // Deleting variable with current variable implementation shouldn't fail.
1797 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1798 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1800 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1804 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1805 instances, has the same partition node with HardDriveDevicePath device path
1807 @param BlockIoDevicePath Multi device path instances which need to check
1808 @param HardDriveDevicePath A device path which starts with a hard drive media
1811 @retval TRUE There is a matched device path instance.
1812 @retval FALSE There is no matched device path instance.
1816 BmMatchPartitionDevicePathNode (
1817 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1818 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1821 HARDDRIVE_DEVICE_PATH
*Node
;
1823 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1828 // find the partition device path node
1830 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1831 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1832 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1837 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1840 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1845 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1847 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1850 // Match Signature and PartitionNumber.
1851 // Unused bytes in Signature are initiaized with zeros.
1854 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1855 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1856 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1857 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1862 Emuerate all possible bootable medias in the following order:
1863 1. Removable BlockIo - The boot option only points to the removable media
1864 device, like USB key, DVD, Floppy etc.
1865 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1867 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1868 SimpleFileSystem Protocol, but not supporting BlockIo
1870 4. LoadFile - The boot option points to the media supporting
1872 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1874 @param BootOptionCount Return the boot option count which has been found.
1876 @retval Pointer to the boot option array.
1878 EFI_BOOT_MANAGER_LOAD_OPTION
*
1879 BmEnumerateBootOptions (
1880 UINTN
*BootOptionCount
1884 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1886 EFI_HANDLE
*Handles
;
1887 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
1890 CHAR16
*Description
;
1892 ASSERT (BootOptionCount
!= NULL
);
1894 *BootOptionCount
= 0;
1898 // Parse removable block io followed by fixed block io
1900 gBS
->LocateHandleBuffer (
1902 &gEfiBlockIoProtocolGuid
,
1908 for (Removable
= 0; Removable
< 2; Removable
++) {
1909 for (Index
= 0; Index
< HandleCount
; Index
++) {
1910 Status
= gBS
->HandleProtocol (
1912 &gEfiBlockIoProtocolGuid
,
1915 if (EFI_ERROR (Status
)) {
1920 // Skip the logical partitions
1922 if (BlkIo
->Media
->LogicalPartition
) {
1927 // Skip the fixed block io then the removable block io
1929 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
1933 Description
= BmGetBootDescription (Handles
[Index
]);
1934 BootOptions
= ReallocatePool (
1935 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1936 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1939 ASSERT (BootOptions
!= NULL
);
1941 Status
= EfiBootManagerInitializeLoadOption (
1942 &BootOptions
[(*BootOptionCount
)++],
1943 LoadOptionNumberUnassigned
,
1947 DevicePathFromHandle (Handles
[Index
]),
1951 ASSERT_EFI_ERROR (Status
);
1953 FreePool (Description
);
1957 if (HandleCount
!= 0) {
1962 // Parse simple file system not based on block io
1964 gBS
->LocateHandleBuffer (
1966 &gEfiSimpleFileSystemProtocolGuid
,
1971 for (Index
= 0; Index
< HandleCount
; Index
++) {
1972 Status
= gBS
->HandleProtocol (
1974 &gEfiBlockIoProtocolGuid
,
1977 if (!EFI_ERROR (Status
)) {
1979 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
1983 Description
= BmGetBootDescription (Handles
[Index
]);
1984 BootOptions
= ReallocatePool (
1985 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1986 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1989 ASSERT (BootOptions
!= NULL
);
1991 Status
= EfiBootManagerInitializeLoadOption (
1992 &BootOptions
[(*BootOptionCount
)++],
1993 LoadOptionNumberUnassigned
,
1997 DevicePathFromHandle (Handles
[Index
]),
2001 ASSERT_EFI_ERROR (Status
);
2002 FreePool (Description
);
2005 if (HandleCount
!= 0) {
2010 // Parse load file, assuming UEFI Network boot option
2012 gBS
->LocateHandleBuffer (
2014 &gEfiLoadFileProtocolGuid
,
2019 for (Index
= 0; Index
< HandleCount
; Index
++) {
2021 Description
= BmGetBootDescription (Handles
[Index
]);
2022 BootOptions
= ReallocatePool (
2023 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2024 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2027 ASSERT (BootOptions
!= NULL
);
2029 Status
= EfiBootManagerInitializeLoadOption (
2030 &BootOptions
[(*BootOptionCount
)++],
2031 LoadOptionNumberUnassigned
,
2035 DevicePathFromHandle (Handles
[Index
]),
2039 ASSERT_EFI_ERROR (Status
);
2040 FreePool (Description
);
2043 if (HandleCount
!= 0) {
2051 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2055 EfiBootManagerRefreshAllBootOption (
2060 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2061 UINTN NvBootOptionCount
;
2062 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2063 UINTN BootOptionCount
;
2067 // Optionally refresh the legacy boot option
2069 if (mBmRefreshLegacyBootOption
!= NULL
) {
2070 mBmRefreshLegacyBootOption ();
2073 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2074 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2077 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2079 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2080 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2081 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2085 // Remove invalid EFI boot options from NV
2087 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2088 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2089 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2091 (NvBootOptions
[Index
].OptionalDataSize
== sizeof (EFI_GUID
)) &&
2092 CompareGuid ((EFI_GUID
*) NvBootOptions
[Index
].OptionalData
, &mBmAutoCreateBootOptionGuid
)
2095 // Only check those added by BDS
2096 // so that the boot options added by end-user or OS installer won't be deleted
2098 if (BmFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
2099 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2101 // Deleting variable with current variable implementation shouldn't fail.
2103 ASSERT_EFI_ERROR (Status
);
2109 // Add new EFI boot options to NV
2111 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2112 if (BmFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
2113 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2115 // Try best to add the boot options so continue upon failure.
2120 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2121 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2125 This function is called to create the boot option for the Boot Manager Menu.
2127 The Boot Manager Menu is shown after successfully booting a boot option.
2128 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2130 @param BootOption Return the boot option of the Boot Manager Menu
2132 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2133 @retval Status Return status of gRT->SetVariable (). BootOption still points
2134 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2137 BmRegisterBootManagerMenu (
2138 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2142 CHAR16
*Description
;
2143 UINTN DescriptionLength
;
2144 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2145 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2146 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2148 Status
= GetSectionFromFv (
2149 PcdGetPtr (PcdBootManagerMenuFile
),
2150 EFI_SECTION_USER_INTERFACE
,
2152 (VOID
**) &Description
,
2155 if (EFI_ERROR (Status
)) {
2159 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2160 Status
= gBS
->HandleProtocol (
2162 &gEfiLoadedImageProtocolGuid
,
2163 (VOID
**) &LoadedImage
2165 ASSERT_EFI_ERROR (Status
);
2166 DevicePath
= AppendDevicePathNode (
2167 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2168 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2170 ASSERT (DevicePath
!= NULL
);
2172 Status
= EfiBootManagerInitializeLoadOption (
2174 LoadOptionNumberUnassigned
,
2176 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2177 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2182 ASSERT_EFI_ERROR (Status
);
2183 FreePool (DevicePath
);
2184 if (Description
!= NULL
) {
2185 FreePool (Description
);
2189 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2190 UINTN BootOptionCount
;
2192 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2193 ASSERT (BmFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2194 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2197 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2201 Return the boot option corresponding to the Boot Manager Menu.
2202 It may automatically create one if the boot option hasn't been created yet.
2204 @param BootOption Return the Boot Manager Menu.
2206 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2207 @retval Status Return status of gRT->SetVariable (). BootOption still points
2208 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2212 EfiBootManagerGetBootManagerMenu (
2213 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2217 UINTN BootOptionCount
;
2218 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2220 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2221 EFI_HANDLE FvHandle
;
2223 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2225 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2226 Node
= BootOptions
[Index
].FilePath
;
2227 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2228 if (!EFI_ERROR (Status
)) {
2230 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2231 PcdGetPtr (PcdBootManagerMenuFile
)
2234 Status
= EfiBootManagerInitializeLoadOption (
2236 BootOptions
[Index
].OptionNumber
,
2237 BootOptions
[Index
].OptionType
,
2238 BootOptions
[Index
].Attributes
,
2239 BootOptions
[Index
].Description
,
2240 BootOptions
[Index
].FilePath
,
2241 BootOptions
[Index
].OptionalData
,
2242 BootOptions
[Index
].OptionalDataSize
2244 ASSERT_EFI_ERROR (Status
);
2250 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2253 // Automatically create the Boot#### for Boot Manager Menu when not found.
2255 if (Index
== BootOptionCount
) {
2256 return BmRegisterBootManagerMenu (BootOption
);