2 Library functions which relate with boot option description.
4 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "InternalBm.h"
12 #define VENDOR_IDENTIFICATION_OFFSET 3
13 #define VENDOR_IDENTIFICATION_LENGTH 8
14 #define PRODUCT_IDENTIFICATION_OFFSET 11
15 #define PRODUCT_IDENTIFICATION_LENGTH 16
17 CONST UINT16 mBmUsbLangId
= 0x0409; // English
18 CHAR16 mBmUefiPrefix
[] = L
"UEFI ";
20 LIST_ENTRY mPlatformBootDescriptionHandlers
= INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers
);
23 For a bootable Device path, return its boot type.
25 @param DevicePath The bootable device Path to check
27 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
28 which HID is floppy device.
29 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
30 and its last device path node's subtype is MSG_ATAPI_DP.
31 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
32 and its last device path node's subtype is MSG_SATA_DP.
33 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
34 and its last device path node's subtype is MSG_SCSI_DP.
35 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
36 and its last device path node's subtype is MSG_USB_DP.
37 @retval BmMiscBoot If tiven device path doesn't match the above condition.
42 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
45 EFI_DEVICE_PATH_PROTOCOL
*Node
;
46 EFI_DEVICE_PATH_PROTOCOL
*NextNode
;
48 ASSERT (DevicePath
!= NULL
);
50 for (Node
= DevicePath
; !IsDevicePathEndType (Node
); Node
= NextDevicePathNode (Node
)) {
51 switch (DevicePathType (Node
)) {
53 case ACPI_DEVICE_PATH
:
54 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH
*) Node
)->HID
) == 0x0604) {
55 return BmAcpiFloppyBoot
;
59 case HARDWARE_DEVICE_PATH
:
60 if (DevicePathSubType (Node
) == HW_CONTROLLER_DP
) {
61 return BmHardwareDeviceBoot
;
65 case MESSAGING_DEVICE_PATH
:
67 // Skip LUN device node
71 NextNode
= NextDevicePathNode (NextNode
);
73 (DevicePathType (NextNode
) == MESSAGING_DEVICE_PATH
) &&
74 (DevicePathSubType(NextNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
)
78 // If the device path not only point to driver device, it is not a messaging device path,
80 if (!IsDevicePathEndType (NextNode
)) {
84 switch (DevicePathSubType (Node
)) {
86 return BmMessageAtapiBoot
;
90 return BmMessageSataBoot
;
94 return BmMessageUsbBoot
;
98 return BmMessageScsiBoot
;
108 Eliminate the extra spaces in the Str to one space.
110 @param Str Input string info.
113 BmEliminateExtraSpaces (
120 for (Index
= 0, ActualIndex
= 0; Str
[Index
] != L
'\0'; Index
++) {
121 if ((Str
[Index
] != L
' ') || ((ActualIndex
> 0) && (Str
[ActualIndex
- 1] != L
' '))) {
122 Str
[ActualIndex
++] = Str
[Index
];
125 Str
[ActualIndex
] = L
'\0';
129 Try to get the controller's ATA/ATAPI description.
131 @param Handle Controller handle.
133 @return The description string.
136 BmGetDescriptionFromDiskInfo (
142 EFI_DISK_INFO_PROTOCOL
*DiskInfo
;
144 EFI_ATAPI_IDENTIFY_DATA IdentifyData
;
145 EFI_SCSI_INQUIRY_DATA InquiryData
;
148 CONST UINTN ModelNameLength
= 40;
149 CONST UINTN SerialNumberLength
= 20;
152 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
156 Status
= gBS
->HandleProtocol (
158 &gEfiDiskInfoProtocolGuid
,
161 if (EFI_ERROR (Status
)) {
165 if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoAhciInterfaceGuid
) ||
166 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoIdeInterfaceGuid
)) {
167 BufferSize
= sizeof (EFI_ATAPI_IDENTIFY_DATA
);
168 Status
= DiskInfo
->Identify (
173 if (!EFI_ERROR (Status
)) {
174 Description
= AllocateZeroPool ((ModelNameLength
+ SerialNumberLength
+ 2) * sizeof (CHAR16
));
175 ASSERT (Description
!= NULL
);
176 for (Index
= 0; Index
+ 1 < ModelNameLength
; Index
+= 2) {
177 Description
[Index
] = (CHAR16
) IdentifyData
.ModelName
[Index
+ 1];
178 Description
[Index
+ 1] = (CHAR16
) IdentifyData
.ModelName
[Index
];
182 Description
[Length
++] = L
' ';
184 for (Index
= 0; Index
+ 1 < SerialNumberLength
; Index
+= 2) {
185 Description
[Length
+ Index
] = (CHAR16
) IdentifyData
.SerialNo
[Index
+ 1];
186 Description
[Length
+ Index
+ 1] = (CHAR16
) IdentifyData
.SerialNo
[Index
];
189 Description
[Length
++] = L
'\0';
190 ASSERT (Length
== ModelNameLength
+ SerialNumberLength
+ 2);
192 BmEliminateExtraSpaces (Description
);
194 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
195 BufferSize
= sizeof (EFI_SCSI_INQUIRY_DATA
);
196 Status
= DiskInfo
->Inquiry (
201 if (!EFI_ERROR (Status
)) {
202 Description
= AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2) * sizeof (CHAR16
));
203 ASSERT (Description
!= NULL
);
206 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
207 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
208 // Here combine the vendor identification and product identification to the description.
210 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
]);
211 Temp
= StrPtr
[VENDOR_IDENTIFICATION_LENGTH
];
212 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = '\0';
213 AsciiStrToUnicodeStrS (StrPtr
, Description
, VENDOR_IDENTIFICATION_LENGTH
+ 1);
214 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = Temp
;
217 // Add one space at the middle of vendor information and product information.
219 Description
[VENDOR_IDENTIFICATION_LENGTH
] = L
' ';
221 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
]);
222 StrPtr
[PRODUCT_IDENTIFICATION_LENGTH
] = '\0';
223 AsciiStrToUnicodeStrS (StrPtr
, Description
+ VENDOR_IDENTIFICATION_LENGTH
+ 1, PRODUCT_IDENTIFICATION_LENGTH
+ 1);
225 BmEliminateExtraSpaces (Description
);
227 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoSdMmcInterfaceGuid
)) {
228 DevicePath
= DevicePathFromHandle (Handle
);
229 if (DevicePath
== NULL
) {
233 while (!IsDevicePathEnd (DevicePath
) && (DevicePathType (DevicePath
) != MESSAGING_DEVICE_PATH
)) {
234 DevicePath
= NextDevicePathNode (DevicePath
);
236 if (IsDevicePathEnd (DevicePath
)) {
240 if (DevicePathSubType (DevicePath
) == MSG_SD_DP
) {
241 Description
= L
"SD Device";
242 } else if (DevicePathSubType (DevicePath
) == MSG_EMMC_DP
) {
243 Description
= L
"eMMC Device";
248 Description
= AllocateCopyPool (StrSize (Description
), Description
);
255 Try to get the controller's USB description.
257 @param Handle Controller handle.
259 @return The description string.
262 BmGetUsbDescription (
267 EFI_USB_IO_PROTOCOL
*UsbIo
;
269 CHAR16
*Manufacturer
;
271 CHAR16
*SerialNumber
;
273 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
276 Status
= gBS
->HandleProtocol (
278 &gEfiUsbIoProtocolGuid
,
281 if (EFI_ERROR (Status
)) {
287 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
288 if (EFI_ERROR (Status
)) {
292 Status
= UsbIo
->UsbGetStringDescriptor (
295 DevDesc
.StrManufacturer
,
298 if (EFI_ERROR (Status
)) {
299 Manufacturer
= &NullChar
;
302 Status
= UsbIo
->UsbGetStringDescriptor (
308 if (EFI_ERROR (Status
)) {
312 Status
= UsbIo
->UsbGetStringDescriptor (
315 DevDesc
.StrSerialNumber
,
318 if (EFI_ERROR (Status
)) {
319 SerialNumber
= &NullChar
;
322 if ((Manufacturer
== &NullChar
) &&
323 (Product
== &NullChar
) &&
324 (SerialNumber
== &NullChar
)
329 DescMaxSize
= StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
);
330 Description
= AllocateZeroPool (DescMaxSize
);
331 ASSERT (Description
!= NULL
);
332 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Manufacturer
);
333 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
335 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Product
);
336 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
338 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), SerialNumber
);
340 if (Manufacturer
!= &NullChar
) {
341 FreePool (Manufacturer
);
343 if (Product
!= &NullChar
) {
346 if (SerialNumber
!= &NullChar
) {
347 FreePool (SerialNumber
);
350 BmEliminateExtraSpaces (Description
);
356 Return the description for network boot device.
358 @param Handle Controller handle.
360 @return The description string.
363 BmGetNetworkDescription (
368 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
369 MAC_ADDR_DEVICE_PATH
*Mac
;
370 VLAN_DEVICE_PATH
*Vlan
;
371 EFI_DEVICE_PATH_PROTOCOL
*Ip
;
372 EFI_DEVICE_PATH_PROTOCOL
*Uri
;
374 UINTN DescriptionSize
;
376 Status
= gBS
->OpenProtocol (
378 &gEfiLoadFileProtocolGuid
,
382 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
384 if (EFI_ERROR (Status
)) {
388 Status
= gBS
->OpenProtocol (
390 &gEfiDevicePathProtocolGuid
,
391 (VOID
**) &DevicePath
,
394 EFI_OPEN_PROTOCOL_GET_PROTOCOL
396 if (EFI_ERROR (Status
) || (DevicePath
== NULL
)) {
401 // The PXE device path is like:
402 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]
403 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)
404 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)
406 // The HTTP device path is like:
407 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)
408 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)
410 while (!IsDevicePathEnd (DevicePath
) &&
411 ((DevicePathType (DevicePath
) != MESSAGING_DEVICE_PATH
) ||
412 (DevicePathSubType (DevicePath
) != MSG_MAC_ADDR_DP
))
414 DevicePath
= NextDevicePathNode (DevicePath
);
417 if (IsDevicePathEnd (DevicePath
)) {
421 Mac
= (MAC_ADDR_DEVICE_PATH
*) DevicePath
;
422 DevicePath
= NextDevicePathNode (DevicePath
);
425 // Locate the optional Vlan node
427 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
428 (DevicePathSubType (DevicePath
) == MSG_VLAN_DP
)
430 Vlan
= (VLAN_DEVICE_PATH
*) DevicePath
;
431 DevicePath
= NextDevicePathNode (DevicePath
);
437 // Skip the optional Wi-Fi node
439 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
440 (DevicePathSubType (DevicePath
) == MSG_WIFI_DP
)
442 DevicePath
= NextDevicePathNode (DevicePath
);
446 // Locate the IP node
448 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
449 ((DevicePathSubType (DevicePath
) == MSG_IPv4_DP
) ||
450 (DevicePathSubType (DevicePath
) == MSG_IPv6_DP
))
453 DevicePath
= NextDevicePathNode (DevicePath
);
459 // Skip the optional DNS node
461 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
462 (DevicePathSubType (DevicePath
) == MSG_DNS_DP
)
464 DevicePath
= NextDevicePathNode (DevicePath
);
468 // Locate the URI node
470 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
471 (DevicePathSubType (DevicePath
) == MSG_URI_DP
)
474 DevicePath
= NextDevicePathNode (DevicePath
);
480 // Build description like below:
481 // "PXEv6 (MAC:112233445566 VLAN1)"
482 // "HTTPv4 (MAC:112233445566)"
484 DescriptionSize
= sizeof (L
"HTTPv6 (MAC:112233445566 VLAN65535)");
485 Description
= AllocatePool (DescriptionSize
);
486 ASSERT (Description
!= NULL
);
488 Description
, DescriptionSize
,
490 L
"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :
491 L
"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",
492 (Uri
== NULL
) ? L
"PXE" : L
"HTTP",
493 ((Ip
== NULL
) || (DevicePathSubType (Ip
) == MSG_IPv4_DP
)) ? 4 : 6,
494 Mac
->MacAddress
.Addr
[0], Mac
->MacAddress
.Addr
[1], Mac
->MacAddress
.Addr
[2],
495 Mac
->MacAddress
.Addr
[3], Mac
->MacAddress
.Addr
[4], Mac
->MacAddress
.Addr
[5],
496 (Vlan
== NULL
) ? 0 : Vlan
->VlanId
502 Return the boot description for LoadFile
504 @param Handle Controller handle.
506 @return The description string.
509 BmGetLoadFileDescription (
514 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
515 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
517 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
519 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&LoadFile
);
520 if (EFI_ERROR (Status
)) {
528 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FilePath
);
529 if (!EFI_ERROR (Status
)) {
530 DevicePathNode
= FilePath
;
531 while (!IsDevicePathEnd (DevicePathNode
)) {
532 if (DevicePathNode
->Type
== MEDIA_DEVICE_PATH
&& DevicePathNode
->SubType
== MEDIA_FILEPATH_DP
) {
533 Description
= (CHAR16
*)(DevicePathNode
+ 1);
536 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
540 if (Description
!= NULL
) {
541 return AllocateCopyPool (StrSize (Description
), Description
);
548 Return the boot description for NVME boot device.
550 @param Handle Controller handle.
552 @return The description string.
555 BmGetNvmeDescription (
560 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL
*NvmePassthru
;
561 EFI_DEV_PATH_PTR DevicePath
;
562 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
563 EFI_NVM_EXPRESS_COMMAND Command
;
564 EFI_NVM_EXPRESS_COMPLETION Completion
;
565 NVME_ADMIN_CONTROLLER_DATA ControllerData
;
570 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePath
.DevPath
);
571 if (EFI_ERROR (Status
)) {
575 Status
= gBS
->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid
, &DevicePath
.DevPath
, &Handle
);
576 if (EFI_ERROR (Status
) ||
577 (DevicePathType (DevicePath
.DevPath
) != MESSAGING_DEVICE_PATH
) ||
578 (DevicePathSubType (DevicePath
.DevPath
) != MSG_NVME_NAMESPACE_DP
)) {
580 // Do not return description when the Handle is not a child of NVME controller.
586 // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.
588 Status
= gBS
->HandleProtocol (Handle
, &gEfiNvmExpressPassThruProtocolGuid
, (VOID
**) &NvmePassthru
);
589 ASSERT_EFI_ERROR (Status
);
591 ZeroMem (&CommandPacket
, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
592 ZeroMem (&Command
, sizeof(EFI_NVM_EXPRESS_COMMAND
));
593 ZeroMem (&Completion
, sizeof(EFI_NVM_EXPRESS_COMPLETION
));
595 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_CMD
;
597 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
598 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
601 CommandPacket
.NvmeCmd
= &Command
;
602 CommandPacket
.NvmeCompletion
= &Completion
;
603 CommandPacket
.TransferBuffer
= &ControllerData
;
604 CommandPacket
.TransferLength
= sizeof (ControllerData
);
605 CommandPacket
.CommandTimeout
= EFI_TIMER_PERIOD_SECONDS (5);
606 CommandPacket
.QueueType
= NVME_ADMIN_QUEUE
;
608 // Set bit 0 (Cns bit) to 1 to identify a controller
611 Command
.Flags
= CDW10_VALID
;
613 Status
= NvmePassthru
->PassThru (
619 if (EFI_ERROR (Status
)) {
623 Description
= AllocateZeroPool (
624 (ARRAY_SIZE (ControllerData
.Mn
) + 1
625 + ARRAY_SIZE (ControllerData
.Sn
) + 1
626 + MAXIMUM_VALUE_CHARACTERS
+ 1
627 ) * sizeof (CHAR16
));
628 if (Description
!= NULL
) {
630 for (Index
= 0; Index
< ARRAY_SIZE (ControllerData
.Mn
); Index
++) {
631 *(Char
++) = (CHAR16
) ControllerData
.Mn
[Index
];
634 for (Index
= 0; Index
< ARRAY_SIZE (ControllerData
.Sn
); Index
++) {
635 *(Char
++) = (CHAR16
) ControllerData
.Sn
[Index
];
638 UnicodeValueToStringS (
639 Char
, sizeof (CHAR16
) * (MAXIMUM_VALUE_CHARACTERS
+ 1),
640 0, DevicePath
.NvmeNamespace
->NamespaceId
, 0
642 BmEliminateExtraSpaces (Description
);
649 Return the boot description for the controller based on the type.
651 @param Handle Controller handle.
653 @return The description string.
656 BmGetMiscDescription (
662 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
663 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
665 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
666 case BmAcpiFloppyBoot
:
667 Description
= L
"Floppy";
670 case BmMessageAtapiBoot
:
671 case BmMessageSataBoot
:
672 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
673 ASSERT_EFI_ERROR (Status
);
675 // Assume a removable SATA device should be the DVD/CD device
677 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
680 case BmMessageUsbBoot
:
681 Description
= L
"USB Device";
684 case BmMessageScsiBoot
:
685 Description
= L
"SCSI Device";
688 case BmHardwareDeviceBoot
:
689 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
690 if (!EFI_ERROR (Status
)) {
691 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
693 Description
= L
"Misc Device";
698 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**) &Fs
);
699 if (!EFI_ERROR (Status
)) {
700 Description
= L
"Non-Block Boot Device";
702 Description
= L
"Misc Device";
707 return AllocateCopyPool (StrSize (Description
), Description
);
711 Register the platform provided boot description handler.
713 @param Handler The platform provided boot description handler
715 @retval EFI_SUCCESS The handler was registered successfully.
716 @retval EFI_ALREADY_STARTED The handler was already registered.
717 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
721 EfiBootManagerRegisterBootDescriptionHandler (
722 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
726 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
728 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
729 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
730 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
732 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
733 if (Entry
->Handler
== Handler
) {
734 return EFI_ALREADY_STARTED
;
738 Entry
= AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY
));
740 return EFI_OUT_OF_RESOURCES
;
743 Entry
->Signature
= BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
;
744 Entry
->Handler
= Handler
;
745 InsertTailList (&mPlatformBootDescriptionHandlers
, &Entry
->Link
);
749 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers
[] = {
751 BmGetDescriptionFromDiskInfo
,
752 BmGetNetworkDescription
,
753 BmGetLoadFileDescription
,
754 BmGetNvmeDescription
,
759 Return the boot description for the controller.
761 @param Handle Controller handle.
763 @return The description string.
766 BmGetBootDescription (
771 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
773 CHAR16
*DefaultDescription
;
778 // Firstly get the default boot description
780 DefaultDescription
= NULL
;
781 for (Index
= 0; Index
< ARRAY_SIZE (mBmBootDescriptionHandlers
); Index
++) {
782 DefaultDescription
= mBmBootDescriptionHandlers
[Index
] (Handle
);
783 if (DefaultDescription
!= NULL
) {
785 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
786 // ONLY for core provided boot description handler.
788 Temp
= AllocatePool (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
));
789 ASSERT (Temp
!= NULL
);
790 StrCpyS (Temp
, (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
)) / sizeof (CHAR16
), mBmUefiPrefix
);
791 StrCatS (Temp
, (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
)) / sizeof (CHAR16
), DefaultDescription
);
792 FreePool (DefaultDescription
);
793 DefaultDescription
= Temp
;
797 ASSERT (DefaultDescription
!= NULL
);
800 // Secondly query platform for the better boot description
802 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
803 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
804 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
806 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
807 Description
= Entry
->Handler (Handle
, DefaultDescription
);
808 if (Description
!= NULL
) {
809 FreePool (DefaultDescription
);
814 return DefaultDescription
;
818 Enumerate all boot option descriptions and append " 2"/" 3"/... to make
821 @param BootOptions Array of boot options.
822 @param BootOptionCount Count of boot options.
825 BmMakeBootOptionDescriptionUnique (
826 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
,
827 UINTN BootOptionCount
832 UINTN DescriptionSize
;
837 if (BootOptionCount
== 0) {
842 // Calculate the maximum buffer size for the number suffix.
843 // The initial sizeof (CHAR16) is for the blank space before the number.
845 MaxSuffixSize
= sizeof (CHAR16
);
846 for (Index
= BootOptionCount
; Index
!= 0; Index
= Index
/ 10) {
847 MaxSuffixSize
+= sizeof (CHAR16
);
850 Visited
= AllocateZeroPool (sizeof (BOOLEAN
) * BootOptionCount
);
851 ASSERT (Visited
!= NULL
);
853 for (Base
= 0; Base
< BootOptionCount
; Base
++) {
854 if (!Visited
[Base
]) {
856 Visited
[Base
] = TRUE
;
857 DescriptionSize
= StrSize (BootOptions
[Base
].Description
);
858 for (Index
= Base
+ 1; Index
< BootOptionCount
; Index
++) {
859 if (!Visited
[Index
] && StrCmp (BootOptions
[Base
].Description
, BootOptions
[Index
].Description
) == 0) {
860 Visited
[Index
] = TRUE
;
862 FreePool (BootOptions
[Index
].Description
);
863 BootOptions
[Index
].Description
= AllocatePool (DescriptionSize
+ MaxSuffixSize
);
865 BootOptions
[Index
].Description
, DescriptionSize
+ MaxSuffixSize
,
867 BootOptions
[Base
].Description
, MatchCount