2 Library functions which relates with booting.
4 Copyright (c) 2011 - 2015, 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 For a bootable Device path, return its boot type.
58 @param DevicePath The bootable device Path to check
60 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
61 which HID is floppy device.
62 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
63 and its last device path node's subtype is MSG_ATAPI_DP.
64 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
65 and its last device path node's subtype is MSG_SATA_DP.
66 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
67 and its last device path node's subtype is MSG_SCSI_DP.
68 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
69 and its last device path node's subtype is MSG_USB_DP.
70 @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
71 and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
72 MSG_IPv4_DP or MSG_IPv6_DP.
73 @retval MessageHttpBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
74 and its last device path node's subtype is MSG_URI_DP.
75 @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.
80 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
83 EFI_DEVICE_PATH_PROTOCOL
*Node
;
84 EFI_DEVICE_PATH_PROTOCOL
*NextNode
;
86 ASSERT (DevicePath
!= NULL
);
88 for (Node
= DevicePath
; !IsDevicePathEndType (Node
); Node
= NextDevicePathNode (Node
)) {
89 switch (DevicePathType (Node
)) {
91 case ACPI_DEVICE_PATH
:
92 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH
*) Node
)->HID
) == 0x0604) {
93 return BmAcpiFloppyBoot
;
97 case HARDWARE_DEVICE_PATH
:
98 if (DevicePathSubType (Node
) == HW_CONTROLLER_DP
) {
99 return BmHardwareDeviceBoot
;
103 case MESSAGING_DEVICE_PATH
:
105 // Skip LUN device node
109 NextNode
= NextDevicePathNode (NextNode
);
111 (DevicePathType (NextNode
) == MESSAGING_DEVICE_PATH
) &&
112 (DevicePathSubType(NextNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
)
116 // If the device path not only point to driver device, it is not a messaging device path,
118 if (!IsDevicePathEndType (NextNode
)) {
122 switch (DevicePathSubType (Node
)) {
124 return BmMessageAtapiBoot
;
128 return BmMessageSataBoot
;
132 return BmMessageUsbBoot
;
136 return BmMessageScsiBoot
;
139 case MSG_MAC_ADDR_DP
:
143 return BmMessageNetworkBoot
;
147 return BmMessageHttpBoot
;
157 Find the boot option in the NV storage and return the option number.
159 @param OptionToFind Boot option to be checked.
161 @return The option number of the found boot option.
165 BmFindBootOptionInVariable (
166 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
170 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
172 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
173 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
174 UINTN BootOptionCount
;
177 OptionNumber
= LoadOptionNumberUnassigned
;
180 // Try to match the variable exactly if the option number is assigned
182 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
184 OptionName
, sizeof (OptionName
), L
"%s%04x",
185 mBmLoadOptionName
[OptionToFind
->OptionType
], OptionToFind
->OptionNumber
187 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
189 if (!EFI_ERROR (Status
)) {
190 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
191 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
192 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
193 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
194 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
195 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
197 OptionNumber
= OptionToFind
->OptionNumber
;
199 EfiBootManagerFreeLoadOption (&BootOption
);
204 // The option number assigned is either incorrect or unassigned.
206 if (OptionNumber
== LoadOptionNumberUnassigned
) {
207 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
209 Index
= EfiBootManagerFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
211 OptionNumber
= BootOptions
[Index
].OptionNumber
;
214 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
221 Get the file buffer using a Memory Mapped Device Path.
223 FV address may change across reboot. This routine promises the FV file device path is right.
225 @param DevicePath The Memory Mapped Device Path to get the file buffer.
226 @param FullPath Receive the updated FV Device Path pointint to the file.
227 @param FileSize Receive the file buffer size.
229 @return The file buffer.
232 BmGetFileBufferByMemmapFv (
233 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
234 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
240 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
242 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
243 UINT32 AuthenticationStatus
;
245 EFI_HANDLE
*FvHandles
;
246 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
249 FvFileNode
= DevicePath
;
250 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
251 if (!EFI_ERROR (Status
)) {
252 FileBuffer
= GetFileBufferByFilePath (TRUE
, DevicePath
, FileSize
, &AuthenticationStatus
);
253 if (FileBuffer
!= NULL
) {
254 *FullPath
= DuplicateDevicePath (DevicePath
);
259 FvFileNode
= NextDevicePathNode (DevicePath
);
262 // Firstly find the FV file in current FV
264 gBS
->HandleProtocol (
266 &gEfiLoadedImageProtocolGuid
,
267 (VOID
**) &LoadedImage
269 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
270 FileBuffer
= BmGetFileBufferByMemmapFv (NewDevicePath
, FullPath
, FileSize
);
271 FreePool (NewDevicePath
);
273 if (FileBuffer
!= NULL
) {
278 // Secondly find the FV file in all other FVs
280 gBS
->LocateHandleBuffer (
282 &gEfiFirmwareVolume2ProtocolGuid
,
287 for (Index
= 0; (Index
< FvHandleCount
) && (FileBuffer
== NULL
); Index
++) {
288 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
294 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
295 FileBuffer
= BmGetFileBufferByMemmapFv (NewDevicePath
, FullPath
, FileSize
);
296 FreePool (NewDevicePath
);
299 if (FvHandles
!= NULL
) {
300 FreePool (FvHandles
);
306 Check if it's a Memory Mapped FV Device Path.
308 The function doesn't garentee the device path points to existing FV file.
310 @param DevicePath Input device path.
312 @retval TRUE The device path is a Memory Mapped FV Device Path.
313 @retval FALSE The device path is NOT a Memory Mapped FV Device Path.
316 BmIsMemmapFvFilePath (
317 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
320 EFI_DEVICE_PATH_PROTOCOL
*FileNode
;
322 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
323 FileNode
= NextDevicePathNode (DevicePath
);
324 if ((DevicePathType (FileNode
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (FileNode
) == MEDIA_PIWG_FW_FILE_DP
)) {
325 return IsDevicePathEnd (NextDevicePathNode (FileNode
));
333 Check whether a USB device match the specified USB Class device path. This
334 function follows "Load Option Processing" behavior in UEFI specification.
336 @param UsbIo USB I/O protocol associated with the USB device.
337 @param UsbClass The USB Class device path to match.
339 @retval TRUE The USB device match the USB Class device path.
340 @retval FALSE The USB device does not match the USB Class device path.
345 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
346 IN USB_CLASS_DEVICE_PATH
*UsbClass
350 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
351 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
353 UINT8 DeviceSubClass
;
354 UINT8 DeviceProtocol
;
356 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
357 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
362 // Check Vendor Id and Product Id.
364 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
365 if (EFI_ERROR (Status
)) {
369 if ((UsbClass
->VendorId
!= 0xffff) &&
370 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
374 if ((UsbClass
->ProductId
!= 0xffff) &&
375 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
379 DeviceClass
= DevDesc
.DeviceClass
;
380 DeviceSubClass
= DevDesc
.DeviceSubClass
;
381 DeviceProtocol
= DevDesc
.DeviceProtocol
;
382 if (DeviceClass
== 0) {
384 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
385 // Protocol in Interface Descriptor instead.
387 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
388 if (EFI_ERROR (Status
)) {
392 DeviceClass
= IfDesc
.InterfaceClass
;
393 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
394 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
398 // Check Class, SubClass and Protocol.
400 if ((UsbClass
->DeviceClass
!= 0xff) &&
401 (UsbClass
->DeviceClass
!= DeviceClass
)) {
405 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
406 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
410 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
411 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
419 Eliminate the extra spaces in the Str to one space.
421 @param Str Input string info.
424 BmEliminateExtraSpaces (
431 for (Index
= 0, ActualIndex
= 0; Str
[Index
] != L
'\0'; Index
++) {
432 if ((Str
[Index
] != L
' ') || ((ActualIndex
> 0) && (Str
[ActualIndex
- 1] != L
' '))) {
433 Str
[ActualIndex
++] = Str
[Index
];
436 Str
[ActualIndex
] = L
'\0';
440 Try to get the controller's ATA/ATAPI description.
442 @param Handle Controller handle.
444 @return The description string.
447 BmGetDescriptionFromDiskInfo (
453 EFI_DISK_INFO_PROTOCOL
*DiskInfo
;
455 EFI_ATAPI_IDENTIFY_DATA IdentifyData
;
456 EFI_SCSI_INQUIRY_DATA InquiryData
;
459 CONST UINTN ModelNameLength
= 40;
460 CONST UINTN SerialNumberLength
= 20;
466 Status
= gBS
->HandleProtocol (
468 &gEfiDiskInfoProtocolGuid
,
471 if (EFI_ERROR (Status
)) {
475 if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoAhciInterfaceGuid
) ||
476 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoIdeInterfaceGuid
)) {
477 BufferSize
= sizeof (EFI_ATAPI_IDENTIFY_DATA
);
478 Status
= DiskInfo
->Identify (
483 if (!EFI_ERROR (Status
)) {
484 Description
= AllocateZeroPool ((ModelNameLength
+ SerialNumberLength
+ 2) * sizeof (CHAR16
));
485 ASSERT (Description
!= NULL
);
486 for (Index
= 0; Index
+ 1 < ModelNameLength
; Index
+= 2) {
487 Description
[Index
] = (CHAR16
) IdentifyData
.ModelName
[Index
+ 1];
488 Description
[Index
+ 1] = (CHAR16
) IdentifyData
.ModelName
[Index
];
492 Description
[Length
++] = L
' ';
494 for (Index
= 0; Index
+ 1 < SerialNumberLength
; Index
+= 2) {
495 Description
[Length
+ Index
] = (CHAR16
) IdentifyData
.SerialNo
[Index
+ 1];
496 Description
[Length
+ Index
+ 1] = (CHAR16
) IdentifyData
.SerialNo
[Index
];
499 Description
[Length
++] = L
'\0';
500 ASSERT (Length
== ModelNameLength
+ SerialNumberLength
+ 2);
502 BmEliminateExtraSpaces (Description
);
504 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
505 BufferSize
= sizeof (EFI_SCSI_INQUIRY_DATA
);
506 Status
= DiskInfo
->Inquiry (
511 if (!EFI_ERROR (Status
)) {
512 Description
= AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2) * sizeof (CHAR16
));
513 ASSERT (Description
!= NULL
);
516 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
517 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
518 // Here combine the vendor identification and product identification to the description.
520 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
]);
521 Temp
= StrPtr
[VENDOR_IDENTIFICATION_LENGTH
];
522 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = '\0';
523 AsciiStrToUnicodeStr (StrPtr
, Description
);
524 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = Temp
;
527 // Add one space at the middle of vendor information and product information.
529 Description
[VENDOR_IDENTIFICATION_LENGTH
] = L
' ';
531 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
]);
532 StrPtr
[PRODUCT_IDENTIFICATION_LENGTH
] = '\0';
533 AsciiStrToUnicodeStr (StrPtr
, Description
+ VENDOR_IDENTIFICATION_LENGTH
+ 1);
535 BmEliminateExtraSpaces (Description
);
543 Try to get the controller's USB description.
545 @param Handle Controller handle.
547 @return The description string.
550 BmGetUsbDescription (
555 EFI_USB_IO_PROTOCOL
*UsbIo
;
557 CHAR16
*Manufacturer
;
559 CHAR16
*SerialNumber
;
561 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
564 Status
= gBS
->HandleProtocol (
566 &gEfiUsbIoProtocolGuid
,
569 if (EFI_ERROR (Status
)) {
575 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
576 if (EFI_ERROR (Status
)) {
580 Status
= UsbIo
->UsbGetStringDescriptor (
583 DevDesc
.StrManufacturer
,
586 if (EFI_ERROR (Status
)) {
587 Manufacturer
= &NullChar
;
590 Status
= UsbIo
->UsbGetStringDescriptor (
596 if (EFI_ERROR (Status
)) {
600 Status
= UsbIo
->UsbGetStringDescriptor (
603 DevDesc
.StrSerialNumber
,
606 if (EFI_ERROR (Status
)) {
607 SerialNumber
= &NullChar
;
610 if ((Manufacturer
== &NullChar
) &&
611 (Product
== &NullChar
) &&
612 (SerialNumber
== &NullChar
)
617 DescMaxSize
= StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
);
618 Description
= AllocateZeroPool (DescMaxSize
);
619 ASSERT (Description
!= NULL
);
620 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Manufacturer
);
621 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
623 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Product
);
624 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
626 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), SerialNumber
);
628 if (Manufacturer
!= &NullChar
) {
629 FreePool (Manufacturer
);
631 if (Product
!= &NullChar
) {
634 if (SerialNumber
!= &NullChar
) {
635 FreePool (SerialNumber
);
638 BmEliminateExtraSpaces (Description
);
644 Return the boot description for the controller based on the type.
646 @param Handle Controller handle.
648 @return The description string.
651 BmGetMiscDescription (
657 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
658 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
660 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
661 case BmAcpiFloppyBoot
:
662 Description
= L
"Floppy";
665 case BmMessageAtapiBoot
:
666 case BmMessageSataBoot
:
667 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
668 ASSERT_EFI_ERROR (Status
);
670 // Assume a removable SATA device should be the DVD/CD device
672 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
675 case BmMessageUsbBoot
:
676 Description
= L
"USB Device";
679 case BmMessageScsiBoot
:
680 Description
= L
"SCSI Device";
683 case BmHardwareDeviceBoot
:
684 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
685 if (!EFI_ERROR (Status
)) {
686 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
688 Description
= L
"Misc Device";
692 case BmMessageNetworkBoot
:
693 Description
= L
"Network";
696 case BmMessageHttpBoot
:
697 Description
= L
"Http";
701 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**) &Fs
);
702 if (!EFI_ERROR (Status
)) {
703 Description
= L
"Non-Block Boot Device";
705 Description
= L
"Misc Device";
710 return AllocateCopyPool (StrSize (Description
), Description
);
714 Register the platform provided boot description handler.
716 @param Handler The platform provided boot description handler
718 @retval EFI_SUCCESS The handler was registered successfully.
719 @retval EFI_ALREADY_STARTED The handler was already registered.
720 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
724 EfiBootManagerRegisterBootDescriptionHandler (
725 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
729 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
731 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
732 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
733 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
735 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
736 if (Entry
->Handler
== Handler
) {
737 return EFI_ALREADY_STARTED
;
741 Entry
= AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY
));
743 return EFI_OUT_OF_RESOURCES
;
746 Entry
->Signature
= BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
;
747 Entry
->Handler
= Handler
;
748 InsertTailList (&mPlatformBootDescriptionHandlers
, &Entry
->Link
);
752 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers
[] = {
754 BmGetDescriptionFromDiskInfo
,
759 Return the boot description for the controller.
761 @param Handle Controller handle.
763 @return The description string.
766 BmGetBootDescription (
771 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
773 CHAR16
*DefaultDescription
;
778 // Firstly get the default boot description
780 DefaultDescription
= NULL
;
781 for (Index
= 0; Index
< sizeof (mBmBootDescriptionHandlers
) / sizeof (mBmBootDescriptionHandlers
[0]); Index
++) {
782 DefaultDescription
= mBmBootDescriptionHandlers
[Index
] (Handle
);
783 if (DefaultDescription
!= NULL
) {
785 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
786 // ONLY for core provided boot description handler.
788 Temp
= AllocatePool (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
));
789 ASSERT (Temp
!= NULL
);
791 (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
))/sizeof(CHAR16
),
795 (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
))/sizeof(CHAR16
),
798 FreePool (DefaultDescription
);
799 DefaultDescription
= Temp
;
803 ASSERT (DefaultDescription
!= NULL
);
806 // Secondly query platform for the better boot description
808 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
809 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
810 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
812 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
813 Description
= Entry
->Handler (Handle
, DefaultDescription
);
814 if (Description
!= NULL
) {
815 FreePool (DefaultDescription
);
820 return DefaultDescription
;
824 Check whether a USB device match the specified USB WWID device path. This
825 function follows "Load Option Processing" behavior in UEFI specification.
827 @param UsbIo USB I/O protocol associated with the USB device.
828 @param UsbWwid The USB WWID device path to match.
830 @retval TRUE The USB device match the USB WWID device path.
831 @retval FALSE The USB device does not match the USB WWID device path.
836 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
837 IN USB_WWID_DEVICE_PATH
*UsbWwid
841 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
842 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
848 CHAR16
*SerialNumberStr
;
851 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
852 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
857 // Check Vendor Id and Product Id.
859 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
860 if (EFI_ERROR (Status
)) {
863 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
864 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
869 // Check Interface Number.
871 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
872 if (EFI_ERROR (Status
)) {
875 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
880 // Check Serial Number.
882 if (DevDesc
.StrSerialNumber
== 0) {
887 // Get all supported languages.
891 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
892 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
897 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
899 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
900 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
901 if (CompareStr
[CompareLen
- 1] == L
'\0') {
906 // Compare serial number in each supported language.
908 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
909 SerialNumberStr
= NULL
;
910 Status
= UsbIo
->UsbGetStringDescriptor (
913 DevDesc
.StrSerialNumber
,
916 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
920 Length
= StrLen (SerialNumberStr
);
921 if ((Length
>= CompareLen
) &&
922 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
923 FreePool (SerialNumberStr
);
927 FreePool (SerialNumberStr
);
934 Find a USB device which match the specified short-form device path start with
935 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
936 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
937 this function will only search in its child devices.
939 @param DevicePath The device path that contains USB Class or USB WWID device path.
940 @param ParentDevicePathSize The length of the device path before the USB Class or
941 USB WWID device path.
942 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
944 @retval NULL The matched USB IO handles cannot be found.
945 @retval other The matched USB IO handles.
950 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
951 IN UINTN ParentDevicePathSize
,
952 OUT UINTN
*UsbIoHandleCount
956 EFI_HANDLE
*UsbIoHandles
;
957 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
958 EFI_USB_IO_PROTOCOL
*UsbIo
;
962 ASSERT (UsbIoHandleCount
!= NULL
);
965 // Get all UsbIo Handles.
967 Status
= gBS
->LocateHandleBuffer (
969 &gEfiUsbIoProtocolGuid
,
974 if (EFI_ERROR (Status
)) {
975 *UsbIoHandleCount
= 0;
979 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
981 // Get the Usb IO interface.
983 Status
= gBS
->HandleProtocol(
985 &gEfiUsbIoProtocolGuid
,
988 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
990 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
993 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
995 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
996 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
997 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
1004 (*UsbIoHandleCount
) --;
1005 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
1011 return UsbIoHandles
;
1015 Expand USB Class or USB WWID device path node to be full device path of a USB
1018 This function support following 4 cases:
1019 1) Boot Option device path starts with a USB Class or USB WWID device path,
1020 and there is no Media FilePath device path in the end.
1021 In this case, it will follow Removable Media Boot Behavior.
1022 2) Boot Option device path starts with a USB Class or USB WWID device path,
1023 and ended with Media FilePath device path.
1024 3) Boot Option device path starts with a full device path to a USB Host Controller,
1025 contains a USB Class or USB WWID device path node, while not ended with Media
1026 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
1027 4) Boot Option device path starts with a full device path to a USB Host Controller,
1028 contains a USB Class or USB WWID device path node, and ended with Media
1029 FilePath device path.
1031 @param FilePath The device path pointing to a load option.
1032 It could be a short-form device path.
1033 @param FullPath Return the full device path of the load option after
1034 short-form device path expanding.
1035 Caller is responsible to free it.
1036 @param FileSize Return the load option size.
1037 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
1039 @return The load option buffer. Caller is responsible to free the memory.
1042 BmExpandUsbDevicePath (
1043 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1044 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1045 OUT UINTN
*FileSize
,
1046 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
1049 UINTN ParentDevicePathSize
;
1050 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
1051 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
1052 EFI_HANDLE
*Handles
;
1057 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
1058 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
1060 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
1062 for (Index
= 0; (Index
< HandleCount
) && (FileBuffer
== NULL
); Index
++) {
1063 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
1064 FileBuffer
= BmGetLoadOptionBuffer (FullDevicePath
, FullPath
, FileSize
);
1065 FreePool (FullDevicePath
);
1068 if (Handles
!= NULL
) {
1076 Expand File-path device path node to be full device path in platform.
1078 @param FilePath The device path pointing to a load option.
1079 It could be a short-form device path.
1080 @param FullPath Return the full device path of the load option after
1081 short-form device path expanding.
1082 Caller is responsible to free it.
1083 @param FileSize Return the load option size.
1085 @return The load option buffer. Caller is responsible to free the memory.
1088 BmExpandFileDevicePath (
1089 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1090 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1097 EFI_HANDLE
*Handles
;
1098 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1100 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
1102 UINT32 AuthenticationStatus
;
1104 EfiBootManagerConnectAll ();
1105 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &Handles
);
1106 if (EFI_ERROR (Status
)) {
1112 // Enumerate all removable media devices followed by all fixed media devices,
1113 // followed by media devices which don't layer on block io.
1115 for (MediaType
= 0; MediaType
< 3; MediaType
++) {
1116 for (Index
= 0; Index
< HandleCount
; Index
++) {
1117 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiBlockIoProtocolGuid
, (VOID
*) &BlockIo
);
1118 if (EFI_ERROR (Status
)) {
1121 if ((MediaType
== 0 && BlockIo
!= NULL
&& BlockIo
->Media
->RemovableMedia
) ||
1122 (MediaType
== 1 && BlockIo
!= NULL
&& !BlockIo
->Media
->RemovableMedia
) ||
1123 (MediaType
== 2 && BlockIo
== NULL
)
1125 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
);
1126 FileBuffer
= GetFileBufferByFilePath (TRUE
, FullDevicePath
, FileSize
, &AuthenticationStatus
);
1127 if (FileBuffer
!= NULL
) {
1128 *FullPath
= FullDevicePath
;
1132 FreePool (FullDevicePath
);
1137 if (Handles
!= NULL
) {
1146 Save the partition DevicePath to the CachedDevicePath as the first instance.
1148 @param CachedDevicePath The device path cache.
1149 @param DevicePath The partition device path to be cached.
1152 BmCachePartitionDevicePath (
1153 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
1154 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1157 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1160 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
1161 TempDevicePath
= *CachedDevicePath
;
1162 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
1163 FreePool (TempDevicePath
);
1166 if (*CachedDevicePath
== NULL
) {
1167 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
1171 TempDevicePath
= *CachedDevicePath
;
1172 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
1173 if (TempDevicePath
!= NULL
) {
1174 FreePool (TempDevicePath
);
1178 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
1179 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
1182 TempDevicePath
= *CachedDevicePath
;
1183 while (!IsDevicePathEnd (TempDevicePath
)) {
1184 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1186 // Parse one instance
1188 while (!IsDevicePathEndType (TempDevicePath
)) {
1189 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1193 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
1196 SetDevicePathEndNode (TempDevicePath
);
1203 Expand a device path that starts with a hard drive media device path node to be a
1204 full device path that includes the full hardware path to the device. We need
1205 to do this so it can be booted. As an optimization the front match (the part point
1206 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
1207 so a connect all is not required on every boot. All successful history device path
1208 which point to partition node (the front part) will be saved.
1210 @param FilePath The device path pointing to a load option.
1211 It could be a short-form device path.
1212 @param FullPath Return the full device path of the load option after
1213 short-form device path expanding.
1214 Caller is responsible to free it.
1215 @param FileSize Return the load option size.
1217 @return The load option buffer. Caller is responsible to free the memory.
1220 BmExpandPartitionDevicePath (
1221 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1222 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1227 UINTN BlockIoHandleCount
;
1228 EFI_HANDLE
*BlockIoBuffer
;
1230 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
1232 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
1233 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
1234 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1235 UINTN CachedDevicePathSize
;
1237 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1242 // Check if there is prestore 'HDDP' variable.
1243 // If exist, search the front path which point to partition node in the variable instants.
1244 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
1246 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
1249 // Delete the invalid 'HDDP' variable.
1251 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
1252 FreePool (CachedDevicePath
);
1253 CachedDevicePath
= NULL
;
1254 Status
= gRT
->SetVariable (
1256 &mBmHardDriveBootVariableGuid
,
1261 ASSERT_EFI_ERROR (Status
);
1264 if (CachedDevicePath
!= NULL
) {
1265 TempNewDevicePath
= CachedDevicePath
;
1269 // Check every instance of the variable
1270 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
1271 // partial partition boot option. Second, check whether the instance could be connected.
1273 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
1274 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1276 // Connect the device path instance, the device path point to hard drive media device path node
1277 // e.g. ACPI() /PCI()/ATA()/Partition()
1279 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
1280 if (!EFI_ERROR (Status
)) {
1281 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
1282 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1283 FreePool (TempDevicePath
);
1285 if (FileBuffer
!= NULL
) {
1287 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
1290 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
1292 // Save the matching Device Path so we don't need to do a connect all next time
1293 // Failing to save only impacts performance next time expanding the short-form device path
1295 Status
= gRT
->SetVariable (
1297 &mBmHardDriveBootVariableGuid
,
1298 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1299 GetDevicePathSize (CachedDevicePath
),
1304 FreePool (Instance
);
1305 FreePool (CachedDevicePath
);
1311 // Come here means the first instance is not matched
1315 } while (TempNewDevicePath
!= NULL
);
1319 // If we get here we fail to find or 'HDDP' not exist, and now we need
1320 // to search all devices in the system for a matched partition
1322 EfiBootManagerConnectAll ();
1323 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
1324 if (EFI_ERROR (Status
)) {
1325 BlockIoHandleCount
= 0;
1326 BlockIoBuffer
= NULL
;
1329 // Loop through all the device handles that support the BLOCK_IO Protocol
1331 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
1332 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
1333 if (BlockIoDevicePath
== NULL
) {
1337 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1339 // Find the matched partition device path
1341 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
1342 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1343 FreePool (TempDevicePath
);
1345 if (FileBuffer
!= NULL
) {
1346 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
1349 // Save the matching Device Path so we don't need to do a connect all next time
1350 // Failing to save only impacts performance next time expanding the short-form device path
1352 Status
= gRT
->SetVariable (
1354 &mBmHardDriveBootVariableGuid
,
1355 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1356 GetDevicePathSize (CachedDevicePath
),
1365 if (CachedDevicePath
!= NULL
) {
1366 FreePool (CachedDevicePath
);
1368 if (BlockIoBuffer
!= NULL
) {
1369 FreePool (BlockIoBuffer
);
1375 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
1376 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1378 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1379 @param FullPath Return the full device path pointing to the load option.
1380 @param FileSize Return the size of the load option.
1382 @return The load option buffer.
1385 BmExpandMediaDevicePath (
1386 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1387 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1393 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1395 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1398 EFI_HANDLE
*SimpleFileSystemHandles
;
1399 UINTN NumberSimpleFileSystemHandles
;
1402 UINT32 AuthenticationStatus
;
1405 // Check whether the device is connected
1407 TempDevicePath
= DevicePath
;
1408 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1409 if (!EFI_ERROR (Status
)) {
1410 ASSERT (IsDevicePathEnd (TempDevicePath
));
1412 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1413 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1414 if (FileBuffer
== NULL
) {
1415 FreePool (TempDevicePath
);
1416 TempDevicePath
= NULL
;
1418 *FullPath
= TempDevicePath
;
1423 // For device boot option only pointing to the removable device handle,
1424 // should make sure all its children handles (its child partion or media handles) are created and connected.
1426 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1429 // Issue a dummy read to the device to check for media change.
1430 // When the removable media is changed, any Block IO read/write will
1431 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1432 // returned. After the Block IO protocol is reinstalled, subsequent
1433 // Block IO read/write will success.
1435 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1436 ASSERT_EFI_ERROR (Status
);
1437 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1438 ASSERT_EFI_ERROR (Status
);
1439 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1440 if (Buffer
!= NULL
) {
1441 BlockIo
->ReadBlocks (
1443 BlockIo
->Media
->MediaId
,
1445 BlockIo
->Media
->BlockSize
,
1452 // Detect the the default boot file from removable Media
1456 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1457 gBS
->LocateHandleBuffer (
1459 &gEfiSimpleFileSystemProtocolGuid
,
1461 &NumberSimpleFileSystemHandles
,
1462 &SimpleFileSystemHandles
1464 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1466 // Get the device path size of SimpleFileSystem handle
1468 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1469 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1471 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1473 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1474 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1475 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1476 if (FileBuffer
!= NULL
) {
1477 *FullPath
= TempDevicePath
;
1480 FreePool (TempDevicePath
);
1484 if (SimpleFileSystemHandles
!= NULL
) {
1485 FreePool (SimpleFileSystemHandles
);
1492 Get the load option by its device path.
1494 @param FilePath The device path pointing to a load option.
1495 It could be a short-form device path.
1496 @param FullPath Return the full device path of the load option after
1497 short-form device path expanding.
1498 Caller is responsible to free it.
1499 @param FileSize Return the load option size.
1501 @return The load option buffer. Caller is responsible to free the memory.
1504 BmGetLoadOptionBuffer (
1505 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1506 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1512 UINT32 AuthenticationStatus
;
1513 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1516 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1518 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1525 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1528 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1529 if (EFI_ERROR (Status
)) {
1530 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1533 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1534 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1538 // Expand the short-form device path to full device path
1540 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1541 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1543 // Expand the Harddrive device path
1545 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1546 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1547 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
)) {
1549 // Expand the File-path device path
1551 return BmExpandFileDevicePath (FilePath
, FullPath
, FileSize
);
1553 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1554 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1555 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1560 if (!IsDevicePathEnd (Node
)) {
1562 // Expand the USB WWID/Class device path
1564 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1565 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1567 // Boot Option device path starts with USB Class or USB WWID device path.
1568 // For Boot Option device path which doesn't begin with the USB Class or
1569 // USB WWID device path, it's not needed to connect again here.
1571 BmConnectUsbShortFormDevicePath (FilePath
);
1572 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1579 // Fix up the boot option path if it points to a FV in memory map style of device path
1581 if (BmIsMemmapFvFilePath (FilePath
)) {
1582 return BmGetFileBufferByMemmapFv (FilePath
, FullPath
, FileSize
);
1586 // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),
1587 // or it directly points to a file in simple file system instance.
1590 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1591 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1592 if (FileBuffer
!= NULL
) {
1593 if (EFI_ERROR (Status
)) {
1594 *FullPath
= DuplicateDevicePath (FilePath
);
1597 // LoadFile () may cause the device path of the Handle be updated.
1599 *FullPath
= AppendDevicePath (DevicePathFromHandle (Handle
), Node
);
1607 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1608 also signals the EFI ready to boot event. If the device path for the option
1609 starts with a BBS device path a legacy boot is attempted via the registered
1610 gLegacyBoot function. Short form device paths are also supported via this
1611 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1612 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1613 If the BootOption Device Path fails the removable media boot algorithm
1614 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1615 is tried per processor type)
1617 @param BootOption Boot Option to try and boot.
1618 On return, BootOption->Status contains the boot status.
1619 EFI_SUCCESS BootOption was booted
1620 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1621 registered via EfiBootManagerInitialize().
1622 EFI_NOT_FOUND The BootOption was not found on the system
1623 !EFI_SUCCESS BootOption failed with this error status
1628 EfiBootManagerBoot (
1629 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1633 EFI_HANDLE ImageHandle
;
1634 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1637 UINTN OriginalOptionNumber
;
1638 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1639 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1640 EFI_HANDLE FvHandle
;
1643 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1644 EFI_EVENT LegacyBootEvent
;
1646 if (BootOption
== NULL
) {
1650 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1651 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1656 // 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")
1658 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1659 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1660 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1661 if (!EFI_ERROR (Status
)) {
1663 // Save the BootOption->OptionNumber to restore later
1665 OptionNumber
= Uint16
;
1666 OriginalOptionNumber
= BootOption
->OptionNumber
;
1667 BootOption
->OptionNumber
= OptionNumber
;
1668 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1669 BootOption
->OptionNumber
= OriginalOptionNumber
;
1672 if (EFI_ERROR (Status
)) {
1673 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1674 BootOption
->Status
= Status
;
1680 // 2. Set BootCurrent
1682 Uint16
= (UINT16
) OptionNumber
;
1683 BmSetVariableAndReportStatusCodeOnError (
1685 &gEfiGlobalVariableGuid
,
1686 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1692 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1695 Node
= BootOption
->FilePath
;
1696 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1697 if (!EFI_ERROR (Status
) && CompareGuid (
1698 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1699 PcdGetPtr (PcdBootManagerMenuFile
)
1701 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1702 BmStopHotkeyService (NULL
, NULL
);
1704 EfiSignalEventReadyToBoot();
1706 // Report Status Code to indicate ReadyToBoot was signalled
1708 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1710 // 4. Repair system through DriverHealth protocol
1712 BmRepairAllControllers ();
1715 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1718 // 5. Load EFI boot option to ImageHandle
1721 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1722 Status
= EFI_NOT_FOUND
;
1723 FileBuffer
= BmGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1725 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1726 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1727 BmPrintDp (BootOption
->FilePath
);
1728 DEBUG ((EFI_D_INFO
, " -> "));
1729 BmPrintDp (FilePath
);
1730 DEBUG ((EFI_D_INFO
, "\n"));
1733 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1734 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1735 Status
= gBS
->LoadImage (
1744 if (FileBuffer
!= NULL
) {
1745 FreePool (FileBuffer
);
1747 if (FilePath
!= NULL
) {
1748 FreePool (FilePath
);
1751 if (EFI_ERROR (Status
)) {
1753 // Report Status Code to indicate that the failure to load boot option
1755 REPORT_STATUS_CODE (
1756 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1757 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1759 BootOption
->Status
= Status
;
1765 // 6. Adjust the different type memory page number just before booting
1766 // and save the updated info into the variable for next boot to use
1768 BmSetMemoryTypeInformationVariable (
1769 (BOOLEAN
) ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1773 if (BootOption
->Description
== NULL
) {
1774 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1776 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1781 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1782 // Write boot to OS performance data for Legacy boot
1784 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1785 if (mBmLegacyBoot
!= NULL
) {
1787 // Write boot to OS performance data for legacy boot.
1791 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1793 Status
= EfiCreateEventLegacyBootEx(
1795 BmWriteBootToOsPerformanceData
,
1799 ASSERT_EFI_ERROR (Status
);
1802 mBmLegacyBoot (BootOption
);
1804 BootOption
->Status
= EFI_UNSUPPORTED
;
1807 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1812 // Provide the image with its load options
1814 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1815 ASSERT_EFI_ERROR (Status
);
1817 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1818 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1821 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1823 ImageInfo
->ParentHandle
= NULL
;
1826 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1828 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1831 // Write boot to OS performance data for UEFI boot
1834 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1837 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1839 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1840 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1841 BootOption
->Status
= Status
;
1842 if (EFI_ERROR (Status
)) {
1844 // Report Status Code to indicate that boot failure
1846 REPORT_STATUS_CODE (
1847 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1848 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1851 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1854 // Clear the Watchdog Timer after the image returns
1856 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1859 // Set Logo status invalid after trying one boot option
1862 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1863 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1864 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1865 ASSERT_EFI_ERROR (Status
);
1869 // Clear Boot Current
1871 Status
= gRT
->SetVariable (
1873 &gEfiGlobalVariableGuid
,
1879 // Deleting variable with current variable implementation shouldn't fail.
1880 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1881 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1883 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1887 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1888 instances, has the same partition node with HardDriveDevicePath device path
1890 @param BlockIoDevicePath Multi device path instances which need to check
1891 @param HardDriveDevicePath A device path which starts with a hard drive media
1894 @retval TRUE There is a matched device path instance.
1895 @retval FALSE There is no matched device path instance.
1899 BmMatchPartitionDevicePathNode (
1900 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1901 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1904 HARDDRIVE_DEVICE_PATH
*Node
;
1906 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1911 // find the partition device path node
1913 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1914 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1915 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1920 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1923 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1928 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1930 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1933 // Match Signature and PartitionNumber.
1934 // Unused bytes in Signature are initiaized with zeros.
1937 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1938 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1939 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1940 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1945 Enumerate all boot option descriptions and append " 2"/" 3"/... to make
1948 @param BootOptions Array of boot options.
1949 @param BootOptionCount Count of boot options.
1952 BmMakeBootOptionDescriptionUnique (
1953 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
,
1954 UINTN BootOptionCount
1959 UINTN DescriptionSize
;
1960 UINTN MaxSuffixSize
;
1964 if (BootOptionCount
== 0) {
1969 // Calculate the maximum buffer size for the number suffix.
1970 // The initial sizeof (CHAR16) is for the blank space before the number.
1972 MaxSuffixSize
= sizeof (CHAR16
);
1973 for (Index
= BootOptionCount
; Index
!= 0; Index
= Index
/ 10) {
1974 MaxSuffixSize
+= sizeof (CHAR16
);
1977 Visited
= AllocateZeroPool (sizeof (BOOLEAN
) * BootOptionCount
);
1978 ASSERT (Visited
!= NULL
);
1980 for (Base
= 0; Base
< BootOptionCount
; Base
++) {
1981 if (!Visited
[Base
]) {
1983 Visited
[Base
] = TRUE
;
1984 DescriptionSize
= StrSize (BootOptions
[Base
].Description
);
1985 for (Index
= Base
+ 1; Index
< BootOptionCount
; Index
++) {
1986 if (!Visited
[Index
] && StrCmp (BootOptions
[Base
].Description
, BootOptions
[Index
].Description
) == 0) {
1987 Visited
[Index
] = TRUE
;
1989 FreePool (BootOptions
[Index
].Description
);
1990 BootOptions
[Index
].Description
= AllocatePool (DescriptionSize
+ MaxSuffixSize
);
1992 BootOptions
[Index
].Description
, DescriptionSize
+ MaxSuffixSize
,
1994 BootOptions
[Base
].Description
, MatchCount
2005 Emuerate all possible bootable medias in the following order:
2006 1. Removable BlockIo - The boot option only points to the removable media
2007 device, like USB key, DVD, Floppy etc.
2008 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
2010 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
2011 SimpleFileSystem Protocol, but not supporting BlockIo
2013 4. LoadFile - The boot option points to the media supporting
2015 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
2017 @param BootOptionCount Return the boot option count which has been found.
2019 @retval Pointer to the boot option array.
2021 EFI_BOOT_MANAGER_LOAD_OPTION
*
2022 BmEnumerateBootOptions (
2023 UINTN
*BootOptionCount
2027 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2029 EFI_HANDLE
*Handles
;
2030 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
2033 CHAR16
*Description
;
2035 ASSERT (BootOptionCount
!= NULL
);
2037 *BootOptionCount
= 0;
2041 // Parse removable block io followed by fixed block io
2043 gBS
->LocateHandleBuffer (
2045 &gEfiBlockIoProtocolGuid
,
2051 for (Removable
= 0; Removable
< 2; Removable
++) {
2052 for (Index
= 0; Index
< HandleCount
; Index
++) {
2053 Status
= gBS
->HandleProtocol (
2055 &gEfiBlockIoProtocolGuid
,
2058 if (EFI_ERROR (Status
)) {
2063 // Skip the logical partitions
2065 if (BlkIo
->Media
->LogicalPartition
) {
2070 // Skip the fixed block io then the removable block io
2072 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
2076 Description
= BmGetBootDescription (Handles
[Index
]);
2077 BootOptions
= ReallocatePool (
2078 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2079 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2082 ASSERT (BootOptions
!= NULL
);
2084 Status
= EfiBootManagerInitializeLoadOption (
2085 &BootOptions
[(*BootOptionCount
)++],
2086 LoadOptionNumberUnassigned
,
2090 DevicePathFromHandle (Handles
[Index
]),
2094 ASSERT_EFI_ERROR (Status
);
2096 FreePool (Description
);
2100 if (HandleCount
!= 0) {
2105 // Parse simple file system not based on block io
2107 gBS
->LocateHandleBuffer (
2109 &gEfiSimpleFileSystemProtocolGuid
,
2114 for (Index
= 0; Index
< HandleCount
; Index
++) {
2115 Status
= gBS
->HandleProtocol (
2117 &gEfiBlockIoProtocolGuid
,
2120 if (!EFI_ERROR (Status
)) {
2122 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2126 Description
= BmGetBootDescription (Handles
[Index
]);
2127 BootOptions
= ReallocatePool (
2128 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2129 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2132 ASSERT (BootOptions
!= NULL
);
2134 Status
= EfiBootManagerInitializeLoadOption (
2135 &BootOptions
[(*BootOptionCount
)++],
2136 LoadOptionNumberUnassigned
,
2140 DevicePathFromHandle (Handles
[Index
]),
2144 ASSERT_EFI_ERROR (Status
);
2145 FreePool (Description
);
2148 if (HandleCount
!= 0) {
2153 // Parse load file, assuming UEFI Network boot option
2155 gBS
->LocateHandleBuffer (
2157 &gEfiLoadFileProtocolGuid
,
2162 for (Index
= 0; Index
< HandleCount
; Index
++) {
2164 Description
= BmGetBootDescription (Handles
[Index
]);
2165 BootOptions
= ReallocatePool (
2166 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2167 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2170 ASSERT (BootOptions
!= NULL
);
2172 Status
= EfiBootManagerInitializeLoadOption (
2173 &BootOptions
[(*BootOptionCount
)++],
2174 LoadOptionNumberUnassigned
,
2178 DevicePathFromHandle (Handles
[Index
]),
2182 ASSERT_EFI_ERROR (Status
);
2183 FreePool (Description
);
2186 if (HandleCount
!= 0) {
2190 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
2195 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2199 EfiBootManagerRefreshAllBootOption (
2204 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2205 UINTN NvBootOptionCount
;
2206 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2207 UINTN BootOptionCount
;
2211 // Optionally refresh the legacy boot option
2213 if (mBmRefreshLegacyBootOption
!= NULL
) {
2214 mBmRefreshLegacyBootOption ();
2217 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2218 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2221 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2223 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2224 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2225 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2229 // Remove invalid EFI boot options from NV
2231 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2232 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2233 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2235 (NvBootOptions
[Index
].OptionalDataSize
== sizeof (EFI_GUID
)) &&
2236 CompareGuid ((EFI_GUID
*) NvBootOptions
[Index
].OptionalData
, &mBmAutoCreateBootOptionGuid
)
2239 // Only check those added by BDS
2240 // so that the boot options added by end-user or OS installer won't be deleted
2242 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
2243 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2245 // Deleting variable with current variable implementation shouldn't fail.
2247 ASSERT_EFI_ERROR (Status
);
2253 // Add new EFI boot options to NV
2255 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2256 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
2257 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2259 // Try best to add the boot options so continue upon failure.
2264 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2265 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2269 This function is called to create the boot option for the Boot Manager Menu.
2271 The Boot Manager Menu is shown after successfully booting a boot option.
2272 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2274 @param BootOption Return the boot option of the Boot Manager Menu
2276 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2277 @retval Status Return status of gRT->SetVariable (). BootOption still points
2278 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2281 BmRegisterBootManagerMenu (
2282 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2286 CHAR16
*Description
;
2287 UINTN DescriptionLength
;
2288 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2289 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2290 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2292 Status
= GetSectionFromFv (
2293 PcdGetPtr (PcdBootManagerMenuFile
),
2294 EFI_SECTION_USER_INTERFACE
,
2296 (VOID
**) &Description
,
2299 if (EFI_ERROR (Status
)) {
2303 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2304 Status
= gBS
->HandleProtocol (
2306 &gEfiLoadedImageProtocolGuid
,
2307 (VOID
**) &LoadedImage
2309 ASSERT_EFI_ERROR (Status
);
2310 DevicePath
= AppendDevicePathNode (
2311 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2312 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2314 ASSERT (DevicePath
!= NULL
);
2316 Status
= EfiBootManagerInitializeLoadOption (
2318 LoadOptionNumberUnassigned
,
2320 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2321 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2326 ASSERT_EFI_ERROR (Status
);
2327 FreePool (DevicePath
);
2328 if (Description
!= NULL
) {
2329 FreePool (Description
);
2333 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2334 UINTN BootOptionCount
;
2336 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2337 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2338 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2341 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2345 Return the boot option corresponding to the Boot Manager Menu.
2346 It may automatically create one if the boot option hasn't been created yet.
2348 @param BootOption Return the Boot Manager Menu.
2350 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2351 @retval Status Return status of gRT->SetVariable (). BootOption still points
2352 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2356 EfiBootManagerGetBootManagerMenu (
2357 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2361 UINTN BootOptionCount
;
2362 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2364 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2365 EFI_HANDLE FvHandle
;
2367 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2369 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2370 Node
= BootOptions
[Index
].FilePath
;
2371 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2372 if (!EFI_ERROR (Status
)) {
2374 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2375 PcdGetPtr (PcdBootManagerMenuFile
)
2378 Status
= EfiBootManagerInitializeLoadOption (
2380 BootOptions
[Index
].OptionNumber
,
2381 BootOptions
[Index
].OptionType
,
2382 BootOptions
[Index
].Attributes
,
2383 BootOptions
[Index
].Description
,
2384 BootOptions
[Index
].FilePath
,
2385 BootOptions
[Index
].OptionalData
,
2386 BootOptions
[Index
].OptionalDataSize
2388 ASSERT_EFI_ERROR (Status
);
2394 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2397 // Automatically create the Boot#### for Boot Manager Menu when not found.
2399 if (Index
== BootOptionCount
) {
2400 return BmRegisterBootManagerMenu (BootOption
);