2 Library functions which relates with booting.
4 Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
5 Copyright (c) 2011 - 2021, Intel Corporation. All rights reserved.<BR>
6 (C) Copyright 2015-2021 Hewlett Packard Enterprise Development LP<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "InternalBm.h"
13 EFI_RAM_DISK_PROTOCOL
*mRamDisk
= NULL
;
15 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption
= NULL
;
16 EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot
= NULL
;
19 /// This GUID is used for an EFI Variable that stores the front device pathes
20 /// for a partial device path that starts with the HD node.
22 EFI_GUID mBmHardDriveBootVariableGuid
= {
23 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde }
25 EFI_GUID mBmAutoCreateBootOptionGuid
= {
26 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 }
33 @param Event The triggered event.
34 @param Context Context for this event.
45 // Record the performance data for End of BDS
47 PERF_CROSSMODULE_END ("BDS");
53 The function registers the legacy boot support capabilities.
55 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
56 @param LegacyBoot The function pointer to boot the legacy boot option.
60 EfiBootManagerRegisterLegacyBootSupport (
61 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption
,
62 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
65 mBmRefreshLegacyBootOption
= RefreshLegacyBootOption
;
66 mBmLegacyBoot
= LegacyBoot
;
70 Return TRUE when the boot option is auto-created instead of manually added.
72 @param BootOption Pointer to the boot option to check.
74 @retval TRUE The boot option is auto-created.
75 @retval FALSE The boot option is manually added.
78 BmIsAutoCreateBootOption (
79 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
82 if ((BootOption
->OptionalDataSize
== sizeof (EFI_GUID
)) &&
83 CompareGuid ((EFI_GUID
*)BootOption
->OptionalData
, &mBmAutoCreateBootOptionGuid
)
93 Find the boot option in the NV storage and return the option number.
95 @param OptionToFind Boot option to be checked.
97 @return The option number of the found boot option.
101 BmFindBootOptionInVariable (
102 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
106 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
108 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
109 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
110 UINTN BootOptionCount
;
113 OptionNumber
= LoadOptionNumberUnassigned
;
116 // Try to match the variable exactly if the option number is assigned
118 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
123 mBmLoadOptionName
[OptionToFind
->OptionType
],
124 OptionToFind
->OptionNumber
126 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
128 if (!EFI_ERROR (Status
)) {
129 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
130 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
131 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
132 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
133 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
134 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
137 OptionNumber
= OptionToFind
->OptionNumber
;
140 EfiBootManagerFreeLoadOption (&BootOption
);
145 // The option number assigned is either incorrect or unassigned.
147 if (OptionNumber
== LoadOptionNumberUnassigned
) {
148 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
150 Index
= EfiBootManagerFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
152 OptionNumber
= BootOptions
[Index
].OptionNumber
;
155 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
162 Return the correct FV file path.
163 FV address may change across reboot. This routine promises the FV file device path is right.
165 @param FilePath The Memory Mapped Device Path to get the file buffer.
167 @return The updated FV Device Path pointint to the file.
169 EFI_DEVICE_PATH_PROTOCOL
*
171 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
176 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
178 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
180 EFI_HANDLE
*FvHandles
;
181 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
182 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
185 // Get the file buffer by using the exactly FilePath.
187 FvFileNode
= FilePath
;
188 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
189 if (!EFI_ERROR (Status
)) {
190 return DuplicateDevicePath (FilePath
);
194 // Only wide match other FVs if it's a memory mapped FV file path.
196 if ((DevicePathType (FilePath
) != HARDWARE_DEVICE_PATH
) || (DevicePathSubType (FilePath
) != HW_MEMMAP_DP
)) {
200 FvFileNode
= NextDevicePathNode (FilePath
);
203 // Firstly find the FV file in current FV
205 gBS
->HandleProtocol (
207 &gEfiLoadedImageProtocolGuid
,
208 (VOID
**)&LoadedImage
210 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
211 FullPath
= BmAdjustFvFilePath (NewDevicePath
);
212 FreePool (NewDevicePath
);
213 if (FullPath
!= NULL
) {
218 // Secondly find the FV file in all other FVs
220 gBS
->LocateHandleBuffer (
222 &gEfiFirmwareVolume2ProtocolGuid
,
227 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
228 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
230 // Skip current FV, it was handed in first step.
235 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
236 FullPath
= BmAdjustFvFilePath (NewDevicePath
);
237 FreePool (NewDevicePath
);
238 if (FullPath
!= NULL
) {
243 if (FvHandles
!= NULL
) {
244 FreePool (FvHandles
);
251 Check if it's a Device Path pointing to FV file.
253 The function doesn't garentee the device path points to existing FV file.
255 @param DevicePath Input device path.
257 @retval TRUE The device path is a FV File Device Path.
258 @retval FALSE The device path is NOT a FV File Device Path.
262 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
267 EFI_DEVICE_PATH_PROTOCOL
*Node
;
270 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &Handle
);
271 if (!EFI_ERROR (Status
)) {
275 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
276 DevicePath
= NextDevicePathNode (DevicePath
);
277 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == MEDIA_PIWG_FW_FILE_DP
)) {
278 return IsDevicePathEnd (NextDevicePathNode (DevicePath
));
286 Check whether a USB device match the specified USB Class device path. This
287 function follows "Load Option Processing" behavior in UEFI specification.
289 @param UsbIo USB I/O protocol associated with the USB device.
290 @param UsbClass The USB Class device path to match.
292 @retval TRUE The USB device match the USB Class device path.
293 @retval FALSE The USB device does not match the USB Class device path.
298 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
299 IN USB_CLASS_DEVICE_PATH
*UsbClass
303 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
304 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
306 UINT8 DeviceSubClass
;
307 UINT8 DeviceProtocol
;
309 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
310 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
))
316 // Check Vendor Id and Product Id.
318 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
319 if (EFI_ERROR (Status
)) {
323 if ((UsbClass
->VendorId
!= 0xffff) &&
324 (UsbClass
->VendorId
!= DevDesc
.IdVendor
))
329 if ((UsbClass
->ProductId
!= 0xffff) &&
330 (UsbClass
->ProductId
!= DevDesc
.IdProduct
))
335 DeviceClass
= DevDesc
.DeviceClass
;
336 DeviceSubClass
= DevDesc
.DeviceSubClass
;
337 DeviceProtocol
= DevDesc
.DeviceProtocol
;
338 if (DeviceClass
== 0) {
340 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
341 // Protocol in Interface Descriptor instead.
343 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
344 if (EFI_ERROR (Status
)) {
348 DeviceClass
= IfDesc
.InterfaceClass
;
349 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
350 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
354 // Check Class, SubClass and Protocol.
356 if ((UsbClass
->DeviceClass
!= 0xff) &&
357 (UsbClass
->DeviceClass
!= DeviceClass
))
362 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
363 (UsbClass
->DeviceSubClass
!= DeviceSubClass
))
368 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
369 (UsbClass
->DeviceProtocol
!= DeviceProtocol
))
378 Check whether a USB device match the specified USB WWID device path. This
379 function follows "Load Option Processing" behavior in UEFI specification.
381 @param UsbIo USB I/O protocol associated with the USB device.
382 @param UsbWwid The USB WWID device path to match.
384 @retval TRUE The USB device match the USB WWID device path.
385 @retval FALSE The USB device does not match the USB WWID device path.
390 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
391 IN USB_WWID_DEVICE_PATH
*UsbWwid
395 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
396 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
402 CHAR16
*SerialNumberStr
;
405 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
406 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
))
412 // Check Vendor Id and Product Id.
414 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
415 if (EFI_ERROR (Status
)) {
419 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
420 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
))
426 // Check Interface Number.
428 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
429 if (EFI_ERROR (Status
)) {
433 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
438 // Check Serial Number.
440 if (DevDesc
.StrSerialNumber
== 0) {
445 // Get all supported languages.
449 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
450 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
455 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
457 CompareStr
= (CHAR16
*)(UINTN
)(UsbWwid
+ 1);
458 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
459 if (CompareStr
[CompareLen
- 1] == L
'\0') {
464 // Compare serial number in each supported language.
466 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
467 SerialNumberStr
= NULL
;
468 Status
= UsbIo
->UsbGetStringDescriptor (
471 DevDesc
.StrSerialNumber
,
474 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
478 Length
= StrLen (SerialNumberStr
);
479 if ((Length
>= CompareLen
) &&
480 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0))
482 FreePool (SerialNumberStr
);
486 FreePool (SerialNumberStr
);
493 Find a USB device which match the specified short-form device path start with
494 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
495 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
496 this function will only search in its child devices.
498 @param DevicePath The device path that contains USB Class or USB WWID device path.
499 @param ParentDevicePathSize The length of the device path before the USB Class or
500 USB WWID device path.
501 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
503 @retval NULL The matched USB IO handles cannot be found.
504 @retval other The matched USB IO handles.
509 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
510 IN UINTN ParentDevicePathSize
,
511 OUT UINTN
*UsbIoHandleCount
515 EFI_HANDLE
*UsbIoHandles
;
516 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
517 EFI_USB_IO_PROTOCOL
*UsbIo
;
521 ASSERT (UsbIoHandleCount
!= NULL
);
524 // Get all UsbIo Handles.
526 Status
= gBS
->LocateHandleBuffer (
528 &gEfiUsbIoProtocolGuid
,
533 if (EFI_ERROR (Status
)) {
534 *UsbIoHandleCount
= 0;
538 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
540 // Get the Usb IO interface.
542 Status
= gBS
->HandleProtocol (
544 &gEfiUsbIoProtocolGuid
,
547 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
549 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
551 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
553 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
554 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*)((UINTN
)DevicePath
+ ParentDevicePathSize
)) ||
555 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*)((UINTN
)DevicePath
+ ParentDevicePathSize
)))
563 (*UsbIoHandleCount
)--;
564 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
574 Expand USB Class or USB WWID device path node to be full device path of a USB
577 This function support following 4 cases:
578 1) Boot Option device path starts with a USB Class or USB WWID device path,
579 and there is no Media FilePath device path in the end.
580 In this case, it will follow Removable Media Boot Behavior.
581 2) Boot Option device path starts with a USB Class or USB WWID device path,
582 and ended with Media FilePath device path.
583 3) Boot Option device path starts with a full device path to a USB Host Controller,
584 contains a USB Class or USB WWID device path node, while not ended with Media
585 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
586 4) Boot Option device path starts with a full device path to a USB Host Controller,
587 contains a USB Class or USB WWID device path node, and ended with Media
588 FilePath device path.
590 @param FilePath The device path pointing to a load option.
591 It could be a short-form device path.
592 @param FullPath The full path returned by the routine in last call.
593 Set to NULL in first call.
594 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
596 @return The next possible full path pointing to the load option.
597 Caller is responsible to free the memory.
599 EFI_DEVICE_PATH_PROTOCOL
*
600 BmExpandUsbDevicePath (
601 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
602 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
,
603 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
606 UINTN ParentDevicePathSize
;
607 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
608 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
615 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
616 ParentDevicePathSize
= (UINTN
)ShortformNode
- (UINTN
)FilePath
;
617 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
618 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
620 for (Index
= 0; Index
< HandleCount
; Index
++) {
621 FilePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
622 if (FilePath
== NULL
) {
629 NextFullPath
= BmGetNextLoadOptionDevicePath (FilePath
, NULL
);
631 if (NextFullPath
== NULL
) {
633 // No BlockIo or SimpleFileSystem under FilePath.
641 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
642 FreePool (NextFullPath
);
647 if (Handles
!= NULL
) {
655 Expand File-path device path node to be full device path in platform.
657 @param FilePath The device path pointing to a load option.
658 It could be a short-form device path.
659 @param FullPath The full path returned by the routine in last call.
660 Set to NULL in first call.
662 @return The next possible full path pointing to the load option.
663 Caller is responsible to free the memory.
665 EFI_DEVICE_PATH_PROTOCOL
*
666 BmExpandFileDevicePath (
667 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
668 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
675 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
677 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
680 EfiBootManagerConnectAll ();
681 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &Handles
);
682 if (EFI_ERROR (Status
)) {
687 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
690 // Enumerate all removable media devices followed by all fixed media devices,
691 // followed by media devices which don't layer on block io.
693 for (MediaType
= 0; MediaType
< 3; MediaType
++) {
694 for (Index
= 0; Index
< HandleCount
; Index
++) {
695 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiBlockIoProtocolGuid
, (VOID
*)&BlockIo
);
696 if (EFI_ERROR (Status
)) {
700 if (((MediaType
== 0) && (BlockIo
!= NULL
) && BlockIo
->Media
->RemovableMedia
) ||
701 ((MediaType
== 1) && (BlockIo
!= NULL
) && !BlockIo
->Media
->RemovableMedia
) ||
702 ((MediaType
== 2) && (BlockIo
== NULL
))
705 NextFullPath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
);
709 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
710 FreePool (NextFullPath
);
716 if (NextFullPath
!= NULL
) {
721 if (Handles
!= NULL
) {
729 Expand URI device path node to be full device path in platform.
731 @param FilePath The device path pointing to a load option.
732 It could be a short-form device path.
733 @param FullPath The full path returned by the routine in last call.
734 Set to NULL in first call.
736 @return The next possible full path pointing to the load option.
737 Caller is responsible to free the memory.
739 EFI_DEVICE_PATH_PROTOCOL
*
740 BmExpandUriDevicePath (
741 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
742 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
749 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
750 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
753 EfiBootManagerConnectAll ();
754 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &HandleCount
, &Handles
);
755 if (EFI_ERROR (Status
)) {
761 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
762 for (Index
= 0; Index
< HandleCount
; Index
++) {
763 NextFullPath
= BmExpandLoadFile (Handles
[Index
], FilePath
);
765 if (NextFullPath
== NULL
) {
772 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
774 // Free the resource occupied by the RAM disk.
776 RamDiskDevicePath
= BmGetRamDiskDevicePath (NextFullPath
);
777 if (RamDiskDevicePath
!= NULL
) {
778 BmDestroyRamDisk (RamDiskDevicePath
);
779 FreePool (RamDiskDevicePath
);
782 FreePool (NextFullPath
);
787 if (Handles
!= NULL
) {
795 Save the partition DevicePath to the CachedDevicePath as the first instance.
797 @param CachedDevicePath The device path cache.
798 @param DevicePath The partition device path to be cached.
801 BmCachePartitionDevicePath (
802 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
803 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
806 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
809 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
810 TempDevicePath
= *CachedDevicePath
;
811 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
812 FreePool (TempDevicePath
);
815 if (*CachedDevicePath
== NULL
) {
816 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
820 TempDevicePath
= *CachedDevicePath
;
821 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
822 if (TempDevicePath
!= NULL
) {
823 FreePool (TempDevicePath
);
827 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
828 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
831 TempDevicePath
= *CachedDevicePath
;
832 while (!IsDevicePathEnd (TempDevicePath
)) {
833 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
835 // Parse one instance
837 while (!IsDevicePathEndType (TempDevicePath
)) {
838 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
843 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
846 SetDevicePathEndNode (TempDevicePath
);
853 Expand a device path that starts with a hard drive media device path node to be a
854 full device path that includes the full hardware path to the device. We need
855 to do this so it can be booted. As an optimization the front match (the part point
856 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
857 so a connect all is not required on every boot. All successful history device path
858 which point to partition node (the front part) will be saved.
860 @param FilePath The device path pointing to a load option.
861 It could be a short-form device path.
863 @return The full device path pointing to the load option.
865 EFI_DEVICE_PATH_PROTOCOL
*
866 BmExpandPartitionDevicePath (
867 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
871 UINTN BlockIoHandleCount
;
872 EFI_HANDLE
*BlockIoBuffer
;
873 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
875 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
876 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
877 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
878 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
879 UINTN CachedDevicePathSize
;
881 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
885 // Check if there is prestore 'HDDP' variable.
886 // If exist, search the front path which point to partition node in the variable instants.
887 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
889 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**)&CachedDevicePath
, &CachedDevicePathSize
);
892 // Delete the invalid 'HDDP' variable.
894 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
895 FreePool (CachedDevicePath
);
896 CachedDevicePath
= NULL
;
897 Status
= gRT
->SetVariable (
899 &mBmHardDriveBootVariableGuid
,
904 ASSERT_EFI_ERROR (Status
);
908 if (CachedDevicePath
!= NULL
) {
909 TempNewDevicePath
= CachedDevicePath
;
913 // Check every instance of the variable
914 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
915 // partial partition boot option. Second, check whether the instance could be connected.
917 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
918 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*)FilePath
)) {
920 // Connect the device path instance, the device path point to hard drive media device path node
921 // e.g. ACPI() /PCI()/ATA()/Partition()
923 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
924 if (!EFI_ERROR (Status
)) {
925 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
927 // TempDevicePath = ACPI()/PCI()/ATA()/Partition()
928 // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI
930 // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),
931 // it may expand to two potienal full paths (nested partition, rarely happen):
932 // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI
933 // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI
934 // For simplicity, only #1 is returned.
936 FullPath
= BmGetNextLoadOptionDevicePath (TempDevicePath
, NULL
);
937 FreePool (TempDevicePath
);
939 if (FullPath
!= NULL
) {
941 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
944 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
946 // Save the matching Device Path so we don't need to do a connect all next time
947 // Failing to save only impacts performance next time expanding the short-form device path
949 Status
= gRT
->SetVariable (
951 &mBmHardDriveBootVariableGuid
,
952 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
953 GetDevicePathSize (CachedDevicePath
),
959 FreePool (CachedDevicePath
);
966 // Come here means the first instance is not matched
970 } while (TempNewDevicePath
!= NULL
);
974 // If we get here we fail to find or 'HDDP' not exist, and now we need
975 // to search all devices in the system for a matched partition
977 EfiBootManagerConnectAll ();
978 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
979 if (EFI_ERROR (Status
)) {
980 BlockIoHandleCount
= 0;
981 BlockIoBuffer
= NULL
;
985 // Loop through all the device handles that support the BLOCK_IO Protocol
987 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
988 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
989 if (BlockIoDevicePath
== NULL
) {
993 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*)FilePath
)) {
995 // Find the matched partition device path
997 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
998 FullPath
= BmGetNextLoadOptionDevicePath (TempDevicePath
, NULL
);
999 FreePool (TempDevicePath
);
1001 if (FullPath
!= NULL
) {
1002 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
1005 // Save the matching Device Path so we don't need to do a connect all next time
1006 // Failing to save only impacts performance next time expanding the short-form device path
1008 Status
= gRT
->SetVariable (
1010 &mBmHardDriveBootVariableGuid
,
1011 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1012 GetDevicePathSize (CachedDevicePath
),
1021 if (CachedDevicePath
!= NULL
) {
1022 FreePool (CachedDevicePath
);
1025 if (BlockIoBuffer
!= NULL
) {
1026 FreePool (BlockIoBuffer
);
1033 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
1034 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1036 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1037 @param FullPath The full path returned by the routine in last call.
1038 Set to NULL in first call.
1040 @return The next possible full path pointing to the load option.
1041 Caller is responsible to free the memory.
1043 EFI_DEVICE_PATH_PROTOCOL
*
1044 BmExpandMediaDevicePath (
1045 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1046 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
1051 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1053 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1054 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
1057 EFI_HANDLE
*SimpleFileSystemHandles
;
1058 UINTN NumberSimpleFileSystemHandles
;
1062 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
1064 // Check whether the device is connected
1066 TempDevicePath
= DevicePath
;
1067 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1068 if (!EFI_ERROR (Status
)) {
1069 ASSERT (IsDevicePathEnd (TempDevicePath
));
1071 NextFullPath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1073 // For device path pointing to simple file system, it only expands to one full path.
1076 return NextFullPath
;
1078 FreePool (NextFullPath
);
1083 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1084 ASSERT_EFI_ERROR (Status
);
1087 // For device boot option only pointing to the removable device handle,
1088 // should make sure all its children handles (its child partion or media handles)
1089 // are created and connected.
1091 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1094 // Issue a dummy read to the device to check for media change.
1095 // When the removable media is changed, any Block IO read/write will
1096 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1097 // returned. After the Block IO protocol is reinstalled, subsequent
1098 // Block IO read/write will success.
1100 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
1101 ASSERT_EFI_ERROR (Status
);
1102 if (EFI_ERROR (Status
)) {
1106 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1107 if (Buffer
!= NULL
) {
1108 BlockIo
->ReadBlocks (
1110 BlockIo
->Media
->MediaId
,
1112 BlockIo
->Media
->BlockSize
,
1119 // Detect the the default boot file from removable Media
1121 NextFullPath
= NULL
;
1122 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1123 gBS
->LocateHandleBuffer (
1125 &gEfiSimpleFileSystemProtocolGuid
,
1127 &NumberSimpleFileSystemHandles
,
1128 &SimpleFileSystemHandles
1130 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1132 // Get the device path size of SimpleFileSystem handle
1134 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1135 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1137 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1139 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1140 NextFullPath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1144 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
1145 FreePool (NextFullPath
);
1146 NextFullPath
= NULL
;
1151 if (SimpleFileSystemHandles
!= NULL
) {
1152 FreePool (SimpleFileSystemHandles
);
1155 return NextFullPath
;
1159 Check whether Left and Right are the same without matching the specific
1160 device path data in IP device path and URI device path node.
1162 @retval TRUE Left and Right are the same.
1163 @retval FALSE Left and Right are the different.
1166 BmMatchHttpBootDevicePath (
1167 IN EFI_DEVICE_PATH_PROTOCOL
*Left
,
1168 IN EFI_DEVICE_PATH_PROTOCOL
*Right
1171 for ( ; !IsDevicePathEnd (Left
) && !IsDevicePathEnd (Right
)
1172 ; Left
= NextDevicePathNode (Left
), Right
= NextDevicePathNode (Right
)
1175 if (CompareMem (Left
, Right
, DevicePathNodeLength (Left
)) != 0) {
1176 if ((DevicePathType (Left
) != MESSAGING_DEVICE_PATH
) || (DevicePathType (Right
) != MESSAGING_DEVICE_PATH
)) {
1180 if (DevicePathSubType (Left
) == MSG_DNS_DP
) {
1181 Left
= NextDevicePathNode (Left
);
1184 if (DevicePathSubType (Right
) == MSG_DNS_DP
) {
1185 Right
= NextDevicePathNode (Right
);
1188 if (((DevicePathSubType (Left
) != MSG_IPv4_DP
) || (DevicePathSubType (Right
) != MSG_IPv4_DP
)) &&
1189 ((DevicePathSubType (Left
) != MSG_IPv6_DP
) || (DevicePathSubType (Right
) != MSG_IPv6_DP
)) &&
1190 ((DevicePathSubType (Left
) != MSG_URI_DP
) || (DevicePathSubType (Right
) != MSG_URI_DP
))
1198 return (BOOLEAN
)(IsDevicePathEnd (Left
) && IsDevicePathEnd (Right
));
1202 Get the file buffer from the file system produced by Load File instance.
1204 @param LoadFileHandle The handle of LoadFile instance.
1205 @param RamDiskHandle Return the RAM Disk handle.
1207 @return The next possible full path pointing to the load option.
1208 Caller is responsible to free the memory.
1210 EFI_DEVICE_PATH_PROTOCOL
*
1211 BmExpandNetworkFileSystem (
1212 IN EFI_HANDLE LoadFileHandle
,
1213 OUT EFI_HANDLE
*RamDiskHandle
1218 EFI_HANDLE
*Handles
;
1221 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1223 Status
= gBS
->LocateHandleBuffer (
1225 &gEfiBlockIoProtocolGuid
,
1230 if (EFI_ERROR (Status
)) {
1236 for (Index
= 0; Index
< HandleCount
; Index
++) {
1237 Node
= DevicePathFromHandle (Handles
[Index
]);
1238 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1239 if (!EFI_ERROR (Status
) &&
1240 (Handle
== LoadFileHandle
) &&
1241 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
))
1244 // Find the BlockIo instance populated from the LoadFile.
1246 Handle
= Handles
[Index
];
1251 if (Handles
!= NULL
) {
1255 if (Index
== HandleCount
) {
1259 *RamDiskHandle
= Handle
;
1261 if (Handle
!= NULL
) {
1263 // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
1264 // But assume only one SimpleFileSystem can be found under the BlockIo.
1266 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle
), NULL
);
1273 Return the RAM Disk device path created by LoadFile.
1275 @param FilePath The source file path.
1277 @return Callee-to-free RAM Disk device path
1279 EFI_DEVICE_PATH_PROTOCOL
*
1280 BmGetRamDiskDevicePath (
1281 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1285 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1286 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1290 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1291 if (!EFI_ERROR (Status
) &&
1292 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) &&
1293 (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)
1297 // Construct the device path pointing to RAM Disk
1299 Node
= NextDevicePathNode (Node
);
1300 RamDiskDevicePath
= DuplicateDevicePath (FilePath
);
1301 ASSERT (RamDiskDevicePath
!= NULL
);
1302 SetDevicePathEndNode ((VOID
*)((UINTN
)RamDiskDevicePath
+ ((UINTN
)Node
- (UINTN
)FilePath
)));
1303 return RamDiskDevicePath
;
1310 Return the buffer and buffer size occupied by the RAM Disk.
1312 @param RamDiskDevicePath RAM Disk device path.
1313 @param RamDiskSizeInPages Return RAM Disk size in pages.
1315 @retval RAM Disk buffer.
1318 BmGetRamDiskMemoryInfo (
1319 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
,
1320 OUT UINTN
*RamDiskSizeInPages
1325 UINT64 StartingAddr
;
1328 ASSERT (RamDiskDevicePath
!= NULL
);
1330 *RamDiskSizeInPages
= 0;
1333 // Get the buffer occupied by RAM Disk.
1335 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &RamDiskDevicePath
, &Handle
);
1336 ASSERT_EFI_ERROR (Status
);
1338 (DevicePathType (RamDiskDevicePath
) == MEDIA_DEVICE_PATH
) &&
1339 (DevicePathSubType (RamDiskDevicePath
) == MEDIA_RAM_DISK_DP
)
1341 StartingAddr
= ReadUnaligned64 ((UINT64
*)((MEDIA_RAM_DISK_DEVICE_PATH
*)RamDiskDevicePath
)->StartingAddr
);
1342 EndingAddr
= ReadUnaligned64 ((UINT64
*)((MEDIA_RAM_DISK_DEVICE_PATH
*)RamDiskDevicePath
)->EndingAddr
);
1343 *RamDiskSizeInPages
= EFI_SIZE_TO_PAGES ((UINTN
)(EndingAddr
- StartingAddr
+ 1));
1344 return (VOID
*)(UINTN
)StartingAddr
;
1348 Destroy the RAM Disk.
1350 The destroy operation includes to call RamDisk.Unregister to
1351 unregister the RAM DISK from RAM DISK driver, free the memory
1352 allocated for the RAM Disk.
1354 @param RamDiskDevicePath RAM Disk device path.
1358 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
1362 VOID
*RamDiskBuffer
;
1363 UINTN RamDiskSizeInPages
;
1365 ASSERT (RamDiskDevicePath
!= NULL
);
1367 RamDiskBuffer
= BmGetRamDiskMemoryInfo (RamDiskDevicePath
, &RamDiskSizeInPages
);
1370 // Destroy RAM Disk.
1372 if (mRamDisk
== NULL
) {
1373 Status
= gBS
->LocateProtocol (&gEfiRamDiskProtocolGuid
, NULL
, (VOID
*)&mRamDisk
);
1374 ASSERT_EFI_ERROR (Status
);
1377 Status
= mRamDisk
->Unregister (RamDiskDevicePath
);
1378 ASSERT_EFI_ERROR (Status
);
1379 FreePages (RamDiskBuffer
, RamDiskSizeInPages
);
1383 Get the file buffer from the specified Load File instance.
1385 @param LoadFileHandle The specified Load File instance.
1386 @param FilePath The file path which will pass to LoadFile().
1388 @return The full device path pointing to the load option buffer.
1390 EFI_DEVICE_PATH_PROTOCOL
*
1392 IN EFI_HANDLE LoadFileHandle
,
1393 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1397 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1399 EFI_HANDLE RamDiskHandle
;
1401 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
1403 Status
= gBS
->OpenProtocol (
1405 &gEfiLoadFileProtocolGuid
,
1409 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1411 ASSERT_EFI_ERROR (Status
);
1415 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1416 if ((Status
!= EFI_WARN_FILE_SYSTEM
) && (Status
!= EFI_BUFFER_TOO_SMALL
)) {
1420 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1422 // The load option buffer is directly returned by LoadFile.
1424 return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle
));
1428 // The load option resides in a RAM disk.
1430 FileBuffer
= AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize
));
1431 if (FileBuffer
== NULL
) {
1432 DEBUG_CODE_BEGIN ();
1433 EFI_DEVICE_PATH
*LoadFilePath
;
1434 CHAR16
*LoadFileText
;
1437 LoadFilePath
= DevicePathFromHandle (LoadFileHandle
);
1438 if (LoadFilePath
== NULL
) {
1439 LoadFileText
= NULL
;
1441 LoadFileText
= ConvertDevicePathToText (LoadFilePath
, FALSE
, FALSE
);
1444 FileText
= ConvertDevicePathToText (FilePath
, FALSE
, FALSE
);
1448 "%a:%a: failed to allocate reserved pages: "
1449 "BufferSize=%Lu LoadFile=\"%s\" FilePath=\"%s\"\n",
1457 if (FileText
!= NULL
) {
1458 FreePool (FileText
);
1461 if (LoadFileText
!= NULL
) {
1462 FreePool (LoadFileText
);
1469 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1470 if (EFI_ERROR (Status
)) {
1471 FreePages (FileBuffer
, EFI_SIZE_TO_PAGES (BufferSize
));
1475 FullPath
= BmExpandNetworkFileSystem (LoadFileHandle
, &RamDiskHandle
);
1476 if (FullPath
== NULL
) {
1478 // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
1480 BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle
));
1487 Return the full device path pointing to the load option.
1490 1. Exactly matches to a LoadFile instance.
1491 2. Cannot match to any LoadFile instance. Wide match is required.
1492 In either case, the routine may return:
1493 1. A copy of FilePath when FilePath matches to a LoadFile instance and
1494 the LoadFile returns a load option buffer.
1495 2. A new device path with IP and URI information updated when wide match
1497 3. A new device path pointing to a load option in RAM disk.
1498 In either case, only one full device path is returned for a specified
1501 @param FilePath The media device path pointing to a LoadFile instance.
1503 @return The load option buffer.
1505 EFI_DEVICE_PATH_PROTOCOL
*
1507 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1512 EFI_HANDLE
*Handles
;
1515 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1518 // Get file buffer from load file instance.
1521 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1522 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1524 // When wide match happens, pass full device path to LoadFile (),
1525 // otherwise, pass remaining device path to LoadFile ().
1531 // Use wide match algorithm to find one when
1532 // cannot find a LoadFile instance to exactly match the FilePath
1534 Status
= gBS
->LocateHandleBuffer (
1536 &gEfiLoadFileProtocolGuid
,
1541 if (EFI_ERROR (Status
)) {
1546 for (Index
= 0; Index
< HandleCount
; Index
++) {
1547 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
)) {
1548 Handle
= Handles
[Index
];
1553 if (Handles
!= NULL
) {
1558 if (Handle
== NULL
) {
1562 return BmExpandLoadFile (Handle
, FilePath
);
1566 Get the load option by its device path.
1568 @param FilePath The device path pointing to a load option.
1569 It could be a short-form device path.
1570 @param FullPath Return the full device path of the load option after
1571 short-form device path expanding.
1572 Caller is responsible to free it.
1573 @param FileSize Return the load option size.
1575 @return The load option buffer. Caller is responsible to free the memory.
1579 EfiBootManagerGetLoadOptionBuffer (
1580 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1581 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1587 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1588 return BmGetNextLoadOptionBuffer (LoadOptionTypeMax
, FilePath
, FullPath
, FileSize
);
1592 Get the next possible full path pointing to the load option.
1593 The routine doesn't guarantee the returned full path points to an existing
1594 file, and it also doesn't guarantee the existing file is a valid load option.
1595 BmGetNextLoadOptionBuffer() guarantees.
1597 @param FilePath The device path pointing to a load option.
1598 It could be a short-form device path.
1599 @param FullPath The full path returned by the routine in last call.
1600 Set to NULL in first call.
1602 @return The next possible full path pointing to the load option.
1603 Caller is responsible to free the memory.
1605 EFI_DEVICE_PATH_PROTOCOL
*
1606 BmGetNextLoadOptionDevicePath (
1607 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1608 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
1612 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1615 ASSERT (FilePath
!= NULL
);
1618 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1621 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1622 if (EFI_ERROR (Status
)) {
1623 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1626 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1627 return BmExpandMediaDevicePath (FilePath
, FullPath
);
1631 // Expand the short-form device path to full device path
1633 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1634 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
))
1637 // Expand the Harddrive device path
1639 if (FullPath
== NULL
) {
1640 return BmExpandPartitionDevicePath (FilePath
);
1644 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1645 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
))
1648 // Expand the File-path device path
1650 return BmExpandFileDevicePath (FilePath
, FullPath
);
1651 } else if ((DevicePathType (FilePath
) == MESSAGING_DEVICE_PATH
) &&
1652 (DevicePathSubType (FilePath
) == MSG_URI_DP
))
1655 // Expand the URI device path
1657 return BmExpandUriDevicePath (FilePath
, FullPath
);
1660 Status
= gBS
->LocateDevicePath (&gEfiUsbIoProtocolGuid
, &Node
, &Handle
);
1661 if (EFI_ERROR (Status
)) {
1663 // Only expand the USB WWID/Class device path
1664 // when FilePath doesn't point to a physical UsbIo controller.
1665 // Otherwise, infinite recursion will happen.
1667 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1668 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1669 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
)))
1676 // Expand the USB WWID/Class device path
1678 if (!IsDevicePathEnd (Node
)) {
1679 if (FilePath
== Node
) {
1681 // Boot Option device path starts with USB Class or USB WWID device path.
1682 // For Boot Option device path which doesn't begin with the USB Class or
1683 // USB WWID device path, it's not needed to connect again here.
1685 BmConnectUsbShortFormDevicePath (FilePath
);
1688 return BmExpandUsbDevicePath (FilePath
, FullPath
, Node
);
1694 // For the below cases, FilePath only expands to one Full path.
1695 // So just handle the case when FullPath == NULL.
1697 if (FullPath
!= NULL
) {
1702 // Load option resides in FV.
1704 if (BmIsFvFilePath (FilePath
)) {
1705 return BmAdjustFvFilePath (FilePath
);
1709 // Load option resides in Simple File System.
1712 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1713 if (!EFI_ERROR (Status
)) {
1714 return DuplicateDevicePath (FilePath
);
1718 // Last chance to try: Load option may be loaded through LoadFile.
1720 return BmExpandLoadFiles (FilePath
);
1724 Check if it's a Device Path pointing to BootManagerMenu.
1726 @param DevicePath Input device path.
1728 @retval TRUE The device path is BootManagerMenu File Device Path.
1729 @retval FALSE The device path is NOT BootManagerMenu File Device Path.
1732 BmIsBootManagerMenuFilePath (
1733 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1736 EFI_HANDLE FvHandle
;
1740 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &DevicePath
, &FvHandle
);
1741 if (!EFI_ERROR (Status
)) {
1742 NameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*)DevicePath
);
1743 if (NameGuid
!= NULL
) {
1744 return CompareGuid (NameGuid
, PcdGetPtr (PcdBootManagerMenuFile
));
1752 Report status code with EFI_RETURN_STATUS_EXTENDED_DATA about LoadImage() or
1753 StartImage() failure.
1755 @param[in] ErrorCode An Error Code in the Software Class, DXE Boot
1756 Service Driver Subclass. ErrorCode will be used to
1757 compose the Value parameter for status code
1758 reporting. Must be one of
1759 EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR and
1760 EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED.
1762 @param[in] FailureStatus The failure status returned by the boot service
1763 that should be reported.
1766 BmReportLoadFailure (
1767 IN UINT32 ErrorCode
,
1768 IN EFI_STATUS FailureStatus
1771 EFI_RETURN_STATUS_EXTENDED_DATA ExtendedData
;
1773 if (!ReportErrorCodeEnabled ()) {
1778 (ErrorCode
== EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
) ||
1779 (ErrorCode
== EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1782 ZeroMem (&ExtendedData
, sizeof (ExtendedData
));
1783 ExtendedData
.ReturnStatus
= FailureStatus
;
1785 REPORT_STATUS_CODE_EX (
1786 (EFI_ERROR_CODE
| EFI_ERROR_MINOR
),
1787 (EFI_SOFTWARE_DXE_BS_DRIVER
| ErrorCode
),
1791 &ExtendedData
.DataHeader
+ 1,
1792 sizeof (ExtendedData
) - sizeof (ExtendedData
.DataHeader
)
1797 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1798 also signals the EFI ready to boot event. If the device path for the option
1799 starts with a BBS device path a legacy boot is attempted via the registered
1800 gLegacyBoot function. Short form device paths are also supported via this
1801 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1802 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1803 If the BootOption Device Path fails the removable media boot algorithm
1804 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1805 is tried per processor type)
1807 @param BootOption Boot Option to try and boot.
1808 On return, BootOption->Status contains the boot status.
1809 EFI_SUCCESS BootOption was booted
1810 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1811 registered via EfiBootManagerInitialize().
1812 EFI_NOT_FOUND The BootOption was not found on the system
1813 !EFI_SUCCESS BootOption failed with this error status
1818 EfiBootManagerBoot (
1819 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1823 EFI_HANDLE ImageHandle
;
1824 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1827 UINTN OriginalOptionNumber
;
1828 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1829 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1832 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1833 EFI_EVENT LegacyBootEvent
;
1835 if (BootOption
== NULL
) {
1839 if ((BootOption
->FilePath
== NULL
) || (BootOption
->OptionType
!= LoadOptionTypeBoot
)) {
1840 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1845 // 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")
1847 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1848 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1849 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1850 if (!EFI_ERROR (Status
)) {
1852 // Save the BootOption->OptionNumber to restore later
1854 OptionNumber
= Uint16
;
1855 OriginalOptionNumber
= BootOption
->OptionNumber
;
1856 BootOption
->OptionNumber
= OptionNumber
;
1857 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1858 BootOption
->OptionNumber
= OriginalOptionNumber
;
1861 if (EFI_ERROR (Status
)) {
1862 DEBUG ((DEBUG_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1863 BootOption
->Status
= Status
;
1869 // 2. Set BootCurrent
1871 Uint16
= (UINT16
)OptionNumber
;
1872 BmSetVariableAndReportStatusCodeOnError (
1874 &gEfiGlobalVariableGuid
,
1875 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1881 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1884 if (BmIsBootManagerMenuFilePath (BootOption
->FilePath
)) {
1885 DEBUG ((DEBUG_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1886 BmStopHotkeyService (NULL
, NULL
);
1888 EfiSignalEventReadyToBoot ();
1890 // Report Status Code to indicate ReadyToBoot was signalled
1892 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1894 // 4. Repair system through DriverHealth protocol
1896 BmRepairAllControllers (0);
1899 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
)OptionNumber
);
1902 // 5. Adjust the different type memory page number just before booting
1903 // and save the updated info into the variable for next boot to use
1905 BmSetMemoryTypeInformationVariable (
1906 (BOOLEAN
)((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1910 // 6. Load EFI boot option to ImageHandle
1912 DEBUG_CODE_BEGIN ();
1913 if (BootOption
->Description
== NULL
) {
1914 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1916 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1922 RamDiskDevicePath
= NULL
;
1923 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1924 Status
= EFI_NOT_FOUND
;
1926 EfiBootManagerConnectDevicePath (BootOption
->FilePath
, NULL
);
1927 FileBuffer
= BmGetNextLoadOptionBuffer (LoadOptionTypeBoot
, BootOption
->FilePath
, &FilePath
, &FileSize
);
1928 if (FileBuffer
!= NULL
) {
1929 RamDiskDevicePath
= BmGetRamDiskDevicePath (FilePath
);
1931 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1932 Status
= gBS
->LoadImage (
1942 if (FileBuffer
!= NULL
) {
1943 FreePool (FileBuffer
);
1946 if (FilePath
!= NULL
) {
1947 FreePool (FilePath
);
1950 if (EFI_ERROR (Status
)) {
1952 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
1953 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
1954 // If the caller doesn't have the option to defer the execution of an image, we should
1955 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
1957 if (Status
== EFI_SECURITY_VIOLATION
) {
1958 gBS
->UnloadImage (ImageHandle
);
1962 // Destroy the RAM disk
1964 if (RamDiskDevicePath
!= NULL
) {
1965 BmDestroyRamDisk (RamDiskDevicePath
);
1966 FreePool (RamDiskDevicePath
);
1970 // Report Status Code with the failure status to indicate that the failure to load boot option
1972 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
, Status
);
1973 BootOption
->Status
= Status
;
1979 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1980 // Write boot to OS performance data for Legacy boot
1982 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1983 if (mBmLegacyBoot
!= NULL
) {
1985 // Write boot to OS performance data for legacy boot.
1989 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1991 Status
= EfiCreateEventLegacyBootEx (
1997 ASSERT_EFI_ERROR (Status
);
2000 mBmLegacyBoot (BootOption
);
2002 BootOption
->Status
= EFI_UNSUPPORTED
;
2005 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
)OptionNumber
);
2010 // Provide the image with its load options
2012 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**)&ImageInfo
);
2013 ASSERT_EFI_ERROR (Status
);
2015 if (!BmIsAutoCreateBootOption (BootOption
)) {
2016 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
2017 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
2021 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
2023 ImageInfo
->ParentHandle
= NULL
;
2026 // Before calling the image, enable the Watchdog Timer for 5 minutes period
2028 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
2031 // Write boot to OS performance data for UEFI boot
2034 BmEndOfBdsPerfCode (NULL
, NULL
);
2037 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
2039 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
2040 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
2041 BootOption
->Status
= Status
;
2044 // Destroy the RAM disk
2046 if (RamDiskDevicePath
!= NULL
) {
2047 BmDestroyRamDisk (RamDiskDevicePath
);
2048 FreePool (RamDiskDevicePath
);
2051 if (EFI_ERROR (Status
)) {
2053 // Report Status Code with the failure status to indicate that boot failure
2055 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
, Status
);
2058 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
)OptionNumber
);
2061 // Clear the Watchdog Timer after the image returns
2063 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
2066 // Set Logo status invalid after trying one boot option
2069 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**)&BootLogo
);
2070 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
2071 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
2072 ASSERT_EFI_ERROR (Status
);
2076 // Clear Boot Current
2078 Status
= gRT
->SetVariable (
2080 &gEfiGlobalVariableGuid
,
2086 // Deleting variable with current variable implementation shouldn't fail.
2087 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
2088 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
2090 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
2094 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2095 instances, has the same partition node with HardDriveDevicePath device path
2097 @param BlockIoDevicePath Multi device path instances which need to check
2098 @param HardDriveDevicePath A device path which starts with a hard drive media
2101 @retval TRUE There is a matched device path instance.
2102 @retval FALSE There is no matched device path instance.
2106 BmMatchPartitionDevicePathNode (
2107 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
2108 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
2111 HARDDRIVE_DEVICE_PATH
*Node
;
2113 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
2118 // Match all the partition device path nodes including the nested partition nodes
2120 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
2121 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
2122 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
2126 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2128 Node
= (HARDDRIVE_DEVICE_PATH
*)BlockIoDevicePath
;
2131 // Match Signature and PartitionNumber.
2132 // Unused bytes in Signature are initiaized with zeros.
2134 if ((Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
2135 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
2136 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
2137 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0))
2143 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
2150 Emuerate all possible bootable medias in the following order:
2151 1. Removable BlockIo - The boot option only points to the removable media
2152 device, like USB key, DVD, Floppy etc.
2153 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
2155 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
2156 SimpleFileSystem Protocol, but not supporting BlockIo
2158 4. LoadFile - The boot option points to the media supporting
2160 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
2162 @param BootOptionCount Return the boot option count which has been found.
2164 @retval Pointer to the boot option array.
2166 EFI_BOOT_MANAGER_LOAD_OPTION
*
2167 BmEnumerateBootOptions (
2168 UINTN
*BootOptionCount
2172 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2174 EFI_HANDLE
*Handles
;
2175 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
2178 CHAR16
*Description
;
2180 ASSERT (BootOptionCount
!= NULL
);
2182 *BootOptionCount
= 0;
2186 // Parse removable block io followed by fixed block io
2188 gBS
->LocateHandleBuffer (
2190 &gEfiBlockIoProtocolGuid
,
2196 for (Removable
= 0; Removable
< 2; Removable
++) {
2197 for (Index
= 0; Index
< HandleCount
; Index
++) {
2198 Status
= gBS
->HandleProtocol (
2200 &gEfiBlockIoProtocolGuid
,
2203 if (EFI_ERROR (Status
)) {
2208 // Skip the logical partitions
2210 if (BlkIo
->Media
->LogicalPartition
) {
2215 // Skip the fixed block io then the removable block io
2217 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
2221 Description
= BmGetBootDescription (Handles
[Index
]);
2222 BootOptions
= ReallocatePool (
2223 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2224 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2227 ASSERT (BootOptions
!= NULL
);
2229 Status
= EfiBootManagerInitializeLoadOption (
2230 &BootOptions
[(*BootOptionCount
)++],
2231 LoadOptionNumberUnassigned
,
2235 DevicePathFromHandle (Handles
[Index
]),
2239 ASSERT_EFI_ERROR (Status
);
2241 FreePool (Description
);
2245 if (HandleCount
!= 0) {
2250 // Parse simple file system not based on block io
2252 gBS
->LocateHandleBuffer (
2254 &gEfiSimpleFileSystemProtocolGuid
,
2259 for (Index
= 0; Index
< HandleCount
; Index
++) {
2260 Status
= gBS
->HandleProtocol (
2262 &gEfiBlockIoProtocolGuid
,
2265 if (!EFI_ERROR (Status
)) {
2267 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2272 Description
= BmGetBootDescription (Handles
[Index
]);
2273 BootOptions
= ReallocatePool (
2274 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2275 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2278 ASSERT (BootOptions
!= NULL
);
2280 Status
= EfiBootManagerInitializeLoadOption (
2281 &BootOptions
[(*BootOptionCount
)++],
2282 LoadOptionNumberUnassigned
,
2286 DevicePathFromHandle (Handles
[Index
]),
2290 ASSERT_EFI_ERROR (Status
);
2291 FreePool (Description
);
2294 if (HandleCount
!= 0) {
2299 // Parse load file protocol
2301 gBS
->LocateHandleBuffer (
2303 &gEfiLoadFileProtocolGuid
,
2308 for (Index
= 0; Index
< HandleCount
; Index
++) {
2310 // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().
2312 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2316 Description
= BmGetBootDescription (Handles
[Index
]);
2317 BootOptions
= ReallocatePool (
2318 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2319 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2322 ASSERT (BootOptions
!= NULL
);
2324 Status
= EfiBootManagerInitializeLoadOption (
2325 &BootOptions
[(*BootOptionCount
)++],
2326 LoadOptionNumberUnassigned
,
2330 DevicePathFromHandle (Handles
[Index
]),
2334 ASSERT_EFI_ERROR (Status
);
2335 FreePool (Description
);
2338 if (HandleCount
!= 0) {
2342 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
2347 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2351 EfiBootManagerRefreshAllBootOption (
2356 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2357 UINTN NvBootOptionCount
;
2358 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2359 UINTN BootOptionCount
;
2360 EFI_BOOT_MANAGER_LOAD_OPTION
*UpdatedBootOptions
;
2361 UINTN UpdatedBootOptionCount
;
2363 EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL
*PlatformBootManager
;
2366 // Optionally refresh the legacy boot option
2368 if (mBmRefreshLegacyBootOption
!= NULL
) {
2369 mBmRefreshLegacyBootOption ();
2372 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2375 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2377 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2378 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2379 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2383 // Locate Platform Boot Options Protocol
2385 Status
= gBS
->LocateProtocol (
2386 &gEdkiiPlatformBootManagerProtocolGuid
,
2388 (VOID
**)&PlatformBootManager
2390 if (!EFI_ERROR (Status
)) {
2392 // If found, call platform specific refresh to all auto enumerated and NV
2395 Status
= PlatformBootManager
->RefreshAllBootOptions (
2396 (CONST EFI_BOOT_MANAGER_LOAD_OPTION
*)BootOptions
,
2397 (CONST UINTN
)BootOptionCount
,
2398 &UpdatedBootOptions
,
2399 &UpdatedBootOptionCount
2401 if (!EFI_ERROR (Status
)) {
2402 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2403 BootOptions
= UpdatedBootOptions
;
2404 BootOptionCount
= UpdatedBootOptionCount
;
2408 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2411 // Remove invalid EFI boot options from NV
2413 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2414 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2415 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2416 ) && BmIsAutoCreateBootOption (&NvBootOptions
[Index
])
2420 // Only check those added by BDS
2421 // so that the boot options added by end-user or OS installer won't be deleted
2423 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == -1) {
2424 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2426 // Deleting variable with current variable implementation shouldn't fail.
2428 ASSERT_EFI_ERROR (Status
);
2434 // Add new EFI boot options to NV
2436 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2437 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == -1) {
2438 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
)-1);
2440 // Try best to add the boot options so continue upon failure.
2445 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2446 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2450 This function is called to get or create the boot option for the Boot Manager Menu.
2452 The Boot Manager Menu is shown after successfully booting a boot option.
2453 This function will first try to search the BootManagerMenuFile is in the same FV as
2454 the module links to this library. If fails, it will search in all FVs.
2456 @param BootOption Return the boot option of the Boot Manager Menu
2458 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2459 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2460 @retval others Return status of gRT->SetVariable (). BootOption still points
2461 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2465 BmRegisterBootManagerMenu (
2466 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2470 CHAR16
*Description
;
2471 UINTN DescriptionLength
;
2472 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2474 EFI_HANDLE
*Handles
;
2480 // Try to find BootManagerMenu from LoadFile protocol
2482 gBS
->LocateHandleBuffer (
2484 &gEfiLoadFileProtocolGuid
,
2489 for (Index
= 0; Index
< HandleCount
; Index
++) {
2490 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2491 DevicePath
= DuplicateDevicePath (DevicePathFromHandle (Handles
[Index
]));
2492 Description
= BmGetBootDescription (Handles
[Index
]);
2497 if (HandleCount
!= 0) {
2501 if (DevicePath
== NULL
) {
2502 Status
= GetFileDevicePathFromAnyFv (
2503 PcdGetPtr (PcdBootManagerMenuFile
),
2508 if (EFI_ERROR (Status
)) {
2509 DEBUG ((DEBUG_WARN
, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
2510 return EFI_NOT_FOUND
;
2513 ASSERT (DevicePath
!= NULL
);
2515 // Get BootManagerMenu application's description from EFI User Interface Section.
2517 Status
= GetSectionFromAnyFv (
2518 PcdGetPtr (PcdBootManagerMenuFile
),
2519 EFI_SECTION_USER_INTERFACE
,
2521 (VOID
**)&Description
,
2524 if (EFI_ERROR (Status
)) {
2529 Status
= EfiBootManagerInitializeLoadOption (
2531 LoadOptionNumberUnassigned
,
2533 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2534 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2539 ASSERT_EFI_ERROR (Status
);
2540 FreePool (DevicePath
);
2541 if (Description
!= NULL
) {
2542 FreePool (Description
);
2546 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2547 UINTN BootOptionCount
;
2549 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2550 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2551 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2554 return EfiBootManagerAddLoadOptionVariable (BootOption
, (UINTN
)-1);
2558 Return the boot option corresponding to the Boot Manager Menu.
2559 It may automatically create one if the boot option hasn't been created yet.
2561 @param BootOption Return the Boot Manager Menu.
2563 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2564 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2565 @retval others Return status of gRT->SetVariable (). BootOption still points
2566 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2571 EfiBootManagerGetBootManagerMenu (
2572 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2576 UINTN BootOptionCount
;
2577 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2580 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2582 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2583 if (BmIsBootManagerMenuFilePath (BootOptions
[Index
].FilePath
)) {
2584 Status
= EfiBootManagerInitializeLoadOption (
2586 BootOptions
[Index
].OptionNumber
,
2587 BootOptions
[Index
].OptionType
,
2588 BootOptions
[Index
].Attributes
,
2589 BootOptions
[Index
].Description
,
2590 BootOptions
[Index
].FilePath
,
2591 BootOptions
[Index
].OptionalData
,
2592 BootOptions
[Index
].OptionalDataSize
2594 ASSERT_EFI_ERROR (Status
);
2599 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2602 // Automatically create the Boot#### for Boot Manager Menu when not found.
2604 if (Index
== BootOptionCount
) {
2605 return BmRegisterBootManagerMenu (BootOption
);
2612 Get the next possible full path pointing to the load option.
2613 The routine doesn't guarantee the returned full path points to an existing
2614 file, and it also doesn't guarantee the existing file is a valid load option.
2615 BmGetNextLoadOptionBuffer() guarantees.
2617 @param FilePath The device path pointing to a load option.
2618 It could be a short-form device path.
2619 @param FullPath The full path returned by the routine in last call.
2620 Set to NULL in first call.
2622 @return The next possible full path pointing to the load option.
2623 Caller is responsible to free the memory.
2625 EFI_DEVICE_PATH_PROTOCOL
*
2627 EfiBootManagerGetNextLoadOptionDevicePath (
2628 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
2629 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
2632 return BmGetNextLoadOptionDevicePath (FilePath
, FullPath
);