2 Library functions which relates with booting.
4 Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "InternalBm.h"
18 EFI_RAM_DISK_PROTOCOL
*mRamDisk
= NULL
;
20 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption
= NULL
;
21 EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot
= NULL
;
24 /// This GUID is used for an EFI Variable that stores the front device pathes
25 /// for a partial device path that starts with the HD node.
27 EFI_GUID mBmHardDriveBootVariableGuid
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
28 EFI_GUID mBmAutoCreateBootOptionGuid
= { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
31 The function registers the legacy boot support capabilities.
33 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
34 @param LegacyBoot The function pointer to boot the legacy boot option.
38 EfiBootManagerRegisterLegacyBootSupport (
39 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption
,
40 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
43 mBmRefreshLegacyBootOption
= RefreshLegacyBootOption
;
44 mBmLegacyBoot
= LegacyBoot
;
48 Return TRUE when the boot option is auto-created instead of manually added.
50 @param BootOption Pointer to the boot option to check.
52 @retval TRUE The boot option is auto-created.
53 @retval FALSE The boot option is manually added.
56 BmIsAutoCreateBootOption (
57 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
60 if ((BootOption
->OptionalDataSize
== sizeof (EFI_GUID
)) &&
61 CompareGuid ((EFI_GUID
*) BootOption
->OptionalData
, &mBmAutoCreateBootOptionGuid
)
70 Find the boot option in the NV storage and return the option number.
72 @param OptionToFind Boot option to be checked.
74 @return The option number of the found boot option.
78 BmFindBootOptionInVariable (
79 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
83 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
85 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
86 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
87 UINTN BootOptionCount
;
90 OptionNumber
= LoadOptionNumberUnassigned
;
93 // Try to match the variable exactly if the option number is assigned
95 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
97 OptionName
, sizeof (OptionName
), L
"%s%04x",
98 mBmLoadOptionName
[OptionToFind
->OptionType
], OptionToFind
->OptionNumber
100 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
102 if (!EFI_ERROR (Status
)) {
103 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
104 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
105 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
106 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
107 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
108 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
110 OptionNumber
= OptionToFind
->OptionNumber
;
112 EfiBootManagerFreeLoadOption (&BootOption
);
117 // The option number assigned is either incorrect or unassigned.
119 if (OptionNumber
== LoadOptionNumberUnassigned
) {
120 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
122 Index
= EfiBootManagerFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
124 OptionNumber
= BootOptions
[Index
].OptionNumber
;
127 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
134 Return the correct FV file path.
135 FV address may change across reboot. This routine promises the FV file device path is right.
137 @param FilePath The Memory Mapped Device Path to get the file buffer.
139 @return The updated FV Device Path pointint to the file.
141 EFI_DEVICE_PATH_PROTOCOL
*
143 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
148 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
150 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
152 EFI_HANDLE
*FvHandles
;
153 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
154 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
157 // Get the file buffer by using the exactly FilePath.
159 FvFileNode
= FilePath
;
160 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
161 if (!EFI_ERROR (Status
)) {
162 return DuplicateDevicePath (FilePath
);
166 // Only wide match other FVs if it's a memory mapped FV file path.
168 if ((DevicePathType (FilePath
) != HARDWARE_DEVICE_PATH
) || (DevicePathSubType (FilePath
) != HW_MEMMAP_DP
)) {
172 FvFileNode
= NextDevicePathNode (FilePath
);
175 // Firstly find the FV file in current FV
177 gBS
->HandleProtocol (
179 &gEfiLoadedImageProtocolGuid
,
180 (VOID
**) &LoadedImage
182 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
183 FullPath
= BmAdjustFvFilePath (NewDevicePath
);
184 FreePool (NewDevicePath
);
185 if (FullPath
!= NULL
) {
190 // Secondly find the FV file in all other FVs
192 gBS
->LocateHandleBuffer (
194 &gEfiFirmwareVolume2ProtocolGuid
,
199 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
200 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
202 // Skip current FV, it was handed in first step.
206 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
207 FullPath
= BmAdjustFvFilePath (NewDevicePath
);
208 FreePool (NewDevicePath
);
209 if (FullPath
!= NULL
) {
214 if (FvHandles
!= NULL
) {
215 FreePool (FvHandles
);
221 Check if it's a Device Path pointing to FV file.
223 The function doesn't garentee the device path points to existing FV file.
225 @param DevicePath Input device path.
227 @retval TRUE The device path is a FV File Device Path.
228 @retval FALSE The device path is NOT a FV File Device Path.
232 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
237 EFI_DEVICE_PATH_PROTOCOL
*Node
;
240 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &Handle
);
241 if (!EFI_ERROR (Status
)) {
245 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
246 DevicePath
= NextDevicePathNode (DevicePath
);
247 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == MEDIA_PIWG_FW_FILE_DP
)) {
248 return IsDevicePathEnd (NextDevicePathNode (DevicePath
));
255 Check whether a USB device match the specified USB Class device path. This
256 function follows "Load Option Processing" behavior in UEFI specification.
258 @param UsbIo USB I/O protocol associated with the USB device.
259 @param UsbClass The USB Class device path to match.
261 @retval TRUE The USB device match the USB Class device path.
262 @retval FALSE The USB device does not match the USB Class device path.
267 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
268 IN USB_CLASS_DEVICE_PATH
*UsbClass
272 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
273 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
275 UINT8 DeviceSubClass
;
276 UINT8 DeviceProtocol
;
278 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
279 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
284 // Check Vendor Id and Product Id.
286 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
287 if (EFI_ERROR (Status
)) {
291 if ((UsbClass
->VendorId
!= 0xffff) &&
292 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
296 if ((UsbClass
->ProductId
!= 0xffff) &&
297 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
301 DeviceClass
= DevDesc
.DeviceClass
;
302 DeviceSubClass
= DevDesc
.DeviceSubClass
;
303 DeviceProtocol
= DevDesc
.DeviceProtocol
;
304 if (DeviceClass
== 0) {
306 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
307 // Protocol in Interface Descriptor instead.
309 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
310 if (EFI_ERROR (Status
)) {
314 DeviceClass
= IfDesc
.InterfaceClass
;
315 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
316 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
320 // Check Class, SubClass and Protocol.
322 if ((UsbClass
->DeviceClass
!= 0xff) &&
323 (UsbClass
->DeviceClass
!= DeviceClass
)) {
327 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
328 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
332 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
333 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
341 Check whether a USB device match the specified USB WWID device path. This
342 function follows "Load Option Processing" behavior in UEFI specification.
344 @param UsbIo USB I/O protocol associated with the USB device.
345 @param UsbWwid The USB WWID device path to match.
347 @retval TRUE The USB device match the USB WWID device path.
348 @retval FALSE The USB device does not match the USB WWID device path.
353 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
354 IN USB_WWID_DEVICE_PATH
*UsbWwid
358 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
359 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
365 CHAR16
*SerialNumberStr
;
368 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
369 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
374 // Check Vendor Id and Product Id.
376 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
377 if (EFI_ERROR (Status
)) {
380 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
381 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
386 // Check Interface Number.
388 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
389 if (EFI_ERROR (Status
)) {
392 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
397 // Check Serial Number.
399 if (DevDesc
.StrSerialNumber
== 0) {
404 // Get all supported languages.
408 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
409 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
414 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
416 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
417 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
418 if (CompareStr
[CompareLen
- 1] == L
'\0') {
423 // Compare serial number in each supported language.
425 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
426 SerialNumberStr
= NULL
;
427 Status
= UsbIo
->UsbGetStringDescriptor (
430 DevDesc
.StrSerialNumber
,
433 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
437 Length
= StrLen (SerialNumberStr
);
438 if ((Length
>= CompareLen
) &&
439 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
440 FreePool (SerialNumberStr
);
444 FreePool (SerialNumberStr
);
451 Find a USB device which match the specified short-form device path start with
452 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
453 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
454 this function will only search in its child devices.
456 @param DevicePath The device path that contains USB Class or USB WWID device path.
457 @param ParentDevicePathSize The length of the device path before the USB Class or
458 USB WWID device path.
459 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
461 @retval NULL The matched USB IO handles cannot be found.
462 @retval other The matched USB IO handles.
467 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
468 IN UINTN ParentDevicePathSize
,
469 OUT UINTN
*UsbIoHandleCount
473 EFI_HANDLE
*UsbIoHandles
;
474 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
475 EFI_USB_IO_PROTOCOL
*UsbIo
;
479 ASSERT (UsbIoHandleCount
!= NULL
);
482 // Get all UsbIo Handles.
484 Status
= gBS
->LocateHandleBuffer (
486 &gEfiUsbIoProtocolGuid
,
491 if (EFI_ERROR (Status
)) {
492 *UsbIoHandleCount
= 0;
496 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
498 // Get the Usb IO interface.
500 Status
= gBS
->HandleProtocol(
502 &gEfiUsbIoProtocolGuid
,
505 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
507 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
510 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
512 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
513 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
514 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
521 (*UsbIoHandleCount
) --;
522 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
532 Expand USB Class or USB WWID device path node to be full device path of a USB
535 This function support following 4 cases:
536 1) Boot Option device path starts with a USB Class or USB WWID device path,
537 and there is no Media FilePath device path in the end.
538 In this case, it will follow Removable Media Boot Behavior.
539 2) Boot Option device path starts with a USB Class or USB WWID device path,
540 and ended with Media FilePath device path.
541 3) Boot Option device path starts with a full device path to a USB Host Controller,
542 contains a USB Class or USB WWID device path node, while not ended with Media
543 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
544 4) Boot Option device path starts with a full device path to a USB Host Controller,
545 contains a USB Class or USB WWID device path node, and ended with Media
546 FilePath device path.
548 @param FilePath The device path pointing to a load option.
549 It could be a short-form device path.
550 @param FullPath The full path returned by the routine in last call.
551 Set to NULL in first call.
552 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
554 @return The next possible full path pointing to the load option.
555 Caller is responsible to free the memory.
557 EFI_DEVICE_PATH_PROTOCOL
*
558 BmExpandUsbDevicePath (
559 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
560 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
,
561 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
564 UINTN ParentDevicePathSize
;
565 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
566 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
573 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
574 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
575 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
576 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
578 for (Index
= 0; Index
< HandleCount
; Index
++) {
579 FilePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
580 if (FilePath
== NULL
) {
586 NextFullPath
= BmGetNextLoadOptionDevicePath (FilePath
, NULL
);
588 if (NextFullPath
== NULL
) {
590 // No BlockIo or SimpleFileSystem under FilePath.
597 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
598 FreePool (NextFullPath
);
603 if (Handles
!= NULL
) {
611 Expand File-path device path node to be full device path in platform.
613 @param FilePath The device path pointing to a load option.
614 It could be a short-form device path.
615 @param FullPath The full path returned by the routine in last call.
616 Set to NULL in first call.
618 @return The next possible full path pointing to the load option.
619 Caller is responsible to free the memory.
621 EFI_DEVICE_PATH_PROTOCOL
*
622 BmExpandFileDevicePath (
623 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
624 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
631 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
633 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
636 EfiBootManagerConnectAll ();
637 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &Handles
);
638 if (EFI_ERROR (Status
)) {
643 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
646 // Enumerate all removable media devices followed by all fixed media devices,
647 // followed by media devices which don't layer on block io.
649 for (MediaType
= 0; MediaType
< 3; MediaType
++) {
650 for (Index
= 0; Index
< HandleCount
; Index
++) {
651 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiBlockIoProtocolGuid
, (VOID
*) &BlockIo
);
652 if (EFI_ERROR (Status
)) {
655 if ((MediaType
== 0 && BlockIo
!= NULL
&& BlockIo
->Media
->RemovableMedia
) ||
656 (MediaType
== 1 && BlockIo
!= NULL
&& !BlockIo
->Media
->RemovableMedia
) ||
657 (MediaType
== 2 && BlockIo
== NULL
)
659 NextFullPath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
);
663 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
664 FreePool (NextFullPath
);
669 if (NextFullPath
!= NULL
) {
674 if (Handles
!= NULL
) {
682 Expand URI device path node to be full device path in platform.
684 @param FilePath The device path pointing to a load option.
685 It could be a short-form device path.
686 @param FullPath The full path returned by the routine in last call.
687 Set to NULL in first call.
689 @return The next possible full path pointing to the load option.
690 Caller is responsible to free the memory.
692 EFI_DEVICE_PATH_PROTOCOL
*
693 BmExpandUriDevicePath (
694 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
695 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
702 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
703 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
706 EfiBootManagerConnectAll ();
707 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &HandleCount
, &Handles
);
708 if (EFI_ERROR (Status
)) {
714 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
715 for (Index
= 0; Index
< HandleCount
; Index
++) {
716 NextFullPath
= BmExpandLoadFile (Handles
[Index
], FilePath
);
718 if (NextFullPath
== NULL
) {
725 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
727 // Free the resource occupied by the RAM disk.
729 RamDiskDevicePath
= BmGetRamDiskDevicePath (NextFullPath
);
730 if (RamDiskDevicePath
!= NULL
) {
731 BmDestroyRamDisk (RamDiskDevicePath
);
732 FreePool (RamDiskDevicePath
);
734 FreePool (NextFullPath
);
739 if (Handles
!= NULL
) {
747 Save the partition DevicePath to the CachedDevicePath as the first instance.
749 @param CachedDevicePath The device path cache.
750 @param DevicePath The partition device path to be cached.
753 BmCachePartitionDevicePath (
754 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
755 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
758 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
761 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
762 TempDevicePath
= *CachedDevicePath
;
763 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
764 FreePool (TempDevicePath
);
767 if (*CachedDevicePath
== NULL
) {
768 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
772 TempDevicePath
= *CachedDevicePath
;
773 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
774 if (TempDevicePath
!= NULL
) {
775 FreePool (TempDevicePath
);
779 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
780 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
783 TempDevicePath
= *CachedDevicePath
;
784 while (!IsDevicePathEnd (TempDevicePath
)) {
785 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
787 // Parse one instance
789 while (!IsDevicePathEndType (TempDevicePath
)) {
790 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
794 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
797 SetDevicePathEndNode (TempDevicePath
);
804 Expand a device path that starts with a hard drive media device path node to be a
805 full device path that includes the full hardware path to the device. We need
806 to do this so it can be booted. As an optimization the front match (the part point
807 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
808 so a connect all is not required on every boot. All successful history device path
809 which point to partition node (the front part) will be saved.
811 @param FilePath The device path pointing to a load option.
812 It could be a short-form device path.
814 @return The full device path pointing to the load option.
816 EFI_DEVICE_PATH_PROTOCOL
*
817 BmExpandPartitionDevicePath (
818 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
822 UINTN BlockIoHandleCount
;
823 EFI_HANDLE
*BlockIoBuffer
;
824 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
826 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
827 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
828 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
829 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
830 UINTN CachedDevicePathSize
;
832 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
836 // Check if there is prestore 'HDDP' variable.
837 // If exist, search the front path which point to partition node in the variable instants.
838 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
840 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
843 // Delete the invalid 'HDDP' variable.
845 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
846 FreePool (CachedDevicePath
);
847 CachedDevicePath
= NULL
;
848 Status
= gRT
->SetVariable (
850 &mBmHardDriveBootVariableGuid
,
855 ASSERT_EFI_ERROR (Status
);
859 if (CachedDevicePath
!= NULL
) {
860 TempNewDevicePath
= CachedDevicePath
;
864 // Check every instance of the variable
865 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
866 // partial partition boot option. Second, check whether the instance could be connected.
868 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
869 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
871 // Connect the device path instance, the device path point to hard drive media device path node
872 // e.g. ACPI() /PCI()/ATA()/Partition()
874 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
875 if (!EFI_ERROR (Status
)) {
876 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
878 // TempDevicePath = ACPI()/PCI()/ATA()/Partition()
879 // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI
881 // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),
882 // it may expand to two potienal full paths (nested partition, rarely happen):
883 // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI
884 // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI
885 // For simplicity, only #1 is returned.
887 FullPath
= BmGetNextLoadOptionDevicePath (TempDevicePath
, NULL
);
888 FreePool (TempDevicePath
);
890 if (FullPath
!= NULL
) {
892 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
895 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
897 // Save the matching Device Path so we don't need to do a connect all next time
898 // Failing to save only impacts performance next time expanding the short-form device path
900 Status
= gRT
->SetVariable (
902 &mBmHardDriveBootVariableGuid
,
903 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
904 GetDevicePathSize (CachedDevicePath
),
910 FreePool (CachedDevicePath
);
916 // Come here means the first instance is not matched
920 } while (TempNewDevicePath
!= NULL
);
924 // If we get here we fail to find or 'HDDP' not exist, and now we need
925 // to search all devices in the system for a matched partition
927 EfiBootManagerConnectAll ();
928 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
929 if (EFI_ERROR (Status
)) {
930 BlockIoHandleCount
= 0;
931 BlockIoBuffer
= NULL
;
934 // Loop through all the device handles that support the BLOCK_IO Protocol
936 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
937 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
938 if (BlockIoDevicePath
== NULL
) {
942 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
944 // Find the matched partition device path
946 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
947 FullPath
= BmGetNextLoadOptionDevicePath (TempDevicePath
, NULL
);
948 FreePool (TempDevicePath
);
950 if (FullPath
!= NULL
) {
951 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
954 // Save the matching Device Path so we don't need to do a connect all next time
955 // Failing to save only impacts performance next time expanding the short-form device path
957 Status
= gRT
->SetVariable (
959 &mBmHardDriveBootVariableGuid
,
960 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
961 GetDevicePathSize (CachedDevicePath
),
970 if (CachedDevicePath
!= NULL
) {
971 FreePool (CachedDevicePath
);
973 if (BlockIoBuffer
!= NULL
) {
974 FreePool (BlockIoBuffer
);
980 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
981 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
983 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
984 @param FullPath The full path returned by the routine in last call.
985 Set to NULL in first call.
987 @return The next possible full path pointing to the load option.
988 Caller is responsible to free the memory.
990 EFI_DEVICE_PATH_PROTOCOL
*
991 BmExpandMediaDevicePath (
992 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
993 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
998 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1000 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1001 EFI_DEVICE_PATH_PROTOCOL
*NextFullPath
;
1004 EFI_HANDLE
*SimpleFileSystemHandles
;
1005 UINTN NumberSimpleFileSystemHandles
;
1009 GetNext
= (BOOLEAN
)(FullPath
== NULL
);
1011 // Check whether the device is connected
1013 TempDevicePath
= DevicePath
;
1014 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1015 if (!EFI_ERROR (Status
)) {
1016 ASSERT (IsDevicePathEnd (TempDevicePath
));
1018 NextFullPath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1020 // For device path pointing to simple file system, it only expands to one full path.
1023 return NextFullPath
;
1025 FreePool (NextFullPath
);
1030 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1031 ASSERT_EFI_ERROR (Status
);
1034 // For device boot option only pointing to the removable device handle,
1035 // should make sure all its children handles (its child partion or media handles)
1036 // are created and connected.
1038 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1041 // Issue a dummy read to the device to check for media change.
1042 // When the removable media is changed, any Block IO read/write will
1043 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1044 // returned. After the Block IO protocol is reinstalled, subsequent
1045 // Block IO read/write will success.
1047 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1048 ASSERT_EFI_ERROR (Status
);
1049 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1050 if (Buffer
!= NULL
) {
1051 BlockIo
->ReadBlocks (
1053 BlockIo
->Media
->MediaId
,
1055 BlockIo
->Media
->BlockSize
,
1062 // Detect the the default boot file from removable Media
1064 NextFullPath
= NULL
;
1065 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1066 gBS
->LocateHandleBuffer (
1068 &gEfiSimpleFileSystemProtocolGuid
,
1070 &NumberSimpleFileSystemHandles
,
1071 &SimpleFileSystemHandles
1073 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1075 // Get the device path size of SimpleFileSystem handle
1077 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1078 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1080 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1082 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1083 NextFullPath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1087 GetNext
= (BOOLEAN
)(CompareMem (NextFullPath
, FullPath
, GetDevicePathSize (NextFullPath
)) == 0);
1088 FreePool (NextFullPath
);
1089 NextFullPath
= NULL
;
1094 if (SimpleFileSystemHandles
!= NULL
) {
1095 FreePool (SimpleFileSystemHandles
);
1098 return NextFullPath
;
1102 Check whether Left and Right are the same without matching the specific
1103 device path data in IP device path and URI device path node.
1105 @retval TRUE Left and Right are the same.
1106 @retval FALSE Left and Right are the different.
1109 BmMatchHttpBootDevicePath (
1110 IN EFI_DEVICE_PATH_PROTOCOL
*Left
,
1111 IN EFI_DEVICE_PATH_PROTOCOL
*Right
1114 for (; !IsDevicePathEnd (Left
) && !IsDevicePathEnd (Right
)
1115 ; Left
= NextDevicePathNode (Left
), Right
= NextDevicePathNode (Right
)
1117 if (CompareMem (Left
, Right
, DevicePathNodeLength (Left
)) != 0) {
1118 if ((DevicePathType (Left
) != MESSAGING_DEVICE_PATH
) || (DevicePathType (Right
) != MESSAGING_DEVICE_PATH
)) {
1122 if (((DevicePathSubType (Left
) != MSG_IPv4_DP
) || (DevicePathSubType (Right
) != MSG_IPv4_DP
)) &&
1123 ((DevicePathSubType (Left
) != MSG_IPv6_DP
) || (DevicePathSubType (Right
) != MSG_IPv6_DP
)) &&
1124 ((DevicePathSubType (Left
) != MSG_URI_DP
) || (DevicePathSubType (Right
) != MSG_URI_DP
))
1130 return (BOOLEAN
) (IsDevicePathEnd (Left
) && IsDevicePathEnd (Right
));
1134 Get the file buffer from the file system produced by Load File instance.
1136 @param LoadFileHandle The handle of LoadFile instance.
1137 @param RamDiskHandle Return the RAM Disk handle.
1139 @return The next possible full path pointing to the load option.
1140 Caller is responsible to free the memory.
1142 EFI_DEVICE_PATH_PROTOCOL
*
1143 BmExpandNetworkFileSystem (
1144 IN EFI_HANDLE LoadFileHandle
,
1145 OUT EFI_HANDLE
*RamDiskHandle
1150 EFI_HANDLE
*Handles
;
1153 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1155 Status
= gBS
->LocateHandleBuffer (
1157 &gEfiBlockIoProtocolGuid
,
1162 if (EFI_ERROR (Status
)) {
1168 for (Index
= 0; Index
< HandleCount
; Index
++) {
1169 Node
= DevicePathFromHandle (Handles
[Index
]);
1170 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1171 if (!EFI_ERROR (Status
) &&
1172 (Handle
== LoadFileHandle
) &&
1173 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)) {
1175 // Find the BlockIo instance populated from the LoadFile.
1177 Handle
= Handles
[Index
];
1182 if (Handles
!= NULL
) {
1186 if (Index
== HandleCount
) {
1190 *RamDiskHandle
= Handle
;
1192 if (Handle
!= NULL
) {
1194 // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
1195 // But assume only one SimpleFileSystem can be found under the BlockIo.
1197 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle
), NULL
);
1204 Return the RAM Disk device path created by LoadFile.
1206 @param FilePath The source file path.
1208 @return Callee-to-free RAM Disk device path
1210 EFI_DEVICE_PATH_PROTOCOL
*
1211 BmGetRamDiskDevicePath (
1212 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1216 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1217 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1221 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1222 if (!EFI_ERROR (Status
) &&
1223 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) &&
1224 (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)
1228 // Construct the device path pointing to RAM Disk
1230 Node
= NextDevicePathNode (Node
);
1231 RamDiskDevicePath
= DuplicateDevicePath (FilePath
);
1232 ASSERT (RamDiskDevicePath
!= NULL
);
1233 SetDevicePathEndNode ((VOID
*) ((UINTN
) RamDiskDevicePath
+ ((UINTN
) Node
- (UINTN
) FilePath
)));
1234 return RamDiskDevicePath
;
1241 Return the buffer and buffer size occupied by the RAM Disk.
1243 @param RamDiskDevicePath RAM Disk device path.
1244 @param RamDiskSizeInPages Return RAM Disk size in pages.
1246 @retval RAM Disk buffer.
1249 BmGetRamDiskMemoryInfo (
1250 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
,
1251 OUT UINTN
*RamDiskSizeInPages
1257 UINT64 StartingAddr
;
1260 ASSERT (RamDiskDevicePath
!= NULL
);
1262 *RamDiskSizeInPages
= 0;
1265 // Get the buffer occupied by RAM Disk.
1267 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &RamDiskDevicePath
, &Handle
);
1268 ASSERT_EFI_ERROR (Status
);
1269 ASSERT ((DevicePathType (RamDiskDevicePath
) == MEDIA_DEVICE_PATH
) &&
1270 (DevicePathSubType (RamDiskDevicePath
) == MEDIA_RAM_DISK_DP
));
1271 StartingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->StartingAddr
);
1272 EndingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->EndingAddr
);
1273 *RamDiskSizeInPages
= EFI_SIZE_TO_PAGES ((UINTN
) (EndingAddr
- StartingAddr
+ 1));
1274 return (VOID
*) (UINTN
) StartingAddr
;
1278 Destroy the RAM Disk.
1280 The destroy operation includes to call RamDisk.Unregister to
1281 unregister the RAM DISK from RAM DISK driver, free the memory
1282 allocated for the RAM Disk.
1284 @param RamDiskDevicePath RAM Disk device path.
1288 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
1292 VOID
*RamDiskBuffer
;
1293 UINTN RamDiskSizeInPages
;
1295 ASSERT (RamDiskDevicePath
!= NULL
);
1297 RamDiskBuffer
= BmGetRamDiskMemoryInfo (RamDiskDevicePath
, &RamDiskSizeInPages
);
1300 // Destroy RAM Disk.
1302 if (mRamDisk
== NULL
) {
1303 Status
= gBS
->LocateProtocol (&gEfiRamDiskProtocolGuid
, NULL
, (VOID
*) &mRamDisk
);
1304 ASSERT_EFI_ERROR (Status
);
1306 Status
= mRamDisk
->Unregister (RamDiskDevicePath
);
1307 ASSERT_EFI_ERROR (Status
);
1308 FreePages (RamDiskBuffer
, RamDiskSizeInPages
);
1312 Get the file buffer from the specified Load File instance.
1314 @param LoadFileHandle The specified Load File instance.
1315 @param FilePath The file path which will pass to LoadFile().
1317 @return The full device path pointing to the load option buffer.
1319 EFI_DEVICE_PATH_PROTOCOL
*
1321 IN EFI_HANDLE LoadFileHandle
,
1322 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1326 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1328 EFI_HANDLE RamDiskHandle
;
1330 EFI_DEVICE_PATH_PROTOCOL
*FullPath
;
1332 Status
= gBS
->OpenProtocol (
1334 &gEfiLoadFileProtocolGuid
,
1335 (VOID
**) &LoadFile
,
1338 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1340 ASSERT_EFI_ERROR (Status
);
1344 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1345 if ((Status
!= EFI_WARN_FILE_SYSTEM
) && (Status
!= EFI_BUFFER_TOO_SMALL
)) {
1349 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1351 // The load option buffer is directly returned by LoadFile.
1353 return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle
));
1357 // The load option resides in a RAM disk.
1359 FileBuffer
= AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize
));
1360 if (FileBuffer
== NULL
) {
1364 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1365 if (EFI_ERROR (Status
)) {
1366 FreePages (FileBuffer
, EFI_SIZE_TO_PAGES (BufferSize
));
1370 FullPath
= BmExpandNetworkFileSystem (LoadFileHandle
, &RamDiskHandle
);
1371 if (FullPath
== NULL
) {
1373 // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
1375 BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle
));
1382 Return the full device path pointing to the load option.
1385 1. Exactly matches to a LoadFile instance.
1386 2. Cannot match to any LoadFile instance. Wide match is required.
1387 In either case, the routine may return:
1388 1. A copy of FilePath when FilePath matches to a LoadFile instance and
1389 the LoadFile returns a load option buffer.
1390 2. A new device path with IP and URI information updated when wide match
1392 3. A new device path pointing to a load option in RAM disk.
1393 In either case, only one full device path is returned for a specified
1396 @param FilePath The media device path pointing to a LoadFile instance.
1398 @return The load option buffer.
1400 EFI_DEVICE_PATH_PROTOCOL
*
1402 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1407 EFI_HANDLE
*Handles
;
1410 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1413 // Get file buffer from load file instance.
1416 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1417 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1419 // When wide match happens, pass full device path to LoadFile (),
1420 // otherwise, pass remaining device path to LoadFile ().
1426 // Use wide match algorithm to find one when
1427 // cannot find a LoadFile instance to exactly match the FilePath
1429 Status
= gBS
->LocateHandleBuffer (
1431 &gEfiLoadFileProtocolGuid
,
1436 if (EFI_ERROR (Status
)) {
1440 for (Index
= 0; Index
< HandleCount
; Index
++) {
1441 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
)) {
1442 Handle
= Handles
[Index
];
1446 if (Handles
!= NULL
) {
1451 if (Handle
== NULL
) {
1455 return BmExpandLoadFile (Handle
, FilePath
);
1459 Get the load option by its device path.
1461 @param FilePath The device path pointing to a load option.
1462 It could be a short-form device path.
1463 @param FullPath Return the full device path of the load option after
1464 short-form device path expanding.
1465 Caller is responsible to free it.
1466 @param FileSize Return the load option size.
1468 @return The load option buffer. Caller is responsible to free the memory.
1472 EfiBootManagerGetLoadOptionBuffer (
1473 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1474 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1480 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1481 return BmGetNextLoadOptionBuffer (LoadOptionTypeMax
, FilePath
, FullPath
, FileSize
);
1485 Get the next possible full path pointing to the load option.
1486 The routine doesn't guarantee the returned full path points to an existing
1487 file, and it also doesn't guarantee the existing file is a valid load option.
1488 BmGetNextLoadOptionBuffer() guarantees.
1490 @param FilePath The device path pointing to a load option.
1491 It could be a short-form device path.
1492 @param FullPath The full path returned by the routine in last call.
1493 Set to NULL in first call.
1495 @return The next possible full path pointing to the load option.
1496 Caller is responsible to free the memory.
1498 EFI_DEVICE_PATH_PROTOCOL
*
1499 BmGetNextLoadOptionDevicePath (
1500 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1501 IN EFI_DEVICE_PATH_PROTOCOL
*FullPath
1505 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1508 ASSERT (FilePath
!= NULL
);
1511 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1514 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1515 if (EFI_ERROR (Status
)) {
1516 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1519 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1520 return BmExpandMediaDevicePath (FilePath
, FullPath
);
1524 // Expand the short-form device path to full device path
1526 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1527 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1529 // Expand the Harddrive device path
1531 if (FullPath
== NULL
) {
1532 return BmExpandPartitionDevicePath (FilePath
);
1536 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1537 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
)) {
1539 // Expand the File-path device path
1541 return BmExpandFileDevicePath (FilePath
, FullPath
);
1542 } else if ((DevicePathType (FilePath
) == MESSAGING_DEVICE_PATH
) &&
1543 (DevicePathSubType (FilePath
) == MSG_URI_DP
)) {
1545 // Expand the URI device path
1547 return BmExpandUriDevicePath (FilePath
, FullPath
);
1549 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1550 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1551 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1557 // Expand the USB WWID/Class device path
1559 if (!IsDevicePathEnd (Node
)) {
1560 if (FilePath
== Node
) {
1562 // Boot Option device path starts with USB Class or USB WWID device path.
1563 // For Boot Option device path which doesn't begin with the USB Class or
1564 // USB WWID device path, it's not needed to connect again here.
1566 BmConnectUsbShortFormDevicePath (FilePath
);
1568 return BmExpandUsbDevicePath (FilePath
, FullPath
, Node
);
1573 // For the below cases, FilePath only expands to one Full path.
1574 // So just handle the case when FullPath == NULL.
1576 if (FullPath
!= NULL
) {
1581 // Load option resides in FV.
1583 if (BmIsFvFilePath (FilePath
)) {
1584 return BmAdjustFvFilePath (FilePath
);
1588 // Load option resides in Simple File System.
1591 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1592 if (!EFI_ERROR (Status
)) {
1593 return DuplicateDevicePath (FilePath
);
1597 // Last chance to try: Load option may be loaded through LoadFile.
1599 return BmExpandLoadFiles (FilePath
);
1603 Check if it's a Device Path pointing to BootManagerMenu.
1605 @param DevicePath Input device path.
1607 @retval TRUE The device path is BootManagerMenu File Device Path.
1608 @retval FALSE The device path is NOT BootManagerMenu File Device Path.
1611 BmIsBootManagerMenuFilePath (
1612 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1615 EFI_HANDLE FvHandle
;
1619 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &DevicePath
, &FvHandle
);
1620 if (!EFI_ERROR (Status
)) {
1621 NameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) DevicePath
);
1622 if (NameGuid
!= NULL
) {
1623 return CompareGuid (NameGuid
, PcdGetPtr (PcdBootManagerMenuFile
));
1631 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1632 also signals the EFI ready to boot event. If the device path for the option
1633 starts with a BBS device path a legacy boot is attempted via the registered
1634 gLegacyBoot function. Short form device paths are also supported via this
1635 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1636 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1637 If the BootOption Device Path fails the removable media boot algorithm
1638 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1639 is tried per processor type)
1641 @param BootOption Boot Option to try and boot.
1642 On return, BootOption->Status contains the boot status.
1643 EFI_SUCCESS BootOption was booted
1644 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1645 registered via EfiBootManagerInitialize().
1646 EFI_NOT_FOUND The BootOption was not found on the system
1647 !EFI_SUCCESS BootOption failed with this error status
1652 EfiBootManagerBoot (
1653 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1657 EFI_HANDLE ImageHandle
;
1658 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1661 UINTN OriginalOptionNumber
;
1662 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1663 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1666 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1667 EFI_EVENT LegacyBootEvent
;
1669 if (BootOption
== NULL
) {
1673 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1674 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1679 // 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")
1681 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1682 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1683 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1684 if (!EFI_ERROR (Status
)) {
1686 // Save the BootOption->OptionNumber to restore later
1688 OptionNumber
= Uint16
;
1689 OriginalOptionNumber
= BootOption
->OptionNumber
;
1690 BootOption
->OptionNumber
= OptionNumber
;
1691 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1692 BootOption
->OptionNumber
= OriginalOptionNumber
;
1695 if (EFI_ERROR (Status
)) {
1696 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1697 BootOption
->Status
= Status
;
1703 // 2. Set BootCurrent
1705 Uint16
= (UINT16
) OptionNumber
;
1706 BmSetVariableAndReportStatusCodeOnError (
1708 &gEfiGlobalVariableGuid
,
1709 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1715 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1718 if (BmIsBootManagerMenuFilePath (BootOption
->FilePath
)) {
1719 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1720 BmStopHotkeyService (NULL
, NULL
);
1722 EfiSignalEventReadyToBoot();
1724 // Report Status Code to indicate ReadyToBoot was signalled
1726 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1728 // 4. Repair system through DriverHealth protocol
1730 BmRepairAllControllers ();
1733 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1736 // 5. Adjust the different type memory page number just before booting
1737 // and save the updated info into the variable for next boot to use
1739 BmSetMemoryTypeInformationVariable (
1740 (BOOLEAN
) ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1744 // 6. Load EFI boot option to ImageHandle
1746 DEBUG_CODE_BEGIN ();
1747 if (BootOption
->Description
== NULL
) {
1748 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1750 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1755 RamDiskDevicePath
= NULL
;
1756 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1757 Status
= EFI_NOT_FOUND
;
1759 EfiBootManagerConnectDevicePath (BootOption
->FilePath
, NULL
);
1760 FileBuffer
= BmGetNextLoadOptionBuffer (LoadOptionTypeBoot
, BootOption
->FilePath
, &FilePath
, &FileSize
);
1761 if (FileBuffer
!= NULL
) {
1762 RamDiskDevicePath
= BmGetRamDiskDevicePath (FilePath
);
1764 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1765 Status
= gBS
->LoadImage (
1774 if (FileBuffer
!= NULL
) {
1775 FreePool (FileBuffer
);
1777 if (FilePath
!= NULL
) {
1778 FreePool (FilePath
);
1781 if (EFI_ERROR (Status
)) {
1783 // Report Status Code to indicate that the failure to load boot option
1785 REPORT_STATUS_CODE (
1786 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1787 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1789 BootOption
->Status
= Status
;
1791 // Destroy the RAM disk
1793 if (RamDiskDevicePath
!= NULL
) {
1794 BmDestroyRamDisk (RamDiskDevicePath
);
1795 FreePool (RamDiskDevicePath
);
1802 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1803 // Write boot to OS performance data for Legacy boot
1805 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1806 if (mBmLegacyBoot
!= NULL
) {
1808 // Write boot to OS performance data for legacy boot.
1812 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1814 Status
= EfiCreateEventLegacyBootEx(
1816 BmWriteBootToOsPerformanceData
,
1820 ASSERT_EFI_ERROR (Status
);
1823 mBmLegacyBoot (BootOption
);
1825 BootOption
->Status
= EFI_UNSUPPORTED
;
1828 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1833 // Provide the image with its load options
1835 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1836 ASSERT_EFI_ERROR (Status
);
1838 if (!BmIsAutoCreateBootOption (BootOption
)) {
1839 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1840 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1844 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1846 ImageInfo
->ParentHandle
= NULL
;
1849 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1851 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1854 // Write boot to OS performance data for UEFI boot
1857 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1860 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1862 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1863 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1864 BootOption
->Status
= Status
;
1865 if (EFI_ERROR (Status
)) {
1867 // Report Status Code to indicate that boot failure
1869 REPORT_STATUS_CODE (
1870 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1871 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1874 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1877 // Destroy the RAM disk
1879 if (RamDiskDevicePath
!= NULL
) {
1880 BmDestroyRamDisk (RamDiskDevicePath
);
1881 FreePool (RamDiskDevicePath
);
1885 // Clear the Watchdog Timer after the image returns
1887 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1890 // Set Logo status invalid after trying one boot option
1893 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1894 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1895 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1896 ASSERT_EFI_ERROR (Status
);
1900 // Clear Boot Current
1902 Status
= gRT
->SetVariable (
1904 &gEfiGlobalVariableGuid
,
1910 // Deleting variable with current variable implementation shouldn't fail.
1911 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1912 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1914 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1918 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1919 instances, has the same partition node with HardDriveDevicePath device path
1921 @param BlockIoDevicePath Multi device path instances which need to check
1922 @param HardDriveDevicePath A device path which starts with a hard drive media
1925 @retval TRUE There is a matched device path instance.
1926 @retval FALSE There is no matched device path instance.
1930 BmMatchPartitionDevicePathNode (
1931 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1932 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1935 HARDDRIVE_DEVICE_PATH
*Node
;
1937 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1942 // find the partition device path node
1944 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1945 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1946 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1951 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1954 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1959 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1961 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1964 // Match Signature and PartitionNumber.
1965 // Unused bytes in Signature are initiaized with zeros.
1968 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1969 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1970 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1971 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1976 Emuerate all possible bootable medias in the following order:
1977 1. Removable BlockIo - The boot option only points to the removable media
1978 device, like USB key, DVD, Floppy etc.
1979 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1981 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1982 SimpleFileSystem Protocol, but not supporting BlockIo
1984 4. LoadFile - The boot option points to the media supporting
1986 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1988 @param BootOptionCount Return the boot option count which has been found.
1990 @retval Pointer to the boot option array.
1992 EFI_BOOT_MANAGER_LOAD_OPTION
*
1993 BmEnumerateBootOptions (
1994 UINTN
*BootOptionCount
1998 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2000 EFI_HANDLE
*Handles
;
2001 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
2004 CHAR16
*Description
;
2006 ASSERT (BootOptionCount
!= NULL
);
2008 *BootOptionCount
= 0;
2012 // Parse removable block io followed by fixed block io
2014 gBS
->LocateHandleBuffer (
2016 &gEfiBlockIoProtocolGuid
,
2022 for (Removable
= 0; Removable
< 2; Removable
++) {
2023 for (Index
= 0; Index
< HandleCount
; Index
++) {
2024 Status
= gBS
->HandleProtocol (
2026 &gEfiBlockIoProtocolGuid
,
2029 if (EFI_ERROR (Status
)) {
2034 // Skip the logical partitions
2036 if (BlkIo
->Media
->LogicalPartition
) {
2041 // Skip the fixed block io then the removable block io
2043 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
2047 Description
= BmGetBootDescription (Handles
[Index
]);
2048 BootOptions
= ReallocatePool (
2049 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2050 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2053 ASSERT (BootOptions
!= NULL
);
2055 Status
= EfiBootManagerInitializeLoadOption (
2056 &BootOptions
[(*BootOptionCount
)++],
2057 LoadOptionNumberUnassigned
,
2061 DevicePathFromHandle (Handles
[Index
]),
2065 ASSERT_EFI_ERROR (Status
);
2067 FreePool (Description
);
2071 if (HandleCount
!= 0) {
2076 // Parse simple file system not based on block io
2078 gBS
->LocateHandleBuffer (
2080 &gEfiSimpleFileSystemProtocolGuid
,
2085 for (Index
= 0; Index
< HandleCount
; Index
++) {
2086 Status
= gBS
->HandleProtocol (
2088 &gEfiBlockIoProtocolGuid
,
2091 if (!EFI_ERROR (Status
)) {
2093 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2097 Description
= BmGetBootDescription (Handles
[Index
]);
2098 BootOptions
= ReallocatePool (
2099 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2100 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2103 ASSERT (BootOptions
!= NULL
);
2105 Status
= EfiBootManagerInitializeLoadOption (
2106 &BootOptions
[(*BootOptionCount
)++],
2107 LoadOptionNumberUnassigned
,
2111 DevicePathFromHandle (Handles
[Index
]),
2115 ASSERT_EFI_ERROR (Status
);
2116 FreePool (Description
);
2119 if (HandleCount
!= 0) {
2124 // Parse load file protocol
2126 gBS
->LocateHandleBuffer (
2128 &gEfiLoadFileProtocolGuid
,
2133 for (Index
= 0; Index
< HandleCount
; Index
++) {
2135 // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().
2137 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2141 Description
= BmGetBootDescription (Handles
[Index
]);
2142 BootOptions
= ReallocatePool (
2143 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2144 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2147 ASSERT (BootOptions
!= NULL
);
2149 Status
= EfiBootManagerInitializeLoadOption (
2150 &BootOptions
[(*BootOptionCount
)++],
2151 LoadOptionNumberUnassigned
,
2155 DevicePathFromHandle (Handles
[Index
]),
2159 ASSERT_EFI_ERROR (Status
);
2160 FreePool (Description
);
2163 if (HandleCount
!= 0) {
2167 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
2172 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2176 EfiBootManagerRefreshAllBootOption (
2181 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2182 UINTN NvBootOptionCount
;
2183 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2184 UINTN BootOptionCount
;
2188 // Optionally refresh the legacy boot option
2190 if (mBmRefreshLegacyBootOption
!= NULL
) {
2191 mBmRefreshLegacyBootOption ();
2194 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2195 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2198 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2200 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2201 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2202 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2206 // Remove invalid EFI boot options from NV
2208 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2209 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2210 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2211 ) && BmIsAutoCreateBootOption (&NvBootOptions
[Index
])
2214 // Only check those added by BDS
2215 // so that the boot options added by end-user or OS installer won't be deleted
2217 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == -1) {
2218 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2220 // Deleting variable with current variable implementation shouldn't fail.
2222 ASSERT_EFI_ERROR (Status
);
2228 // Add new EFI boot options to NV
2230 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2231 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == -1) {
2232 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2234 // Try best to add the boot options so continue upon failure.
2239 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2240 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2244 This function is called to get or create the boot option for the Boot Manager Menu.
2246 The Boot Manager Menu is shown after successfully booting a boot option.
2247 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2249 @param BootOption Return the boot option of the Boot Manager Menu
2251 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2252 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2253 @retval others Return status of gRT->SetVariable (). BootOption still points
2254 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2258 BmRegisterBootManagerMenu (
2259 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2263 CHAR16
*Description
;
2264 UINTN DescriptionLength
;
2265 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2266 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2267 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2269 EFI_HANDLE
*Handles
;
2277 // Try to find BootManagerMenu from LoadFile protocol
2279 gBS
->LocateHandleBuffer (
2281 &gEfiLoadFileProtocolGuid
,
2286 for (Index
= 0; Index
< HandleCount
; Index
++) {
2287 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2288 DevicePath
= DuplicateDevicePath (DevicePathFromHandle (Handles
[Index
]));
2289 Description
= BmGetBootDescription (Handles
[Index
]);
2293 if (HandleCount
!= 0) {
2297 if (DevicePath
== NULL
) {
2299 Status
= GetSectionFromFv (
2300 PcdGetPtr (PcdBootManagerMenuFile
),
2309 if (EFI_ERROR (Status
)) {
2310 DEBUG ((EFI_D_WARN
, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
2311 return EFI_NOT_FOUND
;
2315 // Get BootManagerMenu application's description from EFI User Interface Section.
2317 Status
= GetSectionFromFv (
2318 PcdGetPtr (PcdBootManagerMenuFile
),
2319 EFI_SECTION_USER_INTERFACE
,
2321 (VOID
**) &Description
,
2324 if (EFI_ERROR (Status
)) {
2328 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2329 Status
= gBS
->HandleProtocol (
2331 &gEfiLoadedImageProtocolGuid
,
2332 (VOID
**) &LoadedImage
2334 ASSERT_EFI_ERROR (Status
);
2335 DevicePath
= AppendDevicePathNode (
2336 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2337 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2339 ASSERT (DevicePath
!= NULL
);
2342 Status
= EfiBootManagerInitializeLoadOption (
2344 LoadOptionNumberUnassigned
,
2346 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2347 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2352 ASSERT_EFI_ERROR (Status
);
2353 FreePool (DevicePath
);
2354 if (Description
!= NULL
) {
2355 FreePool (Description
);
2359 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2360 UINTN BootOptionCount
;
2362 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2363 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2364 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2367 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2371 Return the boot option corresponding to the Boot Manager Menu.
2372 It may automatically create one if the boot option hasn't been created yet.
2374 @param BootOption Return the Boot Manager Menu.
2376 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2377 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2378 @retval others Return status of gRT->SetVariable (). BootOption still points
2379 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2384 EfiBootManagerGetBootManagerMenu (
2385 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2389 UINTN BootOptionCount
;
2390 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2393 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2395 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2396 if (BmIsBootManagerMenuFilePath (BootOptions
[Index
].FilePath
)) {
2397 Status
= EfiBootManagerInitializeLoadOption (
2399 BootOptions
[Index
].OptionNumber
,
2400 BootOptions
[Index
].OptionType
,
2401 BootOptions
[Index
].Attributes
,
2402 BootOptions
[Index
].Description
,
2403 BootOptions
[Index
].FilePath
,
2404 BootOptions
[Index
].OptionalData
,
2405 BootOptions
[Index
].OptionalDataSize
2407 ASSERT_EFI_ERROR (Status
);
2412 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2415 // Automatically create the Boot#### for Boot Manager Menu when not found.
2417 if (Index
== BootOptionCount
) {
2418 return BmRegisterBootManagerMenu (BootOption
);