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(...)]
386 // ....../Mac(...)[/Vlan(...)]/IPv4(...)
387 // ....../Mac(...)[/Vlan(...)]/IPv6(...)
389 // The HTTP device path is like:
390 // ....../Mac(...)[/Vlan(...)]/IPv4(...)/Uri(...)
391 // ....../Mac(...)[/Vlan(...)]/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
);
407 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
408 (DevicePathSubType (DevicePath
) == MSG_VLAN_DP
)
410 Vlan
= (VLAN_DEVICE_PATH
*) DevicePath
;
411 DevicePath
= NextDevicePathNode (DevicePath
);
416 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
417 ((DevicePathSubType (DevicePath
) == MSG_IPv4_DP
) ||
418 (DevicePathSubType (DevicePath
) == MSG_IPv6_DP
))
421 DevicePath
= NextDevicePathNode (DevicePath
);
426 if ((DevicePathType (DevicePath
) == MESSAGING_DEVICE_PATH
) &&
427 (DevicePathSubType (DevicePath
) == MSG_URI_DP
)
430 DevicePath
= NextDevicePathNode (DevicePath
);
436 // Build description like below:
437 // "PXEv6 (MAC:112233445566 VLAN1)"
438 // "HTTPv4 (MAC:112233445566)"
440 DescriptionSize
= sizeof (L
"HTTPv6 (MAC:112233445566 VLAN65535)");
441 Description
= AllocatePool (DescriptionSize
);
442 ASSERT (Description
!= NULL
);
444 Description
, DescriptionSize
,
446 L
"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :
447 L
"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",
448 (Uri
== NULL
) ? L
"PXE" : L
"HTTP",
449 ((Ip
== NULL
) || (DevicePathSubType (Ip
) == MSG_IPv4_DP
)) ? 4 : 6,
450 Mac
->MacAddress
.Addr
[0], Mac
->MacAddress
.Addr
[1], Mac
->MacAddress
.Addr
[2],
451 Mac
->MacAddress
.Addr
[3], Mac
->MacAddress
.Addr
[4], Mac
->MacAddress
.Addr
[5],
452 (Vlan
== NULL
) ? 0 : Vlan
->VlanId
458 Return the boot description for LoadFile
460 @param Handle Controller handle.
462 @return The description string.
465 BmGetLoadFileDescription (
470 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
471 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
473 EFI_LOAD_FILE_PROTOCOL
*LoadFile
;
475 Status
= gBS
->HandleProtocol (Handle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&LoadFile
);
476 if (EFI_ERROR (Status
)) {
484 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FilePath
);
485 if (!EFI_ERROR (Status
)) {
486 DevicePathNode
= FilePath
;
487 while (!IsDevicePathEnd (DevicePathNode
)) {
488 if (DevicePathNode
->Type
== MEDIA_DEVICE_PATH
&& DevicePathNode
->SubType
== MEDIA_FILEPATH_DP
) {
489 Description
= (CHAR16
*)(DevicePathNode
+ 1);
492 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
496 if (Description
!= NULL
) {
497 return AllocateCopyPool (StrSize (Description
), Description
);
504 Return the boot description for NVME boot device.
506 @param Handle Controller handle.
508 @return The description string.
511 BmGetNvmeDescription (
516 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL
*NvmePassthru
;
517 EFI_DEV_PATH_PTR DevicePath
;
518 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
519 EFI_NVM_EXPRESS_COMMAND Command
;
520 EFI_NVM_EXPRESS_COMPLETION Completion
;
521 NVME_ADMIN_CONTROLLER_DATA ControllerData
;
526 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePath
.DevPath
);
527 if (EFI_ERROR (Status
)) {
531 Status
= gBS
->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid
, &DevicePath
.DevPath
, &Handle
);
532 if (EFI_ERROR (Status
) ||
533 (DevicePathType (DevicePath
.DevPath
) != MESSAGING_DEVICE_PATH
) ||
534 (DevicePathSubType (DevicePath
.DevPath
) != MSG_NVME_NAMESPACE_DP
)) {
536 // Do not return description when the Handle is not a child of NVME controller.
542 // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.
544 Status
= gBS
->HandleProtocol (Handle
, &gEfiNvmExpressPassThruProtocolGuid
, (VOID
**) &NvmePassthru
);
545 ASSERT_EFI_ERROR (Status
);
547 ZeroMem (&CommandPacket
, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
548 ZeroMem (&Command
, sizeof(EFI_NVM_EXPRESS_COMMAND
));
549 ZeroMem (&Completion
, sizeof(EFI_NVM_EXPRESS_COMPLETION
));
551 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_CMD
;
553 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
554 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
557 CommandPacket
.NvmeCmd
= &Command
;
558 CommandPacket
.NvmeCompletion
= &Completion
;
559 CommandPacket
.TransferBuffer
= &ControllerData
;
560 CommandPacket
.TransferLength
= sizeof (ControllerData
);
561 CommandPacket
.CommandTimeout
= EFI_TIMER_PERIOD_SECONDS (5);
562 CommandPacket
.QueueType
= NVME_ADMIN_QUEUE
;
564 // Set bit 0 (Cns bit) to 1 to identify a controller
567 Command
.Flags
= CDW10_VALID
;
569 Status
= NvmePassthru
->PassThru (
575 if (EFI_ERROR (Status
)) {
579 Description
= AllocateZeroPool (
580 (ARRAY_SIZE (ControllerData
.Mn
) + 1
581 + ARRAY_SIZE (ControllerData
.Sn
) + 1
582 + MAXIMUM_VALUE_CHARACTERS
+ 1
583 ) * sizeof (CHAR16
));
584 if (Description
!= NULL
) {
586 for (Index
= 0; Index
< ARRAY_SIZE (ControllerData
.Mn
); Index
++) {
587 *(Char
++) = (CHAR16
) ControllerData
.Mn
[Index
];
590 for (Index
= 0; Index
< ARRAY_SIZE (ControllerData
.Sn
); Index
++) {
591 *(Char
++) = (CHAR16
) ControllerData
.Sn
[Index
];
594 UnicodeValueToStringS (
595 Char
, sizeof (CHAR16
) * (MAXIMUM_VALUE_CHARACTERS
+ 1),
596 0, DevicePath
.NvmeNamespace
->NamespaceId
, 0
598 BmEliminateExtraSpaces (Description
);
605 Return the boot description for the controller based on the type.
607 @param Handle Controller handle.
609 @return The description string.
612 BmGetMiscDescription (
618 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
619 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
621 switch (BmDevicePathType (DevicePathFromHandle (Handle
))) {
622 case BmAcpiFloppyBoot
:
623 Description
= L
"Floppy";
626 case BmMessageAtapiBoot
:
627 case BmMessageSataBoot
:
628 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
629 ASSERT_EFI_ERROR (Status
);
631 // Assume a removable SATA device should be the DVD/CD device
633 Description
= BlockIo
->Media
->RemovableMedia
? L
"DVD/CDROM" : L
"Hard Drive";
636 case BmMessageUsbBoot
:
637 Description
= L
"USB Device";
640 case BmMessageScsiBoot
:
641 Description
= L
"SCSI Device";
644 case BmHardwareDeviceBoot
:
645 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
646 if (!EFI_ERROR (Status
)) {
647 Description
= BlockIo
->Media
->RemovableMedia
? L
"Removable Disk" : L
"Hard Drive";
649 Description
= L
"Misc Device";
654 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**) &Fs
);
655 if (!EFI_ERROR (Status
)) {
656 Description
= L
"Non-Block Boot Device";
658 Description
= L
"Misc Device";
663 return AllocateCopyPool (StrSize (Description
), Description
);
667 Register the platform provided boot description handler.
669 @param Handler The platform provided boot description handler
671 @retval EFI_SUCCESS The handler was registered successfully.
672 @retval EFI_ALREADY_STARTED The handler was already registered.
673 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
677 EfiBootManagerRegisterBootDescriptionHandler (
678 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
682 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
684 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
685 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
686 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
688 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
689 if (Entry
->Handler
== Handler
) {
690 return EFI_ALREADY_STARTED
;
694 Entry
= AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY
));
696 return EFI_OUT_OF_RESOURCES
;
699 Entry
->Signature
= BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
;
700 Entry
->Handler
= Handler
;
701 InsertTailList (&mPlatformBootDescriptionHandlers
, &Entry
->Link
);
705 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers
[] = {
707 BmGetDescriptionFromDiskInfo
,
708 BmGetNetworkDescription
,
709 BmGetLoadFileDescription
,
710 BmGetNvmeDescription
,
715 Return the boot description for the controller.
717 @param Handle Controller handle.
719 @return The description string.
722 BmGetBootDescription (
727 BM_BOOT_DESCRIPTION_ENTRY
*Entry
;
729 CHAR16
*DefaultDescription
;
734 // Firstly get the default boot description
736 DefaultDescription
= NULL
;
737 for (Index
= 0; Index
< ARRAY_SIZE (mBmBootDescriptionHandlers
); Index
++) {
738 DefaultDescription
= mBmBootDescriptionHandlers
[Index
] (Handle
);
739 if (DefaultDescription
!= NULL
) {
741 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
742 // ONLY for core provided boot description handler.
744 Temp
= AllocatePool (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
));
745 ASSERT (Temp
!= NULL
);
746 StrCpyS (Temp
, (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
)) / sizeof (CHAR16
), mBmUefiPrefix
);
747 StrCatS (Temp
, (StrSize (DefaultDescription
) + sizeof (mBmUefiPrefix
)) / sizeof (CHAR16
), DefaultDescription
);
748 FreePool (DefaultDescription
);
749 DefaultDescription
= Temp
;
753 ASSERT (DefaultDescription
!= NULL
);
756 // Secondly query platform for the better boot description
758 for ( Link
= GetFirstNode (&mPlatformBootDescriptionHandlers
)
759 ; !IsNull (&mPlatformBootDescriptionHandlers
, Link
)
760 ; Link
= GetNextNode (&mPlatformBootDescriptionHandlers
, Link
)
762 Entry
= CR (Link
, BM_BOOT_DESCRIPTION_ENTRY
, Link
, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE
);
763 Description
= Entry
->Handler (Handle
, DefaultDescription
);
764 if (Description
!= NULL
) {
765 FreePool (DefaultDescription
);
770 return DefaultDescription
;
774 Enumerate all boot option descriptions and append " 2"/" 3"/... to make
777 @param BootOptions Array of boot options.
778 @param BootOptionCount Count of boot options.
781 BmMakeBootOptionDescriptionUnique (
782 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
,
783 UINTN BootOptionCount
788 UINTN DescriptionSize
;
793 if (BootOptionCount
== 0) {
798 // Calculate the maximum buffer size for the number suffix.
799 // The initial sizeof (CHAR16) is for the blank space before the number.
801 MaxSuffixSize
= sizeof (CHAR16
);
802 for (Index
= BootOptionCount
; Index
!= 0; Index
= Index
/ 10) {
803 MaxSuffixSize
+= sizeof (CHAR16
);
806 Visited
= AllocateZeroPool (sizeof (BOOLEAN
) * BootOptionCount
);
807 ASSERT (Visited
!= NULL
);
809 for (Base
= 0; Base
< BootOptionCount
; Base
++) {
810 if (!Visited
[Base
]) {
812 Visited
[Base
] = TRUE
;
813 DescriptionSize
= StrSize (BootOptions
[Base
].Description
);
814 for (Index
= Base
+ 1; Index
< BootOptionCount
; Index
++) {
815 if (!Visited
[Index
] && StrCmp (BootOptions
[Base
].Description
, BootOptions
[Index
].Description
) == 0) {
816 Visited
[Index
] = TRUE
;
818 FreePool (BootOptions
[Index
].Description
);
819 BootOptions
[Index
].Description
= AllocatePool (DescriptionSize
+ MaxSuffixSize
);
821 BootOptions
[Index
].Description
, DescriptionSize
+ MaxSuffixSize
,
823 BootOptions
[Base
].Description
, MatchCount