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
)) {
52 case ACPI_DEVICE_PATH
:
53 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH
*)Node
)->HID
) == 0x0604) {
54 return BmAcpiFloppyBoot
;
59 case HARDWARE_DEVICE_PATH
:
60 if (DevicePathSubType (Node
) == HW_CONTROLLER_DP
) {
61 return BmHardwareDeviceBoot
;
66 case MESSAGING_DEVICE_PATH
:
68 // Skip LUN device node
72 NextNode
= NextDevicePathNode (NextNode
);
74 (DevicePathType (NextNode
) == MESSAGING_DEVICE_PATH
) &&
75 (DevicePathSubType (NextNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
)
79 // If the device path not only point to driver device, it is not a messaging device path,
81 if (!IsDevicePathEndType (NextNode
)) {
85 switch (DevicePathSubType (Node
)) {
87 return BmMessageAtapiBoot
;
91 return BmMessageSataBoot
;
95 return BmMessageUsbBoot
;
99 return BmMessageScsiBoot
;
109 Eliminate the extra spaces in the Str to one space.
111 @param Str Input string info.
114 BmEliminateExtraSpaces (
121 for (Index
= 0, ActualIndex
= 0; Str
[Index
] != L
'\0'; Index
++) {
122 if ((Str
[Index
] != L
' ') || ((ActualIndex
> 0) && (Str
[ActualIndex
- 1] != L
' '))) {
123 Str
[ActualIndex
++] = Str
[Index
];
127 Str
[ActualIndex
] = L
'\0';
131 Try to get the controller's ATA/ATAPI description.
133 @param Handle Controller handle.
135 @return The description string.
138 BmGetDescriptionFromDiskInfo (
144 EFI_DISK_INFO_PROTOCOL
*DiskInfo
;
146 EFI_ATAPI_IDENTIFY_DATA IdentifyData
;
147 EFI_SCSI_INQUIRY_DATA InquiryData
;
150 CONST UINTN ModelNameLength
= 40;
151 CONST UINTN SerialNumberLength
= 20;
154 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
158 Status
= gBS
->HandleProtocol (
160 &gEfiDiskInfoProtocolGuid
,
163 if (EFI_ERROR (Status
)) {
167 if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoAhciInterfaceGuid
) ||
168 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoIdeInterfaceGuid
))
170 BufferSize
= sizeof (EFI_ATAPI_IDENTIFY_DATA
);
171 Status
= DiskInfo
->Identify (
176 if (!EFI_ERROR (Status
)) {
177 Description
= AllocateZeroPool ((ModelNameLength
+ SerialNumberLength
+ 2) * sizeof (CHAR16
));
178 ASSERT (Description
!= NULL
);
179 for (Index
= 0; Index
+ 1 < ModelNameLength
; Index
+= 2) {
180 Description
[Index
] = (CHAR16
)IdentifyData
.ModelName
[Index
+ 1];
181 Description
[Index
+ 1] = (CHAR16
)IdentifyData
.ModelName
[Index
];
185 Description
[Length
++] = L
' ';
187 for (Index
= 0; Index
+ 1 < SerialNumberLength
; Index
+= 2) {
188 Description
[Length
+ Index
] = (CHAR16
)IdentifyData
.SerialNo
[Index
+ 1];
189 Description
[Length
+ Index
+ 1] = (CHAR16
)IdentifyData
.SerialNo
[Index
];
193 Description
[Length
++] = L
'\0';
194 ASSERT (Length
== ModelNameLength
+ SerialNumberLength
+ 2);
196 BmEliminateExtraSpaces (Description
);
198 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) ||
199 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
))
201 BufferSize
= sizeof (EFI_SCSI_INQUIRY_DATA
);
202 Status
= DiskInfo
->Inquiry (
207 if (!EFI_ERROR (Status
)) {
208 Description
= AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2) * sizeof (CHAR16
));
209 ASSERT (Description
!= NULL
);
212 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
213 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
214 // Here combine the vendor identification and product identification to the description.
216 StrPtr
= (CHAR8
*)(&InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
]);
217 Temp
= StrPtr
[VENDOR_IDENTIFICATION_LENGTH
];
218 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = '\0';
219 AsciiStrToUnicodeStrS (StrPtr
, Description
, VENDOR_IDENTIFICATION_LENGTH
+ 1);
220 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = Temp
;
223 // Add one space at the middle of vendor information and product information.
225 Description
[VENDOR_IDENTIFICATION_LENGTH
] = L
' ';
227 StrPtr
= (CHAR8
*)(&InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
]);
228 StrPtr
[PRODUCT_IDENTIFICATION_LENGTH
] = '\0';
229 AsciiStrToUnicodeStrS (StrPtr
, Description
+ VENDOR_IDENTIFICATION_LENGTH
+ 1, PRODUCT_IDENTIFICATION_LENGTH
+ 1);
231 BmEliminateExtraSpaces (Description
);
233 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoSdMmcInterfaceGuid
)) {
234 DevicePath
= DevicePathFromHandle (Handle
);
235 if (DevicePath
== NULL
) {
239 while (!IsDevicePathEnd (DevicePath
) && (DevicePathType (DevicePath
) != MESSAGING_DEVICE_PATH
)) {
240 DevicePath
= NextDevicePathNode (DevicePath
);
243 if (IsDevicePathEnd (DevicePath
)) {
247 if (DevicePathSubType (DevicePath
) == MSG_SD_DP
) {
248 Description
= L
"SD Device";
249 } else if (DevicePathSubType (DevicePath
) == MSG_EMMC_DP
) {
250 Description
= L
"eMMC Device";
255 Description
= AllocateCopyPool (StrSize (Description
), Description
);
262 Try to get the controller's USB description.
264 @param Handle Controller handle.
266 @return The description string.
269 BmGetUsbDescription (
274 EFI_USB_IO_PROTOCOL
*UsbIo
;
276 CHAR16
*Manufacturer
;
278 CHAR16
*SerialNumber
;
280 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
283 Status
= gBS
->HandleProtocol (
285 &gEfiUsbIoProtocolGuid
,
288 if (EFI_ERROR (Status
)) {
294 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
295 if (EFI_ERROR (Status
)) {
299 Status
= UsbIo
->UsbGetStringDescriptor (
302 DevDesc
.StrManufacturer
,
305 if (EFI_ERROR (Status
)) {
306 Manufacturer
= &NullChar
;
309 Status
= UsbIo
->UsbGetStringDescriptor (
315 if (EFI_ERROR (Status
)) {
319 Status
= UsbIo
->UsbGetStringDescriptor (
322 DevDesc
.StrSerialNumber
,
325 if (EFI_ERROR (Status
)) {
326 SerialNumber
= &NullChar
;
329 if ((Manufacturer
== &NullChar
) &&
330 (Product
== &NullChar
) &&
331 (SerialNumber
== &NullChar
)
337 DescMaxSize
= StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
);
338 Description
= AllocateZeroPool (DescMaxSize
);
339 ASSERT (Description
!= NULL
);
340 StrCatS (Description
, DescMaxSize
/sizeof (CHAR16
), Manufacturer
);
341 StrCatS (Description
, DescMaxSize
/sizeof (CHAR16
), L
" ");
343 StrCatS (Description
, DescMaxSize
/sizeof (CHAR16
), Product
);
344 StrCatS (Description
, DescMaxSize
/sizeof (CHAR16
), L
" ");
346 StrCatS (Description
, DescMaxSize
/sizeof (CHAR16
), SerialNumber
);
348 if (Manufacturer
!= &NullChar
) {
349 FreePool (Manufacturer
);
352 if (Product
!= &NullChar
) {
356 if (SerialNumber
!= &NullChar
) {
357 FreePool (SerialNumber
);
360 BmEliminateExtraSpaces (Description
);
366 Return the description for network boot device.
368 @param Handle Controller handle.
370 @return The description string.
373 BmGetNetworkDescription (
378 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
379 MAC_ADDR_DEVICE_PATH
*Mac
;
380 VLAN_DEVICE_PATH
*Vlan
;
381 EFI_DEVICE_PATH_PROTOCOL
*Ip
;
382 EFI_DEVICE_PATH_PROTOCOL
*Uri
;
384 UINTN DescriptionSize
;
386 Status
= gBS
->OpenProtocol (
388 &gEfiLoadFileProtocolGuid
,
392 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
394 if (EFI_ERROR (Status
)) {
398 Status
= gBS
->OpenProtocol (
400 &gEfiDevicePathProtocolGuid
,
401 (VOID
**)&DevicePath
,
404 EFI_OPEN_PROTOCOL_GET_PROTOCOL
406 if (EFI_ERROR (Status
) || (DevicePath
== NULL
)) {
411 // The PXE device path is like:
412 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]
413 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)
414 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)
416 // The HTTP device path is like:
417 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)
418 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)
420 while (!IsDevicePathEnd (DevicePath
) &&
421 ((DevicePathType (DevicePath
) != MESSAGING_DEVICE_PATH
) ||
422 (DevicePathSubType (DevicePath
) != MSG_MAC_ADDR_DP
))
425 DevicePath
= NextDevicePathNode (DevicePath
);
428 if (IsDevicePathEnd (DevicePath
)) {
432 Mac
= (MAC_ADDR_DEVICE_PATH
*)DevicePath
;
433 DevicePath
= NextDevicePathNode (DevicePath
);
436 // Locate the optional Vlan node
438 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
439 (DevicePathSubType (DevicePath
) == MSG_VLAN_DP
)
442 Vlan
= (VLAN_DEVICE_PATH
*)DevicePath
;
443 DevicePath
= NextDevicePathNode (DevicePath
);
449 // Skip the optional Wi-Fi node
451 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
452 (DevicePathSubType (DevicePath
) == MSG_WIFI_DP
)
455 DevicePath
= NextDevicePathNode (DevicePath
);
459 // Locate the IP node
461 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
462 ((DevicePathSubType (DevicePath
) == MSG_IPv4_DP
) ||
463 (DevicePathSubType (DevicePath
) == MSG_IPv6_DP
))
467 DevicePath
= NextDevicePathNode (DevicePath
);
473 // Skip the optional DNS node
475 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
476 (DevicePathSubType (DevicePath
) == MSG_DNS_DP
)
479 DevicePath
= NextDevicePathNode (DevicePath
);
483 // Locate the URI node
485 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
486 (DevicePathSubType (DevicePath
) == MSG_URI_DP
)
490 DevicePath
= NextDevicePathNode (DevicePath
);
496 // Build description like below:
497 // "PXEv6 (MAC:112233445566 VLAN1)"
498 // "HTTPv4 (MAC:112233445566)"
500 DescriptionSize
= sizeof (L
"HTTPv6 (MAC:112233445566 VLAN65535)");
501 Description
= AllocatePool (DescriptionSize
);
502 ASSERT (Description
!= NULL
);
507 L
"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :
508 L
"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",
509 (Uri
== NULL
) ? L
"PXE" : L
"HTTP",
510 ((Ip
== NULL
) || (DevicePathSubType (Ip
) == MSG_IPv4_DP
)) ? 4 : 6,
511 Mac
->MacAddress
.Addr
[0],
512 Mac
->MacAddress
.Addr
[1],
513 Mac
->MacAddress
.Addr
[2],
514 Mac
->MacAddress
.Addr
[3],
515 Mac
->MacAddress
.Addr
[4],
516 Mac
->MacAddress
.Addr
[5],
517 (Vlan
== NULL
) ? 0 : Vlan
->VlanId
523 Return the boot description for LoadFile
525 @param Handle Controller handle.
527 @return The description string.
530 BmGetLoadFileDescription (
535 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
536 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
538 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
540 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&LoadFile
);
541 if (EFI_ERROR (Status
)) {
549 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FilePath
);
550 if (!EFI_ERROR (Status
)) {
551 DevicePathNode
= FilePath
;
552 while (!IsDevicePathEnd (DevicePathNode
)) {
553 if ((DevicePathNode
->Type
== MEDIA_DEVICE_PATH
) && (DevicePathNode
->SubType
== MEDIA_FILEPATH_DP
)) {
554 Description
= (CHAR16
*)(DevicePathNode
+ 1);
558 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
562 if (Description
!= NULL
) {
563 return AllocateCopyPool (StrSize (Description
), Description
);
570 Return the boot description for NVME boot device.
572 @param Handle Controller handle.
574 @return The description string.
577 BmGetNvmeDescription (
582 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL
*NvmePassthru
;
583 EFI_DEV_PATH_PTR DevicePath
;
584 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
585 EFI_NVM_EXPRESS_COMMAND Command
;
586 EFI_NVM_EXPRESS_COMPLETION Completion
;
587 NVME_ADMIN_CONTROLLER_DATA ControllerData
;
592 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
.DevPath
);
593 if (EFI_ERROR (Status
)) {
597 Status
= gBS
->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid
, &DevicePath
.DevPath
, &Handle
);
598 if (EFI_ERROR (Status
) ||
599 (DevicePathType (DevicePath
.DevPath
) != MESSAGING_DEVICE_PATH
) ||
600 (DevicePathSubType (DevicePath
.DevPath
) != MSG_NVME_NAMESPACE_DP
))
603 // Do not return description when the Handle is not a child of NVME controller.
609 // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.
611 Status
= gBS
->HandleProtocol (Handle
, &gEfiNvmExpressPassThruProtocolGuid
, (VOID
**)&NvmePassthru
);
612 ASSERT_EFI_ERROR (Status
);
614 ZeroMem (&CommandPacket
, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
615 ZeroMem (&Command
, sizeof (EFI_NVM_EXPRESS_COMMAND
));
616 ZeroMem (&Completion
, sizeof (EFI_NVM_EXPRESS_COMPLETION
));
618 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_CMD
;
620 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
621 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
624 CommandPacket
.NvmeCmd
= &Command
;
625 CommandPacket
.NvmeCompletion
= &Completion
;
626 CommandPacket
.TransferBuffer
= &ControllerData
;
627 CommandPacket
.TransferLength
= sizeof (ControllerData
);
628 CommandPacket
.CommandTimeout
= EFI_TIMER_PERIOD_SECONDS (5);
629 CommandPacket
.QueueType
= NVME_ADMIN_QUEUE
;
631 // Set bit 0 (Cns bit) to 1 to identify a controller
634 Command
.Flags
= CDW10_VALID
;
636 Status
= NvmePassthru
->PassThru (
642 if (EFI_ERROR (Status
)) {
646 Description
= AllocateZeroPool (
647 (ARRAY_SIZE (ControllerData
.Mn
) + 1
648 + ARRAY_SIZE (ControllerData
.Sn
) + 1
649 + MAXIMUM_VALUE_CHARACTERS
+ 1
652 if (Description
!= NULL
) {
654 for (Index
= 0; Index
< ARRAY_SIZE (ControllerData
.Mn
); Index
++) {
655 *(Char
++) = (CHAR16
)ControllerData
.Mn
[Index
];
659 for (Index
= 0; Index
< ARRAY_SIZE (ControllerData
.Sn
); Index
++) {
660 *(Char
++) = (CHAR16
)ControllerData
.Sn
[Index
];
664 UnicodeValueToStringS (
666 sizeof (CHAR16
) * (MAXIMUM_VALUE_CHARACTERS
+ 1),
668 DevicePath
.NvmeNamespace
->NamespaceId
,
671 BmEliminateExtraSpaces (Description
);
678 Return the boot description for the controller based on the type.
680 @param Handle Controller handle.
682 @return The description string.
685 BmGetMiscDescription (
691 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
692 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
694 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
695 case BmAcpiFloppyBoot
:
696 Description
= L
"Floppy";
699 case BmMessageAtapiBoot
:
700 case BmMessageSataBoot
:
701 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
702 ASSERT_EFI_ERROR (Status
);
704 // Assume a removable SATA device should be the DVD/CD device
706 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
709 case BmMessageUsbBoot
:
710 Description
= L
"USB Device";
713 case BmMessageScsiBoot
:
714 Description
= L
"SCSI Device";
717 case BmHardwareDeviceBoot
:
718 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
719 if (!EFI_ERROR (Status
)) {
720 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
722 Description
= L
"Misc Device";
728 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
729 if (!EFI_ERROR (Status
)) {
730 Description
= L
"Non-Block Boot Device";
732 Description
= L
"Misc Device";
738 return AllocateCopyPool (StrSize (Description
), Description
);
742 Register the platform provided boot description handler.
744 @param Handler The platform provided boot description handler
746 @retval EFI_SUCCESS The handler was registered successfully.
747 @retval EFI_ALREADY_STARTED The handler was already registered.
748 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
752 EfiBootManagerRegisterBootDescriptionHandler (
753 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
757 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
759 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
760 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
761 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
764 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
765 if (Entry
->Handler
== Handler
) {
766 return EFI_ALREADY_STARTED
;
770 Entry
= AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY
));
772 return EFI_OUT_OF_RESOURCES
;
775 Entry
->Signature
= BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
;
776 Entry
->Handler
= Handler
;
777 InsertTailList (&mPlatformBootDescriptionHandlers
, &Entry
->Link
);
781 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers
[] = {
783 BmGetDescriptionFromDiskInfo
,
784 BmGetNetworkDescription
,
785 BmGetLoadFileDescription
,
786 BmGetNvmeDescription
,
791 Return the boot description for the controller.
793 @param Handle Controller handle.
795 @return The description string.
798 BmGetBootDescription (
803 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
805 CHAR16
*DefaultDescription
;
810 // Firstly get the default boot description
812 DefaultDescription
= NULL
;
813 for (Index
= 0; Index
< ARRAY_SIZE (mBmBootDescriptionHandlers
); Index
++) {
814 DefaultDescription
= mBmBootDescriptionHandlers
[Index
](Handle
);
815 if (DefaultDescription
!= NULL
) {
817 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
818 // ONLY for core provided boot description handler.
820 Temp
= AllocatePool (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
));
821 ASSERT (Temp
!= NULL
);
822 StrCpyS (Temp
, (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
)) / sizeof (CHAR16
), mBmUefiPrefix
);
823 StrCatS (Temp
, (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
)) / sizeof (CHAR16
), DefaultDescription
);
824 FreePool (DefaultDescription
);
825 DefaultDescription
= Temp
;
830 ASSERT (DefaultDescription
!= NULL
);
833 // Secondly query platform for the better boot description
835 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
836 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
837 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
840 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
841 Description
= Entry
->Handler (Handle
, DefaultDescription
);
842 if (Description
!= NULL
) {
843 FreePool (DefaultDescription
);
848 return DefaultDescription
;
852 Enumerate all boot option descriptions and append " 2"/" 3"/... to make
855 @param BootOptions Array of boot options.
856 @param BootOptionCount Count of boot options.
859 BmMakeBootOptionDescriptionUnique (
860 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
,
861 UINTN BootOptionCount
866 UINTN DescriptionSize
;
871 if (BootOptionCount
== 0) {
876 // Calculate the maximum buffer size for the number suffix.
877 // The initial sizeof (CHAR16) is for the blank space before the number.
879 MaxSuffixSize
= sizeof (CHAR16
);
880 for (Index
= BootOptionCount
; Index
!= 0; Index
= Index
/ 10) {
881 MaxSuffixSize
+= sizeof (CHAR16
);
884 Visited
= AllocateZeroPool (sizeof (BOOLEAN
) * BootOptionCount
);
885 ASSERT (Visited
!= NULL
);
887 for (Base
= 0; Base
< BootOptionCount
; Base
++) {
888 if (!Visited
[Base
]) {
890 Visited
[Base
] = TRUE
;
891 DescriptionSize
= StrSize (BootOptions
[Base
].Description
);
892 for (Index
= Base
+ 1; Index
< BootOptionCount
; Index
++) {
893 if (!Visited
[Index
] && (StrCmp (BootOptions
[Base
].Description
, BootOptions
[Index
].Description
) == 0)) {
894 Visited
[Index
] = TRUE
;
896 FreePool (BootOptions
[Index
].Description
);
897 BootOptions
[Index
].Description
= AllocatePool (DescriptionSize
+ MaxSuffixSize
);
899 BootOptions
[Index
].Description
,
900 DescriptionSize
+ MaxSuffixSize
,
902 BootOptions
[Base
].Description
,