2 Library functions which relates with booting.
4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "InternalBm.h"
17 #define VENDOR_IDENTIFICATION_OFFSET 3
18 #define VENDOR_IDENTIFICATION_LENGTH 8
19 #define PRODUCT_IDENTIFICATION_OFFSET 11
20 #define PRODUCT_IDENTIFICATION_LENGTH 16
22 CONST UINT16 mBmUsbLangId
= 0x0409; // English
23 CHAR16 mBmUefiPrefix
[] = L
"UEFI ";
25 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption
= NULL
;
26 EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot
= NULL
;
29 /// This GUID is used for an EFI Variable that stores the front device pathes
30 /// for a partial device path that starts with the HD node.
32 EFI_GUID mBmHardDriveBootVariableGuid
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
33 EFI_GUID mBmAutoCreateBootOptionGuid
= { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
36 The function registers the legacy boot support capabilities.
38 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
39 @param LegacyBoot The function pointer to boot the legacy boot option.
43 EfiBootManagerRegisterLegacyBootSupport (
44 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption
,
45 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
48 mBmRefreshLegacyBootOption
= RefreshLegacyBootOption
;
49 mBmLegacyBoot
= LegacyBoot
;
53 For a bootable Device path, return its boot type.
55 @param DevicePath The bootable device Path to check
57 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
58 which HID is floppy device.
59 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
60 and its last device path node's subtype is MSG_ATAPI_DP.
61 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
62 and its last device path node's subtype is MSG_SATA_DP.
63 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
64 and its last device path node's subtype is MSG_SCSI_DP.
65 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
66 and its last device path node's subtype is MSG_USB_DP.
67 @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
68 and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
69 MSG_IPv4_DP or MSG_IPv6_DP.
70 @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.
75 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
78 EFI_DEVICE_PATH_PROTOCOL
*Node
;
79 EFI_DEVICE_PATH_PROTOCOL
*NextNode
;
81 ASSERT (DevicePath
!= NULL
);
83 for (Node
= DevicePath
; !IsDevicePathEndType (Node
); Node
= NextDevicePathNode (Node
)) {
84 switch (DevicePathType (Node
)) {
86 case ACPI_DEVICE_PATH
:
87 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH
*) Node
)->HID
) == 0x0604) {
88 return BmAcpiFloppyBoot
;
92 case HARDWARE_DEVICE_PATH
:
93 if (DevicePathSubType (Node
) == HW_CONTROLLER_DP
) {
94 return BmHardwareDeviceBoot
;
98 case MESSAGING_DEVICE_PATH
:
100 // Skip LUN device node
104 NextNode
= NextDevicePathNode (NextNode
);
106 (DevicePathType (NextNode
) == MESSAGING_DEVICE_PATH
) &&
107 (DevicePathSubType(NextNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
)
111 // If the device path not only point to driver device, it is not a messaging device path,
113 if (!IsDevicePathEndType (NextNode
)) {
117 switch (DevicePathSubType (Node
)) {
119 return BmMessageAtapiBoot
;
123 return BmMessageSataBoot
;
127 return BmMessageUsbBoot
;
131 return BmMessageScsiBoot
;
134 case MSG_MAC_ADDR_DP
:
138 return BmMessageNetworkBoot
;
148 Find the boot option in the NV storage and return the option number.
150 @param OptionToFind Boot option to be checked.
152 @return The option number of the found boot option.
156 BmFindBootOptionInVariable (
157 IN EFI_BOOT_MANAGER_LOAD_OPTION
*OptionToFind
161 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
163 CHAR16 OptionName
[BM_OPTION_NAME_LEN
];
164 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
165 UINTN BootOptionCount
;
168 OptionNumber
= LoadOptionNumberUnassigned
;
171 // Try to match the variable exactly if the option number is assigned
173 if (OptionToFind
->OptionNumber
!= LoadOptionNumberUnassigned
) {
175 OptionName
, sizeof (OptionName
), L
"%s%04x",
176 mBmLoadOptionName
[OptionToFind
->OptionType
], OptionToFind
->OptionNumber
178 Status
= EfiBootManagerVariableToLoadOption (OptionName
, &BootOption
);
180 if (!EFI_ERROR (Status
)) {
181 ASSERT (OptionToFind
->OptionNumber
== BootOption
.OptionNumber
);
182 if ((OptionToFind
->Attributes
== BootOption
.Attributes
) &&
183 (StrCmp (OptionToFind
->Description
, BootOption
.Description
) == 0) &&
184 (CompareMem (OptionToFind
->FilePath
, BootOption
.FilePath
, GetDevicePathSize (OptionToFind
->FilePath
)) == 0) &&
185 (OptionToFind
->OptionalDataSize
== BootOption
.OptionalDataSize
) &&
186 (CompareMem (OptionToFind
->OptionalData
, BootOption
.OptionalData
, OptionToFind
->OptionalDataSize
) == 0)
188 OptionNumber
= OptionToFind
->OptionNumber
;
190 EfiBootManagerFreeLoadOption (&BootOption
);
195 // The option number assigned is either incorrect or unassigned.
197 if (OptionNumber
== LoadOptionNumberUnassigned
) {
198 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
200 Index
= BmFindLoadOption (OptionToFind
, BootOptions
, BootOptionCount
);
202 OptionNumber
= BootOptions
[Index
].OptionNumber
;
205 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
212 Get the file buffer using a Memory Mapped Device Path.
214 FV address may change across reboot. This routine promises the FV file device path is right.
216 @param DevicePath The Memory Mapped Device Path to get the file buffer.
217 @param FullPath Receive the updated FV Device Path pointint to the file.
218 @param FileSize Receive the file buffer size.
220 @return The file buffer.
223 BmGetFileBufferByMemmapFv (
224 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
225 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
231 EFI_DEVICE_PATH_PROTOCOL
*FvFileNode
;
233 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
234 UINT32 AuthenticationStatus
;
236 EFI_HANDLE
*FvHandles
;
237 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
240 FvFileNode
= DevicePath
;
241 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &FvFileNode
, &FvHandle
);
242 if (!EFI_ERROR (Status
)) {
243 FileBuffer
= GetFileBufferByFilePath (TRUE
, DevicePath
, FileSize
, &AuthenticationStatus
);
244 if (FileBuffer
!= NULL
) {
245 *FullPath
= DuplicateDevicePath (DevicePath
);
250 FvFileNode
= NextDevicePathNode (DevicePath
);
253 // Firstly find the FV file in current FV
255 gBS
->HandleProtocol (
257 &gEfiLoadedImageProtocolGuid
,
258 (VOID
**) &LoadedImage
260 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (LoadedImage
->DeviceHandle
), FvFileNode
);
261 FileBuffer
= BmGetFileBufferByMemmapFv (NewDevicePath
, FullPath
, FileSize
);
262 FreePool (NewDevicePath
);
264 if (FileBuffer
!= NULL
) {
269 // Secondly find the FV file in all other FVs
271 gBS
->LocateHandleBuffer (
273 &gEfiFirmwareVolume2ProtocolGuid
,
278 for (Index
= 0; (Index
< FvHandleCount
) && (FileBuffer
== NULL
); Index
++) {
279 if (FvHandles
[Index
] == LoadedImage
->DeviceHandle
) {
285 NewDevicePath
= AppendDevicePathNode (DevicePathFromHandle (FvHandles
[Index
]), FvFileNode
);
286 FileBuffer
= BmGetFileBufferByMemmapFv (NewDevicePath
, FullPath
, FileSize
);
287 FreePool (NewDevicePath
);
290 if (FvHandles
!= NULL
) {
291 FreePool (FvHandles
);
297 Check if it's a Memory Mapped FV Device Path.
299 The function doesn't garentee the device path points to existing FV file.
301 @param DevicePath Input device path.
303 @retval TRUE The device path is a Memory Mapped FV Device Path.
304 @retval FALSE The device path is NOT a Memory Mapped FV Device Path.
307 BmIsMemmapFvFilePath (
308 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
311 EFI_DEVICE_PATH_PROTOCOL
*FileNode
;
313 if ((DevicePathType (DevicePath
) == HARDWARE_DEVICE_PATH
) && (DevicePathSubType (DevicePath
) == HW_MEMMAP_DP
)) {
314 FileNode
= NextDevicePathNode (DevicePath
);
315 if ((DevicePathType (FileNode
) == MEDIA_DEVICE_PATH
) && (DevicePathSubType (FileNode
) == MEDIA_PIWG_FW_FILE_DP
)) {
316 return IsDevicePathEnd (NextDevicePathNode (FileNode
));
324 Check whether a USB device match the specified USB Class device path. This
325 function follows "Load Option Processing" behavior in UEFI specification.
327 @param UsbIo USB I/O protocol associated with the USB device.
328 @param UsbClass The USB Class device path to match.
330 @retval TRUE The USB device match the USB Class device path.
331 @retval FALSE The USB device does not match the USB Class device path.
336 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
337 IN USB_CLASS_DEVICE_PATH
*UsbClass
341 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
342 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
344 UINT8 DeviceSubClass
;
345 UINT8 DeviceProtocol
;
347 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
348 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
353 // Check Vendor Id and Product Id.
355 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
356 if (EFI_ERROR (Status
)) {
360 if ((UsbClass
->VendorId
!= 0xffff) &&
361 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
365 if ((UsbClass
->ProductId
!= 0xffff) &&
366 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
370 DeviceClass
= DevDesc
.DeviceClass
;
371 DeviceSubClass
= DevDesc
.DeviceSubClass
;
372 DeviceProtocol
= DevDesc
.DeviceProtocol
;
373 if (DeviceClass
== 0) {
375 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
376 // Protocol in Interface Descriptor instead.
378 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
379 if (EFI_ERROR (Status
)) {
383 DeviceClass
= IfDesc
.InterfaceClass
;
384 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
385 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
389 // Check Class, SubClass and Protocol.
391 if ((UsbClass
->DeviceClass
!= 0xff) &&
392 (UsbClass
->DeviceClass
!= DeviceClass
)) {
396 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
397 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
401 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
402 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
410 Eliminate the extra spaces in the Str to one space.
412 @param Str Input string info.
415 BmEliminateExtraSpaces (
422 for (Index
= 0, ActualIndex
= 0; Str
[Index
] != L
'\0'; Index
++) {
423 if ((Str
[Index
] != L
' ') || ((ActualIndex
> 0) && (Str
[ActualIndex
- 1] != L
' '))) {
424 Str
[ActualIndex
++] = Str
[Index
];
427 Str
[ActualIndex
] = L
'\0';
431 Try to get the controller's ATA/ATAPI description.
433 @param Handle Controller handle.
435 @return The description string.
438 BmGetDescriptionFromDiskInfo (
444 EFI_DISK_INFO_PROTOCOL
*DiskInfo
;
446 EFI_ATAPI_IDENTIFY_DATA IdentifyData
;
447 EFI_SCSI_INQUIRY_DATA InquiryData
;
450 CONST UINTN ModelNameLength
= 40;
451 CONST UINTN SerialNumberLength
= 20;
457 Status
= gBS
->HandleProtocol (
459 &gEfiDiskInfoProtocolGuid
,
462 if (EFI_ERROR (Status
)) {
466 if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoAhciInterfaceGuid
) ||
467 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoIdeInterfaceGuid
)) {
468 BufferSize
= sizeof (EFI_ATAPI_IDENTIFY_DATA
);
469 Status
= DiskInfo
->Identify (
474 if (!EFI_ERROR (Status
)) {
475 Description
= AllocateZeroPool ((ModelNameLength
+ SerialNumberLength
+ 2) * sizeof (CHAR16
));
476 ASSERT (Description
!= NULL
);
477 for (Index
= 0; Index
+ 1 < ModelNameLength
; Index
+= 2) {
478 Description
[Index
] = (CHAR16
) IdentifyData
.ModelName
[Index
+ 1];
479 Description
[Index
+ 1] = (CHAR16
) IdentifyData
.ModelName
[Index
];
483 Description
[Length
++] = L
' ';
485 for (Index
= 0; Index
+ 1 < SerialNumberLength
; Index
+= 2) {
486 Description
[Length
+ Index
] = (CHAR16
) IdentifyData
.SerialNo
[Index
+ 1];
487 Description
[Length
+ Index
+ 1] = (CHAR16
) IdentifyData
.SerialNo
[Index
];
490 Description
[Length
++] = L
'\0';
491 ASSERT (Length
== ModelNameLength
+ SerialNumberLength
+ 2);
493 BmEliminateExtraSpaces (Description
);
495 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
496 BufferSize
= sizeof (EFI_SCSI_INQUIRY_DATA
);
497 Status
= DiskInfo
->Inquiry (
502 if (!EFI_ERROR (Status
)) {
503 Description
= AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2) * sizeof (CHAR16
));
504 ASSERT (Description
!= NULL
);
507 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
508 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
509 // Here combine the vendor identification and product identification to the description.
511 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
]);
512 Temp
= StrPtr
[VENDOR_IDENTIFICATION_LENGTH
];
513 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = '\0';
514 AsciiStrToUnicodeStr (StrPtr
, Description
);
515 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = Temp
;
518 // Add one space at the middle of vendor information and product information.
520 Description
[VENDOR_IDENTIFICATION_LENGTH
] = L
' ';
522 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
]);
523 StrPtr
[PRODUCT_IDENTIFICATION_LENGTH
] = '\0';
524 AsciiStrToUnicodeStr (StrPtr
, Description
+ VENDOR_IDENTIFICATION_LENGTH
+ 1);
526 BmEliminateExtraSpaces (Description
);
534 Try to get the controller's USB description.
536 @param Handle Controller handle.
538 @return The description string.
541 BmGetUsbDescription (
546 EFI_USB_IO_PROTOCOL
*UsbIo
;
548 CHAR16
*Manufacturer
;
550 CHAR16
*SerialNumber
;
552 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
554 Status
= gBS
->HandleProtocol (
556 &gEfiUsbIoProtocolGuid
,
559 if (EFI_ERROR (Status
)) {
565 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
566 if (EFI_ERROR (Status
)) {
570 Status
= UsbIo
->UsbGetStringDescriptor (
573 DevDesc
.StrManufacturer
,
576 if (EFI_ERROR (Status
)) {
577 Manufacturer
= &NullChar
;
580 Status
= UsbIo
->UsbGetStringDescriptor (
586 if (EFI_ERROR (Status
)) {
590 Status
= UsbIo
->UsbGetStringDescriptor (
593 DevDesc
.StrSerialNumber
,
596 if (EFI_ERROR (Status
)) {
597 SerialNumber
= &NullChar
;
600 if ((Manufacturer
== &NullChar
) &&
601 (Product
== &NullChar
) &&
602 (SerialNumber
== &NullChar
)
607 Description
= AllocateZeroPool (StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
));
608 ASSERT (Description
!= NULL
);
609 StrCat (Description
, Manufacturer
);
610 StrCat (Description
, L
" ");
612 StrCat (Description
, Product
);
613 StrCat (Description
, L
" ");
615 StrCat (Description
, SerialNumber
);
617 if (Manufacturer
!= &NullChar
) {
618 FreePool (Manufacturer
);
620 if (Product
!= &NullChar
) {
623 if (SerialNumber
!= &NullChar
) {
624 FreePool (SerialNumber
);
627 BmEliminateExtraSpaces (Description
);
633 Return the boot description for the controller based on the type.
635 @param Handle Controller handle.
637 @return The description string.
640 BmGetMiscDescription (
646 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
648 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
649 case BmAcpiFloppyBoot
:
650 Description
= L
"Floppy";
653 case BmMessageAtapiBoot
:
654 case BmMessageSataBoot
:
655 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
656 ASSERT_EFI_ERROR (Status
);
658 // Assume a removable SATA device should be the DVD/CD device
660 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
663 case BmMessageUsbBoot
:
664 Description
= L
"USB Device";
667 case BmMessageScsiBoot
:
668 Description
= L
"SCSI Device";
671 case BmHardwareDeviceBoot
:
672 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
673 if (!EFI_ERROR (Status
)) {
674 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
676 Description
= L
"Misc Device";
681 Description
= L
"Misc Device";
685 return AllocateCopyPool (StrSize (Description
), Description
);
688 BM_GET_BOOT_DESCRIPTION mBmGetBootDescription
[] = {
690 BmGetDescriptionFromDiskInfo
,
695 Check whether a USB device match the specified USB WWID device path. This
696 function follows "Load Option Processing" behavior in UEFI specification.
698 @param UsbIo USB I/O protocol associated with the USB device.
699 @param UsbWwid The USB WWID device path to match.
701 @retval TRUE The USB device match the USB WWID device path.
702 @retval FALSE The USB device does not match the USB WWID device path.
707 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
708 IN USB_WWID_DEVICE_PATH
*UsbWwid
712 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
713 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
719 CHAR16
*SerialNumberStr
;
722 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
723 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)) {
728 // Check Vendor Id and Product Id.
730 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
731 if (EFI_ERROR (Status
)) {
734 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
735 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
740 // Check Interface Number.
742 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
743 if (EFI_ERROR (Status
)) {
746 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
751 // Check Serial Number.
753 if (DevDesc
.StrSerialNumber
== 0) {
758 // Get all supported languages.
762 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
763 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
768 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
770 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
771 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
772 if (CompareStr
[CompareLen
- 1] == L
'\0') {
777 // Compare serial number in each supported language.
779 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
780 SerialNumberStr
= NULL
;
781 Status
= UsbIo
->UsbGetStringDescriptor (
784 DevDesc
.StrSerialNumber
,
787 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
791 Length
= StrLen (SerialNumberStr
);
792 if ((Length
>= CompareLen
) &&
793 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
794 FreePool (SerialNumberStr
);
798 FreePool (SerialNumberStr
);
805 Find a USB device which match the specified short-form device path start with
806 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
807 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
808 this function will only search in its child devices.
810 @param DevicePath The device path that contains USB Class or USB WWID device path.
811 @param ParentDevicePathSize The length of the device path before the USB Class or
812 USB WWID device path.
813 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
815 @retval NULL The matched USB IO handles cannot be found.
816 @retval other The matched USB IO handles.
821 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
822 IN UINTN ParentDevicePathSize
,
823 OUT UINTN
*UsbIoHandleCount
827 EFI_HANDLE
*UsbIoHandles
;
828 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
829 EFI_USB_IO_PROTOCOL
*UsbIo
;
831 UINTN UsbIoDevicePathSize
;
834 ASSERT (UsbIoHandleCount
!= NULL
);
837 // Get all UsbIo Handles.
839 Status
= gBS
->LocateHandleBuffer (
841 &gEfiUsbIoProtocolGuid
,
846 if (EFI_ERROR (Status
)) {
847 *UsbIoHandleCount
= 0;
851 for (Index
= 0; Index
< *UsbIoHandleCount
; ) {
853 // Get the Usb IO interface.
855 Status
= gBS
->HandleProtocol(
857 &gEfiUsbIoProtocolGuid
,
860 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandles
[Index
]);
862 if (!EFI_ERROR (Status
) && (UsbIoDevicePath
!= NULL
)) {
863 UsbIoDevicePathSize
= GetDevicePathSize (UsbIoDevicePath
) - END_DEVICE_PATH_LENGTH
;
866 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
868 if (CompareMem (UsbIoDevicePath
, DevicePath
, ParentDevicePathSize
) == 0) {
869 if (BmMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
)) ||
870 BmMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ((UINTN
) DevicePath
+ ParentDevicePathSize
))) {
877 (*UsbIoHandleCount
) --;
878 CopyMem (&UsbIoHandles
[Index
], &UsbIoHandles
[Index
+ 1], (*UsbIoHandleCount
- Index
) * sizeof (EFI_HANDLE
));
888 Expand USB Class or USB WWID device path node to be full device path of a USB
891 This function support following 4 cases:
892 1) Boot Option device path starts with a USB Class or USB WWID device path,
893 and there is no Media FilePath device path in the end.
894 In this case, it will follow Removable Media Boot Behavior.
895 2) Boot Option device path starts with a USB Class or USB WWID device path,
896 and ended with Media FilePath device path.
897 3) Boot Option device path starts with a full device path to a USB Host Controller,
898 contains a USB Class or USB WWID device path node, while not ended with Media
899 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
900 4) Boot Option device path starts with a full device path to a USB Host Controller,
901 contains a USB Class or USB WWID device path node, and ended with Media
902 FilePath device path.
904 @param FilePath The device path pointing to a load option.
905 It could be a short-form device path.
906 @param FullPath Return the full device path of the load option after
907 short-form device path expanding.
908 Caller is responsible to free it.
909 @param FileSize Return the load option size.
910 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
912 @return The load option buffer. Caller is responsible to free the memory.
915 BmExpandUsbDevicePath (
916 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
917 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
919 IN EFI_DEVICE_PATH_PROTOCOL
*ShortformNode
922 UINTN ParentDevicePathSize
;
923 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
924 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
930 ParentDevicePathSize
= (UINTN
) ShortformNode
- (UINTN
) FilePath
;
931 RemainingDevicePath
= NextDevicePathNode (ShortformNode
);
933 Handles
= BmFindUsbDevice (FilePath
, ParentDevicePathSize
, &HandleCount
);
935 for (Index
= 0; (Index
< HandleCount
) && (FileBuffer
== NULL
); Index
++) {
936 FullDevicePath
= AppendDevicePath (DevicePathFromHandle (Handles
[Index
]), RemainingDevicePath
);
937 FileBuffer
= BmGetLoadOptionBuffer (FullDevicePath
, FullPath
, FileSize
);
938 FreePool (FullDevicePath
);
941 if (Handles
!= NULL
) {
949 Save the partition DevicePath to the CachedDevicePath as the first instance.
951 @param CachedDevicePath The device path cache.
952 @param DevicePath The partition device path to be cached.
955 BmCachePartitionDevicePath (
956 IN OUT EFI_DEVICE_PATH_PROTOCOL
**CachedDevicePath
,
957 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
960 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
963 if (BmMatchDevicePaths (*CachedDevicePath
, DevicePath
)) {
964 TempDevicePath
= *CachedDevicePath
;
965 *CachedDevicePath
= BmDelPartMatchInstance (*CachedDevicePath
, DevicePath
);
966 FreePool (TempDevicePath
);
969 if (*CachedDevicePath
== NULL
) {
970 *CachedDevicePath
= DuplicateDevicePath (DevicePath
);
974 TempDevicePath
= *CachedDevicePath
;
975 *CachedDevicePath
= AppendDevicePathInstance (DevicePath
, *CachedDevicePath
);
976 if (TempDevicePath
!= NULL
) {
977 FreePool (TempDevicePath
);
981 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
982 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
985 TempDevicePath
= *CachedDevicePath
;
986 while (!IsDevicePathEnd (TempDevicePath
)) {
987 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
989 // Parse one instance
991 while (!IsDevicePathEndType (TempDevicePath
)) {
992 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
996 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
999 SetDevicePathEndNode (TempDevicePath
);
1006 Expand a device path that starts with a hard drive media device path node to be a
1007 full device path that includes the full hardware path to the device. We need
1008 to do this so it can be booted. As an optimization the front match (the part point
1009 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
1010 so a connect all is not required on every boot. All successful history device path
1011 which point to partition node (the front part) will be saved.
1013 @param FilePath The device path pointing to a load option.
1014 It could be a short-form device path.
1015 @param FullPath Return the full device path of the load option after
1016 short-form device path expanding.
1017 Caller is responsible to free it.
1018 @param FileSize Return the load option size.
1020 @return The load option buffer. Caller is responsible to free the memory.
1023 BmExpandPartitionDevicePath (
1024 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1025 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1030 UINTN BlockIoHandleCount
;
1031 EFI_HANDLE
*BlockIoBuffer
;
1033 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
1035 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
1036 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
1037 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1038 UINTN CachedDevicePathSize
;
1040 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
1045 // Check if there is prestore 'HDDP' variable.
1046 // If exist, search the front path which point to partition node in the variable instants.
1047 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
1049 GetVariable2 (L
"HDDP", &mBmHardDriveBootVariableGuid
, (VOID
**) &CachedDevicePath
, &CachedDevicePathSize
);
1052 // Delete the invalid 'HDDP' variable.
1054 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
1055 FreePool (CachedDevicePath
);
1056 CachedDevicePath
= NULL
;
1057 Status
= gRT
->SetVariable (
1059 &mBmHardDriveBootVariableGuid
,
1064 ASSERT_EFI_ERROR (Status
);
1067 if (CachedDevicePath
!= NULL
) {
1068 TempNewDevicePath
= CachedDevicePath
;
1072 // Check every instance of the variable
1073 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
1074 // partial partition boot option. Second, check whether the instance could be connected.
1076 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
1077 if (BmMatchPartitionDevicePathNode (Instance
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1079 // Connect the device path instance, the device path point to hard drive media device path node
1080 // e.g. ACPI() /PCI()/ATA()/Partition()
1082 Status
= EfiBootManagerConnectDevicePath (Instance
, NULL
);
1083 if (!EFI_ERROR (Status
)) {
1084 TempDevicePath
= AppendDevicePath (Instance
, NextDevicePathNode (FilePath
));
1085 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1086 FreePool (TempDevicePath
);
1088 if (FileBuffer
!= NULL
) {
1090 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
1093 BmCachePartitionDevicePath (&CachedDevicePath
, Instance
);
1095 // Save the matching Device Path so we don't need to do a connect all next time
1096 // Failing to save only impacts performance next time expanding the short-form device path
1098 Status
= gRT
->SetVariable (
1100 &mBmHardDriveBootVariableGuid
,
1101 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1102 GetDevicePathSize (CachedDevicePath
),
1107 FreePool (Instance
);
1108 FreePool (CachedDevicePath
);
1114 // Come here means the first instance is not matched
1118 } while (TempNewDevicePath
!= NULL
);
1122 // If we get here we fail to find or 'HDDP' not exist, and now we need
1123 // to search all devices in the system for a matched partition
1125 EfiBootManagerConnectAll ();
1126 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
1127 if (EFI_ERROR (Status
)) {
1128 BlockIoHandleCount
= 0;
1129 BlockIoBuffer
= NULL
;
1132 // Loop through all the device handles that support the BLOCK_IO Protocol
1134 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
1135 BlockIoDevicePath
= DevicePathFromHandle (BlockIoBuffer
[Index
]);
1136 if (BlockIoDevicePath
== NULL
) {
1140 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath
, (HARDDRIVE_DEVICE_PATH
*) FilePath
)) {
1142 // Find the matched partition device path
1144 TempDevicePath
= AppendDevicePath (BlockIoDevicePath
, NextDevicePathNode (FilePath
));
1145 FileBuffer
= BmGetLoadOptionBuffer (TempDevicePath
, FullPath
, FileSize
);
1146 FreePool (TempDevicePath
);
1148 if (FileBuffer
!= NULL
) {
1149 BmCachePartitionDevicePath (&CachedDevicePath
, BlockIoDevicePath
);
1152 // Save the matching Device Path so we don't need to do a connect all next time
1153 // Failing to save only impacts performance next time expanding the short-form device path
1155 Status
= gRT
->SetVariable (
1157 &mBmHardDriveBootVariableGuid
,
1158 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1159 GetDevicePathSize (CachedDevicePath
),
1168 if (CachedDevicePath
!= NULL
) {
1169 FreePool (CachedDevicePath
);
1171 if (BlockIoBuffer
!= NULL
) {
1172 FreePool (BlockIoBuffer
);
1178 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
1179 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1181 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem 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 BmExpandMediaDevicePath (
1189 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1190 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1196 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1198 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1201 EFI_HANDLE
*SimpleFileSystemHandles
;
1202 UINTN NumberSimpleFileSystemHandles
;
1205 UINT32 AuthenticationStatus
;
1208 // Check whether the device is connected
1210 TempDevicePath
= DevicePath
;
1211 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1212 if (!EFI_ERROR (Status
)) {
1213 ASSERT (IsDevicePathEnd (TempDevicePath
));
1215 TempDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
1216 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1217 if (FileBuffer
== NULL
) {
1218 FreePool (TempDevicePath
);
1219 TempDevicePath
= NULL
;
1221 *FullPath
= TempDevicePath
;
1226 // For device boot option only pointing to the removable device handle,
1227 // should make sure all its children handles (its child partion or media handles) are created and connected.
1229 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1232 // Issue a dummy read to the device to check for media change.
1233 // When the removable media is changed, any Block IO read/write will
1234 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1235 // returned. After the Block IO protocol is reinstalled, subsequent
1236 // Block IO read/write will success.
1238 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1239 ASSERT_EFI_ERROR (Status
);
1240 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1241 ASSERT_EFI_ERROR (Status
);
1242 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1243 if (Buffer
!= NULL
) {
1244 BlockIo
->ReadBlocks (
1246 BlockIo
->Media
->MediaId
,
1248 BlockIo
->Media
->BlockSize
,
1255 // Detect the the default boot file from removable Media
1259 Size
= GetDevicePathSize (DevicePath
) - END_DEVICE_PATH_LENGTH
;
1260 gBS
->LocateHandleBuffer (
1262 &gEfiSimpleFileSystemProtocolGuid
,
1264 &NumberSimpleFileSystemHandles
,
1265 &SimpleFileSystemHandles
1267 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1269 // Get the device path size of SimpleFileSystem handle
1271 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1272 TempSize
= GetDevicePathSize (TempDevicePath
) - END_DEVICE_PATH_LENGTH
;
1274 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1276 if ((Size
<= TempSize
) && (CompareMem (TempDevicePath
, DevicePath
, Size
) == 0)) {
1277 TempDevicePath
= FileDevicePath (SimpleFileSystemHandles
[Index
], EFI_REMOVABLE_MEDIA_FILE_NAME
);
1278 FileBuffer
= GetFileBufferByFilePath (TRUE
, TempDevicePath
, FileSize
, &AuthenticationStatus
);
1279 if (FileBuffer
!= NULL
) {
1280 *FullPath
= TempDevicePath
;
1283 FreePool (TempDevicePath
);
1287 if (SimpleFileSystemHandles
!= NULL
) {
1288 FreePool (SimpleFileSystemHandles
);
1295 Get the load option by its device path.
1297 @param FilePath The device path pointing to a load option.
1298 It could be a short-form device path.
1299 @param FullPath Return the full device path of the load option after
1300 short-form device path expanding.
1301 Caller is responsible to free it.
1302 @param FileSize Return the load option size.
1304 @return The load option buffer. Caller is responsible to free the memory.
1307 BmGetLoadOptionBuffer (
1308 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
1309 OUT EFI_DEVICE_PATH_PROTOCOL
**FullPath
,
1315 UINT32 AuthenticationStatus
;
1316 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1319 ASSERT ((FilePath
!= NULL
) && (FullPath
!= NULL
) && (FileSize
!= NULL
));
1321 EfiBootManagerConnectDevicePath (FilePath
, NULL
);
1328 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1331 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &Node
, &Handle
);
1332 if (EFI_ERROR (Status
)) {
1333 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &Node
, &Handle
);
1336 if (!EFI_ERROR (Status
) && IsDevicePathEnd (Node
)) {
1337 return BmExpandMediaDevicePath (FilePath
, FullPath
, FileSize
);
1341 // Expand the short-form device path to full device path
1343 if ((DevicePathType (FilePath
) == MEDIA_DEVICE_PATH
) &&
1344 (DevicePathSubType (FilePath
) == MEDIA_HARDDRIVE_DP
)) {
1346 // Expand the Harddrive device path
1348 return BmExpandPartitionDevicePath (FilePath
, FullPath
, FileSize
);
1350 for (Node
= FilePath
; !IsDevicePathEnd (Node
); Node
= NextDevicePathNode (Node
)) {
1351 if ((DevicePathType (Node
) == MESSAGING_DEVICE_PATH
) &&
1352 ((DevicePathSubType (Node
) == MSG_USB_CLASS_DP
) || (DevicePathSubType (Node
) == MSG_USB_WWID_DP
))) {
1357 if (!IsDevicePathEnd (Node
)) {
1359 // Expand the USB WWID/Class device path
1361 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1362 if ((FileBuffer
== NULL
) && (FilePath
== Node
)) {
1364 // Boot Option device path starts with USB Class or USB WWID device path.
1365 // For Boot Option device path which doesn't begin with the USB Class or
1366 // USB WWID device path, it's not needed to connect again here.
1368 BmConnectUsbShortFormDevicePath (FilePath
);
1369 FileBuffer
= BmExpandUsbDevicePath (FilePath
, FullPath
, FileSize
, Node
);
1376 // Fix up the boot option path if it points to a FV in memory map style of device path
1378 if (BmIsMemmapFvFilePath (FilePath
)) {
1379 return BmGetFileBufferByMemmapFv (FilePath
, FullPath
, FileSize
);
1383 // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),
1384 // or it directly points to a file in simple file system instance.
1386 FileBuffer
= GetFileBufferByFilePath (TRUE
, FilePath
, FileSize
, &AuthenticationStatus
);
1387 if (FileBuffer
!= NULL
) {
1388 *FullPath
= DuplicateDevicePath (FilePath
);
1395 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1396 also signals the EFI ready to boot event. If the device path for the option
1397 starts with a BBS device path a legacy boot is attempted via the registered
1398 gLegacyBoot function. Short form device paths are also supported via this
1399 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1400 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1401 If the BootOption Device Path fails the removable media boot algorithm
1402 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1403 is tried per processor type)
1405 @param BootOption Boot Option to try and boot.
1406 On return, BootOption->Status contains the boot status.
1407 EFI_SUCCESS BootOption was booted
1408 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1409 registered via EfiBootManagerInitialize().
1410 EFI_NOT_FOUND The BootOption was not found on the system
1411 !EFI_SUCCESS BootOption failed with this error status
1416 EfiBootManagerBoot (
1417 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1421 EFI_HANDLE ImageHandle
;
1422 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
1425 UINTN OriginalOptionNumber
;
1426 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
1427 EFI_DEVICE_PATH_PROTOCOL
*Node
;
1428 EFI_HANDLE FvHandle
;
1431 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
1432 EFI_EVENT LegacyBootEvent
;
1434 if (BootOption
== NULL
) {
1438 if (BootOption
->FilePath
== NULL
|| BootOption
->OptionType
!= LoadOptionTypeBoot
) {
1439 BootOption
->Status
= EFI_INVALID_PARAMETER
;
1444 // 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")
1446 OptionNumber
= BmFindBootOptionInVariable (BootOption
);
1447 if (OptionNumber
== LoadOptionNumberUnassigned
) {
1448 Status
= BmGetFreeOptionNumber (LoadOptionTypeBoot
, &Uint16
);
1449 if (!EFI_ERROR (Status
)) {
1451 // Save the BootOption->OptionNumber to restore later
1453 OptionNumber
= Uint16
;
1454 OriginalOptionNumber
= BootOption
->OptionNumber
;
1455 BootOption
->OptionNumber
= OptionNumber
;
1456 Status
= EfiBootManagerLoadOptionToVariable (BootOption
);
1457 BootOption
->OptionNumber
= OriginalOptionNumber
;
1460 if (EFI_ERROR (Status
)) {
1461 DEBUG ((EFI_D_ERROR
, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status
));
1462 BootOption
->Status
= Status
;
1468 // 2. Set BootCurrent
1470 Uint16
= (UINT16
) OptionNumber
;
1471 BmSetVariableAndReportStatusCodeOnError (
1473 &gEfiGlobalVariableGuid
,
1474 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1480 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1483 Node
= BootOption
->FilePath
;
1484 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
1485 if (!EFI_ERROR (Status
) && CompareGuid (
1486 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
1487 PcdGetPtr (PcdBootManagerMenuFile
)
1489 DEBUG ((EFI_D_INFO
, "[Bds] Booting Boot Manager Menu.\n"));
1490 BmStopHotkeyService (NULL
, NULL
);
1492 EfiSignalEventReadyToBoot();
1494 // Report Status Code to indicate ReadyToBoot was signalled
1496 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
1498 // 4. Repair system through DriverHealth protocol
1500 BmRepairAllControllers ();
1503 PERF_START_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1506 // 5. Load EFI boot option to ImageHandle
1509 if (DevicePathType (BootOption
->FilePath
) != BBS_DEVICE_PATH
) {
1510 Status
= EFI_NOT_FOUND
;
1511 FileBuffer
= BmGetLoadOptionBuffer (BootOption
->FilePath
, &FilePath
, &FileSize
);
1513 if (FileBuffer
!= NULL
&& CompareMem (BootOption
->FilePath
, FilePath
, GetDevicePathSize (FilePath
)) != 0) {
1514 DEBUG ((EFI_D_INFO
, "[Bds] DevicePath expand: "));
1515 BmPrintDp (BootOption
->FilePath
);
1516 DEBUG ((EFI_D_INFO
, " -> "));
1517 BmPrintDp (FilePath
);
1518 DEBUG ((EFI_D_INFO
, "\n"));
1521 if (BmIsLoadOptionPeHeaderValid (BootOption
->OptionType
, FileBuffer
, FileSize
)) {
1522 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
1523 Status
= gBS
->LoadImage (
1532 if (FileBuffer
!= NULL
) {
1533 FreePool (FileBuffer
);
1535 if (FilePath
!= NULL
) {
1536 FreePool (FilePath
);
1539 if (EFI_ERROR (Status
)) {
1541 // Report Status Code to indicate that the failure to load boot option
1543 REPORT_STATUS_CODE (
1544 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1545 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
1547 BootOption
->Status
= Status
;
1553 // 6. Adjust the different type memory page number just before booting
1554 // and save the updated info into the variable for next boot to use
1556 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_BOOT
) {
1557 if (PcdGetBool (PcdResetOnMemoryTypeInformationChange
)) {
1558 BmSetMemoryTypeInformationVariable ();
1563 if (BootOption
->Description
== NULL
) {
1564 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting from unknown device path\n"));
1566 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "[Bds]Booting %s\n", BootOption
->Description
));
1571 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1572 // Write boot to OS performance data for Legacy boot
1574 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) && (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1575 if (mBmLegacyBoot
!= NULL
) {
1577 // Write boot to OS performance data for legacy boot.
1581 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1583 Status
= EfiCreateEventLegacyBootEx(
1585 BmWriteBootToOsPerformanceData
,
1589 ASSERT_EFI_ERROR (Status
);
1592 mBmLegacyBoot (BootOption
);
1594 BootOption
->Status
= EFI_UNSUPPORTED
;
1597 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1602 // Provide the image with its load options
1604 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
1605 ASSERT_EFI_ERROR (Status
);
1607 ImageInfo
->LoadOptionsSize
= BootOption
->OptionalDataSize
;
1608 ImageInfo
->LoadOptions
= BootOption
->OptionalData
;
1611 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1613 ImageInfo
->ParentHandle
= NULL
;
1616 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1618 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
1621 // Write boot to OS performance data for UEFI boot
1624 BmWriteBootToOsPerformanceData (NULL
, NULL
);
1627 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
1629 Status
= gBS
->StartImage (ImageHandle
, &BootOption
->ExitDataSize
, &BootOption
->ExitData
);
1630 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
1631 BootOption
->Status
= Status
;
1632 if (EFI_ERROR (Status
)) {
1634 // Report Status Code to indicate that boot failure
1636 REPORT_STATUS_CODE (
1637 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1638 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
1641 PERF_END_EX (gImageHandle
, "BdsAttempt", NULL
, 0, (UINT32
) OptionNumber
);
1644 // Clear the Watchdog Timer after the image returns
1646 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
1649 // Set Logo status invalid after trying one boot option
1652 Status
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
1653 if (!EFI_ERROR (Status
) && (BootLogo
!= NULL
)) {
1654 Status
= BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
1655 ASSERT_EFI_ERROR (Status
);
1659 // Clear Boot Current
1661 Status
= gRT
->SetVariable (
1663 &gEfiGlobalVariableGuid
,
1669 // Deleting variable with current variable implementation shouldn't fail.
1670 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1671 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1673 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
1677 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1678 instances, has the same partition node with HardDriveDevicePath device path
1680 @param BlockIoDevicePath Multi device path instances which need to check
1681 @param HardDriveDevicePath A device path which starts with a hard drive media
1684 @retval TRUE There is a matched device path instance.
1685 @retval FALSE There is no matched device path instance.
1689 BmMatchPartitionDevicePathNode (
1690 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
1691 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
1694 HARDDRIVE_DEVICE_PATH
*Node
;
1696 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
1701 // find the partition device path node
1703 while (!IsDevicePathEnd (BlockIoDevicePath
)) {
1704 if ((DevicePathType (BlockIoDevicePath
) == MEDIA_DEVICE_PATH
) &&
1705 (DevicePathSubType (BlockIoDevicePath
) == MEDIA_HARDDRIVE_DP
)
1710 BlockIoDevicePath
= NextDevicePathNode (BlockIoDevicePath
);
1713 if (IsDevicePathEnd (BlockIoDevicePath
)) {
1718 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1720 Node
= (HARDDRIVE_DEVICE_PATH
*) BlockIoDevicePath
;
1723 // Match Signature and PartitionNumber.
1724 // Unused bytes in Signature are initiaized with zeros.
1727 (Node
->PartitionNumber
== HardDriveDevicePath
->PartitionNumber
) &&
1728 (Node
->MBRType
== HardDriveDevicePath
->MBRType
) &&
1729 (Node
->SignatureType
== HardDriveDevicePath
->SignatureType
) &&
1730 (CompareMem (Node
->Signature
, HardDriveDevicePath
->Signature
, sizeof (Node
->Signature
)) == 0)
1735 Emuerate all possible bootable medias in the following order:
1736 1. Removable BlockIo - The boot option only points to the removable media
1737 device, like USB key, DVD, Floppy etc.
1738 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1740 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1741 SimpleFileSystem Protocol, but not supporting BlockIo
1743 4. LoadFile - The boot option points to the media supporting
1745 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1747 @param BootOptionCount Return the boot option count which has been found.
1749 @retval Pointer to the boot option array.
1751 EFI_BOOT_MANAGER_LOAD_OPTION
*
1752 BmEnumerateBootOptions (
1753 UINTN
*BootOptionCount
1757 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1758 UINT16 NonBlockNumber
;
1760 EFI_HANDLE
*Handles
;
1761 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
1764 UINTN FunctionIndex
;
1766 CHAR16
*DescriptionPtr
;
1767 CHAR16 Description
[30];
1769 ASSERT (BootOptionCount
!= NULL
);
1771 *BootOptionCount
= 0;
1775 // Parse removable block io followed by fixed block io
1777 gBS
->LocateHandleBuffer (
1779 &gEfiBlockIoProtocolGuid
,
1785 for (Removable
= 0; Removable
< 2; Removable
++) {
1786 for (Index
= 0; Index
< HandleCount
; Index
++) {
1787 Status
= gBS
->HandleProtocol (
1789 &gEfiBlockIoProtocolGuid
,
1792 if (EFI_ERROR (Status
)) {
1797 // Skip the logical partitions
1799 if (BlkIo
->Media
->LogicalPartition
) {
1804 // Skip the fixed block io then the removable block io
1806 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
1810 DescriptionPtr
= NULL
;
1811 for (FunctionIndex
= 0; FunctionIndex
< sizeof (mBmGetBootDescription
) / sizeof (mBmGetBootDescription
[0]); FunctionIndex
++) {
1812 DescriptionPtr
= mBmGetBootDescription
[FunctionIndex
] (Handles
[Index
]);
1813 if (DescriptionPtr
!= NULL
) {
1818 if (DescriptionPtr
== NULL
) {
1823 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
1825 Temp
= AllocatePool (StrSize (DescriptionPtr
) + sizeof (mBmUefiPrefix
));
1826 ASSERT (Temp
!= NULL
);
1827 StrCpy (Temp
, mBmUefiPrefix
);
1828 StrCat (Temp
, DescriptionPtr
);
1829 FreePool (DescriptionPtr
);
1830 DescriptionPtr
= Temp
;
1832 BootOptions
= ReallocatePool (
1833 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1834 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1837 ASSERT (BootOptions
!= NULL
);
1839 Status
= EfiBootManagerInitializeLoadOption (
1840 &BootOptions
[(*BootOptionCount
)++],
1841 LoadOptionNumberUnassigned
,
1845 DevicePathFromHandle (Handles
[Index
]),
1849 ASSERT_EFI_ERROR (Status
);
1851 FreePool (DescriptionPtr
);
1855 if (HandleCount
!= 0) {
1860 // Parse simple file system not based on block io
1863 gBS
->LocateHandleBuffer (
1865 &gEfiSimpleFileSystemProtocolGuid
,
1870 for (Index
= 0; Index
< HandleCount
; Index
++) {
1871 Status
= gBS
->HandleProtocol (
1873 &gEfiBlockIoProtocolGuid
,
1876 if (!EFI_ERROR (Status
)) {
1878 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
1882 UnicodeSPrint (Description
, sizeof (Description
), NonBlockNumber
> 0 ? L
"%s %d" : L
"%s", L
"UEFI Non-Block Boot Device", NonBlockNumber
);
1884 BootOptions
= ReallocatePool (
1885 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1886 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1889 ASSERT (BootOptions
!= NULL
);
1891 Status
= EfiBootManagerInitializeLoadOption (
1892 &BootOptions
[(*BootOptionCount
)++],
1893 LoadOptionNumberUnassigned
,
1897 DevicePathFromHandle (Handles
[Index
]),
1901 ASSERT_EFI_ERROR (Status
);
1904 if (HandleCount
!= 0) {
1909 // Parse load file, assuming UEFI Network boot option
1911 gBS
->LocateHandleBuffer (
1913 &gEfiLoadFileProtocolGuid
,
1918 for (Index
= 0; Index
< HandleCount
; Index
++) {
1920 UnicodeSPrint (Description
, sizeof (Description
), Index
> 0 ? L
"%s %d" : L
"%s", L
"UEFI Network", Index
);
1922 BootOptions
= ReallocatePool (
1923 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1924 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1927 ASSERT (BootOptions
!= NULL
);
1929 Status
= EfiBootManagerInitializeLoadOption (
1930 &BootOptions
[(*BootOptionCount
)++],
1931 LoadOptionNumberUnassigned
,
1935 DevicePathFromHandle (Handles
[Index
]),
1939 ASSERT_EFI_ERROR (Status
);
1942 if (HandleCount
!= 0) {
1950 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
1954 EfiBootManagerRefreshAllBootOption (
1959 EFI_BOOT_MANAGER_LOAD_OPTION
*NvBootOptions
;
1960 UINTN NvBootOptionCount
;
1961 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1962 UINTN BootOptionCount
;
1966 // Optionally refresh the legacy boot option
1968 if (mBmRefreshLegacyBootOption
!= NULL
) {
1969 mBmRefreshLegacyBootOption ();
1972 BootOptions
= BmEnumerateBootOptions (&BootOptionCount
);
1973 NvBootOptions
= EfiBootManagerGetLoadOptions (&NvBootOptionCount
, LoadOptionTypeBoot
);
1976 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
1978 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
1979 BootOptions
[Index
].OptionalData
= AllocateCopyPool (sizeof (EFI_GUID
), &mBmAutoCreateBootOptionGuid
);
1980 BootOptions
[Index
].OptionalDataSize
= sizeof (EFI_GUID
);
1984 // Remove invalid EFI boot options from NV
1986 for (Index
= 0; Index
< NvBootOptionCount
; Index
++) {
1987 if (((DevicePathType (NvBootOptions
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
1988 (DevicePathSubType (NvBootOptions
[Index
].FilePath
) != BBS_BBS_DP
)
1990 (NvBootOptions
[Index
].OptionalDataSize
== sizeof (EFI_GUID
)) &&
1991 CompareGuid ((EFI_GUID
*) NvBootOptions
[Index
].OptionalData
, &mBmAutoCreateBootOptionGuid
)
1994 // Only check those added by BDS
1995 // so that the boot options added by end-user or OS installer won't be deleted
1997 if (BmFindLoadOption (&NvBootOptions
[Index
], BootOptions
, BootOptionCount
) == (UINTN
) -1) {
1998 Status
= EfiBootManagerDeleteLoadOptionVariable (NvBootOptions
[Index
].OptionNumber
, LoadOptionTypeBoot
);
2000 // Deleting variable with current variable implementation shouldn't fail.
2002 ASSERT_EFI_ERROR (Status
);
2008 // Add new EFI boot options to NV
2010 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2011 if (BmFindLoadOption (&BootOptions
[Index
], NvBootOptions
, NvBootOptionCount
) == (UINTN
) -1) {
2012 EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
2014 // Try best to add the boot options so continue upon failure.
2019 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2020 EfiBootManagerFreeLoadOptions (NvBootOptions
, NvBootOptionCount
);
2024 This function is called to create the boot option for the Boot Manager Menu.
2026 The Boot Manager Menu is shown after successfully booting a boot option.
2027 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2029 @param BootOption Return the boot option of the Boot Manager Menu
2031 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2032 @retval Status Return status of gRT->SetVariable (). BootOption still points
2033 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2036 BmRegisterBootManagerMenu (
2037 OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2041 CHAR16
*Description
;
2042 UINTN DescriptionLength
;
2043 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2044 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
2045 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode
;
2047 Status
= GetSectionFromFv (
2048 PcdGetPtr (PcdBootManagerMenuFile
),
2049 EFI_SECTION_USER_INTERFACE
,
2051 (VOID
**) &Description
,
2054 if (EFI_ERROR (Status
)) {
2058 EfiInitializeFwVolDevicepathNode (&FileNode
, PcdGetPtr (PcdBootManagerMenuFile
));
2059 Status
= gBS
->HandleProtocol (
2061 &gEfiLoadedImageProtocolGuid
,
2062 (VOID
**) &LoadedImage
2064 ASSERT_EFI_ERROR (Status
);
2065 DevicePath
= AppendDevicePathNode (
2066 DevicePathFromHandle (LoadedImage
->DeviceHandle
),
2067 (EFI_DEVICE_PATH_PROTOCOL
*) &FileNode
2069 ASSERT (DevicePath
!= NULL
);
2071 Status
= EfiBootManagerInitializeLoadOption (
2073 LoadOptionNumberUnassigned
,
2075 LOAD_OPTION_CATEGORY_APP
| LOAD_OPTION_ACTIVE
| LOAD_OPTION_HIDDEN
,
2076 (Description
!= NULL
) ? Description
: L
"Boot Manager Menu",
2081 ASSERT_EFI_ERROR (Status
);
2082 FreePool (DevicePath
);
2083 if (Description
!= NULL
) {
2084 FreePool (Description
);
2088 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2089 UINTN BootOptionCount
;
2091 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2092 ASSERT (BmFindLoadOption (BootOption
, BootOptions
, BootOptionCount
) == -1);
2093 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2096 return EfiBootManagerAddLoadOptionVariable (BootOption
, 0);
2100 Return the boot option corresponding to the Boot Manager Menu.
2101 It may automatically create one if the boot option hasn't been created yet.
2103 @param BootOption Return the Boot Manager Menu.
2105 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2106 @retval Status Return status of gRT->SetVariable (). BootOption still points
2107 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2111 EfiBootManagerGetBootManagerMenu (
2112 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
2116 UINTN BootOptionCount
;
2117 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
2119 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2120 EFI_HANDLE FvHandle
;
2122 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
2124 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
2125 Node
= BootOptions
[Index
].FilePath
;
2126 Status
= gBS
->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid
, &Node
, &FvHandle
);
2127 if (!EFI_ERROR (Status
)) {
2129 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) Node
),
2130 PcdGetPtr (PcdBootManagerMenuFile
)
2133 Status
= EfiBootManagerInitializeLoadOption (
2135 BootOptions
[Index
].OptionNumber
,
2136 BootOptions
[Index
].OptionType
,
2137 BootOptions
[Index
].Attributes
,
2138 BootOptions
[Index
].Description
,
2139 BootOptions
[Index
].FilePath
,
2140 BootOptions
[Index
].OptionalData
,
2141 BootOptions
[Index
].OptionalDataSize
2143 ASSERT_EFI_ERROR (Status
);
2149 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
2152 // Automatically create the Boot#### for Boot Manager Menu when not found.
2154 if (Index
== BootOptionCount
) {
2155 return BmRegisterBootManagerMenu (BootOption
);