2 Library functions which relates with booting.
4 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "InternalBm.h"
18 #define VENDOR_IDENTIFICATION_OFFSET 3
19 #define VENDOR_IDENTIFICATION_LENGTH 8
20 #define PRODUCT_IDENTIFICATION_OFFSET 11
21 #define PRODUCT_IDENTIFICATION_LENGTH 16
23 CONST UINT16 mBmUsbLangId
= 0x0409; // English
24 CHAR16 mBmUefiPrefix
[] = L
"UEFI ";
26 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption
= NULL
;
27 EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot
= NULL
;
29 LIST_ENTRY mPlatformBootDescriptionHandlers
= INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers
);
32 /// This GUID is used for an EFI Variable that stores the front device pathes
33 /// for a partial device path that starts with the HD node.
35 EFI_GUID mBmHardDriveBootVariableGuid
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
36 EFI_GUID mBmAutoCreateBootOptionGuid
= { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
39 The function registers the legacy boot support capabilities.
41 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
42 @param LegacyBoot The function pointer to boot the legacy boot option.
46 EfiBootManagerRegisterLegacyBootSupport (
47 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption
,
48 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
51 mBmRefreshLegacyBootOption
= RefreshLegacyBootOption
;
52 mBmLegacyBoot
= LegacyBoot
;
56 Return TRUE when the boot option is auto-created instead of manually added.
58 @param BootOption Pointer to the boot option to check.
60 @retval TRUE The boot option is auto-created.
61 @retval FALSE The boot option is manually added.
64 BmIsAutoCreateBootOption (
65 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
68 if ((BootOption
->OptionalDataSize
== sizeof (EFI_GUID
)) &&
69 CompareGuid ((EFI_GUID
*) BootOption
->OptionalData
, &mBmAutoCreateBootOptionGuid
)
78 For a bootable Device path, return its boot type.
80 @param DevicePath The bootable device Path to check
82 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
83 which HID is floppy device.
84 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
85 and its last device path node's subtype is MSG_ATAPI_DP.
86 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
87 and its last device path node's subtype is MSG_SATA_DP.
88 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
89 and its last device path node's subtype is MSG_SCSI_DP.
90 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
91 and its last device path node's subtype is MSG_USB_DP.
92 @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
93 and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
94 MSG_IPv4_DP or MSG_IPv6_DP.
95 @retval MessageHttpBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
96 and its last device path node's subtype is MSG_URI_DP.
97 @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.
102 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
105 EFI_DEVICE_PATH_PROTOCOL
*Node
;
106 EFI_DEVICE_PATH_PROTOCOL
*NextNode
;
108 ASSERT (DevicePath
!= NULL
);
110 for (Node
= DevicePath
; !IsDevicePathEndType (Node
); Node
= NextDevicePathNode (Node
)) {
111 switch (DevicePathType (Node
)) {
113 case ACPI_DEVICE_PATH
:
114 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH
*) Node
)->HID
) == 0x0604) {
115 return BmAcpiFloppyBoot
;
119 case HARDWARE_DEVICE_PATH
:
120 if (DevicePathSubType (Node
) == HW_CONTROLLER_DP
) {
121 return BmHardwareDeviceBoot
;
125 case MESSAGING_DEVICE_PATH
:
127 // Skip LUN device node
131 NextNode
= NextDevicePathNode (NextNode
);
133 (DevicePathType (NextNode
) == MESSAGING_DEVICE_PATH
) &&
134 (DevicePathSubType(NextNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
)
138 // If the device path not only point to driver device, it is not a messaging device path,
140 if (!IsDevicePathEndType (NextNode
)) {
144 switch (DevicePathSubType (Node
)) {
146 return BmMessageAtapiBoot
;
150 return BmMessageSataBoot
;
154 return BmMessageUsbBoot
;
158 return BmMessageScsiBoot
;
161 case MSG_MAC_ADDR_DP
:
165 return BmMessageNetworkBoot
;
169 return BmMessageHttpBoot
;
179 Find the boot option in the NV storage and return the option number.
181 @param OptionToFind Boot option to be checked.
183 @return The option number of the found boot option.
187 BmFindBootOptionInVariable (
188 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
192 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
194 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
195 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
196 UINTN BootOptionCount
;
199 OptionNumber
= LoadOptionNumberUnassigned
;
202 // Try to match the variable exactly if the option number is assigned
204 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
206 OptionName
, sizeof (OptionName
), L
"%s%04x",
207 mBmLoadOptionName
[OptionToFind
->OptionType
], OptionToFind
->OptionNumber
209 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
211 if (!EFI_ERROR (Status
)) {
212 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
213 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
214 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
215 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
216 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
217 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
219 OptionNumber
= OptionToFind
->OptionNumber
;
221 EfiBootManagerFreeLoadOption (&BootOption
);
226 // The option number assigned is either incorrect or unassigned.
228 if (OptionNumber
== LoadOptionNumberUnassigned
) {
229 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
231 Index
= EfiBootManagerFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
233 OptionNumber
= BootOptions
[Index
].OptionNumber
;
236 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
243 Get the file buffer using a Memory Mapped Device Path.
245 FV address may change across reboot. This routine promises the FV file device path is right.
247 @param FilePath The Memory Mapped Device Path to get the file buffer.
248 @param FullPath Receive the updated FV Device Path pointint to the file.
249 @param FileSize Receive the file buffer size.
251 @return The file buffer.
254 BmGetFileBufferByFvFilePath (
255 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
256 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
262 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
264 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
265 UINT32 AuthenticationStatus
;
267 EFI_HANDLE
*FvHandles
;
268 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
272 // Get the file buffer by using the exactly FilePath.
274 FvFileNode
= FilePath
;
275 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
276 if (!EFI_ERROR (Status
)) {
277 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
278 if (FileBuffer
!= NULL
) {
279 *FullPath
= DuplicateDevicePath (FilePath
);
285 // Only wide match other FVs if it's a memory mapped FV file path.
287 if ((DevicePathType (FilePath
) != HARDWARE_DEVICE_PATH
) || (DevicePathSubType (FilePath
) != HW_MEMMAP_DP
)) {
291 FvFileNode
= NextDevicePathNode (FilePath
);
294 // Firstly find the FV file in current FV
296 gBS
->HandleProtocol (
298 &gEfiLoadedImageProtocolGuid
,
299 (VOID
**) &LoadedImage
301 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
302 FileBuffer
= BmGetFileBufferByFvFilePath (NewDevicePath
, FullPath
, FileSize
);
303 FreePool (NewDevicePath
);
305 if (FileBuffer
!= NULL
) {
310 // Secondly find the FV file in all other FVs
312 gBS
->LocateHandleBuffer (
314 &gEfiFirmwareVolume2ProtocolGuid
,
319 for (Index
= 0; (Index
< FvHandleCount
) && (FileBuffer
== NULL
); Index
++) {
320 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
326 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
327 FileBuffer
= BmGetFileBufferByFvFilePath (NewDevicePath
, FullPath
, FileSize
);
328 FreePool (NewDevicePath
);
331 if (FvHandles
!= NULL
) {
332 FreePool (FvHandles
);
338 Check if it's a Device Path pointing to FV file.
340 The function doesn't garentee the device path points to existing FV file.
342 @param DevicePath Input device path.
344 @retval TRUE The device path is a FV File Device Path.
345 @retval FALSE The device path is NOT a FV File Device Path.
349 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
354 EFI_DEVICE_PATH_PROTOCOL
*Node
;
357 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &Handle
);
358 if (!EFI_ERROR (Status
)) {
362 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
363 DevicePath
= NextDevicePathNode (DevicePath
);
364 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == MEDIA_PIWG_FW_FILE_DP
)) {
365 return IsDevicePathEnd (NextDevicePathNode (DevicePath
));
372 Check whether a USB device match the specified USB Class device path. This
373 function follows "Load Option Processing" behavior in UEFI specification.
375 @param UsbIo USB I/O protocol associated with the USB device.
376 @param UsbClass The USB Class device path to match.
378 @retval TRUE The USB device match the USB Class device path.
379 @retval FALSE The USB device does not match the USB Class device path.
384 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
385 IN USB_CLASS_DEVICE_PATH
*UsbClass
389 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
390 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
392 UINT8 DeviceSubClass
;
393 UINT8 DeviceProtocol
;
395 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
396 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
401 // Check Vendor Id and Product Id.
403 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
404 if (EFI_ERROR (Status
)) {
408 if ((UsbClass
->VendorId
!= 0xffff) &&
409 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
413 if ((UsbClass
->ProductId
!= 0xffff) &&
414 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
418 DeviceClass
= DevDesc
.DeviceClass
;
419 DeviceSubClass
= DevDesc
.DeviceSubClass
;
420 DeviceProtocol
= DevDesc
.DeviceProtocol
;
421 if (DeviceClass
== 0) {
423 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
424 // Protocol in Interface Descriptor instead.
426 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
427 if (EFI_ERROR (Status
)) {
431 DeviceClass
= IfDesc
.InterfaceClass
;
432 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
433 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
437 // Check Class, SubClass and Protocol.
439 if ((UsbClass
->DeviceClass
!= 0xff) &&
440 (UsbClass
->DeviceClass
!= DeviceClass
)) {
444 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
445 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
449 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
450 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
458 Eliminate the extra spaces in the Str to one space.
460 @param Str Input string info.
463 BmEliminateExtraSpaces (
470 for (Index
= 0, ActualIndex
= 0; Str
[Index
] != L
'\0'; Index
++) {
471 if ((Str
[Index
] != L
' ') || ((ActualIndex
> 0) && (Str
[ActualIndex
- 1] != L
' '))) {
472 Str
[ActualIndex
++] = Str
[Index
];
475 Str
[ActualIndex
] = L
'\0';
479 Try to get the controller's ATA/ATAPI description.
481 @param Handle Controller handle.
483 @return The description string.
486 BmGetDescriptionFromDiskInfo (
492 EFI_DISK_INFO_PROTOCOL
*DiskInfo
;
494 EFI_ATAPI_IDENTIFY_DATA IdentifyData
;
495 EFI_SCSI_INQUIRY_DATA InquiryData
;
498 CONST UINTN ModelNameLength
= 40;
499 CONST UINTN SerialNumberLength
= 20;
505 Status
= gBS
->HandleProtocol (
507 &gEfiDiskInfoProtocolGuid
,
510 if (EFI_ERROR (Status
)) {
514 if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoAhciInterfaceGuid
) ||
515 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoIdeInterfaceGuid
)) {
516 BufferSize
= sizeof (EFI_ATAPI_IDENTIFY_DATA
);
517 Status
= DiskInfo
->Identify (
522 if (!EFI_ERROR (Status
)) {
523 Description
= AllocateZeroPool ((ModelNameLength
+ SerialNumberLength
+ 2) * sizeof (CHAR16
));
524 ASSERT (Description
!= NULL
);
525 for (Index
= 0; Index
+ 1 < ModelNameLength
; Index
+= 2) {
526 Description
[Index
] = (CHAR16
) IdentifyData
.ModelName
[Index
+ 1];
527 Description
[Index
+ 1] = (CHAR16
) IdentifyData
.ModelName
[Index
];
531 Description
[Length
++] = L
' ';
533 for (Index
= 0; Index
+ 1 < SerialNumberLength
; Index
+= 2) {
534 Description
[Length
+ Index
] = (CHAR16
) IdentifyData
.SerialNo
[Index
+ 1];
535 Description
[Length
+ Index
+ 1] = (CHAR16
) IdentifyData
.SerialNo
[Index
];
538 Description
[Length
++] = L
'\0';
539 ASSERT (Length
== ModelNameLength
+ SerialNumberLength
+ 2);
541 BmEliminateExtraSpaces (Description
);
543 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
544 BufferSize
= sizeof (EFI_SCSI_INQUIRY_DATA
);
545 Status
= DiskInfo
->Inquiry (
550 if (!EFI_ERROR (Status
)) {
551 Description
= AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2) * sizeof (CHAR16
));
552 ASSERT (Description
!= NULL
);
555 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
556 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
557 // Here combine the vendor identification and product identification to the description.
559 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
]);
560 Temp
= StrPtr
[VENDOR_IDENTIFICATION_LENGTH
];
561 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = '\0';
562 AsciiStrToUnicodeStr (StrPtr
, Description
);
563 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = Temp
;
566 // Add one space at the middle of vendor information and product information.
568 Description
[VENDOR_IDENTIFICATION_LENGTH
] = L
' ';
570 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
]);
571 StrPtr
[PRODUCT_IDENTIFICATION_LENGTH
] = '\0';
572 AsciiStrToUnicodeStr (StrPtr
, Description
+ VENDOR_IDENTIFICATION_LENGTH
+ 1);
574 BmEliminateExtraSpaces (Description
);
582 Try to get the controller's USB description.
584 @param Handle Controller handle.
586 @return The description string.
589 BmGetUsbDescription (
594 EFI_USB_IO_PROTOCOL
*UsbIo
;
596 CHAR16
*Manufacturer
;
598 CHAR16
*SerialNumber
;
600 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
603 Status
= gBS
->HandleProtocol (
605 &gEfiUsbIoProtocolGuid
,
608 if (EFI_ERROR (Status
)) {
614 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
615 if (EFI_ERROR (Status
)) {
619 Status
= UsbIo
->UsbGetStringDescriptor (
622 DevDesc
.StrManufacturer
,
625 if (EFI_ERROR (Status
)) {
626 Manufacturer
= &NullChar
;
629 Status
= UsbIo
->UsbGetStringDescriptor (
635 if (EFI_ERROR (Status
)) {
639 Status
= UsbIo
->UsbGetStringDescriptor (
642 DevDesc
.StrSerialNumber
,
645 if (EFI_ERROR (Status
)) {
646 SerialNumber
= &NullChar
;
649 if ((Manufacturer
== &NullChar
) &&
650 (Product
== &NullChar
) &&
651 (SerialNumber
== &NullChar
)
656 DescMaxSize
= StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
);
657 Description
= AllocateZeroPool (DescMaxSize
);
658 ASSERT (Description
!= NULL
);
659 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Manufacturer
);
660 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
662 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Product
);
663 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
665 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), SerialNumber
);
667 if (Manufacturer
!= &NullChar
) {
668 FreePool (Manufacturer
);
670 if (Product
!= &NullChar
) {
673 if (SerialNumber
!= &NullChar
) {
674 FreePool (SerialNumber
);
677 BmEliminateExtraSpaces (Description
);
683 Return the boot description for the controller based on the type.
685 @param Handle Controller handle.
687 @return The description string.
690 BmGetMiscDescription (
696 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
697 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
699 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
700 case BmAcpiFloppyBoot
:
701 Description
= L
"Floppy";
704 case BmMessageAtapiBoot
:
705 case BmMessageSataBoot
:
706 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
707 ASSERT_EFI_ERROR (Status
);
709 // Assume a removable SATA device should be the DVD/CD device
711 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
714 case BmMessageUsbBoot
:
715 Description
= L
"USB Device";
718 case BmMessageScsiBoot
:
719 Description
= L
"SCSI Device";
722 case BmHardwareDeviceBoot
:
723 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
724 if (!EFI_ERROR (Status
)) {
725 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
727 Description
= L
"Misc Device";
731 case BmMessageNetworkBoot
:
732 Description
= L
"Network";
735 case BmMessageHttpBoot
:
736 Description
= L
"Http";
740 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**) &Fs
);
741 if (!EFI_ERROR (Status
)) {
742 Description
= L
"Non-Block Boot Device";
744 Description
= L
"Misc Device";
749 return AllocateCopyPool (StrSize (Description
), Description
);
753 Register the platform provided boot description handler.
755 @param Handler The platform provided boot description handler
757 @retval EFI_SUCCESS The handler was registered successfully.
758 @retval EFI_ALREADY_STARTED The handler was already registered.
759 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
763 EfiBootManagerRegisterBootDescriptionHandler (
764 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
768 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
770 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
771 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
772 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
774 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
775 if (Entry
->Handler
== Handler
) {
776 return EFI_ALREADY_STARTED
;
780 Entry
= AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY
));
782 return EFI_OUT_OF_RESOURCES
;
785 Entry
->Signature
= BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
;
786 Entry
->Handler
= Handler
;
787 InsertTailList (&mPlatformBootDescriptionHandlers
, &Entry
->Link
);
791 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers
[] = {
793 BmGetDescriptionFromDiskInfo
,
798 Return the boot description for the controller.
800 @param Handle Controller handle.
802 @return The description string.
805 BmGetBootDescription (
810 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
812 CHAR16
*DefaultDescription
;
817 // Firstly get the default boot description
819 DefaultDescription
= NULL
;
820 for (Index
= 0; Index
< sizeof (mBmBootDescriptionHandlers
) / sizeof (mBmBootDescriptionHandlers
[0]); Index
++) {
821 DefaultDescription
= mBmBootDescriptionHandlers
[Index
] (Handle
);
822 if (DefaultDescription
!= NULL
) {
824 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
825 // ONLY for core provided boot description handler.
827 Temp
= AllocatePool (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
));
828 ASSERT (Temp
!= NULL
);
830 (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
))/sizeof(CHAR16
),
834 (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
))/sizeof(CHAR16
),
837 FreePool (DefaultDescription
);
838 DefaultDescription
= Temp
;
842 ASSERT (DefaultDescription
!= NULL
);
845 // Secondly query platform for the better boot description
847 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
848 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
849 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
851 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
852 Description
= Entry
->Handler (Handle
, DefaultDescription
);
853 if (Description
!= NULL
) {
854 FreePool (DefaultDescription
);
859 return DefaultDescription
;
863 Check whether a USB device match the specified USB WWID device path. This
864 function follows "Load Option Processing" behavior in UEFI specification.
866 @param UsbIo USB I/O protocol associated with the USB device.
867 @param UsbWwid The USB WWID device path to match.
869 @retval TRUE The USB device match the USB WWID device path.
870 @retval FALSE The USB device does not match the USB WWID device path.
875 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
876 IN USB_WWID_DEVICE_PATH
*UsbWwid
880 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
881 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
887 CHAR16
*SerialNumberStr
;
890 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
891 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
896 // Check Vendor Id and Product Id.
898 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
899 if (EFI_ERROR (Status
)) {
902 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
903 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
908 // Check Interface Number.
910 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
911 if (EFI_ERROR (Status
)) {
914 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
919 // Check Serial Number.
921 if (DevDesc
.StrSerialNumber
== 0) {
926 // Get all supported languages.
930 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
931 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
936 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
938 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
939 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
940 if (CompareStr
[CompareLen
- 1] == L
'\0') {
945 // Compare serial number in each supported language.
947 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
948 SerialNumberStr
= NULL
;
949 Status
= UsbIo
->UsbGetStringDescriptor (
952 DevDesc
.StrSerialNumber
,
955 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
959 Length
= StrLen (SerialNumberStr
);
960 if ((Length
>= CompareLen
) &&
961 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
962 FreePool (SerialNumberStr
);
966 FreePool (SerialNumberStr
);
973 Find a USB device which match the specified short-form device path start with
974 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
975 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
976 this function will only search in its child devices.
978 @param DevicePath The device path that contains USB Class or USB WWID device path.
979 @param ParentDevicePathSize The length of the device path before the USB Class or
980 USB WWID device path.
981 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
983 @retval NULL The matched USB IO handles cannot be found.
984 @retval other The matched USB IO handles.
989 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
990 IN UINTN ParentDevicePathSize
,
991 OUT UINTN
*UsbIoHandleCount
995 EFI_HANDLE
*UsbIoHandles
;
996 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
997 EFI_USB_IO_PROTOCOL
*UsbIo
;
1001 ASSERT (UsbIoHandleCount
!= NULL
);
1004 // Get all UsbIo Handles.
1006 Status
= gBS
->LocateHandleBuffer (
1008 &gEfiUsbIoProtocolGuid
,
1013 if (EFI_ERROR (Status
)) {
1014 *UsbIoHandleCount
= 0;
1015 UsbIoHandles
= NULL
;
1018 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
1020 // Get the Usb IO interface.
1022 Status
= gBS
->HandleProtocol(
1023 UsbIoHandles
[Index
],
1024 &gEfiUsbIoProtocolGuid
,
1027 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
1029 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
1032 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
1034 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
1035 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
1036 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
1043 (*UsbIoHandleCount
) --;
1044 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
1050 return UsbIoHandles
;
1054 Expand USB Class or USB WWID device path node to be full device path of a USB
1057 This function support following 4 cases:
1058 1) Boot Option device path starts with a USB Class or USB WWID device path,
1059 and there is no Media FilePath device path in the end.
1060 In this case, it will follow Removable Media Boot Behavior.
1061 2) Boot Option device path starts with a USB Class or USB WWID device path,
1062 and ended with Media FilePath device path.
1063 3) Boot Option device path starts with a full device path to a USB Host Controller,
1064 contains a USB Class or USB WWID device path node, while not ended with Media
1065 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
1066 4) Boot Option device path starts with a full device path to a USB Host Controller,
1067 contains a USB Class or USB WWID device path node, and ended with Media
1068 FilePath device path.
1070 @param FilePath The device path pointing to a load option.
1071 It could be a short-form device path.
1072 @param FullPath Return the full device path of the load option after
1073 short-form device path expanding.
1074 Caller is responsible to free it.
1075 @param FileSize Return the load option size.
1076 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
1078 @return The load option buffer. Caller is responsible to free the memory.
1081 BmExpandUsbDevicePath (
1082 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1083 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1084 OUT UINTN
*FileSize
,
1085 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
1088 UINTN ParentDevicePathSize
;
1089 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
1090 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
1091 EFI_HANDLE
*Handles
;
1096 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
1097 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
1099 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
1101 for (Index
= 0; (Index
< HandleCount
) && (FileBuffer
== NULL
); Index
++) {
1102 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
1103 FileBuffer
= BmGetLoadOptionBuffer (FullDevicePath
, FullPath
, FileSize
);
1104 FreePool (FullDevicePath
);
1107 if (Handles
!= NULL
) {
1115 Expand File-path device path node to be full device path in platform.
1117 @param FilePath The device path pointing to a load option.
1118 It could be a short-form device path.
1119 @param FullPath Return the full device path of the load option after
1120 short-form device path expanding.
1121 Caller is responsible to free it.
1122 @param FileSize Return the load option size.
1124 @return The load option buffer. Caller is responsible to free the memory.
1127 BmExpandFileDevicePath (
1128 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1129 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1136 EFI_HANDLE
*Handles
;
1137 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1139 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
1141 UINT32 AuthenticationStatus
;
1143 EfiBootManagerConnectAll ();
1144 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &Handles
);
1145 if (EFI_ERROR (Status
)) {
1151 // Enumerate all removable media devices followed by all fixed media devices,
1152 // followed by media devices which don't layer on block io.
1154 for (MediaType
= 0; MediaType
< 3; MediaType
++) {
1155 for (Index
= 0; Index
< HandleCount
; Index
++) {
1156 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiBlockIoProtocolGuid
, (VOID
*) &BlockIo
);
1157 if (EFI_ERROR (Status
)) {
1160 if ((MediaType
== 0 && BlockIo
!= NULL
&& BlockIo
->Media
->RemovableMedia
) ||
1161 (MediaType
== 1 && BlockIo
!= NULL
&& !BlockIo
->Media
->RemovableMedia
) ||
1162 (MediaType
== 2 && BlockIo
== NULL
)
1164 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
);
1165 FileBuffer
= GetFileBufferByFilePath (TRUE
, FullDevicePath
, FileSize
, &AuthenticationStatus
);
1166 if (FileBuffer
!= NULL
) {
1167 *FullPath
= FullDevicePath
;
1171 FreePool (FullDevicePath
);
1176 if (Handles
!= NULL
) {
1185 Save the partition DevicePath to the CachedDevicePath as the first instance.
1187 @param CachedDevicePath The device path cache.
1188 @param DevicePath The partition device path to be cached.
1191 BmCachePartitionDevicePath (
1192 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
1193 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1196 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1199 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
1200 TempDevicePath
= *CachedDevicePath
;
1201 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
1202 FreePool (TempDevicePath
);
1205 if (*CachedDevicePath
== NULL
) {
1206 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
1210 TempDevicePath
= *CachedDevicePath
;
1211 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
1212 if (TempDevicePath
!= NULL
) {
1213 FreePool (TempDevicePath
);
1217 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
1218 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
1221 TempDevicePath
= *CachedDevicePath
;
1222 while (!IsDevicePathEnd (TempDevicePath
)) {
1223 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1225 // Parse one instance
1227 while (!IsDevicePathEndType (TempDevicePath
)) {
1228 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1232 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
1235 SetDevicePathEndNode (TempDevicePath
);
1242 Expand a device path that starts with a hard drive media device path node to be a
1243 full device path that includes the full hardware path to the device. We need
1244 to do this so it can be booted. As an optimization the front match (the part point
1245 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
1246 so a connect all is not required on every boot. All successful history device path
1247 which point to partition node (the front part) will be saved.
1249 @param FilePath The device path pointing to a load option.
1250 It could be a short-form device path.
1251 @param FullPath Return the full device path of the load option after
1252 short-form device path expanding.
1253 Caller is responsible to free it.
1254 @param FileSize Return the load option size.
1256 @return The load option buffer. Caller is responsible to free the memory.
1259 BmExpandPartitionDevicePath (
1260 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1261 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1266 UINTN BlockIoHandleCount
;
1267 EFI_HANDLE
*BlockIoBuffer
;
1269 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
1271 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
1272 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
1273 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1274 UINTN CachedDevicePathSize
;
1276 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1281 // Check if there is prestore 'HDDP' variable.
1282 // If exist, search the front path which point to partition node in the variable instants.
1283 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
1285 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
1288 // Delete the invalid 'HDDP' variable.
1290 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
1291 FreePool (CachedDevicePath
);
1292 CachedDevicePath
= NULL
;
1293 Status
= gRT
->SetVariable (
1295 &mBmHardDriveBootVariableGuid
,
1300 ASSERT_EFI_ERROR (Status
);
1303 if (CachedDevicePath
!= NULL
) {
1304 TempNewDevicePath
= CachedDevicePath
;
1308 // Check every instance of the variable
1309 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
1310 // partial partition boot option. Second, check whether the instance could be connected.
1312 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
1313 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1315 // Connect the device path instance, the device path point to hard drive media device path node
1316 // e.g. ACPI() /PCI()/ATA()/Partition()
1318 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
1319 if (!EFI_ERROR (Status
)) {
1320 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
1321 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1322 FreePool (TempDevicePath
);
1324 if (FileBuffer
!= NULL
) {
1326 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
1329 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
1331 // Save the matching Device Path so we don't need to do a connect all next time
1332 // Failing to save only impacts performance next time expanding the short-form device path
1334 Status
= gRT
->SetVariable (
1336 &mBmHardDriveBootVariableGuid
,
1337 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1338 GetDevicePathSize (CachedDevicePath
),
1343 FreePool (Instance
);
1344 FreePool (CachedDevicePath
);
1350 // Come here means the first instance is not matched
1354 } while (TempNewDevicePath
!= NULL
);
1358 // If we get here we fail to find or 'HDDP' not exist, and now we need
1359 // to search all devices in the system for a matched partition
1361 EfiBootManagerConnectAll ();
1362 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
1363 if (EFI_ERROR (Status
)) {
1364 BlockIoHandleCount
= 0;
1365 BlockIoBuffer
= NULL
;
1368 // Loop through all the device handles that support the BLOCK_IO Protocol
1370 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
1371 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
1372 if (BlockIoDevicePath
== NULL
) {
1376 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1378 // Find the matched partition device path
1380 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
1381 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1382 FreePool (TempDevicePath
);
1384 if (FileBuffer
!= NULL
) {
1385 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
1388 // Save the matching Device Path so we don't need to do a connect all next time
1389 // Failing to save only impacts performance next time expanding the short-form device path
1391 Status
= gRT
->SetVariable (
1393 &mBmHardDriveBootVariableGuid
,
1394 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1395 GetDevicePathSize (CachedDevicePath
),
1404 if (CachedDevicePath
!= NULL
) {
1405 FreePool (CachedDevicePath
);
1407 if (BlockIoBuffer
!= NULL
) {
1408 FreePool (BlockIoBuffer
);
1414 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
1415 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1417 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1418 @param FullPath Return the full device path pointing to the load option.
1419 @param FileSize Return the size of the load option.
1421 @return The load option buffer.
1424 BmExpandMediaDevicePath (
1425 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1426 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1432 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1434 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1437 EFI_HANDLE
*SimpleFileSystemHandles
;
1438 UINTN NumberSimpleFileSystemHandles
;
1441 UINT32 AuthenticationStatus
;
1444 // Check whether the device is connected
1446 TempDevicePath
= DevicePath
;
1447 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1448 if (!EFI_ERROR (Status
)) {
1449 ASSERT (IsDevicePathEnd (TempDevicePath
));
1451 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1452 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1453 if (FileBuffer
== NULL
) {
1454 FreePool (TempDevicePath
);
1455 TempDevicePath
= NULL
;
1457 *FullPath
= TempDevicePath
;
1462 // For device boot option only pointing to the removable device handle,
1463 // should make sure all its children handles (its child partion or media handles) are created and connected.
1465 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1468 // Issue a dummy read to the device to check for media change.
1469 // When the removable media is changed, any Block IO read/write will
1470 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1471 // returned. After the Block IO protocol is reinstalled, subsequent
1472 // Block IO read/write will success.
1474 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1475 ASSERT_EFI_ERROR (Status
);
1476 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1477 ASSERT_EFI_ERROR (Status
);
1478 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1479 if (Buffer
!= NULL
) {
1480 BlockIo
->ReadBlocks (
1482 BlockIo
->Media
->MediaId
,
1484 BlockIo
->Media
->BlockSize
,
1491 // Detect the the default boot file from removable Media
1495 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1496 gBS
->LocateHandleBuffer (
1498 &gEfiSimpleFileSystemProtocolGuid
,
1500 &NumberSimpleFileSystemHandles
,
1501 &SimpleFileSystemHandles
1503 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1505 // Get the device path size of SimpleFileSystem handle
1507 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1508 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1510 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1512 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1513 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1514 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1515 if (FileBuffer
!= NULL
) {
1516 *FullPath
= TempDevicePath
;
1519 FreePool (TempDevicePath
);
1523 if (SimpleFileSystemHandles
!= NULL
) {
1524 FreePool (SimpleFileSystemHandles
);
1531 Check whether Left and Right are the same without matching the specific
1532 device path data in IP device path and URI device path node.
1534 @retval TRUE Left and Right are the same.
1535 @retval FALSE Left and Right are the different.
1538 BmMatchHttpBootDevicePath (
1539 IN EFI_DEVICE_PATH_PROTOCOL
*Left
,
1540 IN EFI_DEVICE_PATH_PROTOCOL
*Right
1543 for (; !IsDevicePathEnd (Left
) && !IsDevicePathEnd (Right
)
1544 ; Left
= NextDevicePathNode (Left
), Right
= NextDevicePathNode (Right
)
1546 if (CompareMem (Left
, Right
, DevicePathNodeLength (Left
)) != 0) {
1547 if ((DevicePathType (Left
) != MESSAGING_DEVICE_PATH
) || (DevicePathType (Right
) != MESSAGING_DEVICE_PATH
)) {
1551 if (((DevicePathSubType (Left
) != MSG_IPv4_DP
) || (DevicePathSubType (Right
) != MSG_IPv4_DP
)) &&
1552 ((DevicePathSubType (Left
) != MSG_IPv6_DP
) || (DevicePathSubType (Right
) != MSG_IPv6_DP
)) &&
1553 ((DevicePathSubType (Left
) != MSG_URI_DP
) || (DevicePathSubType (Right
) != MSG_URI_DP
))
1559 return (BOOLEAN
) (IsDevicePathEnd (Left
) && IsDevicePathEnd (Right
));
1563 Get the file buffer from Load File instance.
1565 @param FilePath The media device path pointing to a LoadFile instance.
1566 @param FullPath Return the full device path pointing to the load option.
1567 @param FileSize Return the size of the load option.
1569 @return The load option buffer.
1572 BmGetFileBufferFromLoadFile (
1573 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1574 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1581 EFI_HANDLE
*Handles
;
1584 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1585 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1589 // Get file buffer from load file instance.
1592 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1593 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1595 // When wide match happens, pass full device path to LoadFile (),
1596 // otherwise, pass remaining device path to LoadFile ().
1602 // Use wide match algorithm to find one when
1603 // cannot find a LoadFile instance to exactly match the FilePath
1605 Status
= gBS
->LocateHandleBuffer (
1607 &gEfiLoadFileProtocolGuid
,
1612 if (EFI_ERROR (Status
)) {
1616 for (Index
= 0; Index
< HandleCount
; Index
++) {
1617 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
)) {
1618 Handle
= Handles
[Index
];
1622 if (Handles
!= NULL
) {
1627 if (Handle
== NULL
) {
1631 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**) &LoadFile
);
1632 ASSERT_EFI_ERROR (Status
);
1636 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1637 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1638 FileBuffer
= AllocatePool (BufferSize
);
1639 if (FileBuffer
!= NULL
) {
1640 Status
= EFI_SUCCESS
;
1644 if (!EFI_ERROR (Status
)) {
1645 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1648 if (!EFI_ERROR (Status
)) {
1650 // LoadFile () may cause the device path of the Handle be updated.
1652 *FullPath
= DuplicateDevicePath (DevicePathFromHandle (Handle
));
1653 *FileSize
= BufferSize
;
1661 Get the load option by its device path.
1663 @param FilePath The device path pointing to a load option.
1664 It could be a short-form device path.
1665 @param FullPath Return the full device path of the load option after
1666 short-form device path expanding.
1667 Caller is responsible to free it.
1668 @param FileSize Return the load option size.
1670 @return The load option buffer. Caller is responsible to free the memory.
1673 BmGetLoadOptionBuffer (
1674 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1675 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1681 UINT32 AuthenticationStatus
;
1682 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1685 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1687 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1694 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1697 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1698 if (EFI_ERROR (Status
)) {
1699 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1702 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1703 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1707 // Expand the short-form device path to full device path
1709 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1710 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1712 // Expand the Harddrive device path
1714 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1715 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1716 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
)) {
1718 // Expand the File-path device path
1720 return BmExpandFileDevicePath (FilePath
, FullPath
, FileSize
);
1722 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1723 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1724 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1729 if (!IsDevicePathEnd (Node
)) {
1731 // Expand the USB WWID/Class device path
1733 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1734 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1736 // Boot Option device path starts with USB Class or USB WWID device path.
1737 // For Boot Option device path which doesn't begin with the USB Class or
1738 // USB WWID device path, it's not needed to connect again here.
1740 BmConnectUsbShortFormDevicePath (FilePath
);
1741 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1748 // Get file buffer from FV file path.
1750 if (BmIsFvFilePath (FilePath
)) {
1751 return BmGetFileBufferByFvFilePath (FilePath
, FullPath
, FileSize
);
1755 // Get file buffer from simple file system.
1758 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1759 if (!EFI_ERROR (Status
)) {
1760 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1761 if (FileBuffer
!= NULL
) {
1762 *FullPath
= DuplicateDevicePath (FilePath
);
1767 return BmGetFileBufferFromLoadFile (FilePath
, FullPath
, FileSize
);
1771 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1772 also signals the EFI ready to boot event. If the device path for the option
1773 starts with a BBS device path a legacy boot is attempted via the registered
1774 gLegacyBoot function. Short form device paths are also supported via this
1775 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1776 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1777 If the BootOption Device Path fails the removable media boot algorithm
1778 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1779 is tried per processor type)
1781 @param BootOption Boot Option to try and boot.
1782 On return, BootOption->Status contains the boot status.
1783 EFI_SUCCESS BootOption was booted
1784 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1785 registered via EfiBootManagerInitialize().
1786 EFI_NOT_FOUND The BootOption was not found on the system
1787 !EFI_SUCCESS BootOption failed with this error status
1792 EfiBootManagerBoot (
1793 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1797 EFI_HANDLE ImageHandle
;
1798 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1801 UINTN OriginalOptionNumber
;
1802 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1803 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1804 EFI_HANDLE FvHandle
;
1807 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1808 EFI_EVENT LegacyBootEvent
;
1810 if (BootOption
== NULL
) {
1814 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1815 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1820 // 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")
1822 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1823 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1824 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1825 if (!EFI_ERROR (Status
)) {
1827 // Save the BootOption->OptionNumber to restore later
1829 OptionNumber
= Uint16
;
1830 OriginalOptionNumber
= BootOption
->OptionNumber
;
1831 BootOption
->OptionNumber
= OptionNumber
;
1832 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1833 BootOption
->OptionNumber
= OriginalOptionNumber
;
1836 if (EFI_ERROR (Status
)) {
1837 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1838 BootOption
->Status
= Status
;
1844 // 2. Set BootCurrent
1846 Uint16
= (UINT16
) OptionNumber
;
1847 BmSetVariableAndReportStatusCodeOnError (
1849 &gEfiGlobalVariableGuid
,
1850 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1856 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1859 Node
= BootOption
->FilePath
;
1860 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1861 if (!EFI_ERROR (Status
) && CompareGuid (
1862 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1863 PcdGetPtr (PcdBootManagerMenuFile
)
1865 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1866 BmStopHotkeyService (NULL
, NULL
);
1868 EfiSignalEventReadyToBoot();
1870 // Report Status Code to indicate ReadyToBoot was signalled
1872 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1874 // 4. Repair system through DriverHealth protocol
1876 BmRepairAllControllers ();
1879 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1882 // 5. Load EFI boot option to ImageHandle
1885 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1886 Status
= EFI_NOT_FOUND
;
1887 FileBuffer
= BmGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1889 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1890 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1891 BmPrintDp (BootOption
->FilePath
);
1892 DEBUG ((EFI_D_INFO
, " -> "));
1893 BmPrintDp (FilePath
);
1894 DEBUG ((EFI_D_INFO
, "\n"));
1897 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1898 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1899 Status
= gBS
->LoadImage (
1908 if (FileBuffer
!= NULL
) {
1909 FreePool (FileBuffer
);
1911 if (FilePath
!= NULL
) {
1912 FreePool (FilePath
);
1915 if (EFI_ERROR (Status
)) {
1917 // Report Status Code to indicate that the failure to load boot option
1919 REPORT_STATUS_CODE (
1920 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1921 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1923 BootOption
->Status
= Status
;
1929 // 6. Adjust the different type memory page number just before booting
1930 // and save the updated info into the variable for next boot to use
1932 BmSetMemoryTypeInformationVariable (
1933 (BOOLEAN
) ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1937 if (BootOption
->Description
== NULL
) {
1938 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1940 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1945 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1946 // Write boot to OS performance data for Legacy boot
1948 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1949 if (mBmLegacyBoot
!= NULL
) {
1951 // Write boot to OS performance data for legacy boot.
1955 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1957 Status
= EfiCreateEventLegacyBootEx(
1959 BmWriteBootToOsPerformanceData
,
1963 ASSERT_EFI_ERROR (Status
);
1966 mBmLegacyBoot (BootOption
);
1968 BootOption
->Status
= EFI_UNSUPPORTED
;
1971 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1976 // Provide the image with its load options
1978 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1979 ASSERT_EFI_ERROR (Status
);
1981 if (!BmIsAutoCreateBootOption (BootOption
)) {
1982 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1983 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1987 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1989 ImageInfo
->ParentHandle
= NULL
;
1992 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1994 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1997 // Write boot to OS performance data for UEFI boot
2000 BmWriteBootToOsPerformanceData (NULL
, NULL
);
2003 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
2005 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
2006 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
2007 BootOption
->Status
= Status
;
2008 if (EFI_ERROR (Status
)) {
2010 // Report Status Code to indicate that boot failure
2012 REPORT_STATUS_CODE (
2013 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2014 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
2017 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
2020 // Clear the Watchdog Timer after the image returns
2022 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
2025 // Set Logo status invalid after trying one boot option
2028 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
2029 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
2030 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
2031 ASSERT_EFI_ERROR (Status
);
2035 // Clear Boot Current
2037 Status
= gRT
->SetVariable (
2039 &gEfiGlobalVariableGuid
,
2045 // Deleting variable with current variable implementation shouldn't fail.
2046 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
2047 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
2049 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
2053 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2054 instances, has the same partition node with HardDriveDevicePath device path
2056 @param BlockIoDevicePath Multi device path instances which need to check
2057 @param HardDriveDevicePath A device path which starts with a hard drive media
2060 @retval TRUE There is a matched device path instance.
2061 @retval FALSE There is no matched device path instance.
2065 BmMatchPartitionDevicePathNode (
2066 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
2067 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
2070 HARDDRIVE_DEVICE_PATH
*Node
;
2072 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
2077 // find the partition device path node
2079 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
2080 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
2081 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
2086 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
2089 if (IsDevicePathEnd (BlockIoDevicePath
)) {
2094 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2096 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
2099 // Match Signature and PartitionNumber.
2100 // Unused bytes in Signature are initiaized with zeros.
2103 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
2104 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
2105 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
2106 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
2111 Enumerate all boot option descriptions and append " 2"/" 3"/... to make
2114 @param BootOptions Array of boot options.
2115 @param BootOptionCount Count of boot options.
2118 BmMakeBootOptionDescriptionUnique (
2119 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
,
2120 UINTN BootOptionCount
2125 UINTN DescriptionSize
;
2126 UINTN MaxSuffixSize
;
2130 if (BootOptionCount
== 0) {
2135 // Calculate the maximum buffer size for the number suffix.
2136 // The initial sizeof (CHAR16) is for the blank space before the number.
2138 MaxSuffixSize
= sizeof (CHAR16
);
2139 for (Index
= BootOptionCount
; Index
!= 0; Index
= Index
/ 10) {
2140 MaxSuffixSize
+= sizeof (CHAR16
);
2143 Visited
= AllocateZeroPool (sizeof (BOOLEAN
) * BootOptionCount
);
2144 ASSERT (Visited
!= NULL
);
2146 for (Base
= 0; Base
< BootOptionCount
; Base
++) {
2147 if (!Visited
[Base
]) {
2149 Visited
[Base
] = TRUE
;
2150 DescriptionSize
= StrSize (BootOptions
[Base
].Description
);
2151 for (Index
= Base
+ 1; Index
< BootOptionCount
; Index
++) {
2152 if (!Visited
[Index
] && StrCmp (BootOptions
[Base
].Description
, BootOptions
[Index
].Description
) == 0) {
2153 Visited
[Index
] = TRUE
;
2155 FreePool (BootOptions
[Index
].Description
);
2156 BootOptions
[Index
].Description
= AllocatePool (DescriptionSize
+ MaxSuffixSize
);
2158 BootOptions
[Index
].Description
, DescriptionSize
+ MaxSuffixSize
,
2160 BootOptions
[Base
].Description
, MatchCount
2171 Emuerate all possible bootable medias in the following order:
2172 1. Removable BlockIo - The boot option only points to the removable media
2173 device, like USB key, DVD, Floppy etc.
2174 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
2176 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
2177 SimpleFileSystem Protocol, but not supporting BlockIo
2179 4. LoadFile - The boot option points to the media supporting
2181 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
2183 @param BootOptionCount Return the boot option count which has been found.
2185 @retval Pointer to the boot option array.
2187 EFI_BOOT_MANAGER_LOAD_OPTION
*
2188 BmEnumerateBootOptions (
2189 UINTN
*BootOptionCount
2193 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2195 EFI_HANDLE
*Handles
;
2196 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
2199 CHAR16
*Description
;
2201 ASSERT (BootOptionCount
!= NULL
);
2203 *BootOptionCount
= 0;
2207 // Parse removable block io followed by fixed block io
2209 gBS
->LocateHandleBuffer (
2211 &gEfiBlockIoProtocolGuid
,
2217 for (Removable
= 0; Removable
< 2; Removable
++) {
2218 for (Index
= 0; Index
< HandleCount
; Index
++) {
2219 Status
= gBS
->HandleProtocol (
2221 &gEfiBlockIoProtocolGuid
,
2224 if (EFI_ERROR (Status
)) {
2229 // Skip the logical partitions
2231 if (BlkIo
->Media
->LogicalPartition
) {
2236 // Skip the fixed block io then the removable block io
2238 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
2242 Description
= BmGetBootDescription (Handles
[Index
]);
2243 BootOptions
= ReallocatePool (
2244 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2245 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2248 ASSERT (BootOptions
!= NULL
);
2250 Status
= EfiBootManagerInitializeLoadOption (
2251 &BootOptions
[(*BootOptionCount
)++],
2252 LoadOptionNumberUnassigned
,
2256 DevicePathFromHandle (Handles
[Index
]),
2260 ASSERT_EFI_ERROR (Status
);
2262 FreePool (Description
);
2266 if (HandleCount
!= 0) {
2271 // Parse simple file system not based on block io
2273 gBS
->LocateHandleBuffer (
2275 &gEfiSimpleFileSystemProtocolGuid
,
2280 for (Index
= 0; Index
< HandleCount
; Index
++) {
2281 Status
= gBS
->HandleProtocol (
2283 &gEfiBlockIoProtocolGuid
,
2286 if (!EFI_ERROR (Status
)) {
2288 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2292 Description
= BmGetBootDescription (Handles
[Index
]);
2293 BootOptions
= ReallocatePool (
2294 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2295 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2298 ASSERT (BootOptions
!= NULL
);
2300 Status
= EfiBootManagerInitializeLoadOption (
2301 &BootOptions
[(*BootOptionCount
)++],
2302 LoadOptionNumberUnassigned
,
2306 DevicePathFromHandle (Handles
[Index
]),
2310 ASSERT_EFI_ERROR (Status
);
2311 FreePool (Description
);
2314 if (HandleCount
!= 0) {
2319 // Parse load file, assuming UEFI Network boot option
2321 gBS
->LocateHandleBuffer (
2323 &gEfiLoadFileProtocolGuid
,
2328 for (Index
= 0; Index
< HandleCount
; Index
++) {
2330 Description
= BmGetBootDescription (Handles
[Index
]);
2331 BootOptions
= ReallocatePool (
2332 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2333 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2336 ASSERT (BootOptions
!= NULL
);
2338 Status
= EfiBootManagerInitializeLoadOption (
2339 &BootOptions
[(*BootOptionCount
)++],
2340 LoadOptionNumberUnassigned
,
2344 DevicePathFromHandle (Handles
[Index
]),
2348 ASSERT_EFI_ERROR (Status
);
2349 FreePool (Description
);
2352 if (HandleCount
!= 0) {
2356 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
2361 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2365 EfiBootManagerRefreshAllBootOption (
2370 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2371 UINTN NvBootOptionCount
;
2372 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2373 UINTN BootOptionCount
;
2377 // Optionally refresh the legacy boot option
2379 if (mBmRefreshLegacyBootOption
!= NULL
) {
2380 mBmRefreshLegacyBootOption ();
2383 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2384 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2387 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2389 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2390 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2391 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2395 // Remove invalid EFI boot options from NV
2397 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2398 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2399 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2400 ) && BmIsAutoCreateBootOption (&NvBootOptions
[Index
])
2403 // Only check those added by BDS
2404 // so that the boot options added by end-user or OS installer won't be deleted
2406 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
2407 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2409 // Deleting variable with current variable implementation shouldn't fail.
2411 ASSERT_EFI_ERROR (Status
);
2417 // Add new EFI boot options to NV
2419 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2420 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
2421 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2423 // Try best to add the boot options so continue upon failure.
2428 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2429 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2433 This function is called to create the boot option for the Boot Manager Menu.
2435 The Boot Manager Menu is shown after successfully booting a boot option.
2436 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2438 @param BootOption Return the boot option of the Boot Manager Menu
2440 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2441 @retval Status Return status of gRT->SetVariable (). BootOption still points
2442 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2445 BmRegisterBootManagerMenu (
2446 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2450 CHAR16
*Description
;
2451 UINTN DescriptionLength
;
2452 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2453 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2454 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2456 Status
= GetSectionFromFv (
2457 PcdGetPtr (PcdBootManagerMenuFile
),
2458 EFI_SECTION_USER_INTERFACE
,
2460 (VOID
**) &Description
,
2463 if (EFI_ERROR (Status
)) {
2467 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2468 Status
= gBS
->HandleProtocol (
2470 &gEfiLoadedImageProtocolGuid
,
2471 (VOID
**) &LoadedImage
2473 ASSERT_EFI_ERROR (Status
);
2474 DevicePath
= AppendDevicePathNode (
2475 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2476 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2478 ASSERT (DevicePath
!= NULL
);
2480 Status
= EfiBootManagerInitializeLoadOption (
2482 LoadOptionNumberUnassigned
,
2484 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2485 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2490 ASSERT_EFI_ERROR (Status
);
2491 FreePool (DevicePath
);
2492 if (Description
!= NULL
) {
2493 FreePool (Description
);
2497 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2498 UINTN BootOptionCount
;
2500 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2501 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2502 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2505 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2509 Return the boot option corresponding to the Boot Manager Menu.
2510 It may automatically create one if the boot option hasn't been created yet.
2512 @param BootOption Return the Boot Manager Menu.
2514 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2515 @retval Status Return status of gRT->SetVariable (). BootOption still points
2516 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2520 EfiBootManagerGetBootManagerMenu (
2521 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2525 UINTN BootOptionCount
;
2526 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2528 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2529 EFI_HANDLE FvHandle
;
2531 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2533 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2534 Node
= BootOptions
[Index
].FilePath
;
2535 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2536 if (!EFI_ERROR (Status
)) {
2538 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2539 PcdGetPtr (PcdBootManagerMenuFile
)
2542 Status
= EfiBootManagerInitializeLoadOption (
2544 BootOptions
[Index
].OptionNumber
,
2545 BootOptions
[Index
].OptionType
,
2546 BootOptions
[Index
].Attributes
,
2547 BootOptions
[Index
].Description
,
2548 BootOptions
[Index
].FilePath
,
2549 BootOptions
[Index
].OptionalData
,
2550 BootOptions
[Index
].OptionalDataSize
2552 ASSERT_EFI_ERROR (Status
);
2558 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2561 // Automatically create the Boot#### for Boot Manager Menu when not found.
2563 if (Index
== BootOptionCount
) {
2564 return BmRegisterBootManagerMenu (BootOption
);