2 Library functions which relate with boot option description.
4 Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "InternalBm.h"
18 #define VENDOR_IDENTIFICATION_OFFSET 3
19 #define VENDOR_IDENTIFICATION_LENGTH 8
20 #define PRODUCT_IDENTIFICATION_OFFSET 11
21 #define PRODUCT_IDENTIFICATION_LENGTH 16
23 CONST UINT16 mBmUsbLangId
= 0x0409; // English
24 CHAR16 mBmUefiPrefix
[] = L
"UEFI ";
26 LIST_ENTRY mPlatformBootDescriptionHandlers
= INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers
);
29 For a bootable Device path, return its boot type.
31 @param DevicePath The bootable device Path to check
33 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
34 which HID is floppy device.
35 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
36 and its last device path node's subtype is MSG_ATAPI_DP.
37 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
38 and its last device path node's subtype is MSG_SATA_DP.
39 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
40 and its last device path node's subtype is MSG_SCSI_DP.
41 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
42 and its last device path node's subtype is MSG_USB_DP.
43 @retval BmMiscBoot If tiven device path doesn't match the above condition.
48 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
51 EFI_DEVICE_PATH_PROTOCOL
*Node
;
52 EFI_DEVICE_PATH_PROTOCOL
*NextNode
;
54 ASSERT (DevicePath
!= NULL
);
56 for (Node
= DevicePath
; !IsDevicePathEndType (Node
); Node
= NextDevicePathNode (Node
)) {
57 switch (DevicePathType (Node
)) {
59 case ACPI_DEVICE_PATH
:
60 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH
*) Node
)->HID
) == 0x0604) {
61 return BmAcpiFloppyBoot
;
65 case HARDWARE_DEVICE_PATH
:
66 if (DevicePathSubType (Node
) == HW_CONTROLLER_DP
) {
67 return BmHardwareDeviceBoot
;
71 case MESSAGING_DEVICE_PATH
:
73 // Skip LUN device node
77 NextNode
= NextDevicePathNode (NextNode
);
79 (DevicePathType (NextNode
) == MESSAGING_DEVICE_PATH
) &&
80 (DevicePathSubType(NextNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
)
84 // If the device path not only point to driver device, it is not a messaging device path,
86 if (!IsDevicePathEndType (NextNode
)) {
90 switch (DevicePathSubType (Node
)) {
92 return BmMessageAtapiBoot
;
96 return BmMessageSataBoot
;
100 return BmMessageUsbBoot
;
104 return BmMessageScsiBoot
;
114 Eliminate the extra spaces in the Str to one space.
116 @param Str Input string info.
119 BmEliminateExtraSpaces (
126 for (Index
= 0, ActualIndex
= 0; Str
[Index
] != L
'\0'; Index
++) {
127 if ((Str
[Index
] != L
' ') || ((ActualIndex
> 0) && (Str
[ActualIndex
- 1] != L
' '))) {
128 Str
[ActualIndex
++] = Str
[Index
];
131 Str
[ActualIndex
] = L
'\0';
135 Try to get the controller's ATA/ATAPI description.
137 @param Handle Controller handle.
139 @return The description string.
142 BmGetDescriptionFromDiskInfo (
148 EFI_DISK_INFO_PROTOCOL
*DiskInfo
;
150 EFI_ATAPI_IDENTIFY_DATA IdentifyData
;
151 EFI_SCSI_INQUIRY_DATA InquiryData
;
154 CONST UINTN ModelNameLength
= 40;
155 CONST UINTN SerialNumberLength
= 20;
161 Status
= gBS
->HandleProtocol (
163 &gEfiDiskInfoProtocolGuid
,
166 if (EFI_ERROR (Status
)) {
170 if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoAhciInterfaceGuid
) ||
171 CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoIdeInterfaceGuid
)) {
172 BufferSize
= sizeof (EFI_ATAPI_IDENTIFY_DATA
);
173 Status
= DiskInfo
->Identify (
178 if (!EFI_ERROR (Status
)) {
179 Description
= AllocateZeroPool ((ModelNameLength
+ SerialNumberLength
+ 2) * sizeof (CHAR16
));
180 ASSERT (Description
!= NULL
);
181 for (Index
= 0; Index
+ 1 < ModelNameLength
; Index
+= 2) {
182 Description
[Index
] = (CHAR16
) IdentifyData
.ModelName
[Index
+ 1];
183 Description
[Index
+ 1] = (CHAR16
) IdentifyData
.ModelName
[Index
];
187 Description
[Length
++] = L
' ';
189 for (Index
= 0; Index
+ 1 < SerialNumberLength
; Index
+= 2) {
190 Description
[Length
+ Index
] = (CHAR16
) IdentifyData
.SerialNo
[Index
+ 1];
191 Description
[Length
+ Index
+ 1] = (CHAR16
) IdentifyData
.SerialNo
[Index
];
194 Description
[Length
++] = L
'\0';
195 ASSERT (Length
== ModelNameLength
+ SerialNumberLength
+ 2);
197 BmEliminateExtraSpaces (Description
);
199 } else if (CompareGuid (&DiskInfo
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
200 BufferSize
= sizeof (EFI_SCSI_INQUIRY_DATA
);
201 Status
= DiskInfo
->Inquiry (
206 if (!EFI_ERROR (Status
)) {
207 Description
= AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2) * sizeof (CHAR16
));
208 ASSERT (Description
!= NULL
);
211 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
212 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
213 // Here combine the vendor identification and product identification to the description.
215 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
]);
216 Temp
= StrPtr
[VENDOR_IDENTIFICATION_LENGTH
];
217 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = '\0';
218 AsciiStrToUnicodeStrS (StrPtr
, Description
, VENDOR_IDENTIFICATION_LENGTH
+ 1);
219 StrPtr
[VENDOR_IDENTIFICATION_LENGTH
] = Temp
;
222 // Add one space at the middle of vendor information and product information.
224 Description
[VENDOR_IDENTIFICATION_LENGTH
] = L
' ';
226 StrPtr
= (CHAR8
*) (&InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
]);
227 StrPtr
[PRODUCT_IDENTIFICATION_LENGTH
] = '\0';
228 AsciiStrToUnicodeStrS (StrPtr
, Description
+ VENDOR_IDENTIFICATION_LENGTH
+ 1, PRODUCT_IDENTIFICATION_LENGTH
+ 1);
230 BmEliminateExtraSpaces (Description
);
238 Try to get the controller's USB description.
240 @param Handle Controller handle.
242 @return The description string.
245 BmGetUsbDescription (
250 EFI_USB_IO_PROTOCOL
*UsbIo
;
252 CHAR16
*Manufacturer
;
254 CHAR16
*SerialNumber
;
256 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
259 Status
= gBS
->HandleProtocol (
261 &gEfiUsbIoProtocolGuid
,
264 if (EFI_ERROR (Status
)) {
270 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
271 if (EFI_ERROR (Status
)) {
275 Status
= UsbIo
->UsbGetStringDescriptor (
278 DevDesc
.StrManufacturer
,
281 if (EFI_ERROR (Status
)) {
282 Manufacturer
= &NullChar
;
285 Status
= UsbIo
->UsbGetStringDescriptor (
291 if (EFI_ERROR (Status
)) {
295 Status
= UsbIo
->UsbGetStringDescriptor (
298 DevDesc
.StrSerialNumber
,
301 if (EFI_ERROR (Status
)) {
302 SerialNumber
= &NullChar
;
305 if ((Manufacturer
== &NullChar
) &&
306 (Product
== &NullChar
) &&
307 (SerialNumber
== &NullChar
)
312 DescMaxSize
= StrSize (Manufacturer
) + StrSize (Product
) + StrSize (SerialNumber
);
313 Description
= AllocateZeroPool (DescMaxSize
);
314 ASSERT (Description
!= NULL
);
315 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Manufacturer
);
316 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
318 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), Product
);
319 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), L
" ");
321 StrCatS (Description
, DescMaxSize
/sizeof(CHAR16
), SerialNumber
);
323 if (Manufacturer
!= &NullChar
) {
324 FreePool (Manufacturer
);
326 if (Product
!= &NullChar
) {
329 if (SerialNumber
!= &NullChar
) {
330 FreePool (SerialNumber
);
333 BmEliminateExtraSpaces (Description
);
339 Return the description for network boot device.
341 @param Handle Controller handle.
343 @return The description string.
346 BmGetNetworkDescription (
351 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
352 MAC_ADDR_DEVICE_PATH
*Mac
;
353 VLAN_DEVICE_PATH
*Vlan
;
354 EFI_DEVICE_PATH_PROTOCOL
*Ip
;
355 EFI_DEVICE_PATH_PROTOCOL
*Uri
;
357 UINTN DescriptionSize
;
359 Status
= gBS
->OpenProtocol (
361 &gEfiLoadFileProtocolGuid
,
365 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
367 if (EFI_ERROR (Status
)) {
371 Status
= gBS
->OpenProtocol (
373 &gEfiDevicePathProtocolGuid
,
374 (VOID
**) &DevicePath
,
377 EFI_OPEN_PROTOCOL_GET_PROTOCOL
379 if (EFI_ERROR (Status
) || (DevicePath
== NULL
)) {
384 // The PXE device path is like:
385 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]
386 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)
387 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)
389 // The HTTP device path is like:
390 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)/Uri(...)
391 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)/Uri(...)
393 while (!IsDevicePathEnd (DevicePath
) &&
394 ((DevicePathType (DevicePath
) != MESSAGING_DEVICE_PATH
) ||
395 (DevicePathSubType (DevicePath
) != MSG_MAC_ADDR_DP
))
397 DevicePath
= NextDevicePathNode (DevicePath
);
400 if (IsDevicePathEnd (DevicePath
)) {
404 Mac
= (MAC_ADDR_DEVICE_PATH
*) DevicePath
;
405 DevicePath
= NextDevicePathNode (DevicePath
);
408 // Locate the optional Vlan node
410 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
411 (DevicePathSubType (DevicePath
) == MSG_VLAN_DP
)
413 Vlan
= (VLAN_DEVICE_PATH
*) DevicePath
;
414 DevicePath
= NextDevicePathNode (DevicePath
);
420 // Skip the optional Wi-Fi node
422 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
423 (DevicePathSubType (DevicePath
) == MSG_WIFI_DP
)
425 DevicePath
= NextDevicePathNode (DevicePath
);
429 // Locate the IP node
431 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
432 ((DevicePathSubType (DevicePath
) == MSG_IPv4_DP
) ||
433 (DevicePathSubType (DevicePath
) == MSG_IPv6_DP
))
436 DevicePath
= NextDevicePathNode (DevicePath
);
442 // Locate the URI node
444 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
445 (DevicePathSubType (DevicePath
) == MSG_URI_DP
)
448 DevicePath
= NextDevicePathNode (DevicePath
);
454 // Build description like below:
455 // "PXEv6 (MAC:112233445566 VLAN1)"
456 // "HTTPv4 (MAC:112233445566)"
458 DescriptionSize
= sizeof (L
"HTTPv6 (MAC:112233445566 VLAN65535)");
459 Description
= AllocatePool (DescriptionSize
);
460 ASSERT (Description
!= NULL
);
462 Description
, DescriptionSize
,
464 L
"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :
465 L
"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",
466 (Uri
== NULL
) ? L
"PXE" : L
"HTTP",
467 ((Ip
== NULL
) || (DevicePathSubType (Ip
) == MSG_IPv4_DP
)) ? 4 : 6,
468 Mac
->MacAddress
.Addr
[0], Mac
->MacAddress
.Addr
[1], Mac
->MacAddress
.Addr
[2],
469 Mac
->MacAddress
.Addr
[3], Mac
->MacAddress
.Addr
[4], Mac
->MacAddress
.Addr
[5],
470 (Vlan
== NULL
) ? 0 : Vlan
->VlanId
476 Return the boot description for LoadFile
478 @param Handle Controller handle.
480 @return The description string.
483 BmGetLoadFileDescription (
488 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
489 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
491 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
493 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&LoadFile
);
494 if (EFI_ERROR (Status
)) {
502 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FilePath
);
503 if (!EFI_ERROR (Status
)) {
504 DevicePathNode
= FilePath
;
505 while (!IsDevicePathEnd (DevicePathNode
)) {
506 if (DevicePathNode
->Type
== MEDIA_DEVICE_PATH
&& DevicePathNode
->SubType
== MEDIA_FILEPATH_DP
) {
507 Description
= (CHAR16
*)(DevicePathNode
+ 1);
510 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
514 if (Description
!= NULL
) {
515 return AllocateCopyPool (StrSize (Description
), Description
);
522 Return the boot description for NVME boot device.
524 @param Handle Controller handle.
526 @return The description string.
529 BmGetNvmeDescription (
534 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL
*NvmePassthru
;
535 EFI_DEV_PATH_PTR DevicePath
;
536 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
537 EFI_NVM_EXPRESS_COMMAND Command
;
538 EFI_NVM_EXPRESS_COMPLETION Completion
;
539 NVME_ADMIN_CONTROLLER_DATA ControllerData
;
544 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePath
.DevPath
);
545 if (EFI_ERROR (Status
)) {
549 Status
= gBS
->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid
, &DevicePath
.DevPath
, &Handle
);
550 if (EFI_ERROR (Status
) ||
551 (DevicePathType (DevicePath
.DevPath
) != MESSAGING_DEVICE_PATH
) ||
552 (DevicePathSubType (DevicePath
.DevPath
) != MSG_NVME_NAMESPACE_DP
)) {
554 // Do not return description when the Handle is not a child of NVME controller.
560 // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.
562 Status
= gBS
->HandleProtocol (Handle
, &gEfiNvmExpressPassThruProtocolGuid
, (VOID
**) &NvmePassthru
);
563 ASSERT_EFI_ERROR (Status
);
565 ZeroMem (&CommandPacket
, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
566 ZeroMem (&Command
, sizeof(EFI_NVM_EXPRESS_COMMAND
));
567 ZeroMem (&Completion
, sizeof(EFI_NVM_EXPRESS_COMPLETION
));
569 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_CMD
;
571 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
572 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
575 CommandPacket
.NvmeCmd
= &Command
;
576 CommandPacket
.NvmeCompletion
= &Completion
;
577 CommandPacket
.TransferBuffer
= &ControllerData
;
578 CommandPacket
.TransferLength
= sizeof (ControllerData
);
579 CommandPacket
.CommandTimeout
= EFI_TIMER_PERIOD_SECONDS (5);
580 CommandPacket
.QueueType
= NVME_ADMIN_QUEUE
;
582 // Set bit 0 (Cns bit) to 1 to identify a controller
585 Command
.Flags
= CDW10_VALID
;
587 Status
= NvmePassthru
->PassThru (
593 if (EFI_ERROR (Status
)) {
597 Description
= AllocateZeroPool (
598 (ARRAY_SIZE (ControllerData
.Mn
) + 1
599 + ARRAY_SIZE (ControllerData
.Sn
) + 1
600 + MAXIMUM_VALUE_CHARACTERS
+ 1
601 ) * sizeof (CHAR16
));
602 if (Description
!= NULL
) {
604 for (Index
= 0; Index
< ARRAY_SIZE (ControllerData
.Mn
); Index
++) {
605 *(Char
++) = (CHAR16
) ControllerData
.Mn
[Index
];
608 for (Index
= 0; Index
< ARRAY_SIZE (ControllerData
.Sn
); Index
++) {
609 *(Char
++) = (CHAR16
) ControllerData
.Sn
[Index
];
612 UnicodeValueToStringS (
613 Char
, sizeof (CHAR16
) * (MAXIMUM_VALUE_CHARACTERS
+ 1),
614 0, DevicePath
.NvmeNamespace
->NamespaceId
, 0
616 BmEliminateExtraSpaces (Description
);
623 Return the boot description for the controller based on the type.
625 @param Handle Controller handle.
627 @return The description string.
630 BmGetMiscDescription (
636 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
637 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
639 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
640 case BmAcpiFloppyBoot
:
641 Description
= L
"Floppy";
644 case BmMessageAtapiBoot
:
645 case BmMessageSataBoot
:
646 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
647 ASSERT_EFI_ERROR (Status
);
649 // Assume a removable SATA device should be the DVD/CD device
651 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
654 case BmMessageUsbBoot
:
655 Description
= L
"USB Device";
658 case BmMessageScsiBoot
:
659 Description
= L
"SCSI Device";
662 case BmHardwareDeviceBoot
:
663 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
664 if (!EFI_ERROR (Status
)) {
665 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
667 Description
= L
"Misc Device";
672 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**) &Fs
);
673 if (!EFI_ERROR (Status
)) {
674 Description
= L
"Non-Block Boot Device";
676 Description
= L
"Misc Device";
681 return AllocateCopyPool (StrSize (Description
), Description
);
685 Register the platform provided boot description handler.
687 @param Handler The platform provided boot description handler
689 @retval EFI_SUCCESS The handler was registered successfully.
690 @retval EFI_ALREADY_STARTED The handler was already registered.
691 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
695 EfiBootManagerRegisterBootDescriptionHandler (
696 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
700 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
702 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
703 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
704 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
706 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
707 if (Entry
->Handler
== Handler
) {
708 return EFI_ALREADY_STARTED
;
712 Entry
= AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY
));
714 return EFI_OUT_OF_RESOURCES
;
717 Entry
->Signature
= BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
;
718 Entry
->Handler
= Handler
;
719 InsertTailList (&mPlatformBootDescriptionHandlers
, &Entry
->Link
);
723 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers
[] = {
725 BmGetDescriptionFromDiskInfo
,
726 BmGetNetworkDescription
,
727 BmGetLoadFileDescription
,
728 BmGetNvmeDescription
,
733 Return the boot description for the controller.
735 @param Handle Controller handle.
737 @return The description string.
740 BmGetBootDescription (
745 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
747 CHAR16
*DefaultDescription
;
752 // Firstly get the default boot description
754 DefaultDescription
= NULL
;
755 for (Index
= 0; Index
< ARRAY_SIZE (mBmBootDescriptionHandlers
); Index
++) {
756 DefaultDescription
= mBmBootDescriptionHandlers
[Index
] (Handle
);
757 if (DefaultDescription
!= NULL
) {
759 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
760 // ONLY for core provided boot description handler.
762 Temp
= AllocatePool (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
));
763 ASSERT (Temp
!= NULL
);
764 StrCpyS (Temp
, (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
)) / sizeof (CHAR16
), mBmUefiPrefix
);
765 StrCatS (Temp
, (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
)) / sizeof (CHAR16
), DefaultDescription
);
766 FreePool (DefaultDescription
);
767 DefaultDescription
= Temp
;
771 ASSERT (DefaultDescription
!= NULL
);
774 // Secondly query platform for the better boot description
776 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
777 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
778 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
780 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
781 Description
= Entry
->Handler (Handle
, DefaultDescription
);
782 if (Description
!= NULL
) {
783 FreePool (DefaultDescription
);
788 return DefaultDescription
;
792 Enumerate all boot option descriptions and append " 2"/" 3"/... to make
795 @param BootOptions Array of boot options.
796 @param BootOptionCount Count of boot options.
799 BmMakeBootOptionDescriptionUnique (
800 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
,
801 UINTN BootOptionCount
806 UINTN DescriptionSize
;
811 if (BootOptionCount
== 0) {
816 // Calculate the maximum buffer size for the number suffix.
817 // The initial sizeof (CHAR16) is for the blank space before the number.
819 MaxSuffixSize
= sizeof (CHAR16
);
820 for (Index
= BootOptionCount
; Index
!= 0; Index
= Index
/ 10) {
821 MaxSuffixSize
+= sizeof (CHAR16
);
824 Visited
= AllocateZeroPool (sizeof (BOOLEAN
) * BootOptionCount
);
825 ASSERT (Visited
!= NULL
);
827 for (Base
= 0; Base
< BootOptionCount
; Base
++) {
828 if (!Visited
[Base
]) {
830 Visited
[Base
] = TRUE
;
831 DescriptionSize
= StrSize (BootOptions
[Base
].Description
);
832 for (Index
= Base
+ 1; Index
< BootOptionCount
; Index
++) {
833 if (!Visited
[Index
] && StrCmp (BootOptions
[Base
].Description
, BootOptions
[Index
].Description
) == 0) {
834 Visited
[Index
] = TRUE
;
836 FreePool (BootOptions
[Index
].Description
);
837 BootOptions
[Index
].Description
= AllocatePool (DescriptionSize
+ MaxSuffixSize
);
839 BootOptions
[Index
].Description
, DescriptionSize
+ MaxSuffixSize
,
841 BootOptions
[Base
].Description
, MatchCount