2 Library functions which relates with booting.
4 Copyright (c) 2011 - 2016, 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 Get the file buffer using a Memory Mapped Device Path.
136 FV address may change across reboot. This routine promises the FV file device path is right.
138 @param FilePath The Memory Mapped Device Path to get the file buffer.
139 @param FullPath Receive the updated FV Device Path pointint to the file.
140 @param FileSize Receive the file buffer size.
142 @return The file buffer.
145 BmGetFileBufferByFvFilePath (
146 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
147 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
153 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
155 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
156 UINT32 AuthenticationStatus
;
158 EFI_HANDLE
*FvHandles
;
159 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
163 // Get the file buffer by using the exactly FilePath.
165 FvFileNode
= FilePath
;
166 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
167 if (!EFI_ERROR (Status
)) {
168 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
169 if (FileBuffer
!= NULL
) {
170 *FullPath
= DuplicateDevicePath (FilePath
);
176 // Only wide match other FVs if it's a memory mapped FV file path.
178 if ((DevicePathType (FilePath
) != HARDWARE_DEVICE_PATH
) || (DevicePathSubType (FilePath
) != HW_MEMMAP_DP
)) {
182 FvFileNode
= NextDevicePathNode (FilePath
);
185 // Firstly find the FV file in current FV
187 gBS
->HandleProtocol (
189 &gEfiLoadedImageProtocolGuid
,
190 (VOID
**) &LoadedImage
192 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
193 FileBuffer
= BmGetFileBufferByFvFilePath (NewDevicePath
, FullPath
, FileSize
);
194 FreePool (NewDevicePath
);
196 if (FileBuffer
!= NULL
) {
201 // Secondly find the FV file in all other FVs
203 gBS
->LocateHandleBuffer (
205 &gEfiFirmwareVolume2ProtocolGuid
,
210 for (Index
= 0; (Index
< FvHandleCount
) && (FileBuffer
== NULL
); Index
++) {
211 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
217 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
218 FileBuffer
= BmGetFileBufferByFvFilePath (NewDevicePath
, FullPath
, FileSize
);
219 FreePool (NewDevicePath
);
222 if (FvHandles
!= NULL
) {
223 FreePool (FvHandles
);
229 Check if it's a Device Path pointing to FV file.
231 The function doesn't garentee the device path points to existing FV file.
233 @param DevicePath Input device path.
235 @retval TRUE The device path is a FV File Device Path.
236 @retval FALSE The device path is NOT a FV File Device Path.
240 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
245 EFI_DEVICE_PATH_PROTOCOL
*Node
;
248 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &Handle
);
249 if (!EFI_ERROR (Status
)) {
253 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
254 DevicePath
= NextDevicePathNode (DevicePath
);
255 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == MEDIA_PIWG_FW_FILE_DP
)) {
256 return IsDevicePathEnd (NextDevicePathNode (DevicePath
));
263 Check whether a USB device match the specified USB Class device path. This
264 function follows "Load Option Processing" behavior in UEFI specification.
266 @param UsbIo USB I/O protocol associated with the USB device.
267 @param UsbClass The USB Class device path to match.
269 @retval TRUE The USB device match the USB Class device path.
270 @retval FALSE The USB device does not match the USB Class device path.
275 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
276 IN USB_CLASS_DEVICE_PATH
*UsbClass
280 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
281 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
283 UINT8 DeviceSubClass
;
284 UINT8 DeviceProtocol
;
286 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
287 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
292 // Check Vendor Id and Product Id.
294 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
295 if (EFI_ERROR (Status
)) {
299 if ((UsbClass
->VendorId
!= 0xffff) &&
300 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
304 if ((UsbClass
->ProductId
!= 0xffff) &&
305 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
309 DeviceClass
= DevDesc
.DeviceClass
;
310 DeviceSubClass
= DevDesc
.DeviceSubClass
;
311 DeviceProtocol
= DevDesc
.DeviceProtocol
;
312 if (DeviceClass
== 0) {
314 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
315 // Protocol in Interface Descriptor instead.
317 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
318 if (EFI_ERROR (Status
)) {
322 DeviceClass
= IfDesc
.InterfaceClass
;
323 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
324 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
328 // Check Class, SubClass and Protocol.
330 if ((UsbClass
->DeviceClass
!= 0xff) &&
331 (UsbClass
->DeviceClass
!= DeviceClass
)) {
335 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
336 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
340 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
341 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
349 Check whether a USB device match the specified USB WWID device path. This
350 function follows "Load Option Processing" behavior in UEFI specification.
352 @param UsbIo USB I/O protocol associated with the USB device.
353 @param UsbWwid The USB WWID device path to match.
355 @retval TRUE The USB device match the USB WWID device path.
356 @retval FALSE The USB device does not match the USB WWID device path.
361 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
362 IN USB_WWID_DEVICE_PATH
*UsbWwid
366 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
367 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
373 CHAR16
*SerialNumberStr
;
376 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
377 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
382 // Check Vendor Id and Product Id.
384 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
385 if (EFI_ERROR (Status
)) {
388 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
389 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
394 // Check Interface Number.
396 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
397 if (EFI_ERROR (Status
)) {
400 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
405 // Check Serial Number.
407 if (DevDesc
.StrSerialNumber
== 0) {
412 // Get all supported languages.
416 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
417 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
422 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
424 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
425 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
426 if (CompareStr
[CompareLen
- 1] == L
'\0') {
431 // Compare serial number in each supported language.
433 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
434 SerialNumberStr
= NULL
;
435 Status
= UsbIo
->UsbGetStringDescriptor (
438 DevDesc
.StrSerialNumber
,
441 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
445 Length
= StrLen (SerialNumberStr
);
446 if ((Length
>= CompareLen
) &&
447 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
448 FreePool (SerialNumberStr
);
452 FreePool (SerialNumberStr
);
459 Find a USB device which match the specified short-form device path start with
460 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
461 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
462 this function will only search in its child devices.
464 @param DevicePath The device path that contains USB Class or USB WWID device path.
465 @param ParentDevicePathSize The length of the device path before the USB Class or
466 USB WWID device path.
467 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
469 @retval NULL The matched USB IO handles cannot be found.
470 @retval other The matched USB IO handles.
475 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
476 IN UINTN ParentDevicePathSize
,
477 OUT UINTN
*UsbIoHandleCount
481 EFI_HANDLE
*UsbIoHandles
;
482 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
483 EFI_USB_IO_PROTOCOL
*UsbIo
;
487 ASSERT (UsbIoHandleCount
!= NULL
);
490 // Get all UsbIo Handles.
492 Status
= gBS
->LocateHandleBuffer (
494 &gEfiUsbIoProtocolGuid
,
499 if (EFI_ERROR (Status
)) {
500 *UsbIoHandleCount
= 0;
504 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
506 // Get the Usb IO interface.
508 Status
= gBS
->HandleProtocol(
510 &gEfiUsbIoProtocolGuid
,
513 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
515 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
518 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
520 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
521 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
522 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
529 (*UsbIoHandleCount
) --;
530 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
540 Expand USB Class or USB WWID device path node to be full device path of a USB
543 This function support following 4 cases:
544 1) Boot Option device path starts with a USB Class or USB WWID device path,
545 and there is no Media FilePath device path in the end.
546 In this case, it will follow Removable Media Boot Behavior.
547 2) Boot Option device path starts with a USB Class or USB WWID device path,
548 and ended with Media FilePath device path.
549 3) Boot Option device path starts with a full device path to a USB Host Controller,
550 contains a USB Class or USB WWID device path node, while not ended with Media
551 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
552 4) Boot Option device path starts with a full device path to a USB Host Controller,
553 contains a USB Class or USB WWID device path node, and ended with Media
554 FilePath device path.
556 @param FilePath The device path pointing to a load option.
557 It could be a short-form device path.
558 @param FullPath Return the full device path of the load option after
559 short-form device path expanding.
560 Caller is responsible to free it.
561 @param FileSize Return the load option size.
562 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
564 @return The load option buffer. Caller is responsible to free the memory.
567 BmExpandUsbDevicePath (
568 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
569 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
571 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
574 UINTN ParentDevicePathSize
;
575 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
576 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
582 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
583 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
585 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
587 for (Index
= 0; (Index
< HandleCount
) && (FileBuffer
== NULL
); Index
++) {
588 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
589 FileBuffer
= EfiBootManagerGetLoadOptionBuffer (FullDevicePath
, FullPath
, FileSize
);
590 FreePool (FullDevicePath
);
593 if (Handles
!= NULL
) {
601 Expand File-path device path node to be full device path in platform.
603 @param FilePath The device path pointing to a load option.
604 It could be a short-form device path.
605 @param FullPath Return the full device path of the load option after
606 short-form device path expanding.
607 Caller is responsible to free it.
608 @param FileSize Return the load option size.
610 @return The load option buffer. Caller is responsible to free the memory.
613 BmExpandFileDevicePath (
614 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
615 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
623 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
625 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
627 UINT32 AuthenticationStatus
;
629 EfiBootManagerConnectAll ();
630 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &Handles
);
631 if (EFI_ERROR (Status
)) {
637 // Enumerate all removable media devices followed by all fixed media devices,
638 // followed by media devices which don't layer on block io.
640 for (MediaType
= 0; MediaType
< 3; MediaType
++) {
641 for (Index
= 0; Index
< HandleCount
; Index
++) {
642 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiBlockIoProtocolGuid
, (VOID
*) &BlockIo
);
643 if (EFI_ERROR (Status
)) {
646 if ((MediaType
== 0 && BlockIo
!= NULL
&& BlockIo
->Media
->RemovableMedia
) ||
647 (MediaType
== 1 && BlockIo
!= NULL
&& !BlockIo
->Media
->RemovableMedia
) ||
648 (MediaType
== 2 && BlockIo
== NULL
)
650 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
);
651 FileBuffer
= GetFileBufferByFilePath (TRUE
, FullDevicePath
, FileSize
, &AuthenticationStatus
);
652 if (FileBuffer
!= NULL
) {
653 *FullPath
= FullDevicePath
;
657 FreePool (FullDevicePath
);
662 if (Handles
!= NULL
) {
671 Expand URI device path node to be full device path in platform.
673 @param FilePath The device path pointing to a load option.
674 It could be a short-form device path.
675 @param FullPath Return the full device path of the load option after
676 short-form device path expanding.
677 Caller is responsible to free it.
678 @param FileSize Return the load option size.
680 @return The load option buffer. Caller is responsible to free the memory.
683 BmExpandUriDevicePath (
684 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
685 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
695 EfiBootManagerConnectAll ();
696 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &HandleCount
, &Handles
);
697 if (EFI_ERROR (Status
)) {
703 for (Index
= 0; Index
< HandleCount
; Index
++) {
704 FileBuffer
= BmGetFileBufferFromLoadFile (Handles
[Index
], FilePath
, FullPath
, FileSize
);
705 if (FileBuffer
!= NULL
) {
710 if (Handles
!= NULL
) {
718 Save the partition DevicePath to the CachedDevicePath as the first instance.
720 @param CachedDevicePath The device path cache.
721 @param DevicePath The partition device path to be cached.
724 BmCachePartitionDevicePath (
725 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
726 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
729 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
732 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
733 TempDevicePath
= *CachedDevicePath
;
734 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
735 FreePool (TempDevicePath
);
738 if (*CachedDevicePath
== NULL
) {
739 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
743 TempDevicePath
= *CachedDevicePath
;
744 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
745 if (TempDevicePath
!= NULL
) {
746 FreePool (TempDevicePath
);
750 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
751 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
754 TempDevicePath
= *CachedDevicePath
;
755 while (!IsDevicePathEnd (TempDevicePath
)) {
756 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
758 // Parse one instance
760 while (!IsDevicePathEndType (TempDevicePath
)) {
761 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
765 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
768 SetDevicePathEndNode (TempDevicePath
);
775 Expand a device path that starts with a hard drive media device path node to be a
776 full device path that includes the full hardware path to the device. We need
777 to do this so it can be booted. As an optimization the front match (the part point
778 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
779 so a connect all is not required on every boot. All successful history device path
780 which point to partition node (the front part) will be saved.
782 @param FilePath The device path pointing to a load option.
783 It could be a short-form device path.
784 @param FullPath Return the full device path of the load option after
785 short-form device path expanding.
786 Caller is responsible to free it.
787 @param FileSize Return the load option size.
789 @return The load option buffer. Caller is responsible to free the memory.
792 BmExpandPartitionDevicePath (
793 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
794 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
799 UINTN BlockIoHandleCount
;
800 EFI_HANDLE
*BlockIoBuffer
;
802 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
804 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
805 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
806 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
807 UINTN CachedDevicePathSize
;
809 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
814 // Check if there is prestore 'HDDP' variable.
815 // If exist, search the front path which point to partition node in the variable instants.
816 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
818 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
821 // Delete the invalid 'HDDP' variable.
823 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
824 FreePool (CachedDevicePath
);
825 CachedDevicePath
= NULL
;
826 Status
= gRT
->SetVariable (
828 &mBmHardDriveBootVariableGuid
,
833 ASSERT_EFI_ERROR (Status
);
836 if (CachedDevicePath
!= NULL
) {
837 TempNewDevicePath
= CachedDevicePath
;
841 // Check every instance of the variable
842 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
843 // partial partition boot option. Second, check whether the instance could be connected.
845 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
846 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
848 // Connect the device path instance, the device path point to hard drive media device path node
849 // e.g. ACPI() /PCI()/ATA()/Partition()
851 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
852 if (!EFI_ERROR (Status
)) {
853 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
854 FileBuffer
= EfiBootManagerGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
855 FreePool (TempDevicePath
);
857 if (FileBuffer
!= NULL
) {
859 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
862 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
864 // Save the matching Device Path so we don't need to do a connect all next time
865 // Failing to save only impacts performance next time expanding the short-form device path
867 Status
= gRT
->SetVariable (
869 &mBmHardDriveBootVariableGuid
,
870 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
871 GetDevicePathSize (CachedDevicePath
),
877 FreePool (CachedDevicePath
);
883 // Come here means the first instance is not matched
887 } while (TempNewDevicePath
!= NULL
);
891 // If we get here we fail to find or 'HDDP' not exist, and now we need
892 // to search all devices in the system for a matched partition
894 EfiBootManagerConnectAll ();
895 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
896 if (EFI_ERROR (Status
)) {
897 BlockIoHandleCount
= 0;
898 BlockIoBuffer
= NULL
;
901 // Loop through all the device handles that support the BLOCK_IO Protocol
903 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
904 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
905 if (BlockIoDevicePath
== NULL
) {
909 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
911 // Find the matched partition device path
913 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
914 FileBuffer
= EfiBootManagerGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
915 FreePool (TempDevicePath
);
917 if (FileBuffer
!= NULL
) {
918 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
921 // Save the matching Device Path so we don't need to do a connect all next time
922 // Failing to save only impacts performance next time expanding the short-form device path
924 Status
= gRT
->SetVariable (
926 &mBmHardDriveBootVariableGuid
,
927 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
928 GetDevicePathSize (CachedDevicePath
),
937 if (CachedDevicePath
!= NULL
) {
938 FreePool (CachedDevicePath
);
940 if (BlockIoBuffer
!= NULL
) {
941 FreePool (BlockIoBuffer
);
947 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
948 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
950 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
951 @param FullPath Return the full device path pointing to the load option.
952 @param FileSize Return the size of the load option.
954 @return The load option buffer.
957 BmExpandMediaDevicePath (
958 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
959 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
965 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
967 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
970 EFI_HANDLE
*SimpleFileSystemHandles
;
971 UINTN NumberSimpleFileSystemHandles
;
974 UINT32 AuthenticationStatus
;
977 // Check whether the device is connected
979 TempDevicePath
= DevicePath
;
980 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
981 if (!EFI_ERROR (Status
)) {
982 ASSERT (IsDevicePathEnd (TempDevicePath
));
984 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
985 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
986 if (FileBuffer
== NULL
) {
987 FreePool (TempDevicePath
);
988 TempDevicePath
= NULL
;
990 *FullPath
= TempDevicePath
;
995 // For device boot option only pointing to the removable device handle,
996 // should make sure all its children handles (its child partion or media handles) are created and connected.
998 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1001 // Issue a dummy read to the device to check for media change.
1002 // When the removable media is changed, any Block IO read/write will
1003 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1004 // returned. After the Block IO protocol is reinstalled, subsequent
1005 // Block IO read/write will success.
1007 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1008 ASSERT_EFI_ERROR (Status
);
1009 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1010 ASSERT_EFI_ERROR (Status
);
1011 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1012 if (Buffer
!= NULL
) {
1013 BlockIo
->ReadBlocks (
1015 BlockIo
->Media
->MediaId
,
1017 BlockIo
->Media
->BlockSize
,
1024 // Detect the the default boot file from removable Media
1028 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1029 gBS
->LocateHandleBuffer (
1031 &gEfiSimpleFileSystemProtocolGuid
,
1033 &NumberSimpleFileSystemHandles
,
1034 &SimpleFileSystemHandles
1036 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1038 // Get the device path size of SimpleFileSystem handle
1040 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1041 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1043 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1045 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1046 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1047 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1048 if (FileBuffer
!= NULL
) {
1049 *FullPath
= TempDevicePath
;
1052 FreePool (TempDevicePath
);
1056 if (SimpleFileSystemHandles
!= NULL
) {
1057 FreePool (SimpleFileSystemHandles
);
1064 Check whether Left and Right are the same without matching the specific
1065 device path data in IP device path and URI device path node.
1067 @retval TRUE Left and Right are the same.
1068 @retval FALSE Left and Right are the different.
1071 BmMatchHttpBootDevicePath (
1072 IN EFI_DEVICE_PATH_PROTOCOL
*Left
,
1073 IN EFI_DEVICE_PATH_PROTOCOL
*Right
1076 for (; !IsDevicePathEnd (Left
) && !IsDevicePathEnd (Right
)
1077 ; Left
= NextDevicePathNode (Left
), Right
= NextDevicePathNode (Right
)
1079 if (CompareMem (Left
, Right
, DevicePathNodeLength (Left
)) != 0) {
1080 if ((DevicePathType (Left
) != MESSAGING_DEVICE_PATH
) || (DevicePathType (Right
) != MESSAGING_DEVICE_PATH
)) {
1084 if (((DevicePathSubType (Left
) != MSG_IPv4_DP
) || (DevicePathSubType (Right
) != MSG_IPv4_DP
)) &&
1085 ((DevicePathSubType (Left
) != MSG_IPv6_DP
) || (DevicePathSubType (Right
) != MSG_IPv6_DP
)) &&
1086 ((DevicePathSubType (Left
) != MSG_URI_DP
) || (DevicePathSubType (Right
) != MSG_URI_DP
))
1092 return (BOOLEAN
) (IsDevicePathEnd (Left
) && IsDevicePathEnd (Right
));
1096 Get the file buffer from the file system produced by Load File instance.
1098 @param LoadFileHandle The handle of LoadFile instance.
1099 @param FullPath Return the full device path pointing to the load option.
1100 @param FileSize Return the size of the load option.
1101 @param RamDiskHandle Return the RAM Disk handle.
1103 @return The load option buffer.
1106 BmGetFileBufferFromLoadFileSystem (
1107 IN EFI_HANDLE LoadFileHandle
,
1108 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1109 OUT UINTN
*FileSize
,
1110 OUT EFI_HANDLE
*RamDiskHandle
1115 EFI_HANDLE
*Handles
;
1118 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1120 Status
= gBS
->LocateHandleBuffer (
1122 &gEfiBlockIoProtocolGuid
,
1127 if (EFI_ERROR (Status
)) {
1133 for (Index
= 0; Index
< HandleCount
; Index
++) {
1134 Node
= DevicePathFromHandle (Handles
[Index
]);
1135 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1136 if (!EFI_ERROR (Status
) &&
1137 (Handle
== LoadFileHandle
) &&
1138 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)) {
1139 Handle
= Handles
[Index
];
1144 if (Handles
!= NULL
) {
1148 if (Index
== HandleCount
) {
1152 *RamDiskHandle
= Handle
;
1154 if (Handle
!= NULL
) {
1155 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle
), FullPath
, FileSize
);
1163 Return the RAM Disk device path created by LoadFile.
1165 @param FilePath The source file path.
1167 @return Callee-to-free RAM Disk device path
1169 EFI_DEVICE_PATH_PROTOCOL
*
1170 BmGetRamDiskDevicePath (
1171 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1175 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1176 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1180 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1181 if (!EFI_ERROR (Status
) &&
1182 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) &&
1183 (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)
1187 // Construct the device path pointing to RAM Disk
1189 Node
= NextDevicePathNode (Node
);
1190 RamDiskDevicePath
= DuplicateDevicePath (FilePath
);
1191 ASSERT (RamDiskDevicePath
!= NULL
);
1192 SetDevicePathEndNode ((VOID
*) ((UINTN
) RamDiskDevicePath
+ ((UINTN
) Node
- (UINTN
) FilePath
)));
1193 return RamDiskDevicePath
;
1200 Return the buffer and buffer size occupied by the RAM Disk.
1202 @param RamDiskDevicePath RAM Disk device path.
1203 @param RamDiskSizeInPages Return RAM Disk size in pages.
1205 @retval RAM Disk buffer.
1208 BmGetRamDiskMemoryInfo (
1209 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
,
1210 OUT UINTN
*RamDiskSizeInPages
1216 UINT64 StartingAddr
;
1219 ASSERT (RamDiskDevicePath
!= NULL
);
1221 *RamDiskSizeInPages
= 0;
1224 // Get the buffer occupied by RAM Disk.
1226 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &RamDiskDevicePath
, &Handle
);
1227 ASSERT_EFI_ERROR (Status
);
1228 ASSERT ((DevicePathType (RamDiskDevicePath
) == MEDIA_DEVICE_PATH
) &&
1229 (DevicePathSubType (RamDiskDevicePath
) == MEDIA_RAM_DISK_DP
));
1230 StartingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->StartingAddr
);
1231 EndingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->EndingAddr
);
1232 *RamDiskSizeInPages
= EFI_SIZE_TO_PAGES ((UINTN
) (EndingAddr
- StartingAddr
+ 1));
1233 return (VOID
*) (UINTN
) StartingAddr
;
1237 Destroy the RAM Disk.
1239 The destroy operation includes to call RamDisk.Unregister to
1240 unregister the RAM DISK from RAM DISK driver, free the memory
1241 allocated for the RAM Disk.
1243 @param RamDiskDevicePath RAM Disk device path.
1247 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
1251 VOID
*RamDiskBuffer
;
1252 UINTN RamDiskSizeInPages
;
1254 ASSERT (RamDiskDevicePath
!= NULL
);
1256 RamDiskBuffer
= BmGetRamDiskMemoryInfo (RamDiskDevicePath
, &RamDiskSizeInPages
);
1259 // Destroy RAM Disk.
1261 if (mRamDisk
== NULL
) {
1262 Status
= gBS
->LocateProtocol (&gEfiRamDiskProtocolGuid
, NULL
, (VOID
*) &mRamDisk
);
1263 ASSERT_EFI_ERROR (Status
);
1265 Status
= mRamDisk
->Unregister (RamDiskDevicePath
);
1266 ASSERT_EFI_ERROR (Status
);
1267 FreePages (RamDiskBuffer
, RamDiskSizeInPages
);
1271 Get the file buffer from the specified Load File instance.
1273 @param LoadFileHandle The specified Load File instance.
1274 @param FilePath The file path which will pass to LoadFile().
1275 @param FullPath Return the full device path pointing to the load option.
1276 @param FileSize Return the size of the load option.
1278 @return The load option buffer or NULL if fails.
1281 BmGetFileBufferFromLoadFile (
1282 IN EFI_HANDLE LoadFileHandle
,
1283 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1284 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1289 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1291 BOOLEAN LoadFileSystem
;
1292 EFI_HANDLE RamDiskHandle
;
1297 Status
= gBS
->OpenProtocol (
1299 &gEfiLoadFileProtocolGuid
,
1300 (VOID
**) &LoadFile
,
1303 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1305 ASSERT_EFI_ERROR (Status
);
1309 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1310 if ((Status
!= EFI_WARN_FILE_SYSTEM
) && (Status
!= EFI_BUFFER_TOO_SMALL
)) {
1314 LoadFileSystem
= (BOOLEAN
) (Status
== EFI_WARN_FILE_SYSTEM
);
1315 FileBuffer
= LoadFileSystem
? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize
)) : AllocatePool (BufferSize
);
1316 if (FileBuffer
== NULL
) {
1320 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1321 if (EFI_ERROR (Status
)) {
1322 if (LoadFileSystem
) {
1323 FreePages (FileBuffer
, EFI_SIZE_TO_PAGES (BufferSize
));
1325 FreePool (FileBuffer
);
1330 if (LoadFileSystem
) {
1331 FileBuffer
= BmGetFileBufferFromLoadFileSystem (LoadFileHandle
, FullPath
, FileSize
, &RamDiskHandle
);
1332 if (FileBuffer
== NULL
) {
1334 // If there is no bootable executable in the populated
1336 BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle
));
1339 *FileSize
= BufferSize
;
1340 *FullPath
= DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle
));
1347 Get the file buffer from all the Load File instances.
1349 @param FilePath The media device path pointing to a LoadFile instance.
1350 @param FullPath Return the full device path pointing to the load option.
1351 @param FileSize Return the size of the load option.
1353 @return The load option buffer.
1356 BmGetFileBufferFromLoadFiles (
1357 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1358 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1364 EFI_HANDLE
*Handles
;
1367 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1370 // Get file buffer from load file instance.
1373 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1374 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1376 // When wide match happens, pass full device path to LoadFile (),
1377 // otherwise, pass remaining device path to LoadFile ().
1383 // Use wide match algorithm to find one when
1384 // cannot find a LoadFile instance to exactly match the FilePath
1386 Status
= gBS
->LocateHandleBuffer (
1388 &gEfiLoadFileProtocolGuid
,
1393 if (EFI_ERROR (Status
)) {
1397 for (Index
= 0; Index
< HandleCount
; Index
++) {
1398 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
)) {
1399 Handle
= Handles
[Index
];
1403 if (Handles
!= NULL
) {
1408 if (Handle
== NULL
) {
1412 return BmGetFileBufferFromLoadFile (Handle
, FilePath
, FullPath
, FileSize
);
1416 Get the load option by its device path.
1418 @param FilePath The device path pointing to a load option.
1419 It could be a short-form device path.
1420 @param FullPath Return the full device path of the load option after
1421 short-form device path expanding.
1422 Caller is responsible to free it.
1423 @param FileSize Return the load option size.
1425 @return The load option buffer. Caller is responsible to free the memory.
1429 EfiBootManagerGetLoadOptionBuffer (
1430 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1431 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1437 UINT32 AuthenticationStatus
;
1438 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1441 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1443 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1450 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1453 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1454 if (EFI_ERROR (Status
)) {
1455 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1458 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1459 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1463 // Expand the short-form device path to full device path
1465 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1466 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1468 // Expand the Harddrive device path
1470 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1471 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1472 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
)) {
1474 // Expand the File-path device path
1476 return BmExpandFileDevicePath (FilePath
, FullPath
, FileSize
);
1477 } else if ((DevicePathType (FilePath
) == MESSAGING_DEVICE_PATH
) &&
1478 (DevicePathSubType (FilePath
) == MSG_URI_DP
)) {
1480 // Expand the URI device path
1482 return BmExpandUriDevicePath (FilePath
, FullPath
, FileSize
);
1484 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1485 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1486 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1491 if (!IsDevicePathEnd (Node
)) {
1493 // Expand the USB WWID/Class device path
1495 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1496 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1498 // Boot Option device path starts with USB Class or USB WWID device path.
1499 // For Boot Option device path which doesn't begin with the USB Class or
1500 // USB WWID device path, it's not needed to connect again here.
1502 BmConnectUsbShortFormDevicePath (FilePath
);
1503 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1510 // Get file buffer from FV file path.
1512 if (BmIsFvFilePath (FilePath
)) {
1513 return BmGetFileBufferByFvFilePath (FilePath
, FullPath
, FileSize
);
1517 // Get file buffer from simple file system.
1520 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1521 if (!EFI_ERROR (Status
)) {
1522 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1523 if (FileBuffer
!= NULL
) {
1524 *FullPath
= DuplicateDevicePath (FilePath
);
1529 return BmGetFileBufferFromLoadFiles (FilePath
, FullPath
, FileSize
);
1533 Check if it's a Device Path pointing to BootMenuApp.
1535 @param DevicePath Input device path.
1537 @retval TRUE The device path is BootMenuApp File Device Path.
1538 @retval FALSE The device path is NOT BootMenuApp File Device Path.
1541 BmIsBootMenuAppFilePath (
1542 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1545 EFI_HANDLE FvHandle
;
1549 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &DevicePath
, &FvHandle
);
1550 if (!EFI_ERROR (Status
)) {
1551 NameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) DevicePath
);
1552 if (NameGuid
!= NULL
) {
1553 return CompareGuid (NameGuid
, PcdGetPtr (PcdBootManagerMenuFile
));
1561 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1562 also signals the EFI ready to boot event. If the device path for the option
1563 starts with a BBS device path a legacy boot is attempted via the registered
1564 gLegacyBoot function. Short form device paths are also supported via this
1565 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1566 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1567 If the BootOption Device Path fails the removable media boot algorithm
1568 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1569 is tried per processor type)
1571 @param BootOption Boot Option to try and boot.
1572 On return, BootOption->Status contains the boot status.
1573 EFI_SUCCESS BootOption was booted
1574 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1575 registered via EfiBootManagerInitialize().
1576 EFI_NOT_FOUND The BootOption was not found on the system
1577 !EFI_SUCCESS BootOption failed with this error status
1582 EfiBootManagerBoot (
1583 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1587 EFI_HANDLE ImageHandle
;
1588 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1591 UINTN OriginalOptionNumber
;
1592 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1593 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1596 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1597 EFI_EVENT LegacyBootEvent
;
1599 if (BootOption
== NULL
) {
1603 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1604 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1609 // 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")
1611 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1612 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1613 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1614 if (!EFI_ERROR (Status
)) {
1616 // Save the BootOption->OptionNumber to restore later
1618 OptionNumber
= Uint16
;
1619 OriginalOptionNumber
= BootOption
->OptionNumber
;
1620 BootOption
->OptionNumber
= OptionNumber
;
1621 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1622 BootOption
->OptionNumber
= OriginalOptionNumber
;
1625 if (EFI_ERROR (Status
)) {
1626 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1627 BootOption
->Status
= Status
;
1633 // 2. Set BootCurrent
1635 Uint16
= (UINT16
) OptionNumber
;
1636 BmSetVariableAndReportStatusCodeOnError (
1638 &gEfiGlobalVariableGuid
,
1639 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1645 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1648 if (BmIsBootMenuAppFilePath (BootOption
->FilePath
)) {
1649 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1650 BmStopHotkeyService (NULL
, NULL
);
1652 EfiSignalEventReadyToBoot();
1654 // Report Status Code to indicate ReadyToBoot was signalled
1656 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1658 // 4. Repair system through DriverHealth protocol
1660 BmRepairAllControllers ();
1663 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1666 // 5. Adjust the different type memory page number just before booting
1667 // and save the updated info into the variable for next boot to use
1669 BmSetMemoryTypeInformationVariable (
1670 (BOOLEAN
) ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1674 // 6. Load EFI boot option to ImageHandle
1676 DEBUG_CODE_BEGIN ();
1677 if (BootOption
->Description
== NULL
) {
1678 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1680 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1685 RamDiskDevicePath
= NULL
;
1686 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1687 Status
= EFI_NOT_FOUND
;
1688 FileBuffer
= EfiBootManagerGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1689 if (FileBuffer
!= NULL
) {
1690 RamDiskDevicePath
= BmGetRamDiskDevicePath (FilePath
);
1693 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1694 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1695 BmPrintDp (BootOption
->FilePath
);
1696 DEBUG ((EFI_D_INFO
, " -> "));
1697 BmPrintDp (FilePath
);
1698 DEBUG ((EFI_D_INFO
, "\n"));
1701 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1702 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1703 Status
= gBS
->LoadImage (
1712 if (FileBuffer
!= NULL
) {
1713 FreePool (FileBuffer
);
1715 if (FilePath
!= NULL
) {
1716 FreePool (FilePath
);
1719 if (EFI_ERROR (Status
)) {
1721 // Report Status Code to indicate that the failure to load boot option
1723 REPORT_STATUS_CODE (
1724 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1725 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1727 BootOption
->Status
= Status
;
1729 // Destroy the RAM disk
1731 if (RamDiskDevicePath
!= NULL
) {
1732 BmDestroyRamDisk (RamDiskDevicePath
);
1733 FreePool (RamDiskDevicePath
);
1740 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1741 // Write boot to OS performance data for Legacy boot
1743 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1744 if (mBmLegacyBoot
!= NULL
) {
1746 // Write boot to OS performance data for legacy boot.
1750 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1752 Status
= EfiCreateEventLegacyBootEx(
1754 BmWriteBootToOsPerformanceData
,
1758 ASSERT_EFI_ERROR (Status
);
1761 mBmLegacyBoot (BootOption
);
1763 BootOption
->Status
= EFI_UNSUPPORTED
;
1766 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1771 // Provide the image with its load options
1773 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1774 ASSERT_EFI_ERROR (Status
);
1776 if (!BmIsAutoCreateBootOption (BootOption
)) {
1777 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1778 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1782 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1784 ImageInfo
->ParentHandle
= NULL
;
1787 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1789 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1792 // Write boot to OS performance data for UEFI boot
1795 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1798 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1800 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1801 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1802 BootOption
->Status
= Status
;
1803 if (EFI_ERROR (Status
)) {
1805 // Report Status Code to indicate that boot failure
1807 REPORT_STATUS_CODE (
1808 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1809 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1812 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1815 // Destroy the RAM disk
1817 if (RamDiskDevicePath
!= NULL
) {
1818 BmDestroyRamDisk (RamDiskDevicePath
);
1819 FreePool (RamDiskDevicePath
);
1823 // Clear the Watchdog Timer after the image returns
1825 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1828 // Set Logo status invalid after trying one boot option
1831 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1832 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1833 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1834 ASSERT_EFI_ERROR (Status
);
1838 // Clear Boot Current
1840 Status
= gRT
->SetVariable (
1842 &gEfiGlobalVariableGuid
,
1848 // Deleting variable with current variable implementation shouldn't fail.
1849 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1850 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1852 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1856 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1857 instances, has the same partition node with HardDriveDevicePath device path
1859 @param BlockIoDevicePath Multi device path instances which need to check
1860 @param HardDriveDevicePath A device path which starts with a hard drive media
1863 @retval TRUE There is a matched device path instance.
1864 @retval FALSE There is no matched device path instance.
1868 BmMatchPartitionDevicePathNode (
1869 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1870 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1873 HARDDRIVE_DEVICE_PATH
*Node
;
1875 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1880 // find the partition device path node
1882 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1883 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1884 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1889 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1892 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1897 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1899 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1902 // Match Signature and PartitionNumber.
1903 // Unused bytes in Signature are initiaized with zeros.
1906 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1907 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1908 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1909 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1914 Emuerate all possible bootable medias in the following order:
1915 1. Removable BlockIo - The boot option only points to the removable media
1916 device, like USB key, DVD, Floppy etc.
1917 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1919 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1920 SimpleFileSystem Protocol, but not supporting BlockIo
1922 4. LoadFile - The boot option points to the media supporting
1924 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1926 @param BootOptionCount Return the boot option count which has been found.
1928 @retval Pointer to the boot option array.
1930 EFI_BOOT_MANAGER_LOAD_OPTION
*
1931 BmEnumerateBootOptions (
1932 UINTN
*BootOptionCount
1936 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1938 EFI_HANDLE
*Handles
;
1939 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
1942 CHAR16
*Description
;
1943 UINT32 BootAttributes
;
1945 ASSERT (BootOptionCount
!= NULL
);
1947 *BootOptionCount
= 0;
1951 // Parse removable block io followed by fixed block io
1953 gBS
->LocateHandleBuffer (
1955 &gEfiBlockIoProtocolGuid
,
1961 for (Removable
= 0; Removable
< 2; Removable
++) {
1962 for (Index
= 0; Index
< HandleCount
; Index
++) {
1963 Status
= gBS
->HandleProtocol (
1965 &gEfiBlockIoProtocolGuid
,
1968 if (EFI_ERROR (Status
)) {
1973 // Skip the logical partitions
1975 if (BlkIo
->Media
->LogicalPartition
) {
1980 // Skip the fixed block io then the removable block io
1982 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
1986 Description
= BmGetBootDescription (Handles
[Index
]);
1987 BootOptions
= ReallocatePool (
1988 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1989 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1992 ASSERT (BootOptions
!= NULL
);
1994 Status
= EfiBootManagerInitializeLoadOption (
1995 &BootOptions
[(*BootOptionCount
)++],
1996 LoadOptionNumberUnassigned
,
2000 DevicePathFromHandle (Handles
[Index
]),
2004 ASSERT_EFI_ERROR (Status
);
2006 FreePool (Description
);
2010 if (HandleCount
!= 0) {
2015 // Parse simple file system not based on block io
2017 gBS
->LocateHandleBuffer (
2019 &gEfiSimpleFileSystemProtocolGuid
,
2024 for (Index
= 0; Index
< HandleCount
; Index
++) {
2025 Status
= gBS
->HandleProtocol (
2027 &gEfiBlockIoProtocolGuid
,
2030 if (!EFI_ERROR (Status
)) {
2032 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2036 Description
= BmGetBootDescription (Handles
[Index
]);
2037 BootOptions
= ReallocatePool (
2038 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2039 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2042 ASSERT (BootOptions
!= NULL
);
2044 Status
= EfiBootManagerInitializeLoadOption (
2045 &BootOptions
[(*BootOptionCount
)++],
2046 LoadOptionNumberUnassigned
,
2050 DevicePathFromHandle (Handles
[Index
]),
2054 ASSERT_EFI_ERROR (Status
);
2055 FreePool (Description
);
2058 if (HandleCount
!= 0) {
2063 // Parse load file protocol
2065 gBS
->LocateHandleBuffer (
2067 &gEfiLoadFileProtocolGuid
,
2072 for (Index
= 0; Index
< HandleCount
; Index
++) {
2074 Description
= BmGetBootDescription (Handles
[Index
]);
2075 BootOptions
= ReallocatePool (
2076 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2077 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2080 ASSERT (BootOptions
!= NULL
);
2083 // If LoadFile includes BootMenuApp, its boot attribue will be set to APP and HIDDEN.
2085 BootAttributes
= LOAD_OPTION_ACTIVE
;
2086 if (BmIsBootMenuAppFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2087 BootAttributes
= LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
;
2090 Status
= EfiBootManagerInitializeLoadOption (
2091 &BootOptions
[(*BootOptionCount
)++],
2092 LoadOptionNumberUnassigned
,
2096 DevicePathFromHandle (Handles
[Index
]),
2100 ASSERT_EFI_ERROR (Status
);
2101 FreePool (Description
);
2104 if (HandleCount
!= 0) {
2108 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
2113 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2117 EfiBootManagerRefreshAllBootOption (
2122 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2123 UINTN NvBootOptionCount
;
2124 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2125 UINTN BootOptionCount
;
2129 // Optionally refresh the legacy boot option
2131 if (mBmRefreshLegacyBootOption
!= NULL
) {
2132 mBmRefreshLegacyBootOption ();
2135 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2136 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2139 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2141 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2142 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2143 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2147 // Remove invalid EFI boot options from NV
2149 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2150 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2151 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2152 ) && BmIsAutoCreateBootOption (&NvBootOptions
[Index
])
2155 // Only check those added by BDS
2156 // so that the boot options added by end-user or OS installer won't be deleted
2158 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
2159 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2161 // Deleting variable with current variable implementation shouldn't fail.
2163 ASSERT_EFI_ERROR (Status
);
2169 // Add new EFI boot options to NV
2171 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2172 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
2173 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2175 // Try best to add the boot options so continue upon failure.
2180 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2181 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2185 This function is called to get or create the boot option for the Boot Manager Menu.
2187 The Boot Manager Menu is shown after successfully booting a boot option.
2188 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2190 @param BootOption Return the boot option of the Boot Manager Menu
2192 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2193 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2194 @retval others Return status of gRT->SetVariable (). BootOption still points
2195 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2199 BmRegisterBootManagerMenu (
2200 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2204 CHAR16
*Description
;
2205 UINTN DescriptionLength
;
2206 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2207 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2208 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2210 EFI_HANDLE
*Handles
;
2218 // Try to find BootMenuApp from LoadFile protocol
2220 gBS
->LocateHandleBuffer (
2222 &gEfiLoadFileProtocolGuid
,
2227 for (Index
= 0; Index
< HandleCount
; Index
++) {
2228 if (BmIsBootMenuAppFilePath (DevicePathFromHandle (Handles
[Index
]))) {
2229 DevicePath
= DuplicateDevicePath (DevicePathFromHandle (Handles
[Index
]));
2230 Description
= BmGetBootDescription (Handles
[Index
]);
2234 if (HandleCount
!= 0) {
2238 if (DevicePath
== NULL
) {
2240 Status
= GetSectionFromFv (
2241 PcdGetPtr (PcdBootManagerMenuFile
),
2250 if (EFI_ERROR (Status
)) {
2251 DEBUG ((EFI_D_WARN
, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
2252 return EFI_NOT_FOUND
;
2256 // Get BootManagerMenu application's description from EFI User Interface Section.
2258 Status
= GetSectionFromFv (
2259 PcdGetPtr (PcdBootManagerMenuFile
),
2260 EFI_SECTION_USER_INTERFACE
,
2262 (VOID
**) &Description
,
2265 if (EFI_ERROR (Status
)) {
2269 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2270 Status
= gBS
->HandleProtocol (
2272 &gEfiLoadedImageProtocolGuid
,
2273 (VOID
**) &LoadedImage
2275 ASSERT_EFI_ERROR (Status
);
2276 DevicePath
= AppendDevicePathNode (
2277 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2278 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2280 ASSERT (DevicePath
!= NULL
);
2283 Status
= EfiBootManagerInitializeLoadOption (
2285 LoadOptionNumberUnassigned
,
2287 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2288 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2293 ASSERT_EFI_ERROR (Status
);
2294 FreePool (DevicePath
);
2295 if (Description
!= NULL
) {
2296 FreePool (Description
);
2300 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2301 UINTN BootOptionCount
;
2303 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2304 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2305 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2308 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2312 Return the boot option corresponding to the Boot Manager Menu.
2313 It may automatically create one if the boot option hasn't been created yet.
2315 @param BootOption Return the Boot Manager Menu.
2317 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2318 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2319 @retval others Return status of gRT->SetVariable (). BootOption still points
2320 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2325 EfiBootManagerGetBootManagerMenu (
2326 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2330 UINTN BootOptionCount
;
2331 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2334 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2336 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2337 if (BmIsBootMenuAppFilePath (BootOptions
[Index
].FilePath
)) {
2338 Status
= EfiBootManagerInitializeLoadOption (
2340 BootOptions
[Index
].OptionNumber
,
2341 BootOptions
[Index
].OptionType
,
2342 BootOptions
[Index
].Attributes
,
2343 BootOptions
[Index
].Description
,
2344 BootOptions
[Index
].FilePath
,
2345 BootOptions
[Index
].OptionalData
,
2346 BootOptions
[Index
].OptionalDataSize
2348 ASSERT_EFI_ERROR (Status
);
2353 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2356 // Automatically create the Boot#### for Boot Manager Menu when not found.
2358 if (Index
== BootOptionCount
) {
2359 return BmRegisterBootManagerMenu (BootOption
);