/** @file\r
Library functions which relate with boot option description.\r
\r
-Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
/**\r
For a bootable Device path, return its boot type.\r
\r
- @param DevicePath The bootable device Path to check\r
-\r
- @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node\r
- which HID is floppy device.\r
- @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
- and its last device path node's subtype is MSG_ATAPI_DP.\r
- @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
- and its last device path node's subtype is MSG_SATA_DP.\r
- @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
- and its last device path node's subtype is MSG_SCSI_DP.\r
- @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
- and its last device path node's subtype is MSG_USB_DP.\r
- @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
- and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,\r
- MSG_IPv4_DP or MSG_IPv6_DP.\r
- @retval MessageHttpBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
- and its last device path node's subtype is MSG_URI_DP.\r
- @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.\r
+ @param DevicePath The bootable device Path to check\r
+\r
+ @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node\r
+ which HID is floppy device.\r
+ @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+ and its last device path node's subtype is MSG_ATAPI_DP.\r
+ @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+ and its last device path node's subtype is MSG_SATA_DP.\r
+ @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+ and its last device path node's subtype is MSG_SCSI_DP.\r
+ @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+ and its last device path node's subtype is MSG_USB_DP.\r
+ @retval BmMiscBoot If tiven device path doesn't match the above condition.\r
\r
**/\r
BM_BOOT_TYPE\r
case MSG_SCSI_DP:\r
return BmMessageScsiBoot;\r
break;\r
-\r
- case MSG_MAC_ADDR_DP:\r
- case MSG_VLAN_DP:\r
- case MSG_IPv4_DP:\r
- case MSG_IPv6_DP:\r
- return BmMessageNetworkBoot;\r
- break;\r
-\r
- case MSG_URI_DP:\r
- return BmMessageHttpBoot;\r
- break;\r
}\r
}\r
}\r
CONST UINTN SerialNumberLength = 20;\r
CHAR8 *StrPtr;\r
UINT8 Temp;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
\r
Description = NULL;\r
\r
StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);\r
Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];\r
StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';\r
- AsciiStrToUnicodeStr (StrPtr, Description);\r
+ AsciiStrToUnicodeStrS (StrPtr, Description, VENDOR_IDENTIFICATION_LENGTH + 1);\r
StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;\r
\r
//\r
\r
StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);\r
StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';\r
- AsciiStrToUnicodeStr (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1);\r
+ AsciiStrToUnicodeStrS (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1, PRODUCT_IDENTIFICATION_LENGTH + 1);\r
\r
BmEliminateExtraSpaces (Description);\r
}\r
+ } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoSdMmcInterfaceGuid)) {\r
+ DevicePath = DevicePathFromHandle (Handle);\r
+ if (DevicePath == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ while (!IsDevicePathEnd (DevicePath) && (DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH)) {\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ }\r
+ if (IsDevicePathEnd (DevicePath)) {\r
+ return NULL;\r
+ }\r
+\r
+ if (DevicePathSubType (DevicePath) == MSG_SD_DP) {\r
+ Description = L"SD Device";\r
+ } else if (DevicePathSubType (DevicePath) == MSG_EMMC_DP) {\r
+ Description = L"eMMC Device";\r
+ } else {\r
+ return NULL;\r
+ }\r
+\r
+ Description = AllocateCopyPool (StrSize (Description), Description);\r
}\r
\r
return Description;\r
return Description;\r
}\r
\r
+/**\r
+ Return the description for network boot device.\r
+\r
+ @param Handle Controller handle.\r
+\r
+ @return The description string.\r
+**/\r
+CHAR16 *\r
+BmGetNetworkDescription (\r
+ IN EFI_HANDLE Handle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ MAC_ADDR_DEVICE_PATH *Mac;\r
+ VLAN_DEVICE_PATH *Vlan;\r
+ EFI_DEVICE_PATH_PROTOCOL *Ip;\r
+ EFI_DEVICE_PATH_PROTOCOL *Uri;\r
+ CHAR16 *Description;\r
+ UINTN DescriptionSize;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Handle,\r
+ &gEfiLoadFileProtocolGuid,\r
+ NULL,\r
+ gImageHandle,\r
+ Handle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath,\r
+ gImageHandle,\r
+ Handle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status) || (DevicePath == NULL)) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // The PXE device path is like:\r
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]\r
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)\r
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)\r
+ //\r
+ // The HTTP device path is like:\r
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)\r
+ // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)\r
+ //\r
+ while (!IsDevicePathEnd (DevicePath) &&\r
+ ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||\r
+ (DevicePathSubType (DevicePath) != MSG_MAC_ADDR_DP))\r
+ ) {\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ }\r
+\r
+ if (IsDevicePathEnd (DevicePath)) {\r
+ return NULL;\r
+ }\r
+\r
+ Mac = (MAC_ADDR_DEVICE_PATH *) DevicePath;\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+\r
+ //\r
+ // Locate the optional Vlan node\r
+ //\r
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
+ (DevicePathSubType (DevicePath) == MSG_VLAN_DP)\r
+ ) {\r
+ Vlan = (VLAN_DEVICE_PATH *) DevicePath;\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ } else {\r
+ Vlan = NULL;\r
+ }\r
+\r
+ //\r
+ // Skip the optional Wi-Fi node\r
+ //\r
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
+ (DevicePathSubType (DevicePath) == MSG_WIFI_DP)\r
+ ) {\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ }\r
+\r
+ //\r
+ // Locate the IP node\r
+ //\r
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
+ ((DevicePathSubType (DevicePath) == MSG_IPv4_DP) ||\r
+ (DevicePathSubType (DevicePath) == MSG_IPv6_DP))\r
+ ) {\r
+ Ip = DevicePath;\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ } else {\r
+ Ip = NULL;\r
+ }\r
+\r
+ //\r
+ // Skip the optional DNS node\r
+ //\r
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
+ (DevicePathSubType (DevicePath) == MSG_DNS_DP)\r
+ ) {\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ }\r
+\r
+ //\r
+ // Locate the URI node\r
+ //\r
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
+ (DevicePathSubType (DevicePath) == MSG_URI_DP)\r
+ ) {\r
+ Uri = DevicePath;\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ } else {\r
+ Uri = NULL;\r
+ }\r
+\r
+ //\r
+ // Build description like below:\r
+ // "PXEv6 (MAC:112233445566 VLAN1)"\r
+ // "HTTPv4 (MAC:112233445566)"\r
+ //\r
+ DescriptionSize = sizeof (L"HTTPv6 (MAC:112233445566 VLAN65535)");\r
+ Description = AllocatePool (DescriptionSize);\r
+ ASSERT (Description != NULL);\r
+ UnicodeSPrint (\r
+ Description, DescriptionSize,\r
+ (Vlan == NULL) ?\r
+ L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :\r
+ L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",\r
+ (Uri == NULL) ? L"PXE" : L"HTTP",\r
+ ((Ip == NULL) || (DevicePathSubType (Ip) == MSG_IPv4_DP)) ? 4 : 6,\r
+ Mac->MacAddress.Addr[0], Mac->MacAddress.Addr[1], Mac->MacAddress.Addr[2],\r
+ Mac->MacAddress.Addr[3], Mac->MacAddress.Addr[4], Mac->MacAddress.Addr[5],\r
+ (Vlan == NULL) ? 0 : Vlan->VlanId\r
+ );\r
+ return Description;\r
+}\r
+\r
+/**\r
+ Return the boot description for LoadFile\r
+\r
+ @param Handle Controller handle.\r
+\r
+ @return The description string.\r
+**/\r
+CHAR16 *\r
+BmGetLoadFileDescription (\r
+ IN EFI_HANDLE Handle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
+ CHAR16 *Description;\r
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFile);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Get the file name\r
+ //\r
+ Description = NULL;\r
+ Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&FilePath);\r
+ if (!EFI_ERROR (Status)) {\r
+ DevicePathNode = FilePath;\r
+ while (!IsDevicePathEnd (DevicePathNode)) {\r
+ if (DevicePathNode->Type == MEDIA_DEVICE_PATH && DevicePathNode->SubType == MEDIA_FILEPATH_DP) {\r
+ Description = (CHAR16 *)(DevicePathNode + 1);\r
+ break;\r
+ }\r
+ DevicePathNode = NextDevicePathNode (DevicePathNode);\r
+ }\r
+ }\r
+\r
+ if (Description != NULL) {\r
+ return AllocateCopyPool (StrSize (Description), Description);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Return the boot description for NVME boot device.\r
+\r
+ @param Handle Controller handle.\r
+\r
+ @return The description string.\r
+**/\r
+CHAR16 *\r
+BmGetNvmeDescription (\r
+ IN EFI_HANDLE Handle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassthru;\r
+ EFI_DEV_PATH_PTR DevicePath;\r
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ EFI_NVM_EXPRESS_COMMAND Command;\r
+ EFI_NVM_EXPRESS_COMPLETION Completion;\r
+ NVME_ADMIN_CONTROLLER_DATA ControllerData;\r
+ CHAR16 *Description;\r
+ CHAR16 *Char;\r
+ UINTN Index;\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath.DevPath);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Status = gBS->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid, &DevicePath.DevPath, &Handle);\r
+ if (EFI_ERROR (Status) ||\r
+ (DevicePathType (DevicePath.DevPath) != MESSAGING_DEVICE_PATH) ||\r
+ (DevicePathSubType (DevicePath.DevPath) != MSG_NVME_NAMESPACE_DP)) {\r
+ //\r
+ // Do not return description when the Handle is not a child of NVME controller.\r
+ //\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.\r
+ //\r
+ Status = gBS->HandleProtocol (Handle, &gEfiNvmExpressPassThruProtocolGuid, (VOID **) &NvmePassthru);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;\r
+ //\r
+ // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.\r
+ // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.\r
+ //\r
+ Command.Nsid = 0;\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeCompletion = &Completion;\r
+ CommandPacket.TransferBuffer = &ControllerData;\r
+ CommandPacket.TransferLength = sizeof (ControllerData);\r
+ CommandPacket.CommandTimeout = EFI_TIMER_PERIOD_SECONDS (5);\r
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
+ //\r
+ // Set bit 0 (Cns bit) to 1 to identify a controller\r
+ //\r
+ Command.Cdw10 = 1;\r
+ Command.Flags = CDW10_VALID;\r
+\r
+ Status = NvmePassthru->PassThru (\r
+ NvmePassthru,\r
+ 0,\r
+ &CommandPacket,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Description = AllocateZeroPool (\r
+ (ARRAY_SIZE (ControllerData.Mn) + 1\r
+ + ARRAY_SIZE (ControllerData.Sn) + 1\r
+ + MAXIMUM_VALUE_CHARACTERS + 1\r
+ ) * sizeof (CHAR16));\r
+ if (Description != NULL) {\r
+ Char = Description;\r
+ for (Index = 0; Index < ARRAY_SIZE (ControllerData.Mn); Index++) {\r
+ *(Char++) = (CHAR16) ControllerData.Mn[Index];\r
+ }\r
+ *(Char++) = L' ';\r
+ for (Index = 0; Index < ARRAY_SIZE (ControllerData.Sn); Index++) {\r
+ *(Char++) = (CHAR16) ControllerData.Sn[Index];\r
+ }\r
+ *(Char++) = L' ';\r
+ UnicodeValueToStringS (\r
+ Char, sizeof (CHAR16) * (MAXIMUM_VALUE_CHARACTERS + 1),\r
+ 0, DevicePath.NvmeNamespace->NamespaceId, 0\r
+ );\r
+ BmEliminateExtraSpaces (Description);\r
+ }\r
+\r
+ return Description;\r
+}\r
+\r
/**\r
Return the boot description for the controller based on the type.\r
\r
}\r
break;\r
\r
- case BmMessageNetworkBoot:\r
- Description = L"Network";\r
- break;\r
-\r
- case BmMessageHttpBoot:\r
- Description = L"Http";\r
- break;\r
-\r
default:\r
Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs);\r
if (!EFI_ERROR (Status)) {\r
BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {\r
BmGetUsbDescription,\r
BmGetDescriptionFromDiskInfo,\r
+ BmGetNetworkDescription,\r
+ BmGetLoadFileDescription,\r
+ BmGetNvmeDescription,\r
BmGetMiscDescription\r
};\r
\r
// Firstly get the default boot description\r
//\r
DefaultDescription = NULL;\r
- for (Index = 0; Index < sizeof (mBmBootDescriptionHandlers) / sizeof (mBmBootDescriptionHandlers[0]); Index++) {\r
+ for (Index = 0; Index < ARRAY_SIZE (mBmBootDescriptionHandlers); Index++) {\r
DefaultDescription = mBmBootDescriptionHandlers[Index] (Handle);\r
if (DefaultDescription != NULL) {\r
//\r