summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c')
-rw-r--r--MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c1822
1 files changed, 911 insertions, 911 deletions
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c
index 030b2ee3ec..480f0931e0 100644
--- a/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c
+++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c
@@ -1,911 +1,911 @@
-/** @file
- Library functions which relate with boot option description.
-
-Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "InternalBm.h"
-
-#define VENDOR_IDENTIFICATION_OFFSET 3
-#define VENDOR_IDENTIFICATION_LENGTH 8
-#define PRODUCT_IDENTIFICATION_OFFSET 11
-#define PRODUCT_IDENTIFICATION_LENGTH 16
-
-CONST UINT16 mBmUsbLangId = 0x0409; // English
-CHAR16 mBmUefiPrefix[] = L"UEFI ";
-
-LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);
-
-/**
- For a bootable Device path, return its boot type.
-
- @param DevicePath The bootable device Path to check
-
- @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
- which HID is floppy device.
- @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
- and its last device path node's subtype is MSG_ATAPI_DP.
- @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
- and its last device path node's subtype is MSG_SATA_DP.
- @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
- and its last device path node's subtype is MSG_SCSI_DP.
- @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
- and its last device path node's subtype is MSG_USB_DP.
- @retval BmMiscBoot If tiven device path doesn't match the above condition.
-
-**/
-BM_BOOT_TYPE
-BmDevicePathType (
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- EFI_DEVICE_PATH_PROTOCOL *Node;
- EFI_DEVICE_PATH_PROTOCOL *NextNode;
-
- ASSERT (DevicePath != NULL);
-
- for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
- switch (DevicePathType (Node)) {
- case ACPI_DEVICE_PATH:
- if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *)Node)->HID) == 0x0604) {
- return BmAcpiFloppyBoot;
- }
-
- break;
-
- case HARDWARE_DEVICE_PATH:
- if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {
- return BmHardwareDeviceBoot;
- }
-
- break;
-
- case MESSAGING_DEVICE_PATH:
- //
- // Skip LUN device node
- //
- NextNode = Node;
- do {
- NextNode = NextDevicePathNode (NextNode);
- } while (
- (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&
- (DevicePathSubType (NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)
- );
-
- //
- // If the device path not only point to driver device, it is not a messaging device path,
- //
- if (!IsDevicePathEndType (NextNode)) {
- continue;
- }
-
- switch (DevicePathSubType (Node)) {
- case MSG_ATAPI_DP:
- return BmMessageAtapiBoot;
- break;
-
- case MSG_SATA_DP:
- return BmMessageSataBoot;
- break;
-
- case MSG_USB_DP:
- return BmMessageUsbBoot;
- break;
-
- case MSG_SCSI_DP:
- return BmMessageScsiBoot;
- break;
- }
- }
- }
-
- return BmMiscBoot;
-}
-
-/**
- Eliminate the extra spaces in the Str to one space.
-
- @param Str Input string info.
-**/
-VOID
-BmEliminateExtraSpaces (
- IN CHAR16 *Str
- )
-{
- UINTN Index;
- UINTN ActualIndex;
-
- for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
- if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
- Str[ActualIndex++] = Str[Index];
- }
- }
-
- Str[ActualIndex] = L'\0';
-}
-
-/**
- Try to get the controller's ATA/ATAPI description.
-
- @param Handle Controller handle.
-
- @return The description string.
-**/
-CHAR16 *
-BmGetDescriptionFromDiskInfo (
- IN EFI_HANDLE Handle
- )
-{
- UINTN Index;
- EFI_STATUS Status;
- EFI_DISK_INFO_PROTOCOL *DiskInfo;
- UINT32 BufferSize;
- EFI_ATAPI_IDENTIFY_DATA IdentifyData;
- EFI_SCSI_INQUIRY_DATA InquiryData;
- CHAR16 *Description;
- UINTN Length;
- CONST UINTN ModelNameLength = 40;
- CONST UINTN SerialNumberLength = 20;
- CHAR8 *StrPtr;
- UINT8 Temp;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
-
- Description = NULL;
-
- Status = gBS->HandleProtocol (
- Handle,
- &gEfiDiskInfoProtocolGuid,
- (VOID **)&DiskInfo
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) ||
- CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid))
- {
- BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA);
- Status = DiskInfo->Identify (
- DiskInfo,
- &IdentifyData,
- &BufferSize
- );
- if (!EFI_ERROR (Status)) {
- Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));
- ASSERT (Description != NULL);
- for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
- Description[Index] = (CHAR16)IdentifyData.ModelName[Index + 1];
- Description[Index + 1] = (CHAR16)IdentifyData.ModelName[Index];
- }
-
- Length = Index;
- Description[Length++] = L' ';
-
- for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {
- Description[Length + Index] = (CHAR16)IdentifyData.SerialNo[Index + 1];
- Description[Length + Index + 1] = (CHAR16)IdentifyData.SerialNo[Index];
- }
-
- Length += Index;
- Description[Length++] = L'\0';
- ASSERT (Length == ModelNameLength + SerialNumberLength + 2);
-
- BmEliminateExtraSpaces (Description);
- }
- } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid) ||
- CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoUfsInterfaceGuid))
- {
- BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA);
- Status = DiskInfo->Inquiry (
- DiskInfo,
- &InquiryData,
- &BufferSize
- );
- if (!EFI_ERROR (Status)) {
- Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));
- ASSERT (Description != NULL);
-
- //
- // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
- // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
- // Here combine the vendor identification and product identification to the description.
- //
- StrPtr = (CHAR8 *)(&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);
- Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];
- StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';
- AsciiStrToUnicodeStrS (StrPtr, Description, VENDOR_IDENTIFICATION_LENGTH + 1);
- StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;
-
- //
- // Add one space at the middle of vendor information and product information.
- //
- Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';
-
- StrPtr = (CHAR8 *)(&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);
- StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';
- AsciiStrToUnicodeStrS (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1, PRODUCT_IDENTIFICATION_LENGTH + 1);
-
- BmEliminateExtraSpaces (Description);
- }
- } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoSdMmcInterfaceGuid)) {
- DevicePath = DevicePathFromHandle (Handle);
- if (DevicePath == NULL) {
- return NULL;
- }
-
- while (!IsDevicePathEnd (DevicePath) && (DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH)) {
- DevicePath = NextDevicePathNode (DevicePath);
- }
-
- if (IsDevicePathEnd (DevicePath)) {
- return NULL;
- }
-
- if (DevicePathSubType (DevicePath) == MSG_SD_DP) {
- Description = L"SD Device";
- } else if (DevicePathSubType (DevicePath) == MSG_EMMC_DP) {
- Description = L"eMMC Device";
- } else {
- return NULL;
- }
-
- Description = AllocateCopyPool (StrSize (Description), Description);
- }
-
- return Description;
-}
-
-/**
- Try to get the controller's USB description.
-
- @param Handle Controller handle.
-
- @return The description string.
-**/
-CHAR16 *
-BmGetUsbDescription (
- IN EFI_HANDLE Handle
- )
-{
- EFI_STATUS Status;
- EFI_USB_IO_PROTOCOL *UsbIo;
- CHAR16 NullChar;
- CHAR16 *Manufacturer;
- CHAR16 *Product;
- CHAR16 *SerialNumber;
- CHAR16 *Description;
- EFI_USB_DEVICE_DESCRIPTOR DevDesc;
- UINTN DescMaxSize;
-
- Status = gBS->HandleProtocol (
- Handle,
- &gEfiUsbIoProtocolGuid,
- (VOID **)&UsbIo
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- NullChar = L'\0';
-
- Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- Status = UsbIo->UsbGetStringDescriptor (
- UsbIo,
- mBmUsbLangId,
- DevDesc.StrManufacturer,
- &Manufacturer
- );
- if (EFI_ERROR (Status)) {
- Manufacturer = &NullChar;
- }
-
- Status = UsbIo->UsbGetStringDescriptor (
- UsbIo,
- mBmUsbLangId,
- DevDesc.StrProduct,
- &Product
- );
- if (EFI_ERROR (Status)) {
- Product = &NullChar;
- }
-
- Status = UsbIo->UsbGetStringDescriptor (
- UsbIo,
- mBmUsbLangId,
- DevDesc.StrSerialNumber,
- &SerialNumber
- );
- if (EFI_ERROR (Status)) {
- SerialNumber = &NullChar;
- }
-
- if ((Manufacturer == &NullChar) &&
- (Product == &NullChar) &&
- (SerialNumber == &NullChar)
- )
- {
- return NULL;
- }
-
- DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);
- Description = AllocateZeroPool (DescMaxSize);
- ASSERT (Description != NULL);
- StrCatS (Description, DescMaxSize/sizeof (CHAR16), Manufacturer);
- StrCatS (Description, DescMaxSize/sizeof (CHAR16), L" ");
-
- StrCatS (Description, DescMaxSize/sizeof (CHAR16), Product);
- StrCatS (Description, DescMaxSize/sizeof (CHAR16), L" ");
-
- StrCatS (Description, DescMaxSize/sizeof (CHAR16), SerialNumber);
-
- if (Manufacturer != &NullChar) {
- FreePool (Manufacturer);
- }
-
- if (Product != &NullChar) {
- FreePool (Product);
- }
-
- if (SerialNumber != &NullChar) {
- FreePool (SerialNumber);
- }
-
- BmEliminateExtraSpaces (Description);
-
- return Description;
-}
-
-/**
- Return the description for network boot device.
-
- @param Handle Controller handle.
-
- @return The description string.
-**/
-CHAR16 *
-BmGetNetworkDescription (
- IN EFI_HANDLE Handle
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- MAC_ADDR_DEVICE_PATH *Mac;
- VLAN_DEVICE_PATH *Vlan;
- EFI_DEVICE_PATH_PROTOCOL *Ip;
- EFI_DEVICE_PATH_PROTOCOL *Uri;
- CHAR16 *Description;
- UINTN DescriptionSize;
-
- Status = gBS->OpenProtocol (
- Handle,
- &gEfiLoadFileProtocolGuid,
- NULL,
- gImageHandle,
- Handle,
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- Status = gBS->OpenProtocol (
- Handle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&DevicePath,
- gImageHandle,
- Handle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status) || (DevicePath == NULL)) {
- return NULL;
- }
-
- //
- // The PXE device path is like:
- // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]
- // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)
- // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)
- //
- // The HTTP device path is like:
- // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)
- // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)
- //
- while (!IsDevicePathEnd (DevicePath) &&
- ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
- (DevicePathSubType (DevicePath) != MSG_MAC_ADDR_DP))
- )
- {
- DevicePath = NextDevicePathNode (DevicePath);
- }
-
- if (IsDevicePathEnd (DevicePath)) {
- return NULL;
- }
-
- Mac = (MAC_ADDR_DEVICE_PATH *)DevicePath;
- DevicePath = NextDevicePathNode (DevicePath);
-
- //
- // Locate the optional Vlan node
- //
- if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
- (DevicePathSubType (DevicePath) == MSG_VLAN_DP)
- )
- {
- Vlan = (VLAN_DEVICE_PATH *)DevicePath;
- DevicePath = NextDevicePathNode (DevicePath);
- } else {
- Vlan = NULL;
- }
-
- //
- // Skip the optional Wi-Fi node
- //
- if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
- (DevicePathSubType (DevicePath) == MSG_WIFI_DP)
- )
- {
- DevicePath = NextDevicePathNode (DevicePath);
- }
-
- //
- // Locate the IP node
- //
- if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
- ((DevicePathSubType (DevicePath) == MSG_IPv4_DP) ||
- (DevicePathSubType (DevicePath) == MSG_IPv6_DP))
- )
- {
- Ip = DevicePath;
- DevicePath = NextDevicePathNode (DevicePath);
- } else {
- Ip = NULL;
- }
-
- //
- // Skip the optional DNS node
- //
- if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
- (DevicePathSubType (DevicePath) == MSG_DNS_DP)
- )
- {
- DevicePath = NextDevicePathNode (DevicePath);
- }
-
- //
- // Locate the URI node
- //
- if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
- (DevicePathSubType (DevicePath) == MSG_URI_DP)
- )
- {
- Uri = DevicePath;
- DevicePath = NextDevicePathNode (DevicePath);
- } else {
- Uri = NULL;
- }
-
- //
- // Build description like below:
- // "PXEv6 (MAC:112233445566 VLAN1)"
- // "HTTPv4 (MAC:112233445566)"
- //
- DescriptionSize = sizeof (L"HTTPv6 (MAC:112233445566 VLAN65535)");
- Description = AllocatePool (DescriptionSize);
- ASSERT (Description != NULL);
- UnicodeSPrint (
- Description,
- DescriptionSize,
- (Vlan == NULL) ?
- L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :
- L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",
- (Uri == NULL) ? L"PXE" : L"HTTP",
- ((Ip == NULL) || (DevicePathSubType (Ip) == MSG_IPv4_DP)) ? 4 : 6,
- Mac->MacAddress.Addr[0],
- Mac->MacAddress.Addr[1],
- Mac->MacAddress.Addr[2],
- Mac->MacAddress.Addr[3],
- Mac->MacAddress.Addr[4],
- Mac->MacAddress.Addr[5],
- (Vlan == NULL) ? 0 : Vlan->VlanId
- );
- return Description;
-}
-
-/**
- Return the boot description for LoadFile
-
- @param Handle Controller handle.
-
- @return The description string.
-**/
-CHAR16 *
-BmGetLoadFileDescription (
- IN EFI_HANDLE Handle
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *FilePath;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
- CHAR16 *Description;
- EFI_LOAD_FILE_PROTOCOL *LoadFile;
-
- Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFile);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- //
- // Get the file name
- //
- Description = NULL;
- Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&FilePath);
- if (!EFI_ERROR (Status)) {
- DevicePathNode = FilePath;
- while (!IsDevicePathEnd (DevicePathNode)) {
- if ((DevicePathNode->Type == MEDIA_DEVICE_PATH) && (DevicePathNode->SubType == MEDIA_FILEPATH_DP)) {
- Description = (CHAR16 *)(DevicePathNode + 1);
- break;
- }
-
- DevicePathNode = NextDevicePathNode (DevicePathNode);
- }
- }
-
- if (Description != NULL) {
- return AllocateCopyPool (StrSize (Description), Description);
- }
-
- return NULL;
-}
-
-/**
- Return the boot description for NVME boot device.
-
- @param Handle Controller handle.
-
- @return The description string.
-**/
-CHAR16 *
-BmGetNvmeDescription (
- IN EFI_HANDLE Handle
- )
-{
- EFI_STATUS Status;
- EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassthru;
- EFI_DEV_PATH_PTR DevicePath;
- EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
- EFI_NVM_EXPRESS_COMMAND Command;
- EFI_NVM_EXPRESS_COMPLETION Completion;
- NVME_ADMIN_CONTROLLER_DATA ControllerData;
- CHAR16 *Description;
- CHAR16 *Char;
- UINTN Index;
-
- Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath.DevPath);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- Status = gBS->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid, &DevicePath.DevPath, &Handle);
- if (EFI_ERROR (Status) ||
- (DevicePathType (DevicePath.DevPath) != MESSAGING_DEVICE_PATH) ||
- (DevicePathSubType (DevicePath.DevPath) != MSG_NVME_NAMESPACE_DP))
- {
- //
- // Do not return description when the Handle is not a child of NVME controller.
- //
- return NULL;
- }
-
- //
- // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.
- //
- Status = gBS->HandleProtocol (Handle, &gEfiNvmExpressPassThruProtocolGuid, (VOID **)&NvmePassthru);
- ASSERT_EFI_ERROR (Status);
-
- ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
- ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
- ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
-
- Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
- //
- // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
- // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
- //
- Command.Nsid = 0;
- CommandPacket.NvmeCmd = &Command;
- CommandPacket.NvmeCompletion = &Completion;
- CommandPacket.TransferBuffer = &ControllerData;
- CommandPacket.TransferLength = sizeof (ControllerData);
- CommandPacket.CommandTimeout = EFI_TIMER_PERIOD_SECONDS (5);
- CommandPacket.QueueType = NVME_ADMIN_QUEUE;
- //
- // Set bit 0 (Cns bit) to 1 to identify a controller
- //
- Command.Cdw10 = 1;
- Command.Flags = CDW10_VALID;
-
- Status = NvmePassthru->PassThru (
- NvmePassthru,
- 0,
- &CommandPacket,
- NULL
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- Description = AllocateZeroPool (
- (ARRAY_SIZE (ControllerData.Mn) + 1
- + ARRAY_SIZE (ControllerData.Sn) + 1
- + MAXIMUM_VALUE_CHARACTERS + 1
- ) * sizeof (CHAR16)
- );
- if (Description != NULL) {
- Char = Description;
- for (Index = 0; Index < ARRAY_SIZE (ControllerData.Mn); Index++) {
- *(Char++) = (CHAR16)ControllerData.Mn[Index];
- }
-
- *(Char++) = L' ';
- for (Index = 0; Index < ARRAY_SIZE (ControllerData.Sn); Index++) {
- *(Char++) = (CHAR16)ControllerData.Sn[Index];
- }
-
- *(Char++) = L' ';
- UnicodeValueToStringS (
- Char,
- sizeof (CHAR16) * (MAXIMUM_VALUE_CHARACTERS + 1),
- 0,
- DevicePath.NvmeNamespace->NamespaceId,
- 0
- );
- BmEliminateExtraSpaces (Description);
- }
-
- return Description;
-}
-
-/**
- Return the boot description for the controller based on the type.
-
- @param Handle Controller handle.
-
- @return The description string.
-**/
-CHAR16 *
-BmGetMiscDescription (
- IN EFI_HANDLE Handle
- )
-{
- EFI_STATUS Status;
- CHAR16 *Description;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
-
- switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
- case BmAcpiFloppyBoot:
- Description = L"Floppy";
- break;
-
- case BmMessageAtapiBoot:
- case BmMessageSataBoot:
- Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
- ASSERT_EFI_ERROR (Status);
- //
- // Assume a removable SATA device should be the DVD/CD device
- //
- Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";
- break;
-
- case BmMessageUsbBoot:
- Description = L"USB Device";
- break;
-
- case BmMessageScsiBoot:
- Description = L"SCSI Device";
- break;
-
- case BmHardwareDeviceBoot:
- Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
- if (!EFI_ERROR (Status)) {
- Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";
- } else {
- Description = L"Misc Device";
- }
-
- break;
-
- default:
- Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
- if (!EFI_ERROR (Status)) {
- Description = L"Non-Block Boot Device";
- } else {
- Description = L"Misc Device";
- }
-
- break;
- }
-
- return AllocateCopyPool (StrSize (Description), Description);
-}
-
-/**
- Register the platform provided boot description handler.
-
- @param Handler The platform provided boot description handler
-
- @retval EFI_SUCCESS The handler was registered successfully.
- @retval EFI_ALREADY_STARTED The handler was already registered.
- @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerRegisterBootDescriptionHandler (
- IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
- )
-{
- LIST_ENTRY *Link;
- BM_BOOT_DESCRIPTION_ENTRY *Entry;
-
- for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
- ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
- ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
- )
- {
- Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
- if (Entry->Handler == Handler) {
- return EFI_ALREADY_STARTED;
- }
- }
-
- Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));
- if (Entry == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;
- Entry->Handler = Handler;
- InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);
- return EFI_SUCCESS;
-}
-
-BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {
- BmGetUsbDescription,
- BmGetDescriptionFromDiskInfo,
- BmGetNetworkDescription,
- BmGetLoadFileDescription,
- BmGetNvmeDescription,
- BmGetMiscDescription
-};
-
-/**
- Return the boot description for the controller.
-
- @param Handle Controller handle.
-
- @return The description string.
-**/
-CHAR16 *
-BmGetBootDescription (
- IN EFI_HANDLE Handle
- )
-{
- LIST_ENTRY *Link;
- BM_BOOT_DESCRIPTION_ENTRY *Entry;
- CHAR16 *Description;
- CHAR16 *DefaultDescription;
- CHAR16 *Temp;
- UINTN Index;
-
- //
- // Firstly get the default boot description
- //
- DefaultDescription = NULL;
- for (Index = 0; Index < ARRAY_SIZE (mBmBootDescriptionHandlers); Index++) {
- DefaultDescription = mBmBootDescriptionHandlers[Index](Handle);
- if (DefaultDescription != NULL) {
- //
- // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
- // ONLY for core provided boot description handler.
- //
- Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix));
- ASSERT (Temp != NULL);
- StrCpyS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), mBmUefiPrefix);
- StrCatS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), DefaultDescription);
- FreePool (DefaultDescription);
- DefaultDescription = Temp;
- break;
- }
- }
-
- ASSERT (DefaultDescription != NULL);
-
- //
- // Secondly query platform for the better boot description
- //
- for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
- ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
- ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
- )
- {
- Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
- Description = Entry->Handler (Handle, DefaultDescription);
- if (Description != NULL) {
- FreePool (DefaultDescription);
- return Description;
- }
- }
-
- return DefaultDescription;
-}
-
-/**
- Enumerate all boot option descriptions and append " 2"/" 3"/... to make
- unique description.
-
- @param BootOptions Array of boot options.
- @param BootOptionCount Count of boot options.
-**/
-VOID
-BmMakeBootOptionDescriptionUnique (
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
- UINTN BootOptionCount
- )
-{
- UINTN Base;
- UINTN Index;
- UINTN DescriptionSize;
- UINTN MaxSuffixSize;
- BOOLEAN *Visited;
- UINTN MatchCount;
-
- if (BootOptionCount == 0) {
- return;
- }
-
- //
- // Calculate the maximum buffer size for the number suffix.
- // The initial sizeof (CHAR16) is for the blank space before the number.
- //
- MaxSuffixSize = sizeof (CHAR16);
- for (Index = BootOptionCount; Index != 0; Index = Index / 10) {
- MaxSuffixSize += sizeof (CHAR16);
- }
-
- Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);
- ASSERT (Visited != NULL);
-
- for (Base = 0; Base < BootOptionCount; Base++) {
- if (!Visited[Base]) {
- MatchCount = 1;
- Visited[Base] = TRUE;
- DescriptionSize = StrSize (BootOptions[Base].Description);
- for (Index = Base + 1; Index < BootOptionCount; Index++) {
- if (!Visited[Index] && (StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0)) {
- Visited[Index] = TRUE;
- MatchCount++;
- FreePool (BootOptions[Index].Description);
- BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);
- UnicodeSPrint (
- BootOptions[Index].Description,
- DescriptionSize + MaxSuffixSize,
- L"%s %d",
- BootOptions[Base].Description,
- MatchCount
- );
- }
- }
- }
- }
-
- FreePool (Visited);
-}
+/** @file
+ Library functions which relate with boot option description.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalBm.h"
+
+#define VENDOR_IDENTIFICATION_OFFSET 3
+#define VENDOR_IDENTIFICATION_LENGTH 8
+#define PRODUCT_IDENTIFICATION_OFFSET 11
+#define PRODUCT_IDENTIFICATION_LENGTH 16
+
+CONST UINT16 mBmUsbLangId = 0x0409; // English
+CHAR16 mBmUefiPrefix[] = L"UEFI ";
+
+LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);
+
+/**
+ For a bootable Device path, return its boot type.
+
+ @param DevicePath The bootable device Path to check
+
+ @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
+ which HID is floppy device.
+ @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_ATAPI_DP.
+ @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_SATA_DP.
+ @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_SCSI_DP.
+ @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_USB_DP.
+ @retval BmMiscBoot If tiven device path doesn't match the above condition.
+
+**/
+BM_BOOT_TYPE
+BmDevicePathType (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *NextNode;
+
+ ASSERT (DevicePath != NULL);
+
+ for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
+ switch (DevicePathType (Node)) {
+ case ACPI_DEVICE_PATH:
+ if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *)Node)->HID) == 0x0604) {
+ return BmAcpiFloppyBoot;
+ }
+
+ break;
+
+ case HARDWARE_DEVICE_PATH:
+ if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {
+ return BmHardwareDeviceBoot;
+ }
+
+ break;
+
+ case MESSAGING_DEVICE_PATH:
+ //
+ // Skip LUN device node
+ //
+ NextNode = Node;
+ do {
+ NextNode = NextDevicePathNode (NextNode);
+ } while (
+ (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)
+ );
+
+ //
+ // If the device path not only point to driver device, it is not a messaging device path,
+ //
+ if (!IsDevicePathEndType (NextNode)) {
+ continue;
+ }
+
+ switch (DevicePathSubType (Node)) {
+ case MSG_ATAPI_DP:
+ return BmMessageAtapiBoot;
+ break;
+
+ case MSG_SATA_DP:
+ return BmMessageSataBoot;
+ break;
+
+ case MSG_USB_DP:
+ return BmMessageUsbBoot;
+ break;
+
+ case MSG_SCSI_DP:
+ return BmMessageScsiBoot;
+ break;
+ }
+ }
+ }
+
+ return BmMiscBoot;
+}
+
+/**
+ Eliminate the extra spaces in the Str to one space.
+
+ @param Str Input string info.
+**/
+VOID
+BmEliminateExtraSpaces (
+ IN CHAR16 *Str
+ )
+{
+ UINTN Index;
+ UINTN ActualIndex;
+
+ for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
+ if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
+ Str[ActualIndex++] = Str[Index];
+ }
+ }
+
+ Str[ActualIndex] = L'\0';
+}
+
+/**
+ Try to get the controller's ATA/ATAPI description.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetDescriptionFromDiskInfo (
+ IN EFI_HANDLE Handle
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_DISK_INFO_PROTOCOL *DiskInfo;
+ UINT32 BufferSize;
+ EFI_ATAPI_IDENTIFY_DATA IdentifyData;
+ EFI_SCSI_INQUIRY_DATA InquiryData;
+ CHAR16 *Description;
+ UINTN Length;
+ CONST UINTN ModelNameLength = 40;
+ CONST UINTN SerialNumberLength = 20;
+ CHAR8 *StrPtr;
+ UINT8 Temp;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Description = NULL;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiDiskInfoProtocolGuid,
+ (VOID **)&DiskInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) ||
+ CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid))
+ {
+ BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA);
+ Status = DiskInfo->Identify (
+ DiskInfo,
+ &IdentifyData,
+ &BufferSize
+ );
+ if (!EFI_ERROR (Status)) {
+ Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));
+ ASSERT (Description != NULL);
+ for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
+ Description[Index] = (CHAR16)IdentifyData.ModelName[Index + 1];
+ Description[Index + 1] = (CHAR16)IdentifyData.ModelName[Index];
+ }
+
+ Length = Index;
+ Description[Length++] = L' ';
+
+ for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {
+ Description[Length + Index] = (CHAR16)IdentifyData.SerialNo[Index + 1];
+ Description[Length + Index + 1] = (CHAR16)IdentifyData.SerialNo[Index];
+ }
+
+ Length += Index;
+ Description[Length++] = L'\0';
+ ASSERT (Length == ModelNameLength + SerialNumberLength + 2);
+
+ BmEliminateExtraSpaces (Description);
+ }
+ } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid) ||
+ CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoUfsInterfaceGuid))
+ {
+ BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA);
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ &InquiryData,
+ &BufferSize
+ );
+ if (!EFI_ERROR (Status)) {
+ Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));
+ ASSERT (Description != NULL);
+
+ //
+ // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
+ // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
+ // Here combine the vendor identification and product identification to the description.
+ //
+ StrPtr = (CHAR8 *)(&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);
+ Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];
+ StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';
+ AsciiStrToUnicodeStrS (StrPtr, Description, VENDOR_IDENTIFICATION_LENGTH + 1);
+ StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;
+
+ //
+ // Add one space at the middle of vendor information and product information.
+ //
+ Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';
+
+ StrPtr = (CHAR8 *)(&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);
+ StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';
+ AsciiStrToUnicodeStrS (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1, PRODUCT_IDENTIFICATION_LENGTH + 1);
+
+ BmEliminateExtraSpaces (Description);
+ }
+ } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoSdMmcInterfaceGuid)) {
+ DevicePath = DevicePathFromHandle (Handle);
+ if (DevicePath == NULL) {
+ return NULL;
+ }
+
+ while (!IsDevicePathEnd (DevicePath) && (DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH)) {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if (IsDevicePathEnd (DevicePath)) {
+ return NULL;
+ }
+
+ if (DevicePathSubType (DevicePath) == MSG_SD_DP) {
+ Description = L"SD Device";
+ } else if (DevicePathSubType (DevicePath) == MSG_EMMC_DP) {
+ Description = L"eMMC Device";
+ } else {
+ return NULL;
+ }
+
+ Description = AllocateCopyPool (StrSize (Description), Description);
+ }
+
+ return Description;
+}
+
+/**
+ Try to get the controller's USB description.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetUsbDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ CHAR16 NullChar;
+ CHAR16 *Manufacturer;
+ CHAR16 *Product;
+ CHAR16 *SerialNumber;
+ CHAR16 *Description;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ UINTN DescMaxSize;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ NullChar = L'\0';
+
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ mBmUsbLangId,
+ DevDesc.StrManufacturer,
+ &Manufacturer
+ );
+ if (EFI_ERROR (Status)) {
+ Manufacturer = &NullChar;
+ }
+
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ mBmUsbLangId,
+ DevDesc.StrProduct,
+ &Product
+ );
+ if (EFI_ERROR (Status)) {
+ Product = &NullChar;
+ }
+
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ mBmUsbLangId,
+ DevDesc.StrSerialNumber,
+ &SerialNumber
+ );
+ if (EFI_ERROR (Status)) {
+ SerialNumber = &NullChar;
+ }
+
+ if ((Manufacturer == &NullChar) &&
+ (Product == &NullChar) &&
+ (SerialNumber == &NullChar)
+ )
+ {
+ return NULL;
+ }
+
+ DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);
+ Description = AllocateZeroPool (DescMaxSize);
+ ASSERT (Description != NULL);
+ StrCatS (Description, DescMaxSize/sizeof (CHAR16), Manufacturer);
+ StrCatS (Description, DescMaxSize/sizeof (CHAR16), L" ");
+
+ StrCatS (Description, DescMaxSize/sizeof (CHAR16), Product);
+ StrCatS (Description, DescMaxSize/sizeof (CHAR16), L" ");
+
+ StrCatS (Description, DescMaxSize/sizeof (CHAR16), SerialNumber);
+
+ if (Manufacturer != &NullChar) {
+ FreePool (Manufacturer);
+ }
+
+ if (Product != &NullChar) {
+ FreePool (Product);
+ }
+
+ if (SerialNumber != &NullChar) {
+ FreePool (SerialNumber);
+ }
+
+ BmEliminateExtraSpaces (Description);
+
+ return Description;
+}
+
+/**
+ Return the description for network boot device.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetNetworkDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ MAC_ADDR_DEVICE_PATH *Mac;
+ VLAN_DEVICE_PATH *Vlan;
+ EFI_DEVICE_PATH_PROTOCOL *Ip;
+ EFI_DEVICE_PATH_PROTOCOL *Uri;
+ CHAR16 *Description;
+ UINTN DescriptionSize;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ gImageHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath,
+ gImageHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status) || (DevicePath == NULL)) {
+ return NULL;
+ }
+
+ //
+ // The PXE device path is like:
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)
+ //
+ // The HTTP device path is like:
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)
+ //
+ while (!IsDevicePathEnd (DevicePath) &&
+ ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (DevicePath) != MSG_MAC_ADDR_DP))
+ )
+ {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if (IsDevicePathEnd (DevicePath)) {
+ return NULL;
+ }
+
+ Mac = (MAC_ADDR_DEVICE_PATH *)DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+
+ //
+ // Locate the optional Vlan node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MSG_VLAN_DP)
+ )
+ {
+ Vlan = (VLAN_DEVICE_PATH *)DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ } else {
+ Vlan = NULL;
+ }
+
+ //
+ // Skip the optional Wi-Fi node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MSG_WIFI_DP)
+ )
+ {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ //
+ // Locate the IP node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (DevicePath) == MSG_IPv4_DP) ||
+ (DevicePathSubType (DevicePath) == MSG_IPv6_DP))
+ )
+ {
+ Ip = DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ } else {
+ Ip = NULL;
+ }
+
+ //
+ // Skip the optional DNS node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MSG_DNS_DP)
+ )
+ {
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ //
+ // Locate the URI node
+ //
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MSG_URI_DP)
+ )
+ {
+ Uri = DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ } else {
+ Uri = NULL;
+ }
+
+ //
+ // Build description like below:
+ // "PXEv6 (MAC:112233445566 VLAN1)"
+ // "HTTPv4 (MAC:112233445566)"
+ //
+ DescriptionSize = sizeof (L"HTTPv6 (MAC:112233445566 VLAN65535)");
+ Description = AllocatePool (DescriptionSize);
+ ASSERT (Description != NULL);
+ UnicodeSPrint (
+ Description,
+ DescriptionSize,
+ (Vlan == NULL) ?
+ L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :
+ L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",
+ (Uri == NULL) ? L"PXE" : L"HTTP",
+ ((Ip == NULL) || (DevicePathSubType (Ip) == MSG_IPv4_DP)) ? 4 : 6,
+ Mac->MacAddress.Addr[0],
+ Mac->MacAddress.Addr[1],
+ Mac->MacAddress.Addr[2],
+ Mac->MacAddress.Addr[3],
+ Mac->MacAddress.Addr[4],
+ Mac->MacAddress.Addr[5],
+ (Vlan == NULL) ? 0 : Vlan->VlanId
+ );
+ return Description;
+}
+
+/**
+ Return the boot description for LoadFile
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetLoadFileDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ CHAR16 *Description;
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;
+
+ Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFile);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Get the file name
+ //
+ Description = NULL;
+ Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&FilePath);
+ if (!EFI_ERROR (Status)) {
+ DevicePathNode = FilePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ if ((DevicePathNode->Type == MEDIA_DEVICE_PATH) && (DevicePathNode->SubType == MEDIA_FILEPATH_DP)) {
+ Description = (CHAR16 *)(DevicePathNode + 1);
+ break;
+ }
+
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+ }
+
+ if (Description != NULL) {
+ return AllocateCopyPool (StrSize (Description), Description);
+ }
+
+ return NULL;
+}
+
+/**
+ Return the boot description for NVME boot device.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetNvmeDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassthru;
+ EFI_DEV_PATH_PTR DevicePath;
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ NVME_ADMIN_CONTROLLER_DATA ControllerData;
+ CHAR16 *Description;
+ CHAR16 *Char;
+ UINTN Index;
+
+ Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath.DevPath);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = gBS->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid, &DevicePath.DevPath, &Handle);
+ if (EFI_ERROR (Status) ||
+ (DevicePathType (DevicePath.DevPath) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (DevicePath.DevPath) != MSG_NVME_NAMESPACE_DP))
+ {
+ //
+ // Do not return description when the Handle is not a child of NVME controller.
+ //
+ return NULL;
+ }
+
+ //
+ // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiNvmExpressPassThruProtocolGuid, (VOID **)&NvmePassthru);
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
+ //
+ // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
+ // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
+ //
+ Command.Nsid = 0;
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ CommandPacket.TransferBuffer = &ControllerData;
+ CommandPacket.TransferLength = sizeof (ControllerData);
+ CommandPacket.CommandTimeout = EFI_TIMER_PERIOD_SECONDS (5);
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify a controller
+ //
+ Command.Cdw10 = 1;
+ Command.Flags = CDW10_VALID;
+
+ Status = NvmePassthru->PassThru (
+ NvmePassthru,
+ 0,
+ &CommandPacket,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Description = AllocateZeroPool (
+ (ARRAY_SIZE (ControllerData.Mn) + 1
+ + ARRAY_SIZE (ControllerData.Sn) + 1
+ + MAXIMUM_VALUE_CHARACTERS + 1
+ ) * sizeof (CHAR16)
+ );
+ if (Description != NULL) {
+ Char = Description;
+ for (Index = 0; Index < ARRAY_SIZE (ControllerData.Mn); Index++) {
+ *(Char++) = (CHAR16)ControllerData.Mn[Index];
+ }
+
+ *(Char++) = L' ';
+ for (Index = 0; Index < ARRAY_SIZE (ControllerData.Sn); Index++) {
+ *(Char++) = (CHAR16)ControllerData.Sn[Index];
+ }
+
+ *(Char++) = L' ';
+ UnicodeValueToStringS (
+ Char,
+ sizeof (CHAR16) * (MAXIMUM_VALUE_CHARACTERS + 1),
+ 0,
+ DevicePath.NvmeNamespace->NamespaceId,
+ 0
+ );
+ BmEliminateExtraSpaces (Description);
+ }
+
+ return Description;
+}
+
+/**
+ Return the boot description for the controller based on the type.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetMiscDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Description;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+
+ switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
+ case BmAcpiFloppyBoot:
+ Description = L"Floppy";
+ break;
+
+ case BmMessageAtapiBoot:
+ case BmMessageSataBoot:
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Assume a removable SATA device should be the DVD/CD device
+ //
+ Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";
+ break;
+
+ case BmMessageUsbBoot:
+ Description = L"USB Device";
+ break;
+
+ case BmMessageScsiBoot:
+ Description = L"SCSI Device";
+ break;
+
+ case BmHardwareDeviceBoot:
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ if (!EFI_ERROR (Status)) {
+ Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";
+ } else {
+ Description = L"Misc Device";
+ }
+
+ break;
+
+ default:
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (!EFI_ERROR (Status)) {
+ Description = L"Non-Block Boot Device";
+ } else {
+ Description = L"Misc Device";
+ }
+
+ break;
+ }
+
+ return AllocateCopyPool (StrSize (Description), Description);
+}
+
+/**
+ Register the platform provided boot description handler.
+
+ @param Handler The platform provided boot description handler
+
+ @retval EFI_SUCCESS The handler was registered successfully.
+ @retval EFI_ALREADY_STARTED The handler was already registered.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerRegisterBootDescriptionHandler (
+ IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
+ )
+{
+ LIST_ENTRY *Link;
+ BM_BOOT_DESCRIPTION_ENTRY *Entry;
+
+ for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
+ ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
+ ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
+ )
+ {
+ Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
+ if (Entry->Handler == Handler) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));
+ if (Entry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;
+ Entry->Handler = Handler;
+ InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);
+ return EFI_SUCCESS;
+}
+
+BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {
+ BmGetUsbDescription,
+ BmGetDescriptionFromDiskInfo,
+ BmGetNetworkDescription,
+ BmGetLoadFileDescription,
+ BmGetNvmeDescription,
+ BmGetMiscDescription
+};
+
+/**
+ Return the boot description for the controller.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetBootDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ LIST_ENTRY *Link;
+ BM_BOOT_DESCRIPTION_ENTRY *Entry;
+ CHAR16 *Description;
+ CHAR16 *DefaultDescription;
+ CHAR16 *Temp;
+ UINTN Index;
+
+ //
+ // Firstly get the default boot description
+ //
+ DefaultDescription = NULL;
+ for (Index = 0; Index < ARRAY_SIZE (mBmBootDescriptionHandlers); Index++) {
+ DefaultDescription = mBmBootDescriptionHandlers[Index](Handle);
+ if (DefaultDescription != NULL) {
+ //
+ // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
+ // ONLY for core provided boot description handler.
+ //
+ Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix));
+ ASSERT (Temp != NULL);
+ StrCpyS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), mBmUefiPrefix);
+ StrCatS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), DefaultDescription);
+ FreePool (DefaultDescription);
+ DefaultDescription = Temp;
+ break;
+ }
+ }
+
+ ASSERT (DefaultDescription != NULL);
+
+ //
+ // Secondly query platform for the better boot description
+ //
+ for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
+ ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
+ ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
+ )
+ {
+ Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
+ Description = Entry->Handler (Handle, DefaultDescription);
+ if (Description != NULL) {
+ FreePool (DefaultDescription);
+ return Description;
+ }
+ }
+
+ return DefaultDescription;
+}
+
+/**
+ Enumerate all boot option descriptions and append " 2"/" 3"/... to make
+ unique description.
+
+ @param BootOptions Array of boot options.
+ @param BootOptionCount Count of boot options.
+**/
+VOID
+BmMakeBootOptionDescriptionUnique (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
+ UINTN BootOptionCount
+ )
+{
+ UINTN Base;
+ UINTN Index;
+ UINTN DescriptionSize;
+ UINTN MaxSuffixSize;
+ BOOLEAN *Visited;
+ UINTN MatchCount;
+
+ if (BootOptionCount == 0) {
+ return;
+ }
+
+ //
+ // Calculate the maximum buffer size for the number suffix.
+ // The initial sizeof (CHAR16) is for the blank space before the number.
+ //
+ MaxSuffixSize = sizeof (CHAR16);
+ for (Index = BootOptionCount; Index != 0; Index = Index / 10) {
+ MaxSuffixSize += sizeof (CHAR16);
+ }
+
+ Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);
+ ASSERT (Visited != NULL);
+
+ for (Base = 0; Base < BootOptionCount; Base++) {
+ if (!Visited[Base]) {
+ MatchCount = 1;
+ Visited[Base] = TRUE;
+ DescriptionSize = StrSize (BootOptions[Base].Description);
+ for (Index = Base + 1; Index < BootOptionCount; Index++) {
+ if (!Visited[Index] && (StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0)) {
+ Visited[Index] = TRUE;
+ MatchCount++;
+ FreePool (BootOptions[Index].Description);
+ BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);
+ UnicodeSPrint (
+ BootOptions[Index].Description,
+ DescriptionSize + MaxSuffixSize,
+ L"%s %d",
+ BootOptions[Base].Description,
+ MatchCount
+ );
+ }
+ }
+ }
+ }
+
+ FreePool (Visited);
+}