2 Library functions which relates with booting.
4 Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
5 Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
6 (C) Copyright 2015-2016 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
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
23 EFI_GUID mBmAutoCreateBootOptionGuid
= { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
29 @param Event The triggered event.
30 @param Context Context for this event.
41 // Record the performance data for End of BDS
43 PERF_CROSSMODULE_END("BDS");
49 The function registers the legacy boot support capabilities.
51 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
52 @param LegacyBoot The function pointer to boot the legacy boot option.
56 EfiBootManagerRegisterLegacyBootSupport (
57 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption
,
58 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
61 mBmRefreshLegacyBootOption
= RefreshLegacyBootOption
;
62 mBmLegacyBoot
= LegacyBoot
;
66 Return TRUE when the boot option is auto-created instead of manually added.
68 @param BootOption Pointer to the boot option to check.
70 @retval TRUE The boot option is auto-created.
71 @retval FALSE The boot option is manually added.
74 BmIsAutoCreateBootOption (
75 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
78 if ((BootOption
->OptionalDataSize
== sizeof (EFI_GUID
)) &&
79 CompareGuid ((EFI_GUID
*) BootOption
->OptionalData
, &mBmAutoCreateBootOptionGuid
)
88 Find the boot option in the NV storage and return the option number.
90 @param OptionToFind Boot option to be checked.
92 @return The option number of the found boot option.
96 BmFindBootOptionInVariable (
97 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
101 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
103 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
104 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
105 UINTN BootOptionCount
;
108 OptionNumber
= LoadOptionNumberUnassigned
;
111 // Try to match the variable exactly if the option number is assigned
113 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
115 OptionName
, sizeof (OptionName
), L
"%s%04x",
116 mBmLoadOptionName
[OptionToFind
->OptionType
], OptionToFind
->OptionNumber
118 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
120 if (!EFI_ERROR (Status
)) {
121 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
122 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
123 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
124 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
125 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
126 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
128 OptionNumber
= OptionToFind
->OptionNumber
;
130 EfiBootManagerFreeLoadOption (&BootOption
);
135 // The option number assigned is either incorrect or unassigned.
137 if (OptionNumber
== LoadOptionNumberUnassigned
) {
138 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
140 Index
= EfiBootManagerFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
142 OptionNumber
= BootOptions
[Index
].OptionNumber
;
145 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
152 Return the correct FV file path.
153 FV address may change across reboot. This routine promises the FV file device path is right.
155 @param FilePath The Memory Mapped Device Path to get the file buffer.
157 @return The updated FV Device Path pointint to the file.
159 EFI_DEVICE_PATH_PROTOCOL
*
161 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
166 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
168 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
170 EFI_HANDLE
*FvHandles
;
171 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
172 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
175 // Get the file buffer by using the exactly FilePath.
177 FvFileNode
= FilePath
;
178 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
179 if (!EFI_ERROR (Status
)) {
180 return DuplicateDevicePath (FilePath
);
184 // Only wide match other FVs if it's a memory mapped FV file path.
186 if ((DevicePathType (FilePath
) != HARDWARE_DEVICE_PATH
) || (DevicePathSubType (FilePath
) != HW_MEMMAP_DP
)) {
190 FvFileNode
= NextDevicePathNode (FilePath
);
193 // Firstly find the FV file in current FV
195 gBS
->HandleProtocol (
197 &gEfiLoadedImageProtocolGuid
,
198 (VOID
**) &LoadedImage
200 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
201 FullPath
= BmAdjustFvFilePath (NewDevicePath
);
202 FreePool (NewDevicePath
);
203 if (FullPath
!= NULL
) {
208 // Secondly find the FV file in all other FVs
210 gBS
->LocateHandleBuffer (
212 &gEfiFirmwareVolume2ProtocolGuid
,
217 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
218 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
220 // Skip current FV, it was handed in first step.
224 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
225 FullPath
= BmAdjustFvFilePath (NewDevicePath
);
226 FreePool (NewDevicePath
);
227 if (FullPath
!= NULL
) {
232 if (FvHandles
!= NULL
) {
233 FreePool (FvHandles
);
239 Check if it's a Device Path pointing to FV file.
241 The function doesn't garentee the device path points to existing FV file.
243 @param DevicePath Input device path.
245 @retval TRUE The device path is a FV File Device Path.
246 @retval FALSE The device path is NOT a FV File Device Path.
250 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
255 EFI_DEVICE_PATH_PROTOCOL
*Node
;
258 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &Handle
);
259 if (!EFI_ERROR (Status
)) {
263 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
264 DevicePath
= NextDevicePathNode (DevicePath
);
265 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == MEDIA_PIWG_FW_FILE_DP
)) {
266 return IsDevicePathEnd (NextDevicePathNode (DevicePath
));
273 Check whether a USB device match the specified USB Class device path. This
274 function follows "Load Option Processing" behavior in UEFI specification.
276 @param UsbIo USB I/O protocol associated with the USB device.
277 @param UsbClass The USB Class device path to match.
279 @retval TRUE The USB device match the USB Class device path.
280 @retval FALSE The USB device does not match the USB Class device path.
285 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
286 IN USB_CLASS_DEVICE_PATH
*UsbClass
290 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
291 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
293 UINT8 DeviceSubClass
;
294 UINT8 DeviceProtocol
;
296 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
297 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
302 // Check Vendor Id and Product Id.
304 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
305 if (EFI_ERROR (Status
)) {
309 if ((UsbClass
->VendorId
!= 0xffff) &&
310 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
314 if ((UsbClass
->ProductId
!= 0xffff) &&
315 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
319 DeviceClass
= DevDesc
.DeviceClass
;
320 DeviceSubClass
= DevDesc
.DeviceSubClass
;
321 DeviceProtocol
= DevDesc
.DeviceProtocol
;
322 if (DeviceClass
== 0) {
324 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
325 // Protocol in Interface Descriptor instead.
327 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
328 if (EFI_ERROR (Status
)) {
332 DeviceClass
= IfDesc
.InterfaceClass
;
333 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
334 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
338 // Check Class, SubClass and Protocol.
340 if ((UsbClass
->DeviceClass
!= 0xff) &&
341 (UsbClass
->DeviceClass
!= DeviceClass
)) {
345 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
346 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
350 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
351 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
359 Check whether a USB device match the specified USB WWID device path. This
360 function follows "Load Option Processing" behavior in UEFI specification.
362 @param UsbIo USB I/O protocol associated with the USB device.
363 @param UsbWwid The USB WWID device path to match.
365 @retval TRUE The USB device match the USB WWID device path.
366 @retval FALSE The USB device does not match the USB WWID device path.
371 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
372 IN USB_WWID_DEVICE_PATH
*UsbWwid
376 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
377 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
383 CHAR16
*SerialNumberStr
;
386 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
387 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
392 // Check Vendor Id and Product Id.
394 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
395 if (EFI_ERROR (Status
)) {
398 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
399 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
404 // Check Interface Number.
406 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
407 if (EFI_ERROR (Status
)) {
410 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
415 // Check Serial Number.
417 if (DevDesc
.StrSerialNumber
== 0) {
422 // Get all supported languages.
426 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
427 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
432 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
434 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
435 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
436 if (CompareStr
[CompareLen
- 1] == L
'\0') {
441 // Compare serial number in each supported language.
443 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
444 SerialNumberStr
= NULL
;
445 Status
= UsbIo
->UsbGetStringDescriptor (
448 DevDesc
.StrSerialNumber
,
451 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
455 Length
= StrLen (SerialNumberStr
);
456 if ((Length
>= CompareLen
) &&
457 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
458 FreePool (SerialNumberStr
);
462 FreePool (SerialNumberStr
);
469 Find a USB device which match the specified short-form device path start with
470 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
471 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
472 this function will only search in its child devices.
474 @param DevicePath The device path that contains USB Class or USB WWID device path.
475 @param ParentDevicePathSize The length of the device path before the USB Class or
476 USB WWID device path.
477 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
479 @retval NULL The matched USB IO handles cannot be found.
480 @retval other The matched USB IO handles.
485 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
486 IN UINTN ParentDevicePathSize
,
487 OUT UINTN
*UsbIoHandleCount
491 EFI_HANDLE
*UsbIoHandles
;
492 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
493 EFI_USB_IO_PROTOCOL
*UsbIo
;
497 ASSERT (UsbIoHandleCount
!= NULL
);
500 // Get all UsbIo Handles.
502 Status
= gBS
->LocateHandleBuffer (
504 &gEfiUsbIoProtocolGuid
,
509 if (EFI_ERROR (Status
)) {
510 *UsbIoHandleCount
= 0;
514 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
516 // Get the Usb IO interface.
518 Status
= gBS
->HandleProtocol(
520 &gEfiUsbIoProtocolGuid
,
523 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
525 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
528 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
530 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
531 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
532 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
539 (*UsbIoHandleCount
) --;
540 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
550 Expand USB Class or USB WWID device path node to be full device path of a USB
553 This function support following 4 cases:
554 1) Boot Option device path starts with a USB Class or USB WWID device path,
555 and there is no Media FilePath device path in the end.
556 In this case, it will follow Removable Media Boot Behavior.
557 2) Boot Option device path starts with a USB Class or USB WWID device path,
558 and ended with Media FilePath device path.
559 3) Boot Option device path starts with a full device path to a USB Host Controller,
560 contains a USB Class or USB WWID device path node, while not ended with Media
561 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
562 4) Boot Option device path starts with a full device path to a USB Host Controller,
563 contains a USB Class or USB WWID device path node, and ended with Media
564 FilePath device path.
566 @param FilePath The device path pointing to a load option.
567 It could be a short-form device path.
568 @param FullPath The full path returned by the routine in last call.
569 Set to NULL in first call.
570 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
572 @return The next possible full path pointing to the load option.
573 Caller is responsible to free the memory.
575 EFI_DEVICE_PATH_PROTOCOL
*
576 BmExpandUsbDevicePath (
577 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
578 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
,
579 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
582 UINTN ParentDevicePathSize
;
583 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
584 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
591 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
592 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
593 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
594 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
596 for (Index
= 0; Index
< HandleCount
; Index
++) {
597 FilePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
598 if (FilePath
== NULL
) {
604 NextFullPath
= BmGetNextLoadOptionDevicePath (FilePath
, NULL
);
606 if (NextFullPath
== NULL
) {
608 // No BlockIo or SimpleFileSystem under FilePath.
615 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
616 FreePool (NextFullPath
);
621 if (Handles
!= NULL
) {
629 Expand File-path device path node to be full device path in platform.
631 @param FilePath The device path pointing to a load option.
632 It could be a short-form device path.
633 @param FullPath The full path returned by the routine in last call.
634 Set to NULL in first call.
636 @return The next possible full path pointing to the load option.
637 Caller is responsible to free the memory.
639 EFI_DEVICE_PATH_PROTOCOL
*
640 BmExpandFileDevicePath (
641 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
642 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
649 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
651 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
654 EfiBootManagerConnectAll ();
655 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &Handles
);
656 if (EFI_ERROR (Status
)) {
661 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
664 // Enumerate all removable media devices followed by all fixed media devices,
665 // followed by media devices which don't layer on block io.
667 for (MediaType
= 0; MediaType
< 3; MediaType
++) {
668 for (Index
= 0; Index
< HandleCount
; Index
++) {
669 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiBlockIoProtocolGuid
, (VOID
*) &BlockIo
);
670 if (EFI_ERROR (Status
)) {
673 if ((MediaType
== 0 && BlockIo
!= NULL
&& BlockIo
->Media
->RemovableMedia
) ||
674 (MediaType
== 1 && BlockIo
!= NULL
&& !BlockIo
->Media
->RemovableMedia
) ||
675 (MediaType
== 2 && BlockIo
== NULL
)
677 NextFullPath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
);
681 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
682 FreePool (NextFullPath
);
687 if (NextFullPath
!= NULL
) {
692 if (Handles
!= NULL
) {
700 Expand URI device path node to be full device path in platform.
702 @param FilePath The device path pointing to a load option.
703 It could be a short-form device path.
704 @param FullPath The full path returned by the routine in last call.
705 Set to NULL in first call.
707 @return The next possible full path pointing to the load option.
708 Caller is responsible to free the memory.
710 EFI_DEVICE_PATH_PROTOCOL
*
711 BmExpandUriDevicePath (
712 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
713 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
720 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
721 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
724 EfiBootManagerConnectAll ();
725 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &HandleCount
, &Handles
);
726 if (EFI_ERROR (Status
)) {
732 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
733 for (Index
= 0; Index
< HandleCount
; Index
++) {
734 NextFullPath
= BmExpandLoadFile (Handles
[Index
], FilePath
);
736 if (NextFullPath
== NULL
) {
743 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
745 // Free the resource occupied by the RAM disk.
747 RamDiskDevicePath
= BmGetRamDiskDevicePath (NextFullPath
);
748 if (RamDiskDevicePath
!= NULL
) {
749 BmDestroyRamDisk (RamDiskDevicePath
);
750 FreePool (RamDiskDevicePath
);
752 FreePool (NextFullPath
);
757 if (Handles
!= NULL
) {
765 Save the partition DevicePath to the CachedDevicePath as the first instance.
767 @param CachedDevicePath The device path cache.
768 @param DevicePath The partition device path to be cached.
771 BmCachePartitionDevicePath (
772 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
773 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
776 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
779 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
780 TempDevicePath
= *CachedDevicePath
;
781 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
782 FreePool (TempDevicePath
);
785 if (*CachedDevicePath
== NULL
) {
786 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
790 TempDevicePath
= *CachedDevicePath
;
791 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
792 if (TempDevicePath
!= NULL
) {
793 FreePool (TempDevicePath
);
797 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
798 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
801 TempDevicePath
= *CachedDevicePath
;
802 while (!IsDevicePathEnd (TempDevicePath
)) {
803 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
805 // Parse one instance
807 while (!IsDevicePathEndType (TempDevicePath
)) {
808 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
812 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
815 SetDevicePathEndNode (TempDevicePath
);
822 Expand a device path that starts with a hard drive media device path node to be a
823 full device path that includes the full hardware path to the device. We need
824 to do this so it can be booted. As an optimization the front match (the part point
825 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
826 so a connect all is not required on every boot. All successful history device path
827 which point to partition node (the front part) will be saved.
829 @param FilePath The device path pointing to a load option.
830 It could be a short-form device path.
832 @return The full device path pointing to the load option.
834 EFI_DEVICE_PATH_PROTOCOL
*
835 BmExpandPartitionDevicePath (
836 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
840 UINTN BlockIoHandleCount
;
841 EFI_HANDLE
*BlockIoBuffer
;
842 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
844 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
845 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
846 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
847 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
848 UINTN CachedDevicePathSize
;
850 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
854 // Check if there is prestore 'HDDP' variable.
855 // If exist, search the front path which point to partition node in the variable instants.
856 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
858 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
861 // Delete the invalid 'HDDP' variable.
863 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
864 FreePool (CachedDevicePath
);
865 CachedDevicePath
= NULL
;
866 Status
= gRT
->SetVariable (
868 &mBmHardDriveBootVariableGuid
,
873 ASSERT_EFI_ERROR (Status
);
877 if (CachedDevicePath
!= NULL
) {
878 TempNewDevicePath
= CachedDevicePath
;
882 // Check every instance of the variable
883 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
884 // partial partition boot option. Second, check whether the instance could be connected.
886 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
887 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
889 // Connect the device path instance, the device path point to hard drive media device path node
890 // e.g. ACPI() /PCI()/ATA()/Partition()
892 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
893 if (!EFI_ERROR (Status
)) {
894 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
896 // TempDevicePath = ACPI()/PCI()/ATA()/Partition()
897 // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI
899 // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),
900 // it may expand to two potienal full paths (nested partition, rarely happen):
901 // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI
902 // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI
903 // For simplicity, only #1 is returned.
905 FullPath
= BmGetNextLoadOptionDevicePath (TempDevicePath
, NULL
);
906 FreePool (TempDevicePath
);
908 if (FullPath
!= NULL
) {
910 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
913 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
915 // Save the matching Device Path so we don't need to do a connect all next time
916 // Failing to save only impacts performance next time expanding the short-form device path
918 Status
= gRT
->SetVariable (
920 &mBmHardDriveBootVariableGuid
,
921 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
922 GetDevicePathSize (CachedDevicePath
),
928 FreePool (CachedDevicePath
);
934 // Come here means the first instance is not matched
938 } while (TempNewDevicePath
!= NULL
);
942 // If we get here we fail to find or 'HDDP' not exist, and now we need
943 // to search all devices in the system for a matched partition
945 EfiBootManagerConnectAll ();
946 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
947 if (EFI_ERROR (Status
)) {
948 BlockIoHandleCount
= 0;
949 BlockIoBuffer
= NULL
;
952 // Loop through all the device handles that support the BLOCK_IO Protocol
954 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
955 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
956 if (BlockIoDevicePath
== NULL
) {
960 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
962 // Find the matched partition device path
964 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
965 FullPath
= BmGetNextLoadOptionDevicePath (TempDevicePath
, NULL
);
966 FreePool (TempDevicePath
);
968 if (FullPath
!= NULL
) {
969 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
972 // Save the matching Device Path so we don't need to do a connect all next time
973 // Failing to save only impacts performance next time expanding the short-form device path
975 Status
= gRT
->SetVariable (
977 &mBmHardDriveBootVariableGuid
,
978 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
979 GetDevicePathSize (CachedDevicePath
),
988 if (CachedDevicePath
!= NULL
) {
989 FreePool (CachedDevicePath
);
991 if (BlockIoBuffer
!= NULL
) {
992 FreePool (BlockIoBuffer
);
998 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
999 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1001 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1002 @param FullPath The full path returned by the routine in last call.
1003 Set to NULL in first call.
1005 @return The next possible full path pointing to the load option.
1006 Caller is responsible to free the memory.
1008 EFI_DEVICE_PATH_PROTOCOL
*
1009 BmExpandMediaDevicePath (
1010 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1011 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
1016 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1018 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1019 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
1022 EFI_HANDLE
*SimpleFileSystemHandles
;
1023 UINTN NumberSimpleFileSystemHandles
;
1027 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
1029 // Check whether the device is connected
1031 TempDevicePath
= DevicePath
;
1032 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1033 if (!EFI_ERROR (Status
)) {
1034 ASSERT (IsDevicePathEnd (TempDevicePath
));
1036 NextFullPath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1038 // For device path pointing to simple file system, it only expands to one full path.
1041 return NextFullPath
;
1043 FreePool (NextFullPath
);
1048 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1049 ASSERT_EFI_ERROR (Status
);
1052 // For device boot option only pointing to the removable device handle,
1053 // should make sure all its children handles (its child partion or media handles)
1054 // are created and connected.
1056 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1059 // Issue a dummy read to the device to check for media change.
1060 // When the removable media is changed, any Block IO read/write will
1061 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1062 // returned. After the Block IO protocol is reinstalled, subsequent
1063 // Block IO read/write will success.
1065 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1066 ASSERT_EFI_ERROR (Status
);
1067 if (EFI_ERROR (Status
)) {
1070 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1071 if (Buffer
!= NULL
) {
1072 BlockIo
->ReadBlocks (
1074 BlockIo
->Media
->MediaId
,
1076 BlockIo
->Media
->BlockSize
,
1083 // Detect the the default boot file from removable Media
1085 NextFullPath
= NULL
;
1086 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1087 gBS
->LocateHandleBuffer (
1089 &gEfiSimpleFileSystemProtocolGuid
,
1091 &NumberSimpleFileSystemHandles
,
1092 &SimpleFileSystemHandles
1094 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1096 // Get the device path size of SimpleFileSystem handle
1098 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1099 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1101 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1103 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1104 NextFullPath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1108 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
1109 FreePool (NextFullPath
);
1110 NextFullPath
= NULL
;
1115 if (SimpleFileSystemHandles
!= NULL
) {
1116 FreePool (SimpleFileSystemHandles
);
1119 return NextFullPath
;
1123 Check whether Left and Right are the same without matching the specific
1124 device path data in IP device path and URI device path node.
1126 @retval TRUE Left and Right are the same.
1127 @retval FALSE Left and Right are the different.
1130 BmMatchHttpBootDevicePath (
1131 IN EFI_DEVICE_PATH_PROTOCOL
*Left
,
1132 IN EFI_DEVICE_PATH_PROTOCOL
*Right
1135 for (; !IsDevicePathEnd (Left
) && !IsDevicePathEnd (Right
)
1136 ; Left
= NextDevicePathNode (Left
), Right
= NextDevicePathNode (Right
)
1138 if (CompareMem (Left
, Right
, DevicePathNodeLength (Left
)) != 0) {
1139 if ((DevicePathType (Left
) != MESSAGING_DEVICE_PATH
) || (DevicePathType (Right
) != MESSAGING_DEVICE_PATH
)) {
1143 if (DevicePathSubType (Left
) == MSG_DNS_DP
) {
1144 Left
= NextDevicePathNode (Left
);
1147 if (DevicePathSubType (Right
) == MSG_DNS_DP
) {
1148 Right
= NextDevicePathNode (Right
);
1151 if (((DevicePathSubType (Left
) != MSG_IPv4_DP
) || (DevicePathSubType (Right
) != MSG_IPv4_DP
)) &&
1152 ((DevicePathSubType (Left
) != MSG_IPv6_DP
) || (DevicePathSubType (Right
) != MSG_IPv6_DP
)) &&
1153 ((DevicePathSubType (Left
) != MSG_URI_DP
) || (DevicePathSubType (Right
) != MSG_URI_DP
))
1159 return (BOOLEAN
) (IsDevicePathEnd (Left
) && IsDevicePathEnd (Right
));
1163 Get the file buffer from the file system produced by Load File instance.
1165 @param LoadFileHandle The handle of LoadFile instance.
1166 @param RamDiskHandle Return the RAM Disk handle.
1168 @return The next possible full path pointing to the load option.
1169 Caller is responsible to free the memory.
1171 EFI_DEVICE_PATH_PROTOCOL
*
1172 BmExpandNetworkFileSystem (
1173 IN EFI_HANDLE LoadFileHandle
,
1174 OUT EFI_HANDLE
*RamDiskHandle
1179 EFI_HANDLE
*Handles
;
1182 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1184 Status
= gBS
->LocateHandleBuffer (
1186 &gEfiBlockIoProtocolGuid
,
1191 if (EFI_ERROR (Status
)) {
1197 for (Index
= 0; Index
< HandleCount
; Index
++) {
1198 Node
= DevicePathFromHandle (Handles
[Index
]);
1199 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1200 if (!EFI_ERROR (Status
) &&
1201 (Handle
== LoadFileHandle
) &&
1202 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)) {
1204 // Find the BlockIo instance populated from the LoadFile.
1206 Handle
= Handles
[Index
];
1211 if (Handles
!= NULL
) {
1215 if (Index
== HandleCount
) {
1219 *RamDiskHandle
= Handle
;
1221 if (Handle
!= NULL
) {
1223 // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
1224 // But assume only one SimpleFileSystem can be found under the BlockIo.
1226 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle
), NULL
);
1233 Return the RAM Disk device path created by LoadFile.
1235 @param FilePath The source file path.
1237 @return Callee-to-free RAM Disk device path
1239 EFI_DEVICE_PATH_PROTOCOL
*
1240 BmGetRamDiskDevicePath (
1241 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1245 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1246 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1250 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1251 if (!EFI_ERROR (Status
) &&
1252 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) &&
1253 (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)
1257 // Construct the device path pointing to RAM Disk
1259 Node
= NextDevicePathNode (Node
);
1260 RamDiskDevicePath
= DuplicateDevicePath (FilePath
);
1261 ASSERT (RamDiskDevicePath
!= NULL
);
1262 SetDevicePathEndNode ((VOID
*) ((UINTN
) RamDiskDevicePath
+ ((UINTN
) Node
- (UINTN
) FilePath
)));
1263 return RamDiskDevicePath
;
1270 Return the buffer and buffer size occupied by the RAM Disk.
1272 @param RamDiskDevicePath RAM Disk device path.
1273 @param RamDiskSizeInPages Return RAM Disk size in pages.
1275 @retval RAM Disk buffer.
1278 BmGetRamDiskMemoryInfo (
1279 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
,
1280 OUT UINTN
*RamDiskSizeInPages
1286 UINT64 StartingAddr
;
1289 ASSERT (RamDiskDevicePath
!= NULL
);
1291 *RamDiskSizeInPages
= 0;
1294 // Get the buffer occupied by RAM Disk.
1296 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &RamDiskDevicePath
, &Handle
);
1297 ASSERT_EFI_ERROR (Status
);
1298 ASSERT ((DevicePathType (RamDiskDevicePath
) == MEDIA_DEVICE_PATH
) &&
1299 (DevicePathSubType (RamDiskDevicePath
) == MEDIA_RAM_DISK_DP
));
1300 StartingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->StartingAddr
);
1301 EndingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->EndingAddr
);
1302 *RamDiskSizeInPages
= EFI_SIZE_TO_PAGES ((UINTN
) (EndingAddr
- StartingAddr
+ 1));
1303 return (VOID
*) (UINTN
) StartingAddr
;
1307 Destroy the RAM Disk.
1309 The destroy operation includes to call RamDisk.Unregister to
1310 unregister the RAM DISK from RAM DISK driver, free the memory
1311 allocated for the RAM Disk.
1313 @param RamDiskDevicePath RAM Disk device path.
1317 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
1321 VOID
*RamDiskBuffer
;
1322 UINTN RamDiskSizeInPages
;
1324 ASSERT (RamDiskDevicePath
!= NULL
);
1326 RamDiskBuffer
= BmGetRamDiskMemoryInfo (RamDiskDevicePath
, &RamDiskSizeInPages
);
1329 // Destroy RAM Disk.
1331 if (mRamDisk
== NULL
) {
1332 Status
= gBS
->LocateProtocol (&gEfiRamDiskProtocolGuid
, NULL
, (VOID
*) &mRamDisk
);
1333 ASSERT_EFI_ERROR (Status
);
1335 Status
= mRamDisk
->Unregister (RamDiskDevicePath
);
1336 ASSERT_EFI_ERROR (Status
);
1337 FreePages (RamDiskBuffer
, RamDiskSizeInPages
);
1341 Get the file buffer from the specified Load File instance.
1343 @param LoadFileHandle The specified Load File instance.
1344 @param FilePath The file path which will pass to LoadFile().
1346 @return The full device path pointing to the load option buffer.
1348 EFI_DEVICE_PATH_PROTOCOL
*
1350 IN EFI_HANDLE LoadFileHandle
,
1351 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1355 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1357 EFI_HANDLE RamDiskHandle
;
1359 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
1361 Status
= gBS
->OpenProtocol (
1363 &gEfiLoadFileProtocolGuid
,
1364 (VOID
**) &LoadFile
,
1367 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1369 ASSERT_EFI_ERROR (Status
);
1373 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1374 if ((Status
!= EFI_WARN_FILE_SYSTEM
) && (Status
!= EFI_BUFFER_TOO_SMALL
)) {
1378 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1380 // The load option buffer is directly returned by LoadFile.
1382 return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle
));
1386 // The load option resides in a RAM disk.
1388 FileBuffer
= AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize
));
1389 if (FileBuffer
== NULL
) {
1391 EFI_DEVICE_PATH
*LoadFilePath
;
1392 CHAR16
*LoadFileText
;
1395 LoadFilePath
= DevicePathFromHandle (LoadFileHandle
);
1396 if (LoadFilePath
== NULL
) {
1397 LoadFileText
= NULL
;
1399 LoadFileText
= ConvertDevicePathToText (LoadFilePath
, FALSE
, FALSE
);
1401 FileText
= ConvertDevicePathToText (FilePath
, FALSE
, FALSE
);
1405 "%a:%a: failed to allocate reserved pages: "
1406 "BufferSize=%Lu LoadFile=\"%s\" FilePath=\"%s\"\n",
1414 if (FileText
!= NULL
) {
1415 FreePool (FileText
);
1417 if (LoadFileText
!= NULL
) {
1418 FreePool (LoadFileText
);
1424 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1425 if (EFI_ERROR (Status
)) {
1426 FreePages (FileBuffer
, EFI_SIZE_TO_PAGES (BufferSize
));
1430 FullPath
= BmExpandNetworkFileSystem (LoadFileHandle
, &RamDiskHandle
);
1431 if (FullPath
== NULL
) {
1433 // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
1435 BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle
));
1442 Return the full device path pointing to the load option.
1445 1. Exactly matches to a LoadFile instance.
1446 2. Cannot match to any LoadFile instance. Wide match is required.
1447 In either case, the routine may return:
1448 1. A copy of FilePath when FilePath matches to a LoadFile instance and
1449 the LoadFile returns a load option buffer.
1450 2. A new device path with IP and URI information updated when wide match
1452 3. A new device path pointing to a load option in RAM disk.
1453 In either case, only one full device path is returned for a specified
1456 @param FilePath The media device path pointing to a LoadFile instance.
1458 @return The load option buffer.
1460 EFI_DEVICE_PATH_PROTOCOL
*
1462 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1467 EFI_HANDLE
*Handles
;
1470 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1473 // Get file buffer from load file instance.
1476 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1477 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1479 // When wide match happens, pass full device path to LoadFile (),
1480 // otherwise, pass remaining device path to LoadFile ().
1486 // Use wide match algorithm to find one when
1487 // cannot find a LoadFile instance to exactly match the FilePath
1489 Status
= gBS
->LocateHandleBuffer (
1491 &gEfiLoadFileProtocolGuid
,
1496 if (EFI_ERROR (Status
)) {
1500 for (Index
= 0; Index
< HandleCount
; Index
++) {
1501 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
)) {
1502 Handle
= Handles
[Index
];
1506 if (Handles
!= NULL
) {
1511 if (Handle
== NULL
) {
1515 return BmExpandLoadFile (Handle
, FilePath
);
1519 Get the load option by its device path.
1521 @param FilePath The device path pointing to a load option.
1522 It could be a short-form device path.
1523 @param FullPath Return the full device path of the load option after
1524 short-form device path expanding.
1525 Caller is responsible to free it.
1526 @param FileSize Return the load option size.
1528 @return The load option buffer. Caller is responsible to free the memory.
1532 EfiBootManagerGetLoadOptionBuffer (
1533 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1534 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1540 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1541 return BmGetNextLoadOptionBuffer (LoadOptionTypeMax
, FilePath
, FullPath
, FileSize
);
1545 Get the next possible full path pointing to the load option.
1546 The routine doesn't guarantee the returned full path points to an existing
1547 file, and it also doesn't guarantee the existing file is a valid load option.
1548 BmGetNextLoadOptionBuffer() guarantees.
1550 @param FilePath The device path pointing to a load option.
1551 It could be a short-form device path.
1552 @param FullPath The full path returned by the routine in last call.
1553 Set to NULL in first call.
1555 @return The next possible full path pointing to the load option.
1556 Caller is responsible to free the memory.
1558 EFI_DEVICE_PATH_PROTOCOL
*
1559 BmGetNextLoadOptionDevicePath (
1560 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1561 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
1565 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1568 ASSERT (FilePath
!= NULL
);
1571 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1574 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1575 if (EFI_ERROR (Status
)) {
1576 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1579 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1580 return BmExpandMediaDevicePath (FilePath
, FullPath
);
1584 // Expand the short-form device path to full device path
1586 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1587 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1589 // Expand the Harddrive device path
1591 if (FullPath
== NULL
) {
1592 return BmExpandPartitionDevicePath (FilePath
);
1596 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1597 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
)) {
1599 // Expand the File-path device path
1601 return BmExpandFileDevicePath (FilePath
, FullPath
);
1602 } else if ((DevicePathType (FilePath
) == MESSAGING_DEVICE_PATH
) &&
1603 (DevicePathSubType (FilePath
) == MSG_URI_DP
)) {
1605 // Expand the URI device path
1607 return BmExpandUriDevicePath (FilePath
, FullPath
);
1610 Status
= gBS
->LocateDevicePath (&gEfiUsbIoProtocolGuid
, &Node
, &Handle
);
1611 if (EFI_ERROR (Status
)) {
1613 // Only expand the USB WWID/Class device path
1614 // when FilePath doesn't point to a physical UsbIo controller.
1615 // Otherwise, infinite recursion will happen.
1617 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1618 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1619 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1625 // Expand the USB WWID/Class device path
1627 if (!IsDevicePathEnd (Node
)) {
1628 if (FilePath
== Node
) {
1630 // Boot Option device path starts with USB Class or USB WWID device path.
1631 // For Boot Option device path which doesn't begin with the USB Class or
1632 // USB WWID device path, it's not needed to connect again here.
1634 BmConnectUsbShortFormDevicePath (FilePath
);
1636 return BmExpandUsbDevicePath (FilePath
, FullPath
, Node
);
1642 // For the below cases, FilePath only expands to one Full path.
1643 // So just handle the case when FullPath == NULL.
1645 if (FullPath
!= NULL
) {
1650 // Load option resides in FV.
1652 if (BmIsFvFilePath (FilePath
)) {
1653 return BmAdjustFvFilePath (FilePath
);
1657 // Load option resides in Simple File System.
1660 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1661 if (!EFI_ERROR (Status
)) {
1662 return DuplicateDevicePath (FilePath
);
1666 // Last chance to try: Load option may be loaded through LoadFile.
1668 return BmExpandLoadFiles (FilePath
);
1672 Check if it's a Device Path pointing to BootManagerMenu.
1674 @param DevicePath Input device path.
1676 @retval TRUE The device path is BootManagerMenu File Device Path.
1677 @retval FALSE The device path is NOT BootManagerMenu File Device Path.
1680 BmIsBootManagerMenuFilePath (
1681 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1684 EFI_HANDLE FvHandle
;
1688 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &DevicePath
, &FvHandle
);
1689 if (!EFI_ERROR (Status
)) {
1690 NameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) DevicePath
);
1691 if (NameGuid
!= NULL
) {
1692 return CompareGuid (NameGuid
, PcdGetPtr (PcdBootManagerMenuFile
));
1700 Report status code with EFI_RETURN_STATUS_EXTENDED_DATA about LoadImage() or
1701 StartImage() failure.
1703 @param[in] ErrorCode An Error Code in the Software Class, DXE Boot
1704 Service Driver Subclass. ErrorCode will be used to
1705 compose the Value parameter for status code
1706 reporting. Must be one of
1707 EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR and
1708 EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED.
1710 @param[in] FailureStatus The failure status returned by the boot service
1711 that should be reported.
1714 BmReportLoadFailure (
1715 IN UINT32 ErrorCode
,
1716 IN EFI_STATUS FailureStatus
1719 EFI_RETURN_STATUS_EXTENDED_DATA ExtendedData
;
1721 if (!ReportErrorCodeEnabled ()) {
1726 (ErrorCode
== EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
) ||
1727 (ErrorCode
== EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1730 ZeroMem (&ExtendedData
, sizeof (ExtendedData
));
1731 ExtendedData
.ReturnStatus
= FailureStatus
;
1733 REPORT_STATUS_CODE_EX (
1734 (EFI_ERROR_CODE
| EFI_ERROR_MINOR
),
1735 (EFI_SOFTWARE_DXE_BS_DRIVER
| ErrorCode
),
1739 &ExtendedData
.DataHeader
+ 1,
1740 sizeof (ExtendedData
) - sizeof (ExtendedData
.DataHeader
)
1745 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1746 also signals the EFI ready to boot event. If the device path for the option
1747 starts with a BBS device path a legacy boot is attempted via the registered
1748 gLegacyBoot function. Short form device paths are also supported via this
1749 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1750 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1751 If the BootOption Device Path fails the removable media boot algorithm
1752 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1753 is tried per processor type)
1755 @param BootOption Boot Option to try and boot.
1756 On return, BootOption->Status contains the boot status.
1757 EFI_SUCCESS BootOption was booted
1758 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1759 registered via EfiBootManagerInitialize().
1760 EFI_NOT_FOUND The BootOption was not found on the system
1761 !EFI_SUCCESS BootOption failed with this error status
1766 EfiBootManagerBoot (
1767 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1771 EFI_HANDLE ImageHandle
;
1772 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1775 UINTN OriginalOptionNumber
;
1776 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1777 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1780 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1781 EFI_EVENT LegacyBootEvent
;
1783 if (BootOption
== NULL
) {
1787 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1788 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1793 // 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")
1795 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1796 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1797 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1798 if (!EFI_ERROR (Status
)) {
1800 // Save the BootOption->OptionNumber to restore later
1802 OptionNumber
= Uint16
;
1803 OriginalOptionNumber
= BootOption
->OptionNumber
;
1804 BootOption
->OptionNumber
= OptionNumber
;
1805 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1806 BootOption
->OptionNumber
= OriginalOptionNumber
;
1809 if (EFI_ERROR (Status
)) {
1810 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1811 BootOption
->Status
= Status
;
1817 // 2. Set BootCurrent
1819 Uint16
= (UINT16
) OptionNumber
;
1820 BmSetVariableAndReportStatusCodeOnError (
1822 &gEfiGlobalVariableGuid
,
1823 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1829 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1832 if (BmIsBootManagerMenuFilePath (BootOption
->FilePath
)) {
1833 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1834 BmStopHotkeyService (NULL
, NULL
);
1836 EfiSignalEventReadyToBoot();
1838 // Report Status Code to indicate ReadyToBoot was signalled
1840 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1842 // 4. Repair system through DriverHealth protocol
1844 BmRepairAllControllers (0);
1847 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1850 // 5. Adjust the different type memory page number just before booting
1851 // and save the updated info into the variable for next boot to use
1853 BmSetMemoryTypeInformationVariable (
1854 (BOOLEAN
) ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1858 // 6. Load EFI boot option to ImageHandle
1860 DEBUG_CODE_BEGIN ();
1861 if (BootOption
->Description
== NULL
) {
1862 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1864 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1869 RamDiskDevicePath
= NULL
;
1870 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1871 Status
= EFI_NOT_FOUND
;
1873 EfiBootManagerConnectDevicePath (BootOption
->FilePath
, NULL
);
1874 FileBuffer
= BmGetNextLoadOptionBuffer (LoadOptionTypeBoot
, BootOption
->FilePath
, &FilePath
, &FileSize
);
1875 if (FileBuffer
!= NULL
) {
1876 RamDiskDevicePath
= BmGetRamDiskDevicePath (FilePath
);
1878 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1879 Status
= gBS
->LoadImage (
1888 if (FileBuffer
!= NULL
) {
1889 FreePool (FileBuffer
);
1891 if (FilePath
!= NULL
) {
1892 FreePool (FilePath
);
1895 if (EFI_ERROR (Status
)) {
1897 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
1898 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
1899 // If the caller doesn't have the option to defer the execution of an image, we should
1900 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
1902 if (Status
== EFI_SECURITY_VIOLATION
) {
1903 gBS
->UnloadImage (ImageHandle
);
1906 // Report Status Code with the failure status to indicate that the failure to load boot option
1908 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
, Status
);
1909 BootOption
->Status
= Status
;
1911 // Destroy the RAM disk
1913 if (RamDiskDevicePath
!= NULL
) {
1914 BmDestroyRamDisk (RamDiskDevicePath
);
1915 FreePool (RamDiskDevicePath
);
1922 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1923 // Write boot to OS performance data for Legacy boot
1925 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1926 if (mBmLegacyBoot
!= NULL
) {
1928 // Write boot to OS performance data for legacy boot.
1932 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1934 Status
= EfiCreateEventLegacyBootEx(
1940 ASSERT_EFI_ERROR (Status
);
1943 mBmLegacyBoot (BootOption
);
1945 BootOption
->Status
= EFI_UNSUPPORTED
;
1948 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1953 // Provide the image with its load options
1955 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1956 ASSERT_EFI_ERROR (Status
);
1958 if (!BmIsAutoCreateBootOption (BootOption
)) {
1959 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1960 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1964 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1966 ImageInfo
->ParentHandle
= NULL
;
1969 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1971 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1974 // Write boot to OS performance data for UEFI boot
1977 BmEndOfBdsPerfCode (NULL
, NULL
);
1980 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1982 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1983 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1984 BootOption
->Status
= Status
;
1985 if (EFI_ERROR (Status
)) {
1987 // Report Status Code with the failure status to indicate that boot failure
1989 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
, Status
);
1991 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1994 // Destroy the RAM disk
1996 if (RamDiskDevicePath
!= NULL
) {
1997 BmDestroyRamDisk (RamDiskDevicePath
);
1998 FreePool (RamDiskDevicePath
);
2002 // Clear the Watchdog Timer after the image returns
2004 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
2007 // Set Logo status invalid after trying one boot option
2010 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
2011 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
2012 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
2013 ASSERT_EFI_ERROR (Status
);
2017 // Clear Boot Current
2019 Status
= gRT
->SetVariable (
2021 &gEfiGlobalVariableGuid
,
2027 // Deleting variable with current variable implementation shouldn't fail.
2028 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
2029 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
2031 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
2035 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2036 instances, has the same partition node with HardDriveDevicePath device path
2038 @param BlockIoDevicePath Multi device path instances which need to check
2039 @param HardDriveDevicePath A device path which starts with a hard drive media
2042 @retval TRUE There is a matched device path instance.
2043 @retval FALSE There is no matched device path instance.
2047 BmMatchPartitionDevicePathNode (
2048 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
2049 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
2052 HARDDRIVE_DEVICE_PATH
*Node
;
2054 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
2059 // Match all the partition device path nodes including the nested partition nodes
2061 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
2062 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
2063 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
2066 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2068 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
2071 // Match Signature and PartitionNumber.
2072 // Unused bytes in Signature are initiaized with zeros.
2074 if ((Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
2075 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
2076 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
2077 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)) {
2082 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
2089 Emuerate all possible bootable medias in the following order:
2090 1. Removable BlockIo - The boot option only points to the removable media
2091 device, like USB key, DVD, Floppy etc.
2092 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
2094 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
2095 SimpleFileSystem Protocol, but not supporting BlockIo
2097 4. LoadFile - The boot option points to the media supporting
2099 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
2101 @param BootOptionCount Return the boot option count which has been found.
2103 @retval Pointer to the boot option array.
2105 EFI_BOOT_MANAGER_LOAD_OPTION
*
2106 BmEnumerateBootOptions (
2107 UINTN
*BootOptionCount
2111 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2113 EFI_HANDLE
*Handles
;
2114 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
2117 CHAR16
*Description
;
2119 ASSERT (BootOptionCount
!= NULL
);
2121 *BootOptionCount
= 0;
2125 // Parse removable block io followed by fixed block io
2127 gBS
->LocateHandleBuffer (
2129 &gEfiBlockIoProtocolGuid
,
2135 for (Removable
= 0; Removable
< 2; Removable
++) {
2136 for (Index
= 0; Index
< HandleCount
; Index
++) {
2137 Status
= gBS
->HandleProtocol (
2139 &gEfiBlockIoProtocolGuid
,
2142 if (EFI_ERROR (Status
)) {
2147 // Skip the logical partitions
2149 if (BlkIo
->Media
->LogicalPartition
) {
2154 // Skip the fixed block io then the removable block io
2156 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
2160 Description
= BmGetBootDescription (Handles
[Index
]);
2161 BootOptions
= ReallocatePool (
2162 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2163 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2166 ASSERT (BootOptions
!= NULL
);
2168 Status
= EfiBootManagerInitializeLoadOption (
2169 &BootOptions
[(*BootOptionCount
)++],
2170 LoadOptionNumberUnassigned
,
2174 DevicePathFromHandle (Handles
[Index
]),
2178 ASSERT_EFI_ERROR (Status
);
2180 FreePool (Description
);
2184 if (HandleCount
!= 0) {
2189 // Parse simple file system not based on block io
2191 gBS
->LocateHandleBuffer (
2193 &gEfiSimpleFileSystemProtocolGuid
,
2198 for (Index
= 0; Index
< HandleCount
; Index
++) {
2199 Status
= gBS
->HandleProtocol (
2201 &gEfiBlockIoProtocolGuid
,
2204 if (!EFI_ERROR (Status
)) {
2206 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2210 Description
= BmGetBootDescription (Handles
[Index
]);
2211 BootOptions
= ReallocatePool (
2212 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2213 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2216 ASSERT (BootOptions
!= NULL
);
2218 Status
= EfiBootManagerInitializeLoadOption (
2219 &BootOptions
[(*BootOptionCount
)++],
2220 LoadOptionNumberUnassigned
,
2224 DevicePathFromHandle (Handles
[Index
]),
2228 ASSERT_EFI_ERROR (Status
);
2229 FreePool (Description
);
2232 if (HandleCount
!= 0) {
2237 // Parse load file protocol
2239 gBS
->LocateHandleBuffer (
2241 &gEfiLoadFileProtocolGuid
,
2246 for (Index
= 0; Index
< HandleCount
; Index
++) {
2248 // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().
2250 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2254 Description
= BmGetBootDescription (Handles
[Index
]);
2255 BootOptions
= ReallocatePool (
2256 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2257 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2260 ASSERT (BootOptions
!= NULL
);
2262 Status
= EfiBootManagerInitializeLoadOption (
2263 &BootOptions
[(*BootOptionCount
)++],
2264 LoadOptionNumberUnassigned
,
2268 DevicePathFromHandle (Handles
[Index
]),
2272 ASSERT_EFI_ERROR (Status
);
2273 FreePool (Description
);
2276 if (HandleCount
!= 0) {
2280 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
2285 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2289 EfiBootManagerRefreshAllBootOption (
2294 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2295 UINTN NvBootOptionCount
;
2296 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2297 UINTN BootOptionCount
;
2298 EFI_BOOT_MANAGER_LOAD_OPTION
*UpdatedBootOptions
;
2299 UINTN UpdatedBootOptionCount
;
2301 EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL
*PlatformBootManager
;
2304 // Optionally refresh the legacy boot option
2306 if (mBmRefreshLegacyBootOption
!= NULL
) {
2307 mBmRefreshLegacyBootOption ();
2310 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2313 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2315 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2316 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2317 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2321 // Locate Platform Boot Options Protocol
2323 Status
= gBS
->LocateProtocol (&gEdkiiPlatformBootManagerProtocolGuid
,
2325 (VOID
**)&PlatformBootManager
);
2326 if (!EFI_ERROR (Status
)) {
2328 // If found, call platform specific refresh to all auto enumerated and NV
2331 Status
= PlatformBootManager
->RefreshAllBootOptions ((CONST EFI_BOOT_MANAGER_LOAD_OPTION
*)BootOptions
,
2332 (CONST UINTN
)BootOptionCount
,
2333 &UpdatedBootOptions
,
2334 &UpdatedBootOptionCount
);
2335 if (!EFI_ERROR (Status
)) {
2336 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2337 BootOptions
= UpdatedBootOptions
;
2338 BootOptionCount
= UpdatedBootOptionCount
;
2342 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2345 // Remove invalid EFI boot options from NV
2347 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2348 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2349 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2350 ) && BmIsAutoCreateBootOption (&NvBootOptions
[Index
])
2353 // Only check those added by BDS
2354 // so that the boot options added by end-user or OS installer won't be deleted
2356 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == -1) {
2357 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2359 // Deleting variable with current variable implementation shouldn't fail.
2361 ASSERT_EFI_ERROR (Status
);
2367 // Add new EFI boot options to NV
2369 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2370 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == -1) {
2371 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2373 // Try best to add the boot options so continue upon failure.
2378 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2379 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2383 This function is called to get or create the boot option for the Boot Manager Menu.
2385 The Boot Manager Menu is shown after successfully booting a boot option.
2386 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2388 @param BootOption Return the boot option of the Boot Manager Menu
2390 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2391 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2392 @retval others Return status of gRT->SetVariable (). BootOption still points
2393 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2397 BmRegisterBootManagerMenu (
2398 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2402 CHAR16
*Description
;
2403 UINTN DescriptionLength
;
2404 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2405 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2406 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2408 EFI_HANDLE
*Handles
;
2416 // Try to find BootManagerMenu from LoadFile protocol
2418 gBS
->LocateHandleBuffer (
2420 &gEfiLoadFileProtocolGuid
,
2425 for (Index
= 0; Index
< HandleCount
; Index
++) {
2426 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2427 DevicePath
= DuplicateDevicePath (DevicePathFromHandle (Handles
[Index
]));
2428 Description
= BmGetBootDescription (Handles
[Index
]);
2432 if (HandleCount
!= 0) {
2436 if (DevicePath
== NULL
) {
2438 Status
= GetSectionFromFv (
2439 PcdGetPtr (PcdBootManagerMenuFile
),
2448 if (EFI_ERROR (Status
)) {
2449 DEBUG ((EFI_D_WARN
, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
2450 return EFI_NOT_FOUND
;
2454 // Get BootManagerMenu application's description from EFI User Interface Section.
2456 Status
= GetSectionFromFv (
2457 PcdGetPtr (PcdBootManagerMenuFile
),
2458 EFI_SECTION_USER_INTERFACE
,
2460 (VOID
**) &Description
,
2463 if (EFI_ERROR (Status
)) {
2467 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2468 Status
= gBS
->HandleProtocol (
2470 &gEfiLoadedImageProtocolGuid
,
2471 (VOID
**) &LoadedImage
2473 ASSERT_EFI_ERROR (Status
);
2474 DevicePath
= AppendDevicePathNode (
2475 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2476 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2478 ASSERT (DevicePath
!= NULL
);
2481 Status
= EfiBootManagerInitializeLoadOption (
2483 LoadOptionNumberUnassigned
,
2485 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2486 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2491 ASSERT_EFI_ERROR (Status
);
2492 FreePool (DevicePath
);
2493 if (Description
!= NULL
) {
2494 FreePool (Description
);
2498 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2499 UINTN BootOptionCount
;
2501 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2502 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2503 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2506 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2510 Return the boot option corresponding to the Boot Manager Menu.
2511 It may automatically create one if the boot option hasn't been created yet.
2513 @param BootOption Return the Boot Manager Menu.
2515 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2516 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2517 @retval others Return status of gRT->SetVariable (). BootOption still points
2518 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2523 EfiBootManagerGetBootManagerMenu (
2524 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2528 UINTN BootOptionCount
;
2529 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2532 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2534 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2535 if (BmIsBootManagerMenuFilePath (BootOptions
[Index
].FilePath
)) {
2536 Status
= EfiBootManagerInitializeLoadOption (
2538 BootOptions
[Index
].OptionNumber
,
2539 BootOptions
[Index
].OptionType
,
2540 BootOptions
[Index
].Attributes
,
2541 BootOptions
[Index
].Description
,
2542 BootOptions
[Index
].FilePath
,
2543 BootOptions
[Index
].OptionalData
,
2544 BootOptions
[Index
].OptionalDataSize
2546 ASSERT_EFI_ERROR (Status
);
2551 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2554 // Automatically create the Boot#### for Boot Manager Menu when not found.
2556 if (Index
== BootOptionCount
) {
2557 return BmRegisterBootManagerMenu (BootOption
);
2564 Get the next possible full path pointing to the load option.
2565 The routine doesn't guarantee the returned full path points to an existing
2566 file, and it also doesn't guarantee the existing file is a valid load option.
2567 BmGetNextLoadOptionBuffer() guarantees.
2569 @param FilePath The device path pointing to a load option.
2570 It could be a short-form device path.
2571 @param FullPath The full path returned by the routine in last call.
2572 Set to NULL in first call.
2574 @return The next possible full path pointing to the load option.
2575 Caller is responsible to free the memory.
2577 EFI_DEVICE_PATH_PROTOCOL
*
2579 EfiBootManagerGetNextLoadOptionDevicePath (
2580 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
2581 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
2584 return BmGetNextLoadOptionDevicePath(FilePath
, FullPath
);