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_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption
= NULL
;
19 EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot
= NULL
;
22 /// This GUID is used for an EFI Variable that stores the front device pathes
23 /// for a partial device path that starts with the HD node.
25 EFI_GUID mBmHardDriveBootVariableGuid
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
26 EFI_GUID mBmAutoCreateBootOptionGuid
= { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
29 The function registers the legacy boot support capabilities.
31 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
32 @param LegacyBoot The function pointer to boot the legacy boot option.
36 EfiBootManagerRegisterLegacyBootSupport (
37 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption
,
38 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
41 mBmRefreshLegacyBootOption
= RefreshLegacyBootOption
;
42 mBmLegacyBoot
= LegacyBoot
;
46 Return TRUE when the boot option is auto-created instead of manually added.
48 @param BootOption Pointer to the boot option to check.
50 @retval TRUE The boot option is auto-created.
51 @retval FALSE The boot option is manually added.
54 BmIsAutoCreateBootOption (
55 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
58 if ((BootOption
->OptionalDataSize
== sizeof (EFI_GUID
)) &&
59 CompareGuid ((EFI_GUID
*) BootOption
->OptionalData
, &mBmAutoCreateBootOptionGuid
)
68 Find the boot option in the NV storage and return the option number.
70 @param OptionToFind Boot option to be checked.
72 @return The option number of the found boot option.
76 BmFindBootOptionInVariable (
77 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
81 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
83 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
84 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
85 UINTN BootOptionCount
;
88 OptionNumber
= LoadOptionNumberUnassigned
;
91 // Try to match the variable exactly if the option number is assigned
93 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
95 OptionName
, sizeof (OptionName
), L
"%s%04x",
96 mBmLoadOptionName
[OptionToFind
->OptionType
], OptionToFind
->OptionNumber
98 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
100 if (!EFI_ERROR (Status
)) {
101 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
102 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
103 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
104 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
105 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
106 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
108 OptionNumber
= OptionToFind
->OptionNumber
;
110 EfiBootManagerFreeLoadOption (&BootOption
);
115 // The option number assigned is either incorrect or unassigned.
117 if (OptionNumber
== LoadOptionNumberUnassigned
) {
118 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
120 Index
= EfiBootManagerFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
122 OptionNumber
= BootOptions
[Index
].OptionNumber
;
125 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
132 Get the file buffer using a Memory Mapped Device Path.
134 FV address may change across reboot. This routine promises the FV file device path is right.
136 @param FilePath The Memory Mapped Device Path to get the file buffer.
137 @param FullPath Receive the updated FV Device Path pointint to the file.
138 @param FileSize Receive the file buffer size.
140 @return The file buffer.
143 BmGetFileBufferByFvFilePath (
144 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
145 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
151 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
153 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
154 UINT32 AuthenticationStatus
;
156 EFI_HANDLE
*FvHandles
;
157 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
161 // Get the file buffer by using the exactly FilePath.
163 FvFileNode
= FilePath
;
164 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
165 if (!EFI_ERROR (Status
)) {
166 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
167 if (FileBuffer
!= NULL
) {
168 *FullPath
= DuplicateDevicePath (FilePath
);
174 // Only wide match other FVs if it's a memory mapped FV file path.
176 if ((DevicePathType (FilePath
) != HARDWARE_DEVICE_PATH
) || (DevicePathSubType (FilePath
) != HW_MEMMAP_DP
)) {
180 FvFileNode
= NextDevicePathNode (FilePath
);
183 // Firstly find the FV file in current FV
185 gBS
->HandleProtocol (
187 &gEfiLoadedImageProtocolGuid
,
188 (VOID
**) &LoadedImage
190 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
191 FileBuffer
= BmGetFileBufferByFvFilePath (NewDevicePath
, FullPath
, FileSize
);
192 FreePool (NewDevicePath
);
194 if (FileBuffer
!= NULL
) {
199 // Secondly find the FV file in all other FVs
201 gBS
->LocateHandleBuffer (
203 &gEfiFirmwareVolume2ProtocolGuid
,
208 for (Index
= 0; (Index
< FvHandleCount
) && (FileBuffer
== NULL
); Index
++) {
209 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
215 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
216 FileBuffer
= BmGetFileBufferByFvFilePath (NewDevicePath
, FullPath
, FileSize
);
217 FreePool (NewDevicePath
);
220 if (FvHandles
!= NULL
) {
221 FreePool (FvHandles
);
227 Check if it's a Device Path pointing to FV file.
229 The function doesn't garentee the device path points to existing FV file.
231 @param DevicePath Input device path.
233 @retval TRUE The device path is a FV File Device Path.
234 @retval FALSE The device path is NOT a FV File Device Path.
238 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
243 EFI_DEVICE_PATH_PROTOCOL
*Node
;
246 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &Handle
);
247 if (!EFI_ERROR (Status
)) {
251 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
252 DevicePath
= NextDevicePathNode (DevicePath
);
253 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == MEDIA_PIWG_FW_FILE_DP
)) {
254 return IsDevicePathEnd (NextDevicePathNode (DevicePath
));
261 Check whether a USB device match the specified USB Class device path. This
262 function follows "Load Option Processing" behavior in UEFI specification.
264 @param UsbIo USB I/O protocol associated with the USB device.
265 @param UsbClass The USB Class device path to match.
267 @retval TRUE The USB device match the USB Class device path.
268 @retval FALSE The USB device does not match the USB Class device path.
273 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
274 IN USB_CLASS_DEVICE_PATH
*UsbClass
278 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
279 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
281 UINT8 DeviceSubClass
;
282 UINT8 DeviceProtocol
;
284 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
285 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
290 // Check Vendor Id and Product Id.
292 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
293 if (EFI_ERROR (Status
)) {
297 if ((UsbClass
->VendorId
!= 0xffff) &&
298 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
302 if ((UsbClass
->ProductId
!= 0xffff) &&
303 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
307 DeviceClass
= DevDesc
.DeviceClass
;
308 DeviceSubClass
= DevDesc
.DeviceSubClass
;
309 DeviceProtocol
= DevDesc
.DeviceProtocol
;
310 if (DeviceClass
== 0) {
312 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
313 // Protocol in Interface Descriptor instead.
315 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
316 if (EFI_ERROR (Status
)) {
320 DeviceClass
= IfDesc
.InterfaceClass
;
321 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
322 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
326 // Check Class, SubClass and Protocol.
328 if ((UsbClass
->DeviceClass
!= 0xff) &&
329 (UsbClass
->DeviceClass
!= DeviceClass
)) {
333 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
334 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
338 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
339 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
347 Check whether a USB device match the specified USB WWID device path. This
348 function follows "Load Option Processing" behavior in UEFI specification.
350 @param UsbIo USB I/O protocol associated with the USB device.
351 @param UsbWwid The USB WWID device path to match.
353 @retval TRUE The USB device match the USB WWID device path.
354 @retval FALSE The USB device does not match the USB WWID device path.
359 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
360 IN USB_WWID_DEVICE_PATH
*UsbWwid
364 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
365 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
371 CHAR16
*SerialNumberStr
;
374 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
375 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
380 // Check Vendor Id and Product Id.
382 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
383 if (EFI_ERROR (Status
)) {
386 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
387 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
392 // Check Interface Number.
394 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
395 if (EFI_ERROR (Status
)) {
398 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
403 // Check Serial Number.
405 if (DevDesc
.StrSerialNumber
== 0) {
410 // Get all supported languages.
414 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
415 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
420 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
422 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
423 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
424 if (CompareStr
[CompareLen
- 1] == L
'\0') {
429 // Compare serial number in each supported language.
431 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
432 SerialNumberStr
= NULL
;
433 Status
= UsbIo
->UsbGetStringDescriptor (
436 DevDesc
.StrSerialNumber
,
439 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
443 Length
= StrLen (SerialNumberStr
);
444 if ((Length
>= CompareLen
) &&
445 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
446 FreePool (SerialNumberStr
);
450 FreePool (SerialNumberStr
);
457 Find a USB device which match the specified short-form device path start with
458 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
459 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
460 this function will only search in its child devices.
462 @param DevicePath The device path that contains USB Class or USB WWID device path.
463 @param ParentDevicePathSize The length of the device path before the USB Class or
464 USB WWID device path.
465 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
467 @retval NULL The matched USB IO handles cannot be found.
468 @retval other The matched USB IO handles.
473 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
474 IN UINTN ParentDevicePathSize
,
475 OUT UINTN
*UsbIoHandleCount
479 EFI_HANDLE
*UsbIoHandles
;
480 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
481 EFI_USB_IO_PROTOCOL
*UsbIo
;
485 ASSERT (UsbIoHandleCount
!= NULL
);
488 // Get all UsbIo Handles.
490 Status
= gBS
->LocateHandleBuffer (
492 &gEfiUsbIoProtocolGuid
,
497 if (EFI_ERROR (Status
)) {
498 *UsbIoHandleCount
= 0;
502 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
504 // Get the Usb IO interface.
506 Status
= gBS
->HandleProtocol(
508 &gEfiUsbIoProtocolGuid
,
511 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
513 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
516 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
518 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
519 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
520 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
527 (*UsbIoHandleCount
) --;
528 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
538 Expand USB Class or USB WWID device path node to be full device path of a USB
541 This function support following 4 cases:
542 1) Boot Option device path starts with a USB Class or USB WWID device path,
543 and there is no Media FilePath device path in the end.
544 In this case, it will follow Removable Media Boot Behavior.
545 2) Boot Option device path starts with a USB Class or USB WWID device path,
546 and ended with Media FilePath device path.
547 3) Boot Option device path starts with a full device path to a USB Host Controller,
548 contains a USB Class or USB WWID device path node, while not ended with Media
549 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
550 4) Boot Option device path starts with a full device path to a USB Host Controller,
551 contains a USB Class or USB WWID device path node, and ended with Media
552 FilePath device path.
554 @param FilePath The device path pointing to a load option.
555 It could be a short-form device path.
556 @param FullPath Return the full device path of the load option after
557 short-form device path expanding.
558 Caller is responsible to free it.
559 @param FileSize Return the load option size.
560 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
562 @return The load option buffer. Caller is responsible to free the memory.
565 BmExpandUsbDevicePath (
566 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
567 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
569 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
572 UINTN ParentDevicePathSize
;
573 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
574 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
580 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
581 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
583 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
585 for (Index
= 0; (Index
< HandleCount
) && (FileBuffer
== NULL
); Index
++) {
586 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
587 FileBuffer
= BmGetLoadOptionBuffer (FullDevicePath
, FullPath
, FileSize
);
588 FreePool (FullDevicePath
);
591 if (Handles
!= NULL
) {
599 Expand File-path device path node to be full device path in platform.
601 @param FilePath The device path pointing to a load option.
602 It could be a short-form device path.
603 @param FullPath Return the full device path of the load option after
604 short-form device path expanding.
605 Caller is responsible to free it.
606 @param FileSize Return the load option size.
608 @return The load option buffer. Caller is responsible to free the memory.
611 BmExpandFileDevicePath (
612 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
613 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
621 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
623 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
625 UINT32 AuthenticationStatus
;
627 EfiBootManagerConnectAll ();
628 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &HandleCount
, &Handles
);
629 if (EFI_ERROR (Status
)) {
635 // Enumerate all removable media devices followed by all fixed media devices,
636 // followed by media devices which don't layer on block io.
638 for (MediaType
= 0; MediaType
< 3; MediaType
++) {
639 for (Index
= 0; Index
< HandleCount
; Index
++) {
640 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiBlockIoProtocolGuid
, (VOID
*) &BlockIo
);
641 if (EFI_ERROR (Status
)) {
644 if ((MediaType
== 0 && BlockIo
!= NULL
&& BlockIo
->Media
->RemovableMedia
) ||
645 (MediaType
== 1 && BlockIo
!= NULL
&& !BlockIo
->Media
->RemovableMedia
) ||
646 (MediaType
== 2 && BlockIo
== NULL
)
648 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
);
649 FileBuffer
= GetFileBufferByFilePath (TRUE
, FullDevicePath
, FileSize
, &AuthenticationStatus
);
650 if (FileBuffer
!= NULL
) {
651 *FullPath
= FullDevicePath
;
655 FreePool (FullDevicePath
);
660 if (Handles
!= NULL
) {
669 Expand URI device path node to be full device path in platform.
671 @param FilePath The device path pointing to a load option.
672 It could be a short-form device path.
673 @param FullPath Return the full device path of the load option after
674 short-form device path expanding.
675 Caller is responsible to free it.
676 @param FileSize Return the load option size.
678 @return The load option buffer. Caller is responsible to free the memory.
681 BmExpandUriDevicePath (
682 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
683 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
693 EfiBootManagerConnectAll ();
694 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &HandleCount
, &Handles
);
695 if (EFI_ERROR (Status
)) {
700 for (Index
= 0; Index
< HandleCount
; Index
++) {
701 FileBuffer
= BmGetFileBufferFromLoadFile (Handles
[Index
], FilePath
, FullPath
, FileSize
);
702 if (FileBuffer
!= NULL
) {
707 if (Handles
!= NULL
) {
715 Save the partition DevicePath to the CachedDevicePath as the first instance.
717 @param CachedDevicePath The device path cache.
718 @param DevicePath The partition device path to be cached.
721 BmCachePartitionDevicePath (
722 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
723 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
726 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
729 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
730 TempDevicePath
= *CachedDevicePath
;
731 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
732 FreePool (TempDevicePath
);
735 if (*CachedDevicePath
== NULL
) {
736 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
740 TempDevicePath
= *CachedDevicePath
;
741 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
742 if (TempDevicePath
!= NULL
) {
743 FreePool (TempDevicePath
);
747 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
748 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
751 TempDevicePath
= *CachedDevicePath
;
752 while (!IsDevicePathEnd (TempDevicePath
)) {
753 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
755 // Parse one instance
757 while (!IsDevicePathEndType (TempDevicePath
)) {
758 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
762 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
765 SetDevicePathEndNode (TempDevicePath
);
772 Expand a device path that starts with a hard drive media device path node to be a
773 full device path that includes the full hardware path to the device. We need
774 to do this so it can be booted. As an optimization the front match (the part point
775 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
776 so a connect all is not required on every boot. All successful history device path
777 which point to partition node (the front part) will be saved.
779 @param FilePath The device path pointing to a load option.
780 It could be a short-form device path.
781 @param FullPath Return the full device path of the load option after
782 short-form device path expanding.
783 Caller is responsible to free it.
784 @param FileSize Return the load option size.
786 @return The load option buffer. Caller is responsible to free the memory.
789 BmExpandPartitionDevicePath (
790 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
791 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
796 UINTN BlockIoHandleCount
;
797 EFI_HANDLE
*BlockIoBuffer
;
799 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
801 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
802 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
803 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
804 UINTN CachedDevicePathSize
;
806 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
811 // Check if there is prestore 'HDDP' variable.
812 // If exist, search the front path which point to partition node in the variable instants.
813 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
815 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
818 // Delete the invalid 'HDDP' variable.
820 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
821 FreePool (CachedDevicePath
);
822 CachedDevicePath
= NULL
;
823 Status
= gRT
->SetVariable (
825 &mBmHardDriveBootVariableGuid
,
830 ASSERT_EFI_ERROR (Status
);
833 if (CachedDevicePath
!= NULL
) {
834 TempNewDevicePath
= CachedDevicePath
;
838 // Check every instance of the variable
839 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
840 // partial partition boot option. Second, check whether the instance could be connected.
842 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
843 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
845 // Connect the device path instance, the device path point to hard drive media device path node
846 // e.g. ACPI() /PCI()/ATA()/Partition()
848 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
849 if (!EFI_ERROR (Status
)) {
850 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
851 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
852 FreePool (TempDevicePath
);
854 if (FileBuffer
!= NULL
) {
856 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
859 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
861 // Save the matching Device Path so we don't need to do a connect all next time
862 // Failing to save only impacts performance next time expanding the short-form device path
864 Status
= gRT
->SetVariable (
866 &mBmHardDriveBootVariableGuid
,
867 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
868 GetDevicePathSize (CachedDevicePath
),
874 FreePool (CachedDevicePath
);
880 // Come here means the first instance is not matched
884 } while (TempNewDevicePath
!= NULL
);
888 // If we get here we fail to find or 'HDDP' not exist, and now we need
889 // to search all devices in the system for a matched partition
891 EfiBootManagerConnectAll ();
892 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
893 if (EFI_ERROR (Status
)) {
894 BlockIoHandleCount
= 0;
895 BlockIoBuffer
= NULL
;
898 // Loop through all the device handles that support the BLOCK_IO Protocol
900 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
901 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
902 if (BlockIoDevicePath
== NULL
) {
906 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
908 // Find the matched partition device path
910 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
911 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
912 FreePool (TempDevicePath
);
914 if (FileBuffer
!= NULL
) {
915 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
918 // Save the matching Device Path so we don't need to do a connect all next time
919 // Failing to save only impacts performance next time expanding the short-form device path
921 Status
= gRT
->SetVariable (
923 &mBmHardDriveBootVariableGuid
,
924 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
925 GetDevicePathSize (CachedDevicePath
),
934 if (CachedDevicePath
!= NULL
) {
935 FreePool (CachedDevicePath
);
937 if (BlockIoBuffer
!= NULL
) {
938 FreePool (BlockIoBuffer
);
944 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
945 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
947 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
948 @param FullPath Return the full device path pointing to the load option.
949 @param FileSize Return the size of the load option.
951 @return The load option buffer.
954 BmExpandMediaDevicePath (
955 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
956 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
962 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
964 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
967 EFI_HANDLE
*SimpleFileSystemHandles
;
968 UINTN NumberSimpleFileSystemHandles
;
971 UINT32 AuthenticationStatus
;
974 // Check whether the device is connected
976 TempDevicePath
= DevicePath
;
977 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
978 if (!EFI_ERROR (Status
)) {
979 ASSERT (IsDevicePathEnd (TempDevicePath
));
981 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
982 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
983 if (FileBuffer
== NULL
) {
984 FreePool (TempDevicePath
);
985 TempDevicePath
= NULL
;
987 *FullPath
= TempDevicePath
;
992 // For device boot option only pointing to the removable device handle,
993 // should make sure all its children handles (its child partion or media handles) are created and connected.
995 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
998 // Issue a dummy read to the device to check for media change.
999 // When the removable media is changed, any Block IO read/write will
1000 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1001 // returned. After the Block IO protocol is reinstalled, subsequent
1002 // Block IO read/write will success.
1004 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1005 ASSERT_EFI_ERROR (Status
);
1006 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1007 ASSERT_EFI_ERROR (Status
);
1008 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1009 if (Buffer
!= NULL
) {
1010 BlockIo
->ReadBlocks (
1012 BlockIo
->Media
->MediaId
,
1014 BlockIo
->Media
->BlockSize
,
1021 // Detect the the default boot file from removable Media
1025 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1026 gBS
->LocateHandleBuffer (
1028 &gEfiSimpleFileSystemProtocolGuid
,
1030 &NumberSimpleFileSystemHandles
,
1031 &SimpleFileSystemHandles
1033 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1035 // Get the device path size of SimpleFileSystem handle
1037 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1038 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1040 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1042 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1043 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1044 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1045 if (FileBuffer
!= NULL
) {
1046 *FullPath
= TempDevicePath
;
1049 FreePool (TempDevicePath
);
1053 if (SimpleFileSystemHandles
!= NULL
) {
1054 FreePool (SimpleFileSystemHandles
);
1061 Check whether Left and Right are the same without matching the specific
1062 device path data in IP device path and URI device path node.
1064 @retval TRUE Left and Right are the same.
1065 @retval FALSE Left and Right are the different.
1068 BmMatchHttpBootDevicePath (
1069 IN EFI_DEVICE_PATH_PROTOCOL
*Left
,
1070 IN EFI_DEVICE_PATH_PROTOCOL
*Right
1073 for (; !IsDevicePathEnd (Left
) && !IsDevicePathEnd (Right
)
1074 ; Left
= NextDevicePathNode (Left
), Right
= NextDevicePathNode (Right
)
1076 if (CompareMem (Left
, Right
, DevicePathNodeLength (Left
)) != 0) {
1077 if ((DevicePathType (Left
) != MESSAGING_DEVICE_PATH
) || (DevicePathType (Right
) != MESSAGING_DEVICE_PATH
)) {
1081 if (((DevicePathSubType (Left
) != MSG_IPv4_DP
) || (DevicePathSubType (Right
) != MSG_IPv4_DP
)) &&
1082 ((DevicePathSubType (Left
) != MSG_IPv6_DP
) || (DevicePathSubType (Right
) != MSG_IPv6_DP
)) &&
1083 ((DevicePathSubType (Left
) != MSG_URI_DP
) || (DevicePathSubType (Right
) != MSG_URI_DP
))
1089 return (BOOLEAN
) (IsDevicePathEnd (Left
) && IsDevicePathEnd (Right
));
1093 Get the file buffer from the file system produced by Load File instance.
1095 @param LoadFileHandle The handle of LoadFile instance.
1096 @param FullPath Return the full device path pointing to the load option.
1097 @param FileSize Return the size of the load option.
1099 @return The load option buffer.
1102 BmGetFileBufferFromLoadFileSystem (
1103 IN EFI_HANDLE LoadFileHandle
,
1104 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1110 EFI_HANDLE
*Handles
;
1113 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1115 Status
= gBS
->LocateHandleBuffer (
1117 &gEfiBlockIoProtocolGuid
,
1122 if (EFI_ERROR (Status
)) {
1128 for (Index
= 0; Index
< HandleCount
; Index
++) {
1129 Node
= DevicePathFromHandle (Handles
[Index
]);
1130 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1131 if (!EFI_ERROR (Status
) &&
1132 (Handle
== LoadFileHandle
) &&
1133 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)) {
1134 Handle
= Handles
[Index
];
1139 if (Handles
!= NULL
) {
1143 if (Index
!= HandleCount
) {
1144 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle
), FullPath
, FileSize
);
1152 Get the file buffer from the specified Load File instance.
1154 @param LoadFileHandle The specified Load File instance.
1155 @param FilePath The file path which will pass to LoadFile().
1156 @param FullPath Return the full device path pointing to the load option.
1157 @param FileSize Return the size of the load option.
1159 @return The load option buffer or NULL if fails.
1162 BmGetFileBufferFromLoadFile (
1163 EFI_HANDLE LoadFileHandle
,
1164 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1165 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1170 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1172 BOOLEAN LoadFileSystem
;
1177 Status
= gBS
->OpenProtocol (
1179 &gEfiLoadFileProtocolGuid
,
1180 (VOID
**) &LoadFile
,
1183 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1185 ASSERT_EFI_ERROR (Status
);
1189 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1190 if ((Status
!= EFI_WARN_FILE_SYSTEM
) && (Status
!= EFI_BUFFER_TOO_SMALL
)) {
1194 LoadFileSystem
= (BOOLEAN
) (Status
== EFI_WARN_FILE_SYSTEM
);
1195 FileBuffer
= LoadFileSystem
? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize
)) : AllocatePool (BufferSize
);
1196 if (FileBuffer
== NULL
) {
1200 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1201 if (EFI_ERROR (Status
)) {
1202 if (LoadFileSystem
) {
1203 FreePages (FileBuffer
, EFI_SIZE_TO_PAGES (BufferSize
));
1205 FreePool (FileBuffer
);
1210 if (LoadFileSystem
) {
1211 FileBuffer
= BmGetFileBufferFromLoadFileSystem (LoadFileHandle
, FullPath
, FileSize
);
1213 *FileSize
= BufferSize
;
1214 *FullPath
= DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle
));
1221 Get the file buffer from all the Load File instances.
1223 @param FilePath The media device path pointing to a LoadFile instance.
1224 @param FullPath Return the full device path pointing to the load option.
1225 @param FileSize Return the size of the load option.
1227 @return The load option buffer.
1230 BmGetFileBufferFromLoadFiles (
1231 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1232 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1238 EFI_HANDLE
*Handles
;
1241 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1244 // Get file buffer from load file instance.
1247 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1248 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1250 // When wide match happens, pass full device path to LoadFile (),
1251 // otherwise, pass remaining device path to LoadFile ().
1257 // Use wide match algorithm to find one when
1258 // cannot find a LoadFile instance to exactly match the FilePath
1260 Status
= gBS
->LocateHandleBuffer (
1262 &gEfiLoadFileProtocolGuid
,
1267 if (EFI_ERROR (Status
)) {
1271 for (Index
= 0; Index
< HandleCount
; Index
++) {
1272 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
)) {
1273 Handle
= Handles
[Index
];
1277 if (Handles
!= NULL
) {
1282 if (Handle
== NULL
) {
1286 return BmGetFileBufferFromLoadFile (Handle
, FilePath
, FullPath
, FileSize
);
1290 Get the load option by its device path.
1292 @param FilePath The device path pointing to a load option.
1293 It could be a short-form device path.
1294 @param FullPath Return the full device path of the load option after
1295 short-form device path expanding.
1296 Caller is responsible to free it.
1297 @param FileSize Return the load option size.
1299 @return The load option buffer. Caller is responsible to free the memory.
1302 BmGetLoadOptionBuffer (
1303 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1304 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1310 UINT32 AuthenticationStatus
;
1311 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1314 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1316 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1323 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1326 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1327 if (EFI_ERROR (Status
)) {
1328 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1331 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1332 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1336 // Expand the short-form device path to full device path
1338 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1339 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1341 // Expand the Harddrive device path
1343 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1344 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1345 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
)) {
1347 // Expand the File-path device path
1349 return BmExpandFileDevicePath (FilePath
, FullPath
, FileSize
);
1350 } else if ((DevicePathType (FilePath
) == MESSAGING_DEVICE_PATH
) &&
1351 (DevicePathSubType (FilePath
) == MSG_URI_DP
)) {
1353 // Expand the URI device path
1355 return BmExpandUriDevicePath (FilePath
, FullPath
, FileSize
);
1357 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1358 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1359 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1364 if (!IsDevicePathEnd (Node
)) {
1366 // Expand the USB WWID/Class device path
1368 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1369 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1371 // Boot Option device path starts with USB Class or USB WWID device path.
1372 // For Boot Option device path which doesn't begin with the USB Class or
1373 // USB WWID device path, it's not needed to connect again here.
1375 BmConnectUsbShortFormDevicePath (FilePath
);
1376 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1383 // Get file buffer from FV file path.
1385 if (BmIsFvFilePath (FilePath
)) {
1386 return BmGetFileBufferByFvFilePath (FilePath
, FullPath
, FileSize
);
1390 // Get file buffer from simple file system.
1393 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1394 if (!EFI_ERROR (Status
)) {
1395 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1396 if (FileBuffer
!= NULL
) {
1397 *FullPath
= DuplicateDevicePath (FilePath
);
1402 return BmGetFileBufferFromLoadFiles (FilePath
, FullPath
, FileSize
);
1406 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1407 also signals the EFI ready to boot event. If the device path for the option
1408 starts with a BBS device path a legacy boot is attempted via the registered
1409 gLegacyBoot function. Short form device paths are also supported via this
1410 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1411 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1412 If the BootOption Device Path fails the removable media boot algorithm
1413 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1414 is tried per processor type)
1416 @param BootOption Boot Option to try and boot.
1417 On return, BootOption->Status contains the boot status.
1418 EFI_SUCCESS BootOption was booted
1419 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1420 registered via EfiBootManagerInitialize().
1421 EFI_NOT_FOUND The BootOption was not found on the system
1422 !EFI_SUCCESS BootOption failed with this error status
1427 EfiBootManagerBoot (
1428 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1432 EFI_HANDLE ImageHandle
;
1433 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1436 UINTN OriginalOptionNumber
;
1437 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1438 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1439 EFI_HANDLE FvHandle
;
1442 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1443 EFI_EVENT LegacyBootEvent
;
1445 if (BootOption
== NULL
) {
1449 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1450 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1455 // 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")
1457 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1458 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1459 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1460 if (!EFI_ERROR (Status
)) {
1462 // Save the BootOption->OptionNumber to restore later
1464 OptionNumber
= Uint16
;
1465 OriginalOptionNumber
= BootOption
->OptionNumber
;
1466 BootOption
->OptionNumber
= OptionNumber
;
1467 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1468 BootOption
->OptionNumber
= OriginalOptionNumber
;
1471 if (EFI_ERROR (Status
)) {
1472 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1473 BootOption
->Status
= Status
;
1479 // 2. Set BootCurrent
1481 Uint16
= (UINT16
) OptionNumber
;
1482 BmSetVariableAndReportStatusCodeOnError (
1484 &gEfiGlobalVariableGuid
,
1485 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1491 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1494 Node
= BootOption
->FilePath
;
1495 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1496 if (!EFI_ERROR (Status
) && CompareGuid (
1497 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1498 PcdGetPtr (PcdBootManagerMenuFile
)
1500 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1501 BmStopHotkeyService (NULL
, NULL
);
1503 EfiSignalEventReadyToBoot();
1505 // Report Status Code to indicate ReadyToBoot was signalled
1507 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1509 // 4. Repair system through DriverHealth protocol
1511 BmRepairAllControllers ();
1514 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1517 // 5. Load EFI boot option to ImageHandle
1520 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1521 Status
= EFI_NOT_FOUND
;
1522 FileBuffer
= BmGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1524 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1525 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1526 BmPrintDp (BootOption
->FilePath
);
1527 DEBUG ((EFI_D_INFO
, " -> "));
1528 BmPrintDp (FilePath
);
1529 DEBUG ((EFI_D_INFO
, "\n"));
1532 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1533 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1534 Status
= gBS
->LoadImage (
1543 if (FileBuffer
!= NULL
) {
1544 FreePool (FileBuffer
);
1546 if (FilePath
!= NULL
) {
1547 FreePool (FilePath
);
1550 if (EFI_ERROR (Status
)) {
1552 // Report Status Code to indicate that the failure to load boot option
1554 REPORT_STATUS_CODE (
1555 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1556 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1558 BootOption
->Status
= Status
;
1564 // 6. Adjust the different type memory page number just before booting
1565 // and save the updated info into the variable for next boot to use
1567 BmSetMemoryTypeInformationVariable (
1568 (BOOLEAN
) ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1572 if (BootOption
->Description
== NULL
) {
1573 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1575 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1580 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1581 // Write boot to OS performance data for Legacy boot
1583 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1584 if (mBmLegacyBoot
!= NULL
) {
1586 // Write boot to OS performance data for legacy boot.
1590 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1592 Status
= EfiCreateEventLegacyBootEx(
1594 BmWriteBootToOsPerformanceData
,
1598 ASSERT_EFI_ERROR (Status
);
1601 mBmLegacyBoot (BootOption
);
1603 BootOption
->Status
= EFI_UNSUPPORTED
;
1606 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1611 // Provide the image with its load options
1613 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1614 ASSERT_EFI_ERROR (Status
);
1616 if (!BmIsAutoCreateBootOption (BootOption
)) {
1617 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1618 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1622 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1624 ImageInfo
->ParentHandle
= NULL
;
1627 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1629 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1632 // Write boot to OS performance data for UEFI boot
1635 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1638 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1640 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1641 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1642 BootOption
->Status
= Status
;
1643 if (EFI_ERROR (Status
)) {
1645 // Report Status Code to indicate that boot failure
1647 REPORT_STATUS_CODE (
1648 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1649 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1652 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1655 // Clear the Watchdog Timer after the image returns
1657 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1660 // Set Logo status invalid after trying one boot option
1663 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1664 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1665 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1666 ASSERT_EFI_ERROR (Status
);
1670 // Clear Boot Current
1672 Status
= gRT
->SetVariable (
1674 &gEfiGlobalVariableGuid
,
1680 // Deleting variable with current variable implementation shouldn't fail.
1681 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1682 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1684 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1688 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1689 instances, has the same partition node with HardDriveDevicePath device path
1691 @param BlockIoDevicePath Multi device path instances which need to check
1692 @param HardDriveDevicePath A device path which starts with a hard drive media
1695 @retval TRUE There is a matched device path instance.
1696 @retval FALSE There is no matched device path instance.
1700 BmMatchPartitionDevicePathNode (
1701 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1702 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1705 HARDDRIVE_DEVICE_PATH
*Node
;
1707 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1712 // find the partition device path node
1714 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1715 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1716 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1721 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1724 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1729 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1731 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1734 // Match Signature and PartitionNumber.
1735 // Unused bytes in Signature are initiaized with zeros.
1738 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1739 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1740 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1741 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1746 Emuerate all possible bootable medias in the following order:
1747 1. Removable BlockIo - The boot option only points to the removable media
1748 device, like USB key, DVD, Floppy etc.
1749 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1751 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1752 SimpleFileSystem Protocol, but not supporting BlockIo
1754 4. LoadFile - The boot option points to the media supporting
1756 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1758 @param BootOptionCount Return the boot option count which has been found.
1760 @retval Pointer to the boot option array.
1762 EFI_BOOT_MANAGER_LOAD_OPTION
*
1763 BmEnumerateBootOptions (
1764 UINTN
*BootOptionCount
1768 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1770 EFI_HANDLE
*Handles
;
1771 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
1774 CHAR16
*Description
;
1776 ASSERT (BootOptionCount
!= NULL
);
1778 *BootOptionCount
= 0;
1782 // Parse removable block io followed by fixed block io
1784 gBS
->LocateHandleBuffer (
1786 &gEfiBlockIoProtocolGuid
,
1792 for (Removable
= 0; Removable
< 2; Removable
++) {
1793 for (Index
= 0; Index
< HandleCount
; Index
++) {
1794 Status
= gBS
->HandleProtocol (
1796 &gEfiBlockIoProtocolGuid
,
1799 if (EFI_ERROR (Status
)) {
1804 // Skip the logical partitions
1806 if (BlkIo
->Media
->LogicalPartition
) {
1811 // Skip the fixed block io then the removable block io
1813 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
1817 Description
= BmGetBootDescription (Handles
[Index
]);
1818 BootOptions
= ReallocatePool (
1819 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1820 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1823 ASSERT (BootOptions
!= NULL
);
1825 Status
= EfiBootManagerInitializeLoadOption (
1826 &BootOptions
[(*BootOptionCount
)++],
1827 LoadOptionNumberUnassigned
,
1831 DevicePathFromHandle (Handles
[Index
]),
1835 ASSERT_EFI_ERROR (Status
);
1837 FreePool (Description
);
1841 if (HandleCount
!= 0) {
1846 // Parse simple file system not based on block io
1848 gBS
->LocateHandleBuffer (
1850 &gEfiSimpleFileSystemProtocolGuid
,
1855 for (Index
= 0; Index
< HandleCount
; Index
++) {
1856 Status
= gBS
->HandleProtocol (
1858 &gEfiBlockIoProtocolGuid
,
1861 if (!EFI_ERROR (Status
)) {
1863 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
1867 Description
= BmGetBootDescription (Handles
[Index
]);
1868 BootOptions
= ReallocatePool (
1869 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1870 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1873 ASSERT (BootOptions
!= NULL
);
1875 Status
= EfiBootManagerInitializeLoadOption (
1876 &BootOptions
[(*BootOptionCount
)++],
1877 LoadOptionNumberUnassigned
,
1881 DevicePathFromHandle (Handles
[Index
]),
1885 ASSERT_EFI_ERROR (Status
);
1886 FreePool (Description
);
1889 if (HandleCount
!= 0) {
1894 // Parse load file, assuming UEFI Network boot option
1896 gBS
->LocateHandleBuffer (
1898 &gEfiLoadFileProtocolGuid
,
1903 for (Index
= 0; Index
< HandleCount
; Index
++) {
1905 Description
= BmGetBootDescription (Handles
[Index
]);
1906 BootOptions
= ReallocatePool (
1907 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1908 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1911 ASSERT (BootOptions
!= NULL
);
1913 Status
= EfiBootManagerInitializeLoadOption (
1914 &BootOptions
[(*BootOptionCount
)++],
1915 LoadOptionNumberUnassigned
,
1919 DevicePathFromHandle (Handles
[Index
]),
1923 ASSERT_EFI_ERROR (Status
);
1924 FreePool (Description
);
1927 if (HandleCount
!= 0) {
1931 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
1936 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
1940 EfiBootManagerRefreshAllBootOption (
1945 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
1946 UINTN NvBootOptionCount
;
1947 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1948 UINTN BootOptionCount
;
1952 // Optionally refresh the legacy boot option
1954 if (mBmRefreshLegacyBootOption
!= NULL
) {
1955 mBmRefreshLegacyBootOption ();
1958 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
1959 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
1962 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
1964 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
1965 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
1966 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
1970 // Remove invalid EFI boot options from NV
1972 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
1973 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
1974 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
1975 ) && BmIsAutoCreateBootOption (&NvBootOptions
[Index
])
1978 // Only check those added by BDS
1979 // so that the boot options added by end-user or OS installer won't be deleted
1981 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
1982 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
1984 // Deleting variable with current variable implementation shouldn't fail.
1986 ASSERT_EFI_ERROR (Status
);
1992 // Add new EFI boot options to NV
1994 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
1995 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
1996 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
1998 // Try best to add the boot options so continue upon failure.
2003 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2004 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2008 This function is called to create the boot option for the Boot Manager Menu.
2010 The Boot Manager Menu is shown after successfully booting a boot option.
2011 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2013 @param BootOption Return the boot option of the Boot Manager Menu
2015 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2016 @retval Status Return status of gRT->SetVariable (). BootOption still points
2017 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2020 BmRegisterBootManagerMenu (
2021 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2025 CHAR16
*Description
;
2026 UINTN DescriptionLength
;
2027 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2028 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2029 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2031 Status
= GetSectionFromFv (
2032 PcdGetPtr (PcdBootManagerMenuFile
),
2033 EFI_SECTION_USER_INTERFACE
,
2035 (VOID
**) &Description
,
2038 if (EFI_ERROR (Status
)) {
2042 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2043 Status
= gBS
->HandleProtocol (
2045 &gEfiLoadedImageProtocolGuid
,
2046 (VOID
**) &LoadedImage
2048 ASSERT_EFI_ERROR (Status
);
2049 DevicePath
= AppendDevicePathNode (
2050 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2051 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2053 ASSERT (DevicePath
!= NULL
);
2055 Status
= EfiBootManagerInitializeLoadOption (
2057 LoadOptionNumberUnassigned
,
2059 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2060 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2065 ASSERT_EFI_ERROR (Status
);
2066 FreePool (DevicePath
);
2067 if (Description
!= NULL
) {
2068 FreePool (Description
);
2072 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2073 UINTN BootOptionCount
;
2075 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2076 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2077 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2080 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2084 Return the boot option corresponding to the Boot Manager Menu.
2085 It may automatically create one if the boot option hasn't been created yet.
2087 @param BootOption Return the Boot Manager Menu.
2089 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2090 @retval Status Return status of gRT->SetVariable (). BootOption still points
2091 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2095 EfiBootManagerGetBootManagerMenu (
2096 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2100 UINTN BootOptionCount
;
2101 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2103 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2104 EFI_HANDLE FvHandle
;
2106 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2108 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2109 Node
= BootOptions
[Index
].FilePath
;
2110 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2111 if (!EFI_ERROR (Status
)) {
2113 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2114 PcdGetPtr (PcdBootManagerMenuFile
)
2117 Status
= EfiBootManagerInitializeLoadOption (
2119 BootOptions
[Index
].OptionNumber
,
2120 BootOptions
[Index
].OptionType
,
2121 BootOptions
[Index
].Attributes
,
2122 BootOptions
[Index
].Description
,
2123 BootOptions
[Index
].FilePath
,
2124 BootOptions
[Index
].OptionalData
,
2125 BootOptions
[Index
].OptionalDataSize
2127 ASSERT_EFI_ERROR (Status
);
2133 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2136 // Automatically create the Boot#### for Boot Manager Menu when not found.
2138 if (Index
== BootOptionCount
) {
2139 return BmRegisterBootManagerMenu (BootOption
);