2 Library functions which relates with booting.
4 Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "InternalBm.h"
12 EFI_RAM_DISK_PROTOCOL
*mRamDisk
= NULL
;
14 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption
= NULL
;
15 EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot
= NULL
;
18 /// This GUID is used for an EFI Variable that stores the front device pathes
19 /// for a partial device path that starts with the HD node.
21 EFI_GUID mBmHardDriveBootVariableGuid
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
22 EFI_GUID mBmAutoCreateBootOptionGuid
= { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
28 @param Event The triggered event.
29 @param Context Context for this event.
40 // Record the performance data for End of BDS
42 PERF_CROSSMODULE_END("BDS");
48 The function registers the legacy boot support capabilities.
50 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
51 @param LegacyBoot The function pointer to boot the legacy boot option.
55 EfiBootManagerRegisterLegacyBootSupport (
56 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption
,
57 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
60 mBmRefreshLegacyBootOption
= RefreshLegacyBootOption
;
61 mBmLegacyBoot
= LegacyBoot
;
65 Return TRUE when the boot option is auto-created instead of manually added.
67 @param BootOption Pointer to the boot option to check.
69 @retval TRUE The boot option is auto-created.
70 @retval FALSE The boot option is manually added.
73 BmIsAutoCreateBootOption (
74 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
77 if ((BootOption
->OptionalDataSize
== sizeof (EFI_GUID
)) &&
78 CompareGuid ((EFI_GUID
*) BootOption
->OptionalData
, &mBmAutoCreateBootOptionGuid
)
87 Find the boot option in the NV storage and return the option number.
89 @param OptionToFind Boot option to be checked.
91 @return The option number of the found boot option.
95 BmFindBootOptionInVariable (
96 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
100 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
102 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
103 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
104 UINTN BootOptionCount
;
107 OptionNumber
= LoadOptionNumberUnassigned
;
110 // Try to match the variable exactly if the option number is assigned
112 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
114 OptionName
, sizeof (OptionName
), L
"%s%04x",
115 mBmLoadOptionName
[OptionToFind
->OptionType
], OptionToFind
->OptionNumber
117 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
119 if (!EFI_ERROR (Status
)) {
120 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
121 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
122 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
123 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
124 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
125 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
127 OptionNumber
= OptionToFind
->OptionNumber
;
129 EfiBootManagerFreeLoadOption (&BootOption
);
134 // The option number assigned is either incorrect or unassigned.
136 if (OptionNumber
== LoadOptionNumberUnassigned
) {
137 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
139 Index
= EfiBootManagerFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
141 OptionNumber
= BootOptions
[Index
].OptionNumber
;
144 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
151 Return the correct FV file path.
152 FV address may change across reboot. This routine promises the FV file device path is right.
154 @param FilePath The Memory Mapped Device Path to get the file buffer.
156 @return The updated FV Device Path pointint to the file.
158 EFI_DEVICE_PATH_PROTOCOL
*
160 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
165 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
167 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
169 EFI_HANDLE
*FvHandles
;
170 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
171 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
174 // Get the file buffer by using the exactly FilePath.
176 FvFileNode
= FilePath
;
177 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
178 if (!EFI_ERROR (Status
)) {
179 return DuplicateDevicePath (FilePath
);
183 // Only wide match other FVs if it's a memory mapped FV file path.
185 if ((DevicePathType (FilePath
) != HARDWARE_DEVICE_PATH
) || (DevicePathSubType (FilePath
) != HW_MEMMAP_DP
)) {
189 FvFileNode
= NextDevicePathNode (FilePath
);
192 // Firstly find the FV file in current FV
194 gBS
->HandleProtocol (
196 &gEfiLoadedImageProtocolGuid
,
197 (VOID
**) &LoadedImage
199 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
200 FullPath
= BmAdjustFvFilePath (NewDevicePath
);
201 FreePool (NewDevicePath
);
202 if (FullPath
!= NULL
) {
207 // Secondly find the FV file in all other FVs
209 gBS
->LocateHandleBuffer (
211 &gEfiFirmwareVolume2ProtocolGuid
,
216 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
217 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
219 // Skip current FV, it was handed in first step.
223 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
224 FullPath
= BmAdjustFvFilePath (NewDevicePath
);
225 FreePool (NewDevicePath
);
226 if (FullPath
!= NULL
) {
231 if (FvHandles
!= NULL
) {
232 FreePool (FvHandles
);
238 Check if it's a Device Path pointing to FV file.
240 The function doesn't garentee the device path points to existing FV file.
242 @param DevicePath Input device path.
244 @retval TRUE The device path is a FV File Device Path.
245 @retval FALSE The device path is NOT a FV File Device Path.
249 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
254 EFI_DEVICE_PATH_PROTOCOL
*Node
;
257 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &Handle
);
258 if (!EFI_ERROR (Status
)) {
262 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
263 DevicePath
= NextDevicePathNode (DevicePath
);
264 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == MEDIA_PIWG_FW_FILE_DP
)) {
265 return IsDevicePathEnd (NextDevicePathNode (DevicePath
));
272 Check whether a USB device match the specified USB Class device path. This
273 function follows "Load Option Processing" behavior in UEFI specification.
275 @param UsbIo USB I/O protocol associated with the USB device.
276 @param UsbClass The USB Class device path to match.
278 @retval TRUE The USB device match the USB Class device path.
279 @retval FALSE The USB device does not match the USB Class device path.
284 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
285 IN USB_CLASS_DEVICE_PATH
*UsbClass
289 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
290 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
292 UINT8 DeviceSubClass
;
293 UINT8 DeviceProtocol
;
295 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
296 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
301 // Check Vendor Id and Product Id.
303 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
304 if (EFI_ERROR (Status
)) {
308 if ((UsbClass
->VendorId
!= 0xffff) &&
309 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
313 if ((UsbClass
->ProductId
!= 0xffff) &&
314 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
318 DeviceClass
= DevDesc
.DeviceClass
;
319 DeviceSubClass
= DevDesc
.DeviceSubClass
;
320 DeviceProtocol
= DevDesc
.DeviceProtocol
;
321 if (DeviceClass
== 0) {
323 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
324 // Protocol in Interface Descriptor instead.
326 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
327 if (EFI_ERROR (Status
)) {
331 DeviceClass
= IfDesc
.InterfaceClass
;
332 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
333 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
337 // Check Class, SubClass and Protocol.
339 if ((UsbClass
->DeviceClass
!= 0xff) &&
340 (UsbClass
->DeviceClass
!= DeviceClass
)) {
344 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
345 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
349 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
350 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
358 Check whether a USB device match the specified USB WWID device path. This
359 function follows "Load Option Processing" behavior in UEFI specification.
361 @param UsbIo USB I/O protocol associated with the USB device.
362 @param UsbWwid The USB WWID device path to match.
364 @retval TRUE The USB device match the USB WWID device path.
365 @retval FALSE The USB device does not match the USB WWID device path.
370 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
371 IN USB_WWID_DEVICE_PATH
*UsbWwid
375 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
376 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
382 CHAR16
*SerialNumberStr
;
385 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
386 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
391 // Check Vendor Id and Product Id.
393 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
394 if (EFI_ERROR (Status
)) {
397 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
398 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
403 // Check Interface Number.
405 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
406 if (EFI_ERROR (Status
)) {
409 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
414 // Check Serial Number.
416 if (DevDesc
.StrSerialNumber
== 0) {
421 // Get all supported languages.
425 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
426 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
431 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
433 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
434 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
435 if (CompareStr
[CompareLen
- 1] == L
'\0') {
440 // Compare serial number in each supported language.
442 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
443 SerialNumberStr
= NULL
;
444 Status
= UsbIo
->UsbGetStringDescriptor (
447 DevDesc
.StrSerialNumber
,
450 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
454 Length
= StrLen (SerialNumberStr
);
455 if ((Length
>= CompareLen
) &&
456 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
457 FreePool (SerialNumberStr
);
461 FreePool (SerialNumberStr
);
468 Find a USB device which match the specified short-form device path start with
469 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
470 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
471 this function will only search in its child devices.
473 @param DevicePath The device path that contains USB Class or USB WWID device path.
474 @param ParentDevicePathSize The length of the device path before the USB Class or
475 USB WWID device path.
476 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
478 @retval NULL The matched USB IO handles cannot be found.
479 @retval other The matched USB IO handles.
484 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
485 IN UINTN ParentDevicePathSize
,
486 OUT UINTN
*UsbIoHandleCount
490 EFI_HANDLE
*UsbIoHandles
;
491 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
492 EFI_USB_IO_PROTOCOL
*UsbIo
;
496 ASSERT (UsbIoHandleCount
!= NULL
);
499 // Get all UsbIo Handles.
501 Status
= gBS
->LocateHandleBuffer (
503 &gEfiUsbIoProtocolGuid
,
508 if (EFI_ERROR (Status
)) {
509 *UsbIoHandleCount
= 0;
513 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
515 // Get the Usb IO interface.
517 Status
= gBS
->HandleProtocol(
519 &gEfiUsbIoProtocolGuid
,
522 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
524 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
527 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
529 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
530 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
531 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
538 (*UsbIoHandleCount
) --;
539 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
549 Expand USB Class or USB WWID device path node to be full device path of a USB
552 This function support following 4 cases:
553 1) Boot Option device path starts with a USB Class or USB WWID device path,
554 and there is no Media FilePath device path in the end.
555 In this case, it will follow Removable Media Boot Behavior.
556 2) Boot Option device path starts with a USB Class or USB WWID device path,
557 and ended with Media FilePath device path.
558 3) Boot Option device path starts with a full device path to a USB Host Controller,
559 contains a USB Class or USB WWID device path node, while not ended with Media
560 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
561 4) Boot Option device path starts with a full device path to a USB Host Controller,
562 contains a USB Class or USB WWID device path node, and ended with Media
563 FilePath device path.
565 @param FilePath The device path pointing to a load option.
566 It could be a short-form device path.
567 @param FullPath The full path returned by the routine in last call.
568 Set to NULL in first call.
569 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
571 @return The next possible full path pointing to the load option.
572 Caller is responsible to free the memory.
574 EFI_DEVICE_PATH_PROTOCOL
*
575 BmExpandUsbDevicePath (
576 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
577 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
,
578 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
581 UINTN ParentDevicePathSize
;
582 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
583 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
590 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
591 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
592 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
593 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
595 for (Index
= 0; Index
< HandleCount
; Index
++) {
596 FilePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
597 if (FilePath
== NULL
) {
603 NextFullPath
= BmGetNextLoadOptionDevicePath (FilePath
, NULL
);
605 if (NextFullPath
== NULL
) {
607 // No BlockIo or SimpleFileSystem under FilePath.
614 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
615 FreePool (NextFullPath
);
620 if (Handles
!= NULL
) {
628 Expand File-path device path node to be full device path in platform.
630 @param FilePath The device path pointing to a load option.
631 It could be a short-form device path.
632 @param FullPath The full path returned by the routine in last call.
633 Set to NULL in first call.
635 @return The next possible full path pointing to the load option.
636 Caller is responsible to free the memory.
638 EFI_DEVICE_PATH_PROTOCOL
*
639 BmExpandFileDevicePath (
640 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
641 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
648 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
650 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
653 EfiBootManagerConnectAll ();
654 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &Handles
);
655 if (EFI_ERROR (Status
)) {
660 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
663 // Enumerate all removable media devices followed by all fixed media devices,
664 // followed by media devices which don't layer on block io.
666 for (MediaType
= 0; MediaType
< 3; MediaType
++) {
667 for (Index
= 0; Index
< HandleCount
; Index
++) {
668 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiBlockIoProtocolGuid
, (VOID
*) &BlockIo
);
669 if (EFI_ERROR (Status
)) {
672 if ((MediaType
== 0 && BlockIo
!= NULL
&& BlockIo
->Media
->RemovableMedia
) ||
673 (MediaType
== 1 && BlockIo
!= NULL
&& !BlockIo
->Media
->RemovableMedia
) ||
674 (MediaType
== 2 && BlockIo
== NULL
)
676 NextFullPath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
);
680 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
681 FreePool (NextFullPath
);
686 if (NextFullPath
!= NULL
) {
691 if (Handles
!= NULL
) {
699 Expand URI device path node to be full device path in platform.
701 @param FilePath The device path pointing to a load option.
702 It could be a short-form device path.
703 @param FullPath The full path returned by the routine in last call.
704 Set to NULL in first call.
706 @return The next possible full path pointing to the load option.
707 Caller is responsible to free the memory.
709 EFI_DEVICE_PATH_PROTOCOL
*
710 BmExpandUriDevicePath (
711 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
712 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
719 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
720 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
723 EfiBootManagerConnectAll ();
724 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &HandleCount
, &Handles
);
725 if (EFI_ERROR (Status
)) {
731 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
732 for (Index
= 0; Index
< HandleCount
; Index
++) {
733 NextFullPath
= BmExpandLoadFile (Handles
[Index
], FilePath
);
735 if (NextFullPath
== NULL
) {
742 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
744 // Free the resource occupied by the RAM disk.
746 RamDiskDevicePath
= BmGetRamDiskDevicePath (NextFullPath
);
747 if (RamDiskDevicePath
!= NULL
) {
748 BmDestroyRamDisk (RamDiskDevicePath
);
749 FreePool (RamDiskDevicePath
);
751 FreePool (NextFullPath
);
756 if (Handles
!= NULL
) {
764 Save the partition DevicePath to the CachedDevicePath as the first instance.
766 @param CachedDevicePath The device path cache.
767 @param DevicePath The partition device path to be cached.
770 BmCachePartitionDevicePath (
771 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
772 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
775 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
778 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
779 TempDevicePath
= *CachedDevicePath
;
780 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
781 FreePool (TempDevicePath
);
784 if (*CachedDevicePath
== NULL
) {
785 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
789 TempDevicePath
= *CachedDevicePath
;
790 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
791 if (TempDevicePath
!= NULL
) {
792 FreePool (TempDevicePath
);
796 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
797 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
800 TempDevicePath
= *CachedDevicePath
;
801 while (!IsDevicePathEnd (TempDevicePath
)) {
802 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
804 // Parse one instance
806 while (!IsDevicePathEndType (TempDevicePath
)) {
807 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
811 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
814 SetDevicePathEndNode (TempDevicePath
);
821 Expand a device path that starts with a hard drive media device path node to be a
822 full device path that includes the full hardware path to the device. We need
823 to do this so it can be booted. As an optimization the front match (the part point
824 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
825 so a connect all is not required on every boot. All successful history device path
826 which point to partition node (the front part) will be saved.
828 @param FilePath The device path pointing to a load option.
829 It could be a short-form device path.
831 @return The full device path pointing to the load option.
833 EFI_DEVICE_PATH_PROTOCOL
*
834 BmExpandPartitionDevicePath (
835 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
839 UINTN BlockIoHandleCount
;
840 EFI_HANDLE
*BlockIoBuffer
;
841 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
843 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
844 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
845 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
846 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
847 UINTN CachedDevicePathSize
;
849 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
853 // Check if there is prestore 'HDDP' variable.
854 // If exist, search the front path which point to partition node in the variable instants.
855 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
857 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
860 // Delete the invalid 'HDDP' variable.
862 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
863 FreePool (CachedDevicePath
);
864 CachedDevicePath
= NULL
;
865 Status
= gRT
->SetVariable (
867 &mBmHardDriveBootVariableGuid
,
872 ASSERT_EFI_ERROR (Status
);
876 if (CachedDevicePath
!= NULL
) {
877 TempNewDevicePath
= CachedDevicePath
;
881 // Check every instance of the variable
882 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
883 // partial partition boot option. Second, check whether the instance could be connected.
885 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
886 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
888 // Connect the device path instance, the device path point to hard drive media device path node
889 // e.g. ACPI() /PCI()/ATA()/Partition()
891 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
892 if (!EFI_ERROR (Status
)) {
893 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
895 // TempDevicePath = ACPI()/PCI()/ATA()/Partition()
896 // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI
898 // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),
899 // it may expand to two potienal full paths (nested partition, rarely happen):
900 // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI
901 // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI
902 // For simplicity, only #1 is returned.
904 FullPath
= BmGetNextLoadOptionDevicePath (TempDevicePath
, NULL
);
905 FreePool (TempDevicePath
);
907 if (FullPath
!= NULL
) {
909 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
912 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
914 // Save the matching Device Path so we don't need to do a connect all next time
915 // Failing to save only impacts performance next time expanding the short-form device path
917 Status
= gRT
->SetVariable (
919 &mBmHardDriveBootVariableGuid
,
920 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
921 GetDevicePathSize (CachedDevicePath
),
927 FreePool (CachedDevicePath
);
933 // Come here means the first instance is not matched
937 } while (TempNewDevicePath
!= NULL
);
941 // If we get here we fail to find or 'HDDP' not exist, and now we need
942 // to search all devices in the system for a matched partition
944 EfiBootManagerConnectAll ();
945 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
946 if (EFI_ERROR (Status
)) {
947 BlockIoHandleCount
= 0;
948 BlockIoBuffer
= NULL
;
951 // Loop through all the device handles that support the BLOCK_IO Protocol
953 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
954 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
955 if (BlockIoDevicePath
== NULL
) {
959 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
961 // Find the matched partition device path
963 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
964 FullPath
= BmGetNextLoadOptionDevicePath (TempDevicePath
, NULL
);
965 FreePool (TempDevicePath
);
967 if (FullPath
!= NULL
) {
968 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
971 // Save the matching Device Path so we don't need to do a connect all next time
972 // Failing to save only impacts performance next time expanding the short-form device path
974 Status
= gRT
->SetVariable (
976 &mBmHardDriveBootVariableGuid
,
977 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
978 GetDevicePathSize (CachedDevicePath
),
987 if (CachedDevicePath
!= NULL
) {
988 FreePool (CachedDevicePath
);
990 if (BlockIoBuffer
!= NULL
) {
991 FreePool (BlockIoBuffer
);
997 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
998 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1000 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1001 @param FullPath The full path returned by the routine in last call.
1002 Set to NULL in first call.
1004 @return The next possible full path pointing to the load option.
1005 Caller is responsible to free the memory.
1007 EFI_DEVICE_PATH_PROTOCOL
*
1008 BmExpandMediaDevicePath (
1009 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1010 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
1015 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1017 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1018 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
1021 EFI_HANDLE
*SimpleFileSystemHandles
;
1022 UINTN NumberSimpleFileSystemHandles
;
1026 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
1028 // Check whether the device is connected
1030 TempDevicePath
= DevicePath
;
1031 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1032 if (!EFI_ERROR (Status
)) {
1033 ASSERT (IsDevicePathEnd (TempDevicePath
));
1035 NextFullPath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1037 // For device path pointing to simple file system, it only expands to one full path.
1040 return NextFullPath
;
1042 FreePool (NextFullPath
);
1047 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1048 ASSERT_EFI_ERROR (Status
);
1051 // For device boot option only pointing to the removable device handle,
1052 // should make sure all its children handles (its child partion or media handles)
1053 // are created and connected.
1055 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1058 // Issue a dummy read to the device to check for media change.
1059 // When the removable media is changed, any Block IO read/write will
1060 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1061 // returned. After the Block IO protocol is reinstalled, subsequent
1062 // Block IO read/write will success.
1064 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1065 ASSERT_EFI_ERROR (Status
);
1066 if (EFI_ERROR (Status
)) {
1069 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1070 if (Buffer
!= NULL
) {
1071 BlockIo
->ReadBlocks (
1073 BlockIo
->Media
->MediaId
,
1075 BlockIo
->Media
->BlockSize
,
1082 // Detect the the default boot file from removable Media
1084 NextFullPath
= NULL
;
1085 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1086 gBS
->LocateHandleBuffer (
1088 &gEfiSimpleFileSystemProtocolGuid
,
1090 &NumberSimpleFileSystemHandles
,
1091 &SimpleFileSystemHandles
1093 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1095 // Get the device path size of SimpleFileSystem handle
1097 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1098 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1100 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1102 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1103 NextFullPath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1107 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
1108 FreePool (NextFullPath
);
1109 NextFullPath
= NULL
;
1114 if (SimpleFileSystemHandles
!= NULL
) {
1115 FreePool (SimpleFileSystemHandles
);
1118 return NextFullPath
;
1122 Check whether Left and Right are the same without matching the specific
1123 device path data in IP device path and URI device path node.
1125 @retval TRUE Left and Right are the same.
1126 @retval FALSE Left and Right are the different.
1129 BmMatchHttpBootDevicePath (
1130 IN EFI_DEVICE_PATH_PROTOCOL
*Left
,
1131 IN EFI_DEVICE_PATH_PROTOCOL
*Right
1134 for (; !IsDevicePathEnd (Left
) && !IsDevicePathEnd (Right
)
1135 ; Left
= NextDevicePathNode (Left
), Right
= NextDevicePathNode (Right
)
1137 if (CompareMem (Left
, Right
, DevicePathNodeLength (Left
)) != 0) {
1138 if ((DevicePathType (Left
) != MESSAGING_DEVICE_PATH
) || (DevicePathType (Right
) != MESSAGING_DEVICE_PATH
)) {
1142 if (DevicePathSubType (Left
) == MSG_DNS_DP
) {
1143 Left
= NextDevicePathNode (Left
);
1146 if (DevicePathSubType (Right
) == MSG_DNS_DP
) {
1147 Right
= NextDevicePathNode (Right
);
1150 if (((DevicePathSubType (Left
) != MSG_IPv4_DP
) || (DevicePathSubType (Right
) != MSG_IPv4_DP
)) &&
1151 ((DevicePathSubType (Left
) != MSG_IPv6_DP
) || (DevicePathSubType (Right
) != MSG_IPv6_DP
)) &&
1152 ((DevicePathSubType (Left
) != MSG_URI_DP
) || (DevicePathSubType (Right
) != MSG_URI_DP
))
1158 return (BOOLEAN
) (IsDevicePathEnd (Left
) && IsDevicePathEnd (Right
));
1162 Get the file buffer from the file system produced by Load File instance.
1164 @param LoadFileHandle The handle of LoadFile instance.
1165 @param RamDiskHandle Return the RAM Disk handle.
1167 @return The next possible full path pointing to the load option.
1168 Caller is responsible to free the memory.
1170 EFI_DEVICE_PATH_PROTOCOL
*
1171 BmExpandNetworkFileSystem (
1172 IN EFI_HANDLE LoadFileHandle
,
1173 OUT EFI_HANDLE
*RamDiskHandle
1178 EFI_HANDLE
*Handles
;
1181 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1183 Status
= gBS
->LocateHandleBuffer (
1185 &gEfiBlockIoProtocolGuid
,
1190 if (EFI_ERROR (Status
)) {
1196 for (Index
= 0; Index
< HandleCount
; Index
++) {
1197 Node
= DevicePathFromHandle (Handles
[Index
]);
1198 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1199 if (!EFI_ERROR (Status
) &&
1200 (Handle
== LoadFileHandle
) &&
1201 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)) {
1203 // Find the BlockIo instance populated from the LoadFile.
1205 Handle
= Handles
[Index
];
1210 if (Handles
!= NULL
) {
1214 if (Index
== HandleCount
) {
1218 *RamDiskHandle
= Handle
;
1220 if (Handle
!= NULL
) {
1222 // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
1223 // But assume only one SimpleFileSystem can be found under the BlockIo.
1225 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle
), NULL
);
1232 Return the RAM Disk device path created by LoadFile.
1234 @param FilePath The source file path.
1236 @return Callee-to-free RAM Disk device path
1238 EFI_DEVICE_PATH_PROTOCOL
*
1239 BmGetRamDiskDevicePath (
1240 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1244 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1245 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1249 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1250 if (!EFI_ERROR (Status
) &&
1251 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) &&
1252 (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)
1256 // Construct the device path pointing to RAM Disk
1258 Node
= NextDevicePathNode (Node
);
1259 RamDiskDevicePath
= DuplicateDevicePath (FilePath
);
1260 ASSERT (RamDiskDevicePath
!= NULL
);
1261 SetDevicePathEndNode ((VOID
*) ((UINTN
) RamDiskDevicePath
+ ((UINTN
) Node
- (UINTN
) FilePath
)));
1262 return RamDiskDevicePath
;
1269 Return the buffer and buffer size occupied by the RAM Disk.
1271 @param RamDiskDevicePath RAM Disk device path.
1272 @param RamDiskSizeInPages Return RAM Disk size in pages.
1274 @retval RAM Disk buffer.
1277 BmGetRamDiskMemoryInfo (
1278 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
,
1279 OUT UINTN
*RamDiskSizeInPages
1285 UINT64 StartingAddr
;
1288 ASSERT (RamDiskDevicePath
!= NULL
);
1290 *RamDiskSizeInPages
= 0;
1293 // Get the buffer occupied by RAM Disk.
1295 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &RamDiskDevicePath
, &Handle
);
1296 ASSERT_EFI_ERROR (Status
);
1297 ASSERT ((DevicePathType (RamDiskDevicePath
) == MEDIA_DEVICE_PATH
) &&
1298 (DevicePathSubType (RamDiskDevicePath
) == MEDIA_RAM_DISK_DP
));
1299 StartingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->StartingAddr
);
1300 EndingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->EndingAddr
);
1301 *RamDiskSizeInPages
= EFI_SIZE_TO_PAGES ((UINTN
) (EndingAddr
- StartingAddr
+ 1));
1302 return (VOID
*) (UINTN
) StartingAddr
;
1306 Destroy the RAM Disk.
1308 The destroy operation includes to call RamDisk.Unregister to
1309 unregister the RAM DISK from RAM DISK driver, free the memory
1310 allocated for the RAM Disk.
1312 @param RamDiskDevicePath RAM Disk device path.
1316 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
1320 VOID
*RamDiskBuffer
;
1321 UINTN RamDiskSizeInPages
;
1323 ASSERT (RamDiskDevicePath
!= NULL
);
1325 RamDiskBuffer
= BmGetRamDiskMemoryInfo (RamDiskDevicePath
, &RamDiskSizeInPages
);
1328 // Destroy RAM Disk.
1330 if (mRamDisk
== NULL
) {
1331 Status
= gBS
->LocateProtocol (&gEfiRamDiskProtocolGuid
, NULL
, (VOID
*) &mRamDisk
);
1332 ASSERT_EFI_ERROR (Status
);
1334 Status
= mRamDisk
->Unregister (RamDiskDevicePath
);
1335 ASSERT_EFI_ERROR (Status
);
1336 FreePages (RamDiskBuffer
, RamDiskSizeInPages
);
1340 Get the file buffer from the specified Load File instance.
1342 @param LoadFileHandle The specified Load File instance.
1343 @param FilePath The file path which will pass to LoadFile().
1345 @return The full device path pointing to the load option buffer.
1347 EFI_DEVICE_PATH_PROTOCOL
*
1349 IN EFI_HANDLE LoadFileHandle
,
1350 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1354 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1356 EFI_HANDLE RamDiskHandle
;
1358 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
1360 Status
= gBS
->OpenProtocol (
1362 &gEfiLoadFileProtocolGuid
,
1363 (VOID
**) &LoadFile
,
1366 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1368 ASSERT_EFI_ERROR (Status
);
1372 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1373 if ((Status
!= EFI_WARN_FILE_SYSTEM
) && (Status
!= EFI_BUFFER_TOO_SMALL
)) {
1377 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1379 // The load option buffer is directly returned by LoadFile.
1381 return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle
));
1385 // The load option resides in a RAM disk.
1387 FileBuffer
= AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize
));
1388 if (FileBuffer
== NULL
) {
1392 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1393 if (EFI_ERROR (Status
)) {
1394 FreePages (FileBuffer
, EFI_SIZE_TO_PAGES (BufferSize
));
1398 FullPath
= BmExpandNetworkFileSystem (LoadFileHandle
, &RamDiskHandle
);
1399 if (FullPath
== NULL
) {
1401 // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
1403 BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle
));
1410 Return the full device path pointing to the load option.
1413 1. Exactly matches to a LoadFile instance.
1414 2. Cannot match to any LoadFile instance. Wide match is required.
1415 In either case, the routine may return:
1416 1. A copy of FilePath when FilePath matches to a LoadFile instance and
1417 the LoadFile returns a load option buffer.
1418 2. A new device path with IP and URI information updated when wide match
1420 3. A new device path pointing to a load option in RAM disk.
1421 In either case, only one full device path is returned for a specified
1424 @param FilePath The media device path pointing to a LoadFile instance.
1426 @return The load option buffer.
1428 EFI_DEVICE_PATH_PROTOCOL
*
1430 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1435 EFI_HANDLE
*Handles
;
1438 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1441 // Get file buffer from load file instance.
1444 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1445 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1447 // When wide match happens, pass full device path to LoadFile (),
1448 // otherwise, pass remaining device path to LoadFile ().
1454 // Use wide match algorithm to find one when
1455 // cannot find a LoadFile instance to exactly match the FilePath
1457 Status
= gBS
->LocateHandleBuffer (
1459 &gEfiLoadFileProtocolGuid
,
1464 if (EFI_ERROR (Status
)) {
1468 for (Index
= 0; Index
< HandleCount
; Index
++) {
1469 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
)) {
1470 Handle
= Handles
[Index
];
1474 if (Handles
!= NULL
) {
1479 if (Handle
== NULL
) {
1483 return BmExpandLoadFile (Handle
, FilePath
);
1487 Get the load option by its device path.
1489 @param FilePath The device path pointing to a load option.
1490 It could be a short-form device path.
1491 @param FullPath Return the full device path of the load option after
1492 short-form device path expanding.
1493 Caller is responsible to free it.
1494 @param FileSize Return the load option size.
1496 @return The load option buffer. Caller is responsible to free the memory.
1500 EfiBootManagerGetLoadOptionBuffer (
1501 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1502 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1508 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1509 return BmGetNextLoadOptionBuffer (LoadOptionTypeMax
, FilePath
, FullPath
, FileSize
);
1513 Get the next possible full path pointing to the load option.
1514 The routine doesn't guarantee the returned full path points to an existing
1515 file, and it also doesn't guarantee the existing file is a valid load option.
1516 BmGetNextLoadOptionBuffer() guarantees.
1518 @param FilePath The device path pointing to a load option.
1519 It could be a short-form device path.
1520 @param FullPath The full path returned by the routine in last call.
1521 Set to NULL in first call.
1523 @return The next possible full path pointing to the load option.
1524 Caller is responsible to free the memory.
1526 EFI_DEVICE_PATH_PROTOCOL
*
1527 BmGetNextLoadOptionDevicePath (
1528 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1529 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
1533 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1536 ASSERT (FilePath
!= NULL
);
1539 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1542 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1543 if (EFI_ERROR (Status
)) {
1544 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1547 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1548 return BmExpandMediaDevicePath (FilePath
, FullPath
);
1552 // Expand the short-form device path to full device path
1554 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1555 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1557 // Expand the Harddrive device path
1559 if (FullPath
== NULL
) {
1560 return BmExpandPartitionDevicePath (FilePath
);
1564 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1565 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
)) {
1567 // Expand the File-path device path
1569 return BmExpandFileDevicePath (FilePath
, FullPath
);
1570 } else if ((DevicePathType (FilePath
) == MESSAGING_DEVICE_PATH
) &&
1571 (DevicePathSubType (FilePath
) == MSG_URI_DP
)) {
1573 // Expand the URI device path
1575 return BmExpandUriDevicePath (FilePath
, FullPath
);
1578 Status
= gBS
->LocateDevicePath (&gEfiUsbIoProtocolGuid
, &Node
, &Handle
);
1579 if (EFI_ERROR (Status
)) {
1581 // Only expand the USB WWID/Class device path
1582 // when FilePath doesn't point to a physical UsbIo controller.
1583 // Otherwise, infinite recursion will happen.
1585 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1586 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1587 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1593 // Expand the USB WWID/Class device path
1595 if (!IsDevicePathEnd (Node
)) {
1596 if (FilePath
== Node
) {
1598 // Boot Option device path starts with USB Class or USB WWID device path.
1599 // For Boot Option device path which doesn't begin with the USB Class or
1600 // USB WWID device path, it's not needed to connect again here.
1602 BmConnectUsbShortFormDevicePath (FilePath
);
1604 return BmExpandUsbDevicePath (FilePath
, FullPath
, Node
);
1610 // For the below cases, FilePath only expands to one Full path.
1611 // So just handle the case when FullPath == NULL.
1613 if (FullPath
!= NULL
) {
1618 // Load option resides in FV.
1620 if (BmIsFvFilePath (FilePath
)) {
1621 return BmAdjustFvFilePath (FilePath
);
1625 // Load option resides in Simple File System.
1628 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1629 if (!EFI_ERROR (Status
)) {
1630 return DuplicateDevicePath (FilePath
);
1634 // Last chance to try: Load option may be loaded through LoadFile.
1636 return BmExpandLoadFiles (FilePath
);
1640 Check if it's a Device Path pointing to BootManagerMenu.
1642 @param DevicePath Input device path.
1644 @retval TRUE The device path is BootManagerMenu File Device Path.
1645 @retval FALSE The device path is NOT BootManagerMenu File Device Path.
1648 BmIsBootManagerMenuFilePath (
1649 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1652 EFI_HANDLE FvHandle
;
1656 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &DevicePath
, &FvHandle
);
1657 if (!EFI_ERROR (Status
)) {
1658 NameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) DevicePath
);
1659 if (NameGuid
!= NULL
) {
1660 return CompareGuid (NameGuid
, PcdGetPtr (PcdBootManagerMenuFile
));
1668 Report status code with EFI_RETURN_STATUS_EXTENDED_DATA about LoadImage() or
1669 StartImage() failure.
1671 @param[in] ErrorCode An Error Code in the Software Class, DXE Boot
1672 Service Driver Subclass. ErrorCode will be used to
1673 compose the Value parameter for status code
1674 reporting. Must be one of
1675 EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR and
1676 EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED.
1678 @param[in] FailureStatus The failure status returned by the boot service
1679 that should be reported.
1682 BmReportLoadFailure (
1683 IN UINT32 ErrorCode
,
1684 IN EFI_STATUS FailureStatus
1687 EFI_RETURN_STATUS_EXTENDED_DATA ExtendedData
;
1689 if (!ReportErrorCodeEnabled ()) {
1694 (ErrorCode
== EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
) ||
1695 (ErrorCode
== EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1698 ZeroMem (&ExtendedData
, sizeof (ExtendedData
));
1699 ExtendedData
.ReturnStatus
= FailureStatus
;
1701 REPORT_STATUS_CODE_EX (
1702 (EFI_ERROR_CODE
| EFI_ERROR_MINOR
),
1703 (EFI_SOFTWARE_DXE_BS_DRIVER
| ErrorCode
),
1707 &ExtendedData
.DataHeader
+ 1,
1708 sizeof (ExtendedData
) - sizeof (ExtendedData
.DataHeader
)
1713 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1714 also signals the EFI ready to boot event. If the device path for the option
1715 starts with a BBS device path a legacy boot is attempted via the registered
1716 gLegacyBoot function. Short form device paths are also supported via this
1717 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1718 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1719 If the BootOption Device Path fails the removable media boot algorithm
1720 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1721 is tried per processor type)
1723 @param BootOption Boot Option to try and boot.
1724 On return, BootOption->Status contains the boot status.
1725 EFI_SUCCESS BootOption was booted
1726 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1727 registered via EfiBootManagerInitialize().
1728 EFI_NOT_FOUND The BootOption was not found on the system
1729 !EFI_SUCCESS BootOption failed with this error status
1734 EfiBootManagerBoot (
1735 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1739 EFI_HANDLE ImageHandle
;
1740 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1743 UINTN OriginalOptionNumber
;
1744 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1745 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1748 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1749 EFI_EVENT LegacyBootEvent
;
1751 if (BootOption
== NULL
) {
1755 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1756 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1761 // 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")
1763 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1764 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1765 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1766 if (!EFI_ERROR (Status
)) {
1768 // Save the BootOption->OptionNumber to restore later
1770 OptionNumber
= Uint16
;
1771 OriginalOptionNumber
= BootOption
->OptionNumber
;
1772 BootOption
->OptionNumber
= OptionNumber
;
1773 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1774 BootOption
->OptionNumber
= OriginalOptionNumber
;
1777 if (EFI_ERROR (Status
)) {
1778 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1779 BootOption
->Status
= Status
;
1785 // 2. Set BootCurrent
1787 Uint16
= (UINT16
) OptionNumber
;
1788 BmSetVariableAndReportStatusCodeOnError (
1790 &gEfiGlobalVariableGuid
,
1791 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1797 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1800 if (BmIsBootManagerMenuFilePath (BootOption
->FilePath
)) {
1801 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1802 BmStopHotkeyService (NULL
, NULL
);
1804 EfiSignalEventReadyToBoot();
1806 // Report Status Code to indicate ReadyToBoot was signalled
1808 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1810 // 4. Repair system through DriverHealth protocol
1812 BmRepairAllControllers (0);
1815 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1818 // 5. Adjust the different type memory page number just before booting
1819 // and save the updated info into the variable for next boot to use
1821 BmSetMemoryTypeInformationVariable (
1822 (BOOLEAN
) ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1826 // 6. Load EFI boot option to ImageHandle
1828 DEBUG_CODE_BEGIN ();
1829 if (BootOption
->Description
== NULL
) {
1830 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1832 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1837 RamDiskDevicePath
= NULL
;
1838 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1839 Status
= EFI_NOT_FOUND
;
1841 EfiBootManagerConnectDevicePath (BootOption
->FilePath
, NULL
);
1842 FileBuffer
= BmGetNextLoadOptionBuffer (LoadOptionTypeBoot
, BootOption
->FilePath
, &FilePath
, &FileSize
);
1843 if (FileBuffer
!= NULL
) {
1844 RamDiskDevicePath
= BmGetRamDiskDevicePath (FilePath
);
1846 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1847 Status
= gBS
->LoadImage (
1856 if (FileBuffer
!= NULL
) {
1857 FreePool (FileBuffer
);
1859 if (FilePath
!= NULL
) {
1860 FreePool (FilePath
);
1863 if (EFI_ERROR (Status
)) {
1865 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
1866 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
1867 // If the caller doesn't have the option to defer the execution of an image, we should
1868 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
1870 if (Status
== EFI_SECURITY_VIOLATION
) {
1871 gBS
->UnloadImage (ImageHandle
);
1874 // Report Status Code with the failure status to indicate that the failure to load boot option
1876 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
, Status
);
1877 BootOption
->Status
= Status
;
1879 // Destroy the RAM disk
1881 if (RamDiskDevicePath
!= NULL
) {
1882 BmDestroyRamDisk (RamDiskDevicePath
);
1883 FreePool (RamDiskDevicePath
);
1890 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1891 // Write boot to OS performance data for Legacy boot
1893 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1894 if (mBmLegacyBoot
!= NULL
) {
1896 // Write boot to OS performance data for legacy boot.
1900 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1902 Status
= EfiCreateEventLegacyBootEx(
1908 ASSERT_EFI_ERROR (Status
);
1911 mBmLegacyBoot (BootOption
);
1913 BootOption
->Status
= EFI_UNSUPPORTED
;
1916 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1921 // Provide the image with its load options
1923 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1924 ASSERT_EFI_ERROR (Status
);
1926 if (!BmIsAutoCreateBootOption (BootOption
)) {
1927 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1928 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1932 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1934 ImageInfo
->ParentHandle
= NULL
;
1937 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1939 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1942 // Write boot to OS performance data for UEFI boot
1945 BmEndOfBdsPerfCode (NULL
, NULL
);
1948 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1950 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1951 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1952 BootOption
->Status
= Status
;
1953 if (EFI_ERROR (Status
)) {
1955 // Report Status Code with the failure status to indicate that boot failure
1957 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
, Status
);
1959 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1962 // Destroy the RAM disk
1964 if (RamDiskDevicePath
!= NULL
) {
1965 BmDestroyRamDisk (RamDiskDevicePath
);
1966 FreePool (RamDiskDevicePath
);
1970 // Clear the Watchdog Timer after the image returns
1972 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1975 // Set Logo status invalid after trying one boot option
1978 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1979 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1980 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1981 ASSERT_EFI_ERROR (Status
);
1985 // Clear Boot Current
1987 Status
= gRT
->SetVariable (
1989 &gEfiGlobalVariableGuid
,
1995 // Deleting variable with current variable implementation shouldn't fail.
1996 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1997 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1999 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
2003 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2004 instances, has the same partition node with HardDriveDevicePath device path
2006 @param BlockIoDevicePath Multi device path instances which need to check
2007 @param HardDriveDevicePath A device path which starts with a hard drive media
2010 @retval TRUE There is a matched device path instance.
2011 @retval FALSE There is no matched device path instance.
2015 BmMatchPartitionDevicePathNode (
2016 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
2017 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
2020 HARDDRIVE_DEVICE_PATH
*Node
;
2022 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
2027 // Match all the partition device path nodes including the nested partition nodes
2029 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
2030 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
2031 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
2034 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2036 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
2039 // Match Signature and PartitionNumber.
2040 // Unused bytes in Signature are initiaized with zeros.
2042 if ((Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
2043 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
2044 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
2045 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)) {
2050 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
2057 Emuerate all possible bootable medias in the following order:
2058 1. Removable BlockIo - The boot option only points to the removable media
2059 device, like USB key, DVD, Floppy etc.
2060 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
2062 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
2063 SimpleFileSystem Protocol, but not supporting BlockIo
2065 4. LoadFile - The boot option points to the media supporting
2067 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
2069 @param BootOptionCount Return the boot option count which has been found.
2071 @retval Pointer to the boot option array.
2073 EFI_BOOT_MANAGER_LOAD_OPTION
*
2074 BmEnumerateBootOptions (
2075 UINTN
*BootOptionCount
2079 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2081 EFI_HANDLE
*Handles
;
2082 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
2085 CHAR16
*Description
;
2087 ASSERT (BootOptionCount
!= NULL
);
2089 *BootOptionCount
= 0;
2093 // Parse removable block io followed by fixed block io
2095 gBS
->LocateHandleBuffer (
2097 &gEfiBlockIoProtocolGuid
,
2103 for (Removable
= 0; Removable
< 2; Removable
++) {
2104 for (Index
= 0; Index
< HandleCount
; Index
++) {
2105 Status
= gBS
->HandleProtocol (
2107 &gEfiBlockIoProtocolGuid
,
2110 if (EFI_ERROR (Status
)) {
2115 // Skip the logical partitions
2117 if (BlkIo
->Media
->LogicalPartition
) {
2122 // Skip the fixed block io then the removable block io
2124 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
2128 Description
= BmGetBootDescription (Handles
[Index
]);
2129 BootOptions
= ReallocatePool (
2130 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2131 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2134 ASSERT (BootOptions
!= NULL
);
2136 Status
= EfiBootManagerInitializeLoadOption (
2137 &BootOptions
[(*BootOptionCount
)++],
2138 LoadOptionNumberUnassigned
,
2142 DevicePathFromHandle (Handles
[Index
]),
2146 ASSERT_EFI_ERROR (Status
);
2148 FreePool (Description
);
2152 if (HandleCount
!= 0) {
2157 // Parse simple file system not based on block io
2159 gBS
->LocateHandleBuffer (
2161 &gEfiSimpleFileSystemProtocolGuid
,
2166 for (Index
= 0; Index
< HandleCount
; Index
++) {
2167 Status
= gBS
->HandleProtocol (
2169 &gEfiBlockIoProtocolGuid
,
2172 if (!EFI_ERROR (Status
)) {
2174 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2178 Description
= BmGetBootDescription (Handles
[Index
]);
2179 BootOptions
= ReallocatePool (
2180 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2181 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2184 ASSERT (BootOptions
!= NULL
);
2186 Status
= EfiBootManagerInitializeLoadOption (
2187 &BootOptions
[(*BootOptionCount
)++],
2188 LoadOptionNumberUnassigned
,
2192 DevicePathFromHandle (Handles
[Index
]),
2196 ASSERT_EFI_ERROR (Status
);
2197 FreePool (Description
);
2200 if (HandleCount
!= 0) {
2205 // Parse load file protocol
2207 gBS
->LocateHandleBuffer (
2209 &gEfiLoadFileProtocolGuid
,
2214 for (Index
= 0; Index
< HandleCount
; Index
++) {
2216 // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().
2218 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2222 Description
= BmGetBootDescription (Handles
[Index
]);
2223 BootOptions
= ReallocatePool (
2224 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2225 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2228 ASSERT (BootOptions
!= NULL
);
2230 Status
= EfiBootManagerInitializeLoadOption (
2231 &BootOptions
[(*BootOptionCount
)++],
2232 LoadOptionNumberUnassigned
,
2236 DevicePathFromHandle (Handles
[Index
]),
2240 ASSERT_EFI_ERROR (Status
);
2241 FreePool (Description
);
2244 if (HandleCount
!= 0) {
2248 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
2253 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2257 EfiBootManagerRefreshAllBootOption (
2262 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2263 UINTN NvBootOptionCount
;
2264 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2265 UINTN BootOptionCount
;
2269 // Optionally refresh the legacy boot option
2271 if (mBmRefreshLegacyBootOption
!= NULL
) {
2272 mBmRefreshLegacyBootOption ();
2275 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2276 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2279 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2281 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2282 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2283 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2287 // Remove invalid EFI boot options from NV
2289 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2290 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2291 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2292 ) && BmIsAutoCreateBootOption (&NvBootOptions
[Index
])
2295 // Only check those added by BDS
2296 // so that the boot options added by end-user or OS installer won't be deleted
2298 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == -1) {
2299 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2301 // Deleting variable with current variable implementation shouldn't fail.
2303 ASSERT_EFI_ERROR (Status
);
2309 // Add new EFI boot options to NV
2311 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2312 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == -1) {
2313 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2315 // Try best to add the boot options so continue upon failure.
2320 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2321 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2325 This function is called to get or create the boot option for the Boot Manager Menu.
2327 The Boot Manager Menu is shown after successfully booting a boot option.
2328 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2330 @param BootOption Return the boot option of the Boot Manager Menu
2332 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2333 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2334 @retval others Return status of gRT->SetVariable (). BootOption still points
2335 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2339 BmRegisterBootManagerMenu (
2340 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2344 CHAR16
*Description
;
2345 UINTN DescriptionLength
;
2346 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2347 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2348 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2350 EFI_HANDLE
*Handles
;
2358 // Try to find BootManagerMenu from LoadFile protocol
2360 gBS
->LocateHandleBuffer (
2362 &gEfiLoadFileProtocolGuid
,
2367 for (Index
= 0; Index
< HandleCount
; Index
++) {
2368 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2369 DevicePath
= DuplicateDevicePath (DevicePathFromHandle (Handles
[Index
]));
2370 Description
= BmGetBootDescription (Handles
[Index
]);
2374 if (HandleCount
!= 0) {
2378 if (DevicePath
== NULL
) {
2380 Status
= GetSectionFromFv (
2381 PcdGetPtr (PcdBootManagerMenuFile
),
2390 if (EFI_ERROR (Status
)) {
2391 DEBUG ((EFI_D_WARN
, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
2392 return EFI_NOT_FOUND
;
2396 // Get BootManagerMenu application's description from EFI User Interface Section.
2398 Status
= GetSectionFromFv (
2399 PcdGetPtr (PcdBootManagerMenuFile
),
2400 EFI_SECTION_USER_INTERFACE
,
2402 (VOID
**) &Description
,
2405 if (EFI_ERROR (Status
)) {
2409 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2410 Status
= gBS
->HandleProtocol (
2412 &gEfiLoadedImageProtocolGuid
,
2413 (VOID
**) &LoadedImage
2415 ASSERT_EFI_ERROR (Status
);
2416 DevicePath
= AppendDevicePathNode (
2417 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2418 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2420 ASSERT (DevicePath
!= NULL
);
2423 Status
= EfiBootManagerInitializeLoadOption (
2425 LoadOptionNumberUnassigned
,
2427 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2428 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2433 ASSERT_EFI_ERROR (Status
);
2434 FreePool (DevicePath
);
2435 if (Description
!= NULL
) {
2436 FreePool (Description
);
2440 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2441 UINTN BootOptionCount
;
2443 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2444 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2445 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2448 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2452 Return the boot option corresponding to the Boot Manager Menu.
2453 It may automatically create one if the boot option hasn't been created yet.
2455 @param BootOption Return the Boot Manager Menu.
2457 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2458 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2459 @retval others Return status of gRT->SetVariable (). BootOption still points
2460 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2465 EfiBootManagerGetBootManagerMenu (
2466 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2470 UINTN BootOptionCount
;
2471 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2474 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2476 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2477 if (BmIsBootManagerMenuFilePath (BootOptions
[Index
].FilePath
)) {
2478 Status
= EfiBootManagerInitializeLoadOption (
2480 BootOptions
[Index
].OptionNumber
,
2481 BootOptions
[Index
].OptionType
,
2482 BootOptions
[Index
].Attributes
,
2483 BootOptions
[Index
].Description
,
2484 BootOptions
[Index
].FilePath
,
2485 BootOptions
[Index
].OptionalData
,
2486 BootOptions
[Index
].OptionalDataSize
2488 ASSERT_EFI_ERROR (Status
);
2493 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2496 // Automatically create the Boot#### for Boot Manager Menu when not found.
2498 if (Index
== BootOptionCount
) {
2499 return BmRegisterBootManagerMenu (BootOption
);
2506 Get the next possible full path pointing to the load option.
2507 The routine doesn't guarantee the returned full path points to an existing
2508 file, and it also doesn't guarantee the existing file is a valid load option.
2509 BmGetNextLoadOptionBuffer() guarantees.
2511 @param FilePath The device path pointing to a load option.
2512 It could be a short-form device path.
2513 @param FullPath The full path returned by the routine in last call.
2514 Set to NULL in first call.
2516 @return The next possible full path pointing to the load option.
2517 Caller is responsible to free the memory.
2519 EFI_DEVICE_PATH_PROTOCOL
*
2521 EfiBootManagerGetNextLoadOptionDevicePath (
2522 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
2523 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
2526 return BmGetNextLoadOptionDevicePath(FilePath
, FullPath
);