2 Library functions which relates with booting.
4 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 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
= BmGetLoadOptionBuffer (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
)) {
702 for (Index
= 0; Index
< HandleCount
; Index
++) {
703 FileBuffer
= BmGetFileBufferFromLoadFile (Handles
[Index
], FilePath
, FullPath
, FileSize
);
704 if (FileBuffer
!= NULL
) {
709 if (Handles
!= NULL
) {
717 Save the partition DevicePath to the CachedDevicePath as the first instance.
719 @param CachedDevicePath The device path cache.
720 @param DevicePath The partition device path to be cached.
723 BmCachePartitionDevicePath (
724 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
725 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
728 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
731 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
732 TempDevicePath
= *CachedDevicePath
;
733 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
734 FreePool (TempDevicePath
);
737 if (*CachedDevicePath
== NULL
) {
738 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
742 TempDevicePath
= *CachedDevicePath
;
743 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
744 if (TempDevicePath
!= NULL
) {
745 FreePool (TempDevicePath
);
749 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
750 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
753 TempDevicePath
= *CachedDevicePath
;
754 while (!IsDevicePathEnd (TempDevicePath
)) {
755 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
757 // Parse one instance
759 while (!IsDevicePathEndType (TempDevicePath
)) {
760 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
764 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
767 SetDevicePathEndNode (TempDevicePath
);
774 Expand a device path that starts with a hard drive media device path node to be a
775 full device path that includes the full hardware path to the device. We need
776 to do this so it can be booted. As an optimization the front match (the part point
777 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
778 so a connect all is not required on every boot. All successful history device path
779 which point to partition node (the front part) will be saved.
781 @param FilePath The device path pointing to a load option.
782 It could be a short-form device path.
783 @param FullPath Return the full device path of the load option after
784 short-form device path expanding.
785 Caller is responsible to free it.
786 @param FileSize Return the load option size.
788 @return The load option buffer. Caller is responsible to free the memory.
791 BmExpandPartitionDevicePath (
792 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
793 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
798 UINTN BlockIoHandleCount
;
799 EFI_HANDLE
*BlockIoBuffer
;
801 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
803 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
804 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
805 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
806 UINTN CachedDevicePathSize
;
808 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
813 // Check if there is prestore 'HDDP' variable.
814 // If exist, search the front path which point to partition node in the variable instants.
815 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
817 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
820 // Delete the invalid 'HDDP' variable.
822 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
823 FreePool (CachedDevicePath
);
824 CachedDevicePath
= NULL
;
825 Status
= gRT
->SetVariable (
827 &mBmHardDriveBootVariableGuid
,
832 ASSERT_EFI_ERROR (Status
);
835 if (CachedDevicePath
!= NULL
) {
836 TempNewDevicePath
= CachedDevicePath
;
840 // Check every instance of the variable
841 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
842 // partial partition boot option. Second, check whether the instance could be connected.
844 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
845 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
847 // Connect the device path instance, the device path point to hard drive media device path node
848 // e.g. ACPI() /PCI()/ATA()/Partition()
850 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
851 if (!EFI_ERROR (Status
)) {
852 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
853 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
854 FreePool (TempDevicePath
);
856 if (FileBuffer
!= NULL
) {
858 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
861 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
863 // Save the matching Device Path so we don't need to do a connect all next time
864 // Failing to save only impacts performance next time expanding the short-form device path
866 Status
= gRT
->SetVariable (
868 &mBmHardDriveBootVariableGuid
,
869 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
870 GetDevicePathSize (CachedDevicePath
),
876 FreePool (CachedDevicePath
);
882 // Come here means the first instance is not matched
886 } while (TempNewDevicePath
!= NULL
);
890 // If we get here we fail to find or 'HDDP' not exist, and now we need
891 // to search all devices in the system for a matched partition
893 EfiBootManagerConnectAll ();
894 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
895 if (EFI_ERROR (Status
)) {
896 BlockIoHandleCount
= 0;
897 BlockIoBuffer
= NULL
;
900 // Loop through all the device handles that support the BLOCK_IO Protocol
902 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
903 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
904 if (BlockIoDevicePath
== NULL
) {
908 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
910 // Find the matched partition device path
912 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
913 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
914 FreePool (TempDevicePath
);
916 if (FileBuffer
!= NULL
) {
917 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
920 // Save the matching Device Path so we don't need to do a connect all next time
921 // Failing to save only impacts performance next time expanding the short-form device path
923 Status
= gRT
->SetVariable (
925 &mBmHardDriveBootVariableGuid
,
926 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
927 GetDevicePathSize (CachedDevicePath
),
936 if (CachedDevicePath
!= NULL
) {
937 FreePool (CachedDevicePath
);
939 if (BlockIoBuffer
!= NULL
) {
940 FreePool (BlockIoBuffer
);
946 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
947 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
949 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
950 @param FullPath Return the full device path pointing to the load option.
951 @param FileSize Return the size of the load option.
953 @return The load option buffer.
956 BmExpandMediaDevicePath (
957 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
958 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
964 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
966 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
969 EFI_HANDLE
*SimpleFileSystemHandles
;
970 UINTN NumberSimpleFileSystemHandles
;
973 UINT32 AuthenticationStatus
;
976 // Check whether the device is connected
978 TempDevicePath
= DevicePath
;
979 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
980 if (!EFI_ERROR (Status
)) {
981 ASSERT (IsDevicePathEnd (TempDevicePath
));
983 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
984 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
985 if (FileBuffer
== NULL
) {
986 FreePool (TempDevicePath
);
987 TempDevicePath
= NULL
;
989 *FullPath
= TempDevicePath
;
994 // For device boot option only pointing to the removable device handle,
995 // should make sure all its children handles (its child partion or media handles) are created and connected.
997 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1000 // Issue a dummy read to the device to check for media change.
1001 // When the removable media is changed, any Block IO read/write will
1002 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1003 // returned. After the Block IO protocol is reinstalled, subsequent
1004 // Block IO read/write will success.
1006 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1007 ASSERT_EFI_ERROR (Status
);
1008 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1009 ASSERT_EFI_ERROR (Status
);
1010 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1011 if (Buffer
!= NULL
) {
1012 BlockIo
->ReadBlocks (
1014 BlockIo
->Media
->MediaId
,
1016 BlockIo
->Media
->BlockSize
,
1023 // Detect the the default boot file from removable Media
1027 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1028 gBS
->LocateHandleBuffer (
1030 &gEfiSimpleFileSystemProtocolGuid
,
1032 &NumberSimpleFileSystemHandles
,
1033 &SimpleFileSystemHandles
1035 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1037 // Get the device path size of SimpleFileSystem handle
1039 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1040 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1042 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1044 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1045 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1046 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1047 if (FileBuffer
!= NULL
) {
1048 *FullPath
= TempDevicePath
;
1051 FreePool (TempDevicePath
);
1055 if (SimpleFileSystemHandles
!= NULL
) {
1056 FreePool (SimpleFileSystemHandles
);
1063 Check whether Left and Right are the same without matching the specific
1064 device path data in IP device path and URI device path node.
1066 @retval TRUE Left and Right are the same.
1067 @retval FALSE Left and Right are the different.
1070 BmMatchHttpBootDevicePath (
1071 IN EFI_DEVICE_PATH_PROTOCOL
*Left
,
1072 IN EFI_DEVICE_PATH_PROTOCOL
*Right
1075 for (; !IsDevicePathEnd (Left
) && !IsDevicePathEnd (Right
)
1076 ; Left
= NextDevicePathNode (Left
), Right
= NextDevicePathNode (Right
)
1078 if (CompareMem (Left
, Right
, DevicePathNodeLength (Left
)) != 0) {
1079 if ((DevicePathType (Left
) != MESSAGING_DEVICE_PATH
) || (DevicePathType (Right
) != MESSAGING_DEVICE_PATH
)) {
1083 if (((DevicePathSubType (Left
) != MSG_IPv4_DP
) || (DevicePathSubType (Right
) != MSG_IPv4_DP
)) &&
1084 ((DevicePathSubType (Left
) != MSG_IPv6_DP
) || (DevicePathSubType (Right
) != MSG_IPv6_DP
)) &&
1085 ((DevicePathSubType (Left
) != MSG_URI_DP
) || (DevicePathSubType (Right
) != MSG_URI_DP
))
1091 return (BOOLEAN
) (IsDevicePathEnd (Left
) && IsDevicePathEnd (Right
));
1095 Get the file buffer from the file system produced by Load File instance.
1097 @param LoadFileHandle The handle of LoadFile instance.
1098 @param FullPath Return the full device path pointing to the load option.
1099 @param FileSize Return the size of the load option.
1100 @param RamDiskHandle Return the RAM Disk handle.
1102 @return The load option buffer.
1105 BmGetFileBufferFromLoadFileSystem (
1106 IN EFI_HANDLE LoadFileHandle
,
1107 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1108 OUT UINTN
*FileSize
,
1109 OUT EFI_HANDLE
*RamDiskHandle
1114 EFI_HANDLE
*Handles
;
1117 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1119 Status
= gBS
->LocateHandleBuffer (
1121 &gEfiBlockIoProtocolGuid
,
1126 if (EFI_ERROR (Status
)) {
1132 for (Index
= 0; Index
< HandleCount
; Index
++) {
1133 Node
= DevicePathFromHandle (Handles
[Index
]);
1134 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1135 if (!EFI_ERROR (Status
) &&
1136 (Handle
== LoadFileHandle
) &&
1137 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)) {
1138 Handle
= Handles
[Index
];
1143 if (Handles
!= NULL
) {
1147 if (Index
== HandleCount
) {
1151 *RamDiskHandle
= Handle
;
1153 if (Handle
!= NULL
) {
1154 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle
), FullPath
, FileSize
);
1162 Return the RAM Disk device path created by LoadFile.
1164 @param FilePath The source file path.
1166 @return Callee-to-free RAM Disk device path
1168 EFI_DEVICE_PATH_PROTOCOL
*
1169 BmGetRamDiskDevicePath (
1170 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
1174 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1175 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1179 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1180 if (!EFI_ERROR (Status
) &&
1181 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) &&
1182 (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)
1186 // Construct the device path pointing to RAM Disk
1188 Node
= NextDevicePathNode (Node
);
1189 RamDiskDevicePath
= DuplicateDevicePath (FilePath
);
1190 ASSERT (RamDiskDevicePath
!= NULL
);
1191 SetDevicePathEndNode ((VOID
*) ((UINTN
) RamDiskDevicePath
+ ((UINTN
) Node
- (UINTN
) FilePath
)));
1192 return RamDiskDevicePath
;
1199 Return the buffer and buffer size occupied by the RAM Disk.
1201 @param RamDiskDevicePath RAM Disk device path.
1202 @param RamDiskSizeInPages Return RAM Disk size in pages.
1204 @retval RAM Disk buffer.
1207 BmGetRamDiskMemoryInfo (
1208 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
,
1209 OUT UINTN
*RamDiskSizeInPages
1215 UINT64 StartingAddr
;
1218 ASSERT (RamDiskDevicePath
!= NULL
);
1220 *RamDiskSizeInPages
= 0;
1223 // Get the buffer occupied by RAM Disk.
1225 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &RamDiskDevicePath
, &Handle
);
1226 ASSERT_EFI_ERROR (Status
);
1227 ASSERT ((DevicePathType (RamDiskDevicePath
) == MEDIA_DEVICE_PATH
) &&
1228 (DevicePathSubType (RamDiskDevicePath
) == MEDIA_RAM_DISK_DP
));
1229 StartingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->StartingAddr
);
1230 EndingAddr
= ReadUnaligned64 ((UINT64
*) ((MEDIA_RAM_DISK_DEVICE_PATH
*) RamDiskDevicePath
)->EndingAddr
);
1231 *RamDiskSizeInPages
= EFI_SIZE_TO_PAGES ((UINTN
) (EndingAddr
- StartingAddr
+ 1));
1232 return (VOID
*) (UINTN
) StartingAddr
;
1236 Destroy the RAM Disk.
1238 The destroy operation includes to call RamDisk.Unregister to
1239 unregister the RAM DISK from RAM DISK driver, free the memory
1240 allocated for the RAM Disk.
1242 @param RamDiskDevicePath RAM Disk device path.
1246 IN EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
1250 VOID
*RamDiskBuffer
;
1251 UINTN RamDiskSizeInPages
;
1253 ASSERT (RamDiskDevicePath
!= NULL
);
1255 RamDiskBuffer
= BmGetRamDiskMemoryInfo (RamDiskDevicePath
, &RamDiskSizeInPages
);
1258 // Destroy RAM Disk.
1260 if (mRamDisk
== NULL
) {
1261 Status
= gBS
->LocateProtocol (&gEfiRamDiskProtocolGuid
, NULL
, (VOID
*) &mRamDisk
);
1262 ASSERT_EFI_ERROR (Status
);
1264 Status
= mRamDisk
->Unregister (RamDiskDevicePath
);
1265 ASSERT_EFI_ERROR (Status
);
1266 FreePages (RamDiskBuffer
, RamDiskSizeInPages
);
1270 Get the file buffer from the specified Load File instance.
1272 @param LoadFileHandle The specified Load File instance.
1273 @param FilePath The file path which will pass to LoadFile().
1274 @param FullPath Return the full device path pointing to the load option.
1275 @param FileSize Return the size of the load option.
1277 @return The load option buffer or NULL if fails.
1280 BmGetFileBufferFromLoadFile (
1281 IN EFI_HANDLE LoadFileHandle
,
1282 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1283 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1288 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1290 BOOLEAN LoadFileSystem
;
1291 EFI_HANDLE RamDiskHandle
;
1296 Status
= gBS
->OpenProtocol (
1298 &gEfiLoadFileProtocolGuid
,
1299 (VOID
**) &LoadFile
,
1302 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1304 ASSERT_EFI_ERROR (Status
);
1308 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1309 if ((Status
!= EFI_WARN_FILE_SYSTEM
) && (Status
!= EFI_BUFFER_TOO_SMALL
)) {
1313 LoadFileSystem
= (BOOLEAN
) (Status
== EFI_WARN_FILE_SYSTEM
);
1314 FileBuffer
= LoadFileSystem
? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize
)) : AllocatePool (BufferSize
);
1315 if (FileBuffer
== NULL
) {
1319 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1320 if (EFI_ERROR (Status
)) {
1321 if (LoadFileSystem
) {
1322 FreePages (FileBuffer
, EFI_SIZE_TO_PAGES (BufferSize
));
1324 FreePool (FileBuffer
);
1329 if (LoadFileSystem
) {
1330 FileBuffer
= BmGetFileBufferFromLoadFileSystem (LoadFileHandle
, FullPath
, FileSize
, &RamDiskHandle
);
1331 if (FileBuffer
== NULL
) {
1333 // If there is no bootable executable in the populated
1335 BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle
));
1338 *FileSize
= BufferSize
;
1339 *FullPath
= DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle
));
1346 Get the file buffer from all the Load File instances.
1348 @param FilePath The media device path pointing to a LoadFile instance.
1349 @param FullPath Return the full device path pointing to the load option.
1350 @param FileSize Return the size of the load option.
1352 @return The load option buffer.
1355 BmGetFileBufferFromLoadFiles (
1356 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1357 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1363 EFI_HANDLE
*Handles
;
1366 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1369 // Get file buffer from load file instance.
1372 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1373 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1375 // When wide match happens, pass full device path to LoadFile (),
1376 // otherwise, pass remaining device path to LoadFile ().
1382 // Use wide match algorithm to find one when
1383 // cannot find a LoadFile instance to exactly match the FilePath
1385 Status
= gBS
->LocateHandleBuffer (
1387 &gEfiLoadFileProtocolGuid
,
1392 if (EFI_ERROR (Status
)) {
1396 for (Index
= 0; Index
< HandleCount
; Index
++) {
1397 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
)) {
1398 Handle
= Handles
[Index
];
1402 if (Handles
!= NULL
) {
1407 if (Handle
== NULL
) {
1411 return BmGetFileBufferFromLoadFile (Handle
, FilePath
, FullPath
, FileSize
);
1415 Get the load option by its device path.
1417 @param FilePath The device path pointing to a load option.
1418 It could be a short-form device path.
1419 @param FullPath Return the full device path of the load option after
1420 short-form device path expanding.
1421 Caller is responsible to free it.
1422 @param FileSize Return the load option size.
1424 @return The load option buffer. Caller is responsible to free the memory.
1427 BmGetLoadOptionBuffer (
1428 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1429 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1435 UINT32 AuthenticationStatus
;
1436 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1439 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1441 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1448 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1451 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1452 if (EFI_ERROR (Status
)) {
1453 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1456 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1457 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1461 // Expand the short-form device path to full device path
1463 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1464 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1466 // Expand the Harddrive device path
1468 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1469 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1470 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
)) {
1472 // Expand the File-path device path
1474 return BmExpandFileDevicePath (FilePath
, FullPath
, FileSize
);
1475 } else if ((DevicePathType (FilePath
) == MESSAGING_DEVICE_PATH
) &&
1476 (DevicePathSubType (FilePath
) == MSG_URI_DP
)) {
1478 // Expand the URI device path
1480 return BmExpandUriDevicePath (FilePath
, FullPath
, FileSize
);
1482 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1483 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1484 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1489 if (!IsDevicePathEnd (Node
)) {
1491 // Expand the USB WWID/Class device path
1493 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1494 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1496 // Boot Option device path starts with USB Class or USB WWID device path.
1497 // For Boot Option device path which doesn't begin with the USB Class or
1498 // USB WWID device path, it's not needed to connect again here.
1500 BmConnectUsbShortFormDevicePath (FilePath
);
1501 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1508 // Get file buffer from FV file path.
1510 if (BmIsFvFilePath (FilePath
)) {
1511 return BmGetFileBufferByFvFilePath (FilePath
, FullPath
, FileSize
);
1515 // Get file buffer from simple file system.
1518 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1519 if (!EFI_ERROR (Status
)) {
1520 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1521 if (FileBuffer
!= NULL
) {
1522 *FullPath
= DuplicateDevicePath (FilePath
);
1527 return BmGetFileBufferFromLoadFiles (FilePath
, FullPath
, FileSize
);
1531 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1532 also signals the EFI ready to boot event. If the device path for the option
1533 starts with a BBS device path a legacy boot is attempted via the registered
1534 gLegacyBoot function. Short form device paths are also supported via this
1535 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1536 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1537 If the BootOption Device Path fails the removable media boot algorithm
1538 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1539 is tried per processor type)
1541 @param BootOption Boot Option to try and boot.
1542 On return, BootOption->Status contains the boot status.
1543 EFI_SUCCESS BootOption was booted
1544 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1545 registered via EfiBootManagerInitialize().
1546 EFI_NOT_FOUND The BootOption was not found on the system
1547 !EFI_SUCCESS BootOption failed with this error status
1552 EfiBootManagerBoot (
1553 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1557 EFI_HANDLE ImageHandle
;
1558 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1561 UINTN OriginalOptionNumber
;
1562 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1563 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1564 EFI_DEVICE_PATH_PROTOCOL
*RamDiskDevicePath
;
1565 EFI_HANDLE FvHandle
;
1568 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1569 EFI_EVENT LegacyBootEvent
;
1571 if (BootOption
== NULL
) {
1575 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1576 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1581 // 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")
1583 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1584 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1585 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1586 if (!EFI_ERROR (Status
)) {
1588 // Save the BootOption->OptionNumber to restore later
1590 OptionNumber
= Uint16
;
1591 OriginalOptionNumber
= BootOption
->OptionNumber
;
1592 BootOption
->OptionNumber
= OptionNumber
;
1593 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1594 BootOption
->OptionNumber
= OriginalOptionNumber
;
1597 if (EFI_ERROR (Status
)) {
1598 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1599 BootOption
->Status
= Status
;
1605 // 2. Set BootCurrent
1607 Uint16
= (UINT16
) OptionNumber
;
1608 BmSetVariableAndReportStatusCodeOnError (
1610 &gEfiGlobalVariableGuid
,
1611 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1617 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1620 Node
= BootOption
->FilePath
;
1621 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1622 if (!EFI_ERROR (Status
) && CompareGuid (
1623 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1624 PcdGetPtr (PcdBootManagerMenuFile
)
1626 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1627 BmStopHotkeyService (NULL
, NULL
);
1629 EfiSignalEventReadyToBoot();
1631 // Report Status Code to indicate ReadyToBoot was signalled
1633 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1635 // 4. Repair system through DriverHealth protocol
1637 BmRepairAllControllers ();
1640 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1643 // 5. Load EFI boot option to ImageHandle
1646 RamDiskDevicePath
= NULL
;
1647 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1648 Status
= EFI_NOT_FOUND
;
1649 FileBuffer
= BmGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1650 if (FileBuffer
!= NULL
) {
1651 RamDiskDevicePath
= BmGetRamDiskDevicePath (FilePath
);
1654 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1655 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1656 BmPrintDp (BootOption
->FilePath
);
1657 DEBUG ((EFI_D_INFO
, " -> "));
1658 BmPrintDp (FilePath
);
1659 DEBUG ((EFI_D_INFO
, "\n"));
1662 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1663 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1664 Status
= gBS
->LoadImage (
1673 if (FileBuffer
!= NULL
) {
1674 FreePool (FileBuffer
);
1676 if (FilePath
!= NULL
) {
1677 FreePool (FilePath
);
1680 if (EFI_ERROR (Status
)) {
1682 // Report Status Code to indicate that the failure to load boot option
1684 REPORT_STATUS_CODE (
1685 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1686 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1688 BootOption
->Status
= Status
;
1690 // Destroy the RAM disk
1692 if (RamDiskDevicePath
!= NULL
) {
1693 BmDestroyRamDisk (RamDiskDevicePath
);
1694 FreePool (RamDiskDevicePath
);
1701 // 6. Adjust the different type memory page number just before booting
1702 // and save the updated info into the variable for next boot to use
1704 BmSetMemoryTypeInformationVariable (
1705 (BOOLEAN
) ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1709 if (BootOption
->Description
== NULL
) {
1710 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1712 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1717 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1718 // Write boot to OS performance data for Legacy boot
1720 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1721 if (mBmLegacyBoot
!= NULL
) {
1723 // Write boot to OS performance data for legacy boot.
1727 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1729 Status
= EfiCreateEventLegacyBootEx(
1731 BmWriteBootToOsPerformanceData
,
1735 ASSERT_EFI_ERROR (Status
);
1738 mBmLegacyBoot (BootOption
);
1740 BootOption
->Status
= EFI_UNSUPPORTED
;
1743 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1748 // Provide the image with its load options
1750 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1751 ASSERT_EFI_ERROR (Status
);
1753 if (!BmIsAutoCreateBootOption (BootOption
)) {
1754 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1755 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1759 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1761 ImageInfo
->ParentHandle
= NULL
;
1764 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1766 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1769 // Write boot to OS performance data for UEFI boot
1772 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1775 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1777 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1778 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1779 BootOption
->Status
= Status
;
1780 if (EFI_ERROR (Status
)) {
1782 // Report Status Code to indicate that boot failure
1784 REPORT_STATUS_CODE (
1785 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1786 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1789 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1792 // Destroy the RAM disk
1794 if (RamDiskDevicePath
!= NULL
) {
1795 BmDestroyRamDisk (RamDiskDevicePath
);
1796 FreePool (RamDiskDevicePath
);
1800 // Clear the Watchdog Timer after the image returns
1802 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1805 // Set Logo status invalid after trying one boot option
1808 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1809 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1810 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1811 ASSERT_EFI_ERROR (Status
);
1815 // Clear Boot Current
1817 Status
= gRT
->SetVariable (
1819 &gEfiGlobalVariableGuid
,
1825 // Deleting variable with current variable implementation shouldn't fail.
1826 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1827 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1829 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1833 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1834 instances, has the same partition node with HardDriveDevicePath device path
1836 @param BlockIoDevicePath Multi device path instances which need to check
1837 @param HardDriveDevicePath A device path which starts with a hard drive media
1840 @retval TRUE There is a matched device path instance.
1841 @retval FALSE There is no matched device path instance.
1845 BmMatchPartitionDevicePathNode (
1846 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1847 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1850 HARDDRIVE_DEVICE_PATH
*Node
;
1852 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1857 // find the partition device path node
1859 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1860 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1861 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1866 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1869 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1874 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1876 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1879 // Match Signature and PartitionNumber.
1880 // Unused bytes in Signature are initiaized with zeros.
1883 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1884 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1885 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1886 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1891 Emuerate all possible bootable medias in the following order:
1892 1. Removable BlockIo - The boot option only points to the removable media
1893 device, like USB key, DVD, Floppy etc.
1894 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1896 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1897 SimpleFileSystem Protocol, but not supporting BlockIo
1899 4. LoadFile - The boot option points to the media supporting
1901 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1903 @param BootOptionCount Return the boot option count which has been found.
1905 @retval Pointer to the boot option array.
1907 EFI_BOOT_MANAGER_LOAD_OPTION
*
1908 BmEnumerateBootOptions (
1909 UINTN
*BootOptionCount
1913 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1915 EFI_HANDLE
*Handles
;
1916 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
1919 CHAR16
*Description
;
1921 ASSERT (BootOptionCount
!= NULL
);
1923 *BootOptionCount
= 0;
1927 // Parse removable block io followed by fixed block io
1929 gBS
->LocateHandleBuffer (
1931 &gEfiBlockIoProtocolGuid
,
1937 for (Removable
= 0; Removable
< 2; Removable
++) {
1938 for (Index
= 0; Index
< HandleCount
; Index
++) {
1939 Status
= gBS
->HandleProtocol (
1941 &gEfiBlockIoProtocolGuid
,
1944 if (EFI_ERROR (Status
)) {
1949 // Skip the logical partitions
1951 if (BlkIo
->Media
->LogicalPartition
) {
1956 // Skip the fixed block io then the removable block io
1958 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
1962 Description
= BmGetBootDescription (Handles
[Index
]);
1963 BootOptions
= ReallocatePool (
1964 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1965 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1968 ASSERT (BootOptions
!= NULL
);
1970 Status
= EfiBootManagerInitializeLoadOption (
1971 &BootOptions
[(*BootOptionCount
)++],
1972 LoadOptionNumberUnassigned
,
1976 DevicePathFromHandle (Handles
[Index
]),
1980 ASSERT_EFI_ERROR (Status
);
1982 FreePool (Description
);
1986 if (HandleCount
!= 0) {
1991 // Parse simple file system not based on block io
1993 gBS
->LocateHandleBuffer (
1995 &gEfiSimpleFileSystemProtocolGuid
,
2000 for (Index
= 0; Index
< HandleCount
; Index
++) {
2001 Status
= gBS
->HandleProtocol (
2003 &gEfiBlockIoProtocolGuid
,
2006 if (!EFI_ERROR (Status
)) {
2008 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2012 Description
= BmGetBootDescription (Handles
[Index
]);
2013 BootOptions
= ReallocatePool (
2014 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2015 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2018 ASSERT (BootOptions
!= NULL
);
2020 Status
= EfiBootManagerInitializeLoadOption (
2021 &BootOptions
[(*BootOptionCount
)++],
2022 LoadOptionNumberUnassigned
,
2026 DevicePathFromHandle (Handles
[Index
]),
2030 ASSERT_EFI_ERROR (Status
);
2031 FreePool (Description
);
2034 if (HandleCount
!= 0) {
2039 // Parse load file, assuming UEFI Network boot option
2041 gBS
->LocateHandleBuffer (
2043 &gEfiLoadFileProtocolGuid
,
2048 for (Index
= 0; Index
< HandleCount
; Index
++) {
2050 Description
= BmGetBootDescription (Handles
[Index
]);
2051 BootOptions
= ReallocatePool (
2052 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
2053 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
2056 ASSERT (BootOptions
!= NULL
);
2058 Status
= EfiBootManagerInitializeLoadOption (
2059 &BootOptions
[(*BootOptionCount
)++],
2060 LoadOptionNumberUnassigned
,
2064 DevicePathFromHandle (Handles
[Index
]),
2068 ASSERT_EFI_ERROR (Status
);
2069 FreePool (Description
);
2072 if (HandleCount
!= 0) {
2076 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
2081 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2085 EfiBootManagerRefreshAllBootOption (
2090 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
2091 UINTN NvBootOptionCount
;
2092 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2093 UINTN BootOptionCount
;
2097 // Optionally refresh the legacy boot option
2099 if (mBmRefreshLegacyBootOption
!= NULL
) {
2100 mBmRefreshLegacyBootOption ();
2103 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
2104 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
2107 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2109 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2110 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
2111 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
2115 // Remove invalid EFI boot options from NV
2117 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
2118 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
2119 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
2120 ) && BmIsAutoCreateBootOption (&NvBootOptions
[Index
])
2123 // Only check those added by BDS
2124 // so that the boot options added by end-user or OS installer won't be deleted
2126 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
2127 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2129 // Deleting variable with current variable implementation shouldn't fail.
2131 ASSERT_EFI_ERROR (Status
);
2137 // Add new EFI boot options to NV
2139 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2140 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
2141 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2143 // Try best to add the boot options so continue upon failure.
2148 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2149 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2153 This function is called to create the boot option for the Boot Manager Menu.
2155 The Boot Manager Menu is shown after successfully booting a boot option.
2156 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2158 @param BootOption Return the boot option of the Boot Manager Menu
2160 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2161 @retval Status Return status of gRT->SetVariable (). BootOption still points
2162 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2165 BmRegisterBootManagerMenu (
2166 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2170 CHAR16
*Description
;
2171 UINTN DescriptionLength
;
2172 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2173 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2174 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2176 Status
= GetSectionFromFv (
2177 PcdGetPtr (PcdBootManagerMenuFile
),
2178 EFI_SECTION_USER_INTERFACE
,
2180 (VOID
**) &Description
,
2183 if (EFI_ERROR (Status
)) {
2187 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2188 Status
= gBS
->HandleProtocol (
2190 &gEfiLoadedImageProtocolGuid
,
2191 (VOID
**) &LoadedImage
2193 ASSERT_EFI_ERROR (Status
);
2194 DevicePath
= AppendDevicePathNode (
2195 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2196 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2198 ASSERT (DevicePath
!= NULL
);
2200 Status
= EfiBootManagerInitializeLoadOption (
2202 LoadOptionNumberUnassigned
,
2204 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2205 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2210 ASSERT_EFI_ERROR (Status
);
2211 FreePool (DevicePath
);
2212 if (Description
!= NULL
) {
2213 FreePool (Description
);
2217 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2218 UINTN BootOptionCount
;
2220 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2221 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2222 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2225 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2229 Return the boot option corresponding to the Boot Manager Menu.
2230 It may automatically create one if the boot option hasn't been created yet.
2232 @param BootOption Return the Boot Manager Menu.
2234 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2235 @retval Status Return status of gRT->SetVariable (). BootOption still points
2236 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2240 EfiBootManagerGetBootManagerMenu (
2241 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2245 UINTN BootOptionCount
;
2246 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2248 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2249 EFI_HANDLE FvHandle
;
2251 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2253 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2254 Node
= BootOptions
[Index
].FilePath
;
2255 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2256 if (!EFI_ERROR (Status
)) {
2258 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2259 PcdGetPtr (PcdBootManagerMenuFile
)
2262 Status
= EfiBootManagerInitializeLoadOption (
2264 BootOptions
[Index
].OptionNumber
,
2265 BootOptions
[Index
].OptionType
,
2266 BootOptions
[Index
].Attributes
,
2267 BootOptions
[Index
].Description
,
2268 BootOptions
[Index
].FilePath
,
2269 BootOptions
[Index
].OptionalData
,
2270 BootOptions
[Index
].OptionalDataSize
2272 ASSERT_EFI_ERROR (Status
);
2278 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2281 // Automatically create the Boot#### for Boot Manager Menu when not found.
2283 if (Index
== BootOptionCount
) {
2284 return BmRegisterBootManagerMenu (BootOption
);