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
,
691 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
694 EfiBootManagerConnectAll ();
695 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &HandleCount
, &Handles
);
696 if (EFI_ERROR (Status
)) {
703 for (Index
= 0; Index
< HandleCount
; Index
++) {
704 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiLoadFileProtocolGuid
, (VOID
*) &LoadFile
);
705 ASSERT_EFI_ERROR (Status
);
708 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, FileSize
, FileBuffer
);
709 if (Status
== EFI_BUFFER_TOO_SMALL
) {
710 FileBuffer
= AllocatePool (*FileSize
);
711 if (FileBuffer
== NULL
) {
714 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, FileSize
, FileBuffer
);
717 if (!EFI_ERROR (Status
)) {
719 // LoadFile() returns a file buffer mapping to a file system.
721 if (Status
== EFI_WARN_FILE_SYSTEM
) {
722 return BmGetFileBufferFromLoadFileFileSystem (Handles
[Index
], FullPath
, FileSize
);
725 ASSERT (Status
== EFI_SUCCESS
);
726 *FullPath
= DuplicateDevicePath (DevicePathFromHandle (Handles
[Index
]));
730 if (FileBuffer
!= NULL
) {
731 FreePool (FileBuffer
);
735 if (Handles
!= NULL
) {
743 Save the partition DevicePath to the CachedDevicePath as the first instance.
745 @param CachedDevicePath The device path cache.
746 @param DevicePath The partition device path to be cached.
749 BmCachePartitionDevicePath (
750 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
751 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
754 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
757 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
758 TempDevicePath
= *CachedDevicePath
;
759 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
760 FreePool (TempDevicePath
);
763 if (*CachedDevicePath
== NULL
) {
764 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
768 TempDevicePath
= *CachedDevicePath
;
769 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
770 if (TempDevicePath
!= NULL
) {
771 FreePool (TempDevicePath
);
775 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
776 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
779 TempDevicePath
= *CachedDevicePath
;
780 while (!IsDevicePathEnd (TempDevicePath
)) {
781 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
783 // Parse one instance
785 while (!IsDevicePathEndType (TempDevicePath
)) {
786 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
790 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
793 SetDevicePathEndNode (TempDevicePath
);
800 Expand a device path that starts with a hard drive media device path node to be a
801 full device path that includes the full hardware path to the device. We need
802 to do this so it can be booted. As an optimization the front match (the part point
803 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
804 so a connect all is not required on every boot. All successful history device path
805 which point to partition node (the front part) will be saved.
807 @param FilePath The device path pointing to a load option.
808 It could be a short-form device path.
809 @param FullPath Return the full device path of the load option after
810 short-form device path expanding.
811 Caller is responsible to free it.
812 @param FileSize Return the load option size.
814 @return The load option buffer. Caller is responsible to free the memory.
817 BmExpandPartitionDevicePath (
818 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
819 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
824 UINTN BlockIoHandleCount
;
825 EFI_HANDLE
*BlockIoBuffer
;
827 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
829 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
830 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
831 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
832 UINTN CachedDevicePathSize
;
834 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
839 // Check if there is prestore 'HDDP' variable.
840 // If exist, search the front path which point to partition node in the variable instants.
841 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
843 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
846 // Delete the invalid 'HDDP' variable.
848 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
849 FreePool (CachedDevicePath
);
850 CachedDevicePath
= NULL
;
851 Status
= gRT
->SetVariable (
853 &mBmHardDriveBootVariableGuid
,
858 ASSERT_EFI_ERROR (Status
);
861 if (CachedDevicePath
!= NULL
) {
862 TempNewDevicePath
= CachedDevicePath
;
866 // Check every instance of the variable
867 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
868 // partial partition boot option. Second, check whether the instance could be connected.
870 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
871 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
873 // Connect the device path instance, the device path point to hard drive media device path node
874 // e.g. ACPI() /PCI()/ATA()/Partition()
876 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
877 if (!EFI_ERROR (Status
)) {
878 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
879 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
880 FreePool (TempDevicePath
);
882 if (FileBuffer
!= NULL
) {
884 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
887 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
889 // Save the matching Device Path so we don't need to do a connect all next time
890 // Failing to save only impacts performance next time expanding the short-form device path
892 Status
= gRT
->SetVariable (
894 &mBmHardDriveBootVariableGuid
,
895 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
896 GetDevicePathSize (CachedDevicePath
),
902 FreePool (CachedDevicePath
);
908 // Come here means the first instance is not matched
912 } while (TempNewDevicePath
!= NULL
);
916 // If we get here we fail to find or 'HDDP' not exist, and now we need
917 // to search all devices in the system for a matched partition
919 EfiBootManagerConnectAll ();
920 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
921 if (EFI_ERROR (Status
)) {
922 BlockIoHandleCount
= 0;
923 BlockIoBuffer
= NULL
;
926 // Loop through all the device handles that support the BLOCK_IO Protocol
928 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
929 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
930 if (BlockIoDevicePath
== NULL
) {
934 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
936 // Find the matched partition device path
938 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
939 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
940 FreePool (TempDevicePath
);
942 if (FileBuffer
!= NULL
) {
943 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
946 // Save the matching Device Path so we don't need to do a connect all next time
947 // Failing to save only impacts performance next time expanding the short-form device path
949 Status
= gRT
->SetVariable (
951 &mBmHardDriveBootVariableGuid
,
952 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
953 GetDevicePathSize (CachedDevicePath
),
962 if (CachedDevicePath
!= NULL
) {
963 FreePool (CachedDevicePath
);
965 if (BlockIoBuffer
!= NULL
) {
966 FreePool (BlockIoBuffer
);
972 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
973 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
975 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
976 @param FullPath Return the full device path pointing to the load option.
977 @param FileSize Return the size of the load option.
979 @return The load option buffer.
982 BmExpandMediaDevicePath (
983 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
984 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
990 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
992 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
995 EFI_HANDLE
*SimpleFileSystemHandles
;
996 UINTN NumberSimpleFileSystemHandles
;
999 UINT32 AuthenticationStatus
;
1002 // Check whether the device is connected
1004 TempDevicePath
= DevicePath
;
1005 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1006 if (!EFI_ERROR (Status
)) {
1007 ASSERT (IsDevicePathEnd (TempDevicePath
));
1009 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1010 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1011 if (FileBuffer
== NULL
) {
1012 FreePool (TempDevicePath
);
1013 TempDevicePath
= NULL
;
1015 *FullPath
= TempDevicePath
;
1020 // For device boot option only pointing to the removable device handle,
1021 // should make sure all its children handles (its child partion or media handles) are created and connected.
1023 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1026 // Issue a dummy read to the device to check for media change.
1027 // When the removable media is changed, any Block IO read/write will
1028 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1029 // returned. After the Block IO protocol is reinstalled, subsequent
1030 // Block IO read/write will success.
1032 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1033 ASSERT_EFI_ERROR (Status
);
1034 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1035 ASSERT_EFI_ERROR (Status
);
1036 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1037 if (Buffer
!= NULL
) {
1038 BlockIo
->ReadBlocks (
1040 BlockIo
->Media
->MediaId
,
1042 BlockIo
->Media
->BlockSize
,
1049 // Detect the the default boot file from removable Media
1053 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1054 gBS
->LocateHandleBuffer (
1056 &gEfiSimpleFileSystemProtocolGuid
,
1058 &NumberSimpleFileSystemHandles
,
1059 &SimpleFileSystemHandles
1061 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1063 // Get the device path size of SimpleFileSystem handle
1065 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1066 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1068 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1070 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1071 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1072 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1073 if (FileBuffer
!= NULL
) {
1074 *FullPath
= TempDevicePath
;
1077 FreePool (TempDevicePath
);
1081 if (SimpleFileSystemHandles
!= NULL
) {
1082 FreePool (SimpleFileSystemHandles
);
1089 Check whether Left and Right are the same without matching the specific
1090 device path data in IP device path and URI device path node.
1092 @retval TRUE Left and Right are the same.
1093 @retval FALSE Left and Right are the different.
1096 BmMatchHttpBootDevicePath (
1097 IN EFI_DEVICE_PATH_PROTOCOL
*Left
,
1098 IN EFI_DEVICE_PATH_PROTOCOL
*Right
1101 for (; !IsDevicePathEnd (Left
) && !IsDevicePathEnd (Right
)
1102 ; Left
= NextDevicePathNode (Left
), Right
= NextDevicePathNode (Right
)
1104 if (CompareMem (Left
, Right
, DevicePathNodeLength (Left
)) != 0) {
1105 if ((DevicePathType (Left
) != MESSAGING_DEVICE_PATH
) || (DevicePathType (Right
) != MESSAGING_DEVICE_PATH
)) {
1109 if (((DevicePathSubType (Left
) != MSG_IPv4_DP
) || (DevicePathSubType (Right
) != MSG_IPv4_DP
)) &&
1110 ((DevicePathSubType (Left
) != MSG_IPv6_DP
) || (DevicePathSubType (Right
) != MSG_IPv6_DP
)) &&
1111 ((DevicePathSubType (Left
) != MSG_URI_DP
) || (DevicePathSubType (Right
) != MSG_URI_DP
))
1117 return (BOOLEAN
) (IsDevicePathEnd (Left
) && IsDevicePathEnd (Right
));
1121 Get the file buffer from the file system produced by Load File instance.
1123 @param LoadFileHandle The handle of LoadFile instance.
1124 @param FullPath Return the full device path pointing to the load option.
1125 @param FileSize Return the size of the load option.
1127 @return The load option buffer.
1130 BmGetFileBufferFromLoadFileFileSystem (
1131 IN EFI_HANDLE LoadFileHandle
,
1132 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1138 EFI_HANDLE
*Handles
;
1141 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1143 Status
= gBS
->LocateHandleBuffer (
1145 &gEfiBlockIoProtocolGuid
,
1150 if (EFI_ERROR (Status
)) {
1156 for (Index
= 0; Index
< HandleCount
; Index
++) {
1157 Node
= DevicePathFromHandle (Handles
[Index
]);
1158 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1159 if (!EFI_ERROR (Status
) &&
1160 (Handle
== LoadFileHandle
) &&
1161 (DevicePathType (Node
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (Node
) == MEDIA_RAM_DISK_DP
)) {
1162 Handle
= Handles
[Index
];
1167 if (Handles
!= NULL
) {
1171 if (Index
!= HandleCount
) {
1172 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle
), FullPath
, FileSize
);
1179 Get the file buffer from Load File instance.
1181 @param FilePath The media device path pointing to a LoadFile instance.
1182 @param FullPath Return the full device path pointing to the load option.
1183 @param FileSize Return the size of the load option.
1185 @return The load option buffer.
1188 BmGetFileBufferFromLoadFile (
1189 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1190 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1197 EFI_HANDLE
*Handles
;
1200 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1201 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
1205 // Get file buffer from load file instance.
1208 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &Node
, &Handle
);
1209 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1211 // When wide match happens, pass full device path to LoadFile (),
1212 // otherwise, pass remaining device path to LoadFile ().
1218 // Use wide match algorithm to find one when
1219 // cannot find a LoadFile instance to exactly match the FilePath
1221 Status
= gBS
->LocateHandleBuffer (
1223 &gEfiLoadFileProtocolGuid
,
1228 if (EFI_ERROR (Status
)) {
1232 for (Index
= 0; Index
< HandleCount
; Index
++) {
1233 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles
[Index
]), FilePath
)) {
1234 Handle
= Handles
[Index
];
1238 if (Handles
!= NULL
) {
1243 if (Handle
== NULL
) {
1247 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**) &LoadFile
);
1248 ASSERT_EFI_ERROR (Status
);
1252 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1253 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1254 FileBuffer
= AllocatePool (BufferSize
);
1255 if (FileBuffer
!= NULL
) {
1256 Status
= EFI_SUCCESS
;
1260 if (!EFI_ERROR (Status
)) {
1261 Status
= LoadFile
->LoadFile (LoadFile
, FilePath
, TRUE
, &BufferSize
, FileBuffer
);
1264 if (!EFI_ERROR (Status
)) {
1266 // LoadFile() returns a file buffer mapping to a file system.
1268 if (Status
== EFI_WARN_FILE_SYSTEM
) {
1269 return BmGetFileBufferFromLoadFileFileSystem (Handle
, FullPath
, FileSize
);
1272 ASSERT (Status
== EFI_SUCCESS
);
1274 // LoadFile () may cause the device path of the Handle be updated.
1276 *FullPath
= DuplicateDevicePath (DevicePathFromHandle (Handle
));
1277 *FileSize
= BufferSize
;
1285 Get the load option by its device path.
1287 @param FilePath The device path pointing to a load option.
1288 It could be a short-form device path.
1289 @param FullPath Return the full device path of the load option after
1290 short-form device path expanding.
1291 Caller is responsible to free it.
1292 @param FileSize Return the load option size.
1294 @return The load option buffer. Caller is responsible to free the memory.
1297 BmGetLoadOptionBuffer (
1298 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1299 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1305 UINT32 AuthenticationStatus
;
1306 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1309 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1311 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1318 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1321 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1322 if (EFI_ERROR (Status
)) {
1323 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1326 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1327 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1331 // Expand the short-form device path to full device path
1333 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1334 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1336 // Expand the Harddrive device path
1338 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1339 } else if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1340 (DevicePathSubType (FilePath
) == MEDIA_FILEPATH_DP
)) {
1342 // Expand the File-path device path
1344 return BmExpandFileDevicePath (FilePath
, FullPath
, FileSize
);
1345 } else if ((DevicePathType (FilePath
) == MESSAGING_DEVICE_PATH
) &&
1346 (DevicePathSubType (FilePath
) == MSG_URI_DP
)) {
1348 // Expand the URI device path
1350 return BmExpandUriDevicePath (FilePath
, FullPath
, FileSize
);
1352 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1353 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1354 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1359 if (!IsDevicePathEnd (Node
)) {
1361 // Expand the USB WWID/Class device path
1363 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1364 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1366 // Boot Option device path starts with USB Class or USB WWID device path.
1367 // For Boot Option device path which doesn't begin with the USB Class or
1368 // USB WWID device path, it's not needed to connect again here.
1370 BmConnectUsbShortFormDevicePath (FilePath
);
1371 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1378 // Get file buffer from FV file path.
1380 if (BmIsFvFilePath (FilePath
)) {
1381 return BmGetFileBufferByFvFilePath (FilePath
, FullPath
, FileSize
);
1385 // Get file buffer from simple file system.
1388 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1389 if (!EFI_ERROR (Status
)) {
1390 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1391 if (FileBuffer
!= NULL
) {
1392 *FullPath
= DuplicateDevicePath (FilePath
);
1397 return BmGetFileBufferFromLoadFile (FilePath
, FullPath
, FileSize
);
1401 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1402 also signals the EFI ready to boot event. If the device path for the option
1403 starts with a BBS device path a legacy boot is attempted via the registered
1404 gLegacyBoot function. Short form device paths are also supported via this
1405 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1406 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1407 If the BootOption Device Path fails the removable media boot algorithm
1408 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1409 is tried per processor type)
1411 @param BootOption Boot Option to try and boot.
1412 On return, BootOption->Status contains the boot status.
1413 EFI_SUCCESS BootOption was booted
1414 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1415 registered via EfiBootManagerInitialize().
1416 EFI_NOT_FOUND The BootOption was not found on the system
1417 !EFI_SUCCESS BootOption failed with this error status
1422 EfiBootManagerBoot (
1423 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1427 EFI_HANDLE ImageHandle
;
1428 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1431 UINTN OriginalOptionNumber
;
1432 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1433 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1434 EFI_HANDLE FvHandle
;
1437 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1438 EFI_EVENT LegacyBootEvent
;
1440 if (BootOption
== NULL
) {
1444 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1445 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1450 // 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")
1452 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1453 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1454 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1455 if (!EFI_ERROR (Status
)) {
1457 // Save the BootOption->OptionNumber to restore later
1459 OptionNumber
= Uint16
;
1460 OriginalOptionNumber
= BootOption
->OptionNumber
;
1461 BootOption
->OptionNumber
= OptionNumber
;
1462 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1463 BootOption
->OptionNumber
= OriginalOptionNumber
;
1466 if (EFI_ERROR (Status
)) {
1467 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1468 BootOption
->Status
= Status
;
1474 // 2. Set BootCurrent
1476 Uint16
= (UINT16
) OptionNumber
;
1477 BmSetVariableAndReportStatusCodeOnError (
1479 &gEfiGlobalVariableGuid
,
1480 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1486 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1489 Node
= BootOption
->FilePath
;
1490 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1491 if (!EFI_ERROR (Status
) && CompareGuid (
1492 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1493 PcdGetPtr (PcdBootManagerMenuFile
)
1495 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1496 BmStopHotkeyService (NULL
, NULL
);
1498 EfiSignalEventReadyToBoot();
1500 // Report Status Code to indicate ReadyToBoot was signalled
1502 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1504 // 4. Repair system through DriverHealth protocol
1506 BmRepairAllControllers ();
1509 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1512 // 5. Load EFI boot option to ImageHandle
1515 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1516 Status
= EFI_NOT_FOUND
;
1517 FileBuffer
= BmGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1519 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1520 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1521 BmPrintDp (BootOption
->FilePath
);
1522 DEBUG ((EFI_D_INFO
, " -> "));
1523 BmPrintDp (FilePath
);
1524 DEBUG ((EFI_D_INFO
, "\n"));
1527 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1528 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1529 Status
= gBS
->LoadImage (
1538 if (FileBuffer
!= NULL
) {
1539 FreePool (FileBuffer
);
1541 if (FilePath
!= NULL
) {
1542 FreePool (FilePath
);
1545 if (EFI_ERROR (Status
)) {
1547 // Report Status Code to indicate that the failure to load boot option
1549 REPORT_STATUS_CODE (
1550 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1551 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1553 BootOption
->Status
= Status
;
1559 // 6. Adjust the different type memory page number just before booting
1560 // and save the updated info into the variable for next boot to use
1562 BmSetMemoryTypeInformationVariable (
1563 (BOOLEAN
) ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
)
1567 if (BootOption
->Description
== NULL
) {
1568 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1570 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1575 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1576 // Write boot to OS performance data for Legacy boot
1578 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1579 if (mBmLegacyBoot
!= NULL
) {
1581 // Write boot to OS performance data for legacy boot.
1585 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1587 Status
= EfiCreateEventLegacyBootEx(
1589 BmWriteBootToOsPerformanceData
,
1593 ASSERT_EFI_ERROR (Status
);
1596 mBmLegacyBoot (BootOption
);
1598 BootOption
->Status
= EFI_UNSUPPORTED
;
1601 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1606 // Provide the image with its load options
1608 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1609 ASSERT_EFI_ERROR (Status
);
1611 if (!BmIsAutoCreateBootOption (BootOption
)) {
1612 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1613 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1617 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1619 ImageInfo
->ParentHandle
= NULL
;
1622 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1624 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1627 // Write boot to OS performance data for UEFI boot
1630 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1633 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1635 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1636 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1637 BootOption
->Status
= Status
;
1638 if (EFI_ERROR (Status
)) {
1640 // Report Status Code to indicate that boot failure
1642 REPORT_STATUS_CODE (
1643 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1644 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1647 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1650 // Clear the Watchdog Timer after the image returns
1652 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1655 // Set Logo status invalid after trying one boot option
1658 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1659 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1660 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1661 ASSERT_EFI_ERROR (Status
);
1665 // Clear Boot Current
1667 Status
= gRT
->SetVariable (
1669 &gEfiGlobalVariableGuid
,
1675 // Deleting variable with current variable implementation shouldn't fail.
1676 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1677 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1679 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1683 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1684 instances, has the same partition node with HardDriveDevicePath device path
1686 @param BlockIoDevicePath Multi device path instances which need to check
1687 @param HardDriveDevicePath A device path which starts with a hard drive media
1690 @retval TRUE There is a matched device path instance.
1691 @retval FALSE There is no matched device path instance.
1695 BmMatchPartitionDevicePathNode (
1696 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1697 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1700 HARDDRIVE_DEVICE_PATH
*Node
;
1702 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1707 // find the partition device path node
1709 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1710 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1711 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1716 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1719 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1724 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1726 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1729 // Match Signature and PartitionNumber.
1730 // Unused bytes in Signature are initiaized with zeros.
1733 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1734 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1735 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1736 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1741 Emuerate all possible bootable medias in the following order:
1742 1. Removable BlockIo - The boot option only points to the removable media
1743 device, like USB key, DVD, Floppy etc.
1744 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1746 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1747 SimpleFileSystem Protocol, but not supporting BlockIo
1749 4. LoadFile - The boot option points to the media supporting
1751 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1753 @param BootOptionCount Return the boot option count which has been found.
1755 @retval Pointer to the boot option array.
1757 EFI_BOOT_MANAGER_LOAD_OPTION
*
1758 BmEnumerateBootOptions (
1759 UINTN
*BootOptionCount
1763 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1765 EFI_HANDLE
*Handles
;
1766 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
1769 CHAR16
*Description
;
1771 ASSERT (BootOptionCount
!= NULL
);
1773 *BootOptionCount
= 0;
1777 // Parse removable block io followed by fixed block io
1779 gBS
->LocateHandleBuffer (
1781 &gEfiBlockIoProtocolGuid
,
1787 for (Removable
= 0; Removable
< 2; Removable
++) {
1788 for (Index
= 0; Index
< HandleCount
; Index
++) {
1789 Status
= gBS
->HandleProtocol (
1791 &gEfiBlockIoProtocolGuid
,
1794 if (EFI_ERROR (Status
)) {
1799 // Skip the logical partitions
1801 if (BlkIo
->Media
->LogicalPartition
) {
1806 // Skip the fixed block io then the removable block io
1808 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
1812 Description
= BmGetBootDescription (Handles
[Index
]);
1813 BootOptions
= ReallocatePool (
1814 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1815 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1818 ASSERT (BootOptions
!= NULL
);
1820 Status
= EfiBootManagerInitializeLoadOption (
1821 &BootOptions
[(*BootOptionCount
)++],
1822 LoadOptionNumberUnassigned
,
1826 DevicePathFromHandle (Handles
[Index
]),
1830 ASSERT_EFI_ERROR (Status
);
1832 FreePool (Description
);
1836 if (HandleCount
!= 0) {
1841 // Parse simple file system not based on block io
1843 gBS
->LocateHandleBuffer (
1845 &gEfiSimpleFileSystemProtocolGuid
,
1850 for (Index
= 0; Index
< HandleCount
; Index
++) {
1851 Status
= gBS
->HandleProtocol (
1853 &gEfiBlockIoProtocolGuid
,
1856 if (!EFI_ERROR (Status
)) {
1858 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
1862 Description
= BmGetBootDescription (Handles
[Index
]);
1863 BootOptions
= ReallocatePool (
1864 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1865 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1868 ASSERT (BootOptions
!= NULL
);
1870 Status
= EfiBootManagerInitializeLoadOption (
1871 &BootOptions
[(*BootOptionCount
)++],
1872 LoadOptionNumberUnassigned
,
1876 DevicePathFromHandle (Handles
[Index
]),
1880 ASSERT_EFI_ERROR (Status
);
1881 FreePool (Description
);
1884 if (HandleCount
!= 0) {
1889 // Parse load file, assuming UEFI Network boot option
1891 gBS
->LocateHandleBuffer (
1893 &gEfiLoadFileProtocolGuid
,
1898 for (Index
= 0; Index
< HandleCount
; Index
++) {
1900 Description
= BmGetBootDescription (Handles
[Index
]);
1901 BootOptions
= ReallocatePool (
1902 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1903 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1906 ASSERT (BootOptions
!= NULL
);
1908 Status
= EfiBootManagerInitializeLoadOption (
1909 &BootOptions
[(*BootOptionCount
)++],
1910 LoadOptionNumberUnassigned
,
1914 DevicePathFromHandle (Handles
[Index
]),
1918 ASSERT_EFI_ERROR (Status
);
1919 FreePool (Description
);
1922 if (HandleCount
!= 0) {
1926 BmMakeBootOptionDescriptionUnique (BootOptions
, *BootOptionCount
);
1931 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
1935 EfiBootManagerRefreshAllBootOption (
1940 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
1941 UINTN NvBootOptionCount
;
1942 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1943 UINTN BootOptionCount
;
1947 // Optionally refresh the legacy boot option
1949 if (mBmRefreshLegacyBootOption
!= NULL
) {
1950 mBmRefreshLegacyBootOption ();
1953 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
1954 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
1957 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
1959 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
1960 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
1961 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
1965 // Remove invalid EFI boot options from NV
1967 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
1968 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
1969 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
1970 ) && BmIsAutoCreateBootOption (&NvBootOptions
[Index
])
1973 // Only check those added by BDS
1974 // so that the boot options added by end-user or OS installer won't be deleted
1976 if (EfiBootManagerFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
1977 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
1979 // Deleting variable with current variable implementation shouldn't fail.
1981 ASSERT_EFI_ERROR (Status
);
1987 // Add new EFI boot options to NV
1989 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
1990 if (EfiBootManagerFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
1991 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
1993 // Try best to add the boot options so continue upon failure.
1998 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
1999 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2003 This function is called to create the boot option for the Boot Manager Menu.
2005 The Boot Manager Menu is shown after successfully booting a boot option.
2006 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2008 @param BootOption Return the boot option of the Boot Manager Menu
2010 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2011 @retval Status Return status of gRT->SetVariable (). BootOption still points
2012 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2015 BmRegisterBootManagerMenu (
2016 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2020 CHAR16
*Description
;
2021 UINTN DescriptionLength
;
2022 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2023 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2024 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2026 Status
= GetSectionFromFv (
2027 PcdGetPtr (PcdBootManagerMenuFile
),
2028 EFI_SECTION_USER_INTERFACE
,
2030 (VOID
**) &Description
,
2033 if (EFI_ERROR (Status
)) {
2037 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2038 Status
= gBS
->HandleProtocol (
2040 &gEfiLoadedImageProtocolGuid
,
2041 (VOID
**) &LoadedImage
2043 ASSERT_EFI_ERROR (Status
);
2044 DevicePath
= AppendDevicePathNode (
2045 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2046 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2048 ASSERT (DevicePath
!= NULL
);
2050 Status
= EfiBootManagerInitializeLoadOption (
2052 LoadOptionNumberUnassigned
,
2054 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2055 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2060 ASSERT_EFI_ERROR (Status
);
2061 FreePool (DevicePath
);
2062 if (Description
!= NULL
) {
2063 FreePool (Description
);
2067 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2068 UINTN BootOptionCount
;
2070 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2071 ASSERT (EfiBootManagerFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2072 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2075 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2079 Return the boot option corresponding to the Boot Manager Menu.
2080 It may automatically create one if the boot option hasn't been created yet.
2082 @param BootOption Return the Boot Manager Menu.
2084 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2085 @retval Status Return status of gRT->SetVariable (). BootOption still points
2086 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2090 EfiBootManagerGetBootManagerMenu (
2091 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2095 UINTN BootOptionCount
;
2096 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2098 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2099 EFI_HANDLE FvHandle
;
2101 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2103 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2104 Node
= BootOptions
[Index
].FilePath
;
2105 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2106 if (!EFI_ERROR (Status
)) {
2108 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2109 PcdGetPtr (PcdBootManagerMenuFile
)
2112 Status
= EfiBootManagerInitializeLoadOption (
2114 BootOptions
[Index
].OptionNumber
,
2115 BootOptions
[Index
].OptionType
,
2116 BootOptions
[Index
].Attributes
,
2117 BootOptions
[Index
].Description
,
2118 BootOptions
[Index
].FilePath
,
2119 BootOptions
[Index
].OptionalData
,
2120 BootOptions
[Index
].OptionalDataSize
2122 ASSERT_EFI_ERROR (Status
);
2128 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2131 // Automatically create the Boot#### for Boot Manager Menu when not found.
2133 if (Index
== BootOptionCount
) {
2134 return BmRegisterBootManagerMenu (BootOption
);