Author: tsoome
Date: Thu Nov  7 11:17:03 2019
New Revision: 354435
URL: https://svnweb.freebsd.org/changeset/base/354435

Log:
  loader: implement fallback efi_devpath_to_name()
  
  UEFI 1.10 on macs does not seem to provide devpath to name translation,
  provide our own (limited) version, so we can get information about commmon
  devices.
  
  MFC after:    1 week

Modified:
  head/stand/efi/libefi/devpath.c

Modified: head/stand/efi/libefi/devpath.c
==============================================================================
--- head/stand/efi/libefi/devpath.c     Thu Nov  7 07:21:45 2019        
(r354434)
+++ head/stand/efi/libefi/devpath.c     Thu Nov  7 11:17:03 2019        
(r354435)
@@ -29,13 +29,16 @@ __FBSDID("$FreeBSD$");
 #include <efi.h>
 #include <efilib.h>
 #include <efichar.h>
+#include <uuid.h>
+#include <machine/_inttypes.h>
 
 static EFI_GUID ImageDevicePathGUID =
     EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID;
 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
 static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
 static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *toTextProtocol;
-static EFI_GUID DevicePathFromTextGUID = 
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID;
+static EFI_GUID DevicePathFromTextGUID =
+    EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID;
 static EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *fromTextProtocol;
 
 EFI_DEVICE_PATH *
@@ -64,6 +67,427 @@ efi_lookup_devpath(EFI_HANDLE handle)
        return (devpath);
 }
 
+static char *
+efi_make_tail(char *suffix)
+{
+       char *tail;
+
+       tail = NULL;
+       if (suffix != NULL)
+               (void)asprintf(&tail, "/%s", suffix);
+       else
+               tail = strdup("");
+       return (tail);
+}
+
+typedef struct {
+       EFI_DEVICE_PATH Header;
+       EFI_GUID        Guid;
+       UINT8           VendorDefinedData[1];
+} __packed VENDOR_DEVICE_PATH_WITH_DATA;
+
+static char *
+efi_vendor_path(const char *type, VENDOR_DEVICE_PATH *node, char *suffix)
+{
+       uint32_t size = DevicePathNodeLength(&node->Header) - sizeof(*node);
+       VENDOR_DEVICE_PATH_WITH_DATA *dp = (VENDOR_DEVICE_PATH_WITH_DATA *)node;
+       char *name, *tail, *head;
+       char *uuid;
+       int rv;
+
+       uuid_to_string((const uuid_t *)(void *)&node->Guid, &uuid, &rv);
+       if (rv != uuid_s_ok)
+               return (NULL);
+
+       tail = efi_make_tail(suffix);
+       rv = asprintf(&head, "%sVendor(%s)[%x:", type, uuid, size);
+       free(uuid);
+       if (rv < 0)
+               return (NULL);
+
+       if (DevicePathNodeLength(&node->Header) > sizeof(*node)) {
+               for (uint32_t i = 0; i < size; i++) {
+                       rv = asprintf(&name, "%s%02x", head,
+                           dp->VendorDefinedData[i]);
+                       if (rv < 0) {
+                               free(tail);
+                               free(head);
+                               return (NULL);
+                       }
+                       free(head);
+                       head = name;
+               }
+       }
+
+       if (asprintf(&name, "%s]%s", head, tail) < 0)
+               name = NULL;
+       free(head);
+       free(tail);
+       return (name);
+}
+
+static char *
+efi_hw_dev_path(EFI_DEVICE_PATH *node, char *suffix)
+{
+       uint8_t subtype = DevicePathSubType(node);
+       char *name, *tail;
+
+       tail = efi_make_tail(suffix);
+       switch (subtype) {
+       case HW_PCI_DP:
+               if (asprintf(&name, "Pci(%x,%x)%s",
+                   ((PCI_DEVICE_PATH *)node)->Function,
+                   ((PCI_DEVICE_PATH *)node)->Device, tail) < 0)
+                       name = NULL;
+               break;
+       case HW_PCCARD_DP:
+               if (asprintf(&name, "PCCARD(%x)%s",
+                   ((PCCARD_DEVICE_PATH *)node)->FunctionNumber, tail) < 0)
+                       name = NULL;
+               break;
+       case HW_MEMMAP_DP:
+               if (asprintf(&name, "MMap(%x,%" PRIx64 ",%" PRIx64 ")%s",
+                   ((MEMMAP_DEVICE_PATH *)node)->MemoryType,
+                   ((MEMMAP_DEVICE_PATH *)node)->StartingAddress,
+                   ((MEMMAP_DEVICE_PATH *)node)->EndingAddress, tail) < 0)
+                       name = NULL;
+               break;
+       case HW_VENDOR_DP:
+               name = efi_vendor_path("Hardware",
+                   (VENDOR_DEVICE_PATH *)node, tail);
+               break;
+       case HW_CONTROLLER_DP:
+               if (asprintf(&name, "Ctrl(%x)%s",
+                   ((CONTROLLER_DEVICE_PATH *)node)->Controller, tail) < 0)
+                       name = NULL;
+               break;
+       default:
+               if (asprintf(&name, "UnknownHW(%x)%s", subtype, tail) < 0)
+                       name = NULL;
+               break;
+       }
+       free(tail);
+       return (name);
+}
+
+static char *
+efi_acpi_dev_path(EFI_DEVICE_PATH *node, char *suffix)
+{
+       uint8_t subtype = DevicePathSubType(node);
+       ACPI_HID_DEVICE_PATH *acpi = (ACPI_HID_DEVICE_PATH *)node;
+       char *name, *tail;
+
+       tail = efi_make_tail(suffix);
+       switch (subtype) {
+       case ACPI_DP:
+               if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
+                       switch (EISA_ID_TO_NUM (acpi->HID)) {
+                       case 0x0a03:
+                               if (asprintf(&name, "PciRoot(%x)%s",
+                                   acpi->UID, tail) < 0)
+                                       name = NULL;
+                               break;
+                       case 0x0a08:
+                               if (asprintf(&name, "PcieRoot(%x)%s",
+                                   acpi->UID, tail) < 0)
+                                       name = NULL;
+                               break;
+                       case 0x0604:
+                               if (asprintf(&name, "Floppy(%x)%s",
+                                   acpi->UID, tail) < 0)
+                                       name = NULL;
+                               break;
+                       case 0x0301:
+                               if (asprintf(&name, "Keyboard(%x)%s",
+                                   acpi->UID, tail) < 0)
+                                       name = NULL;
+                               break;
+                       case 0x0501:
+                               if (asprintf(&name, "Serial(%x)%s",
+                                   acpi->UID, tail) < 0)
+                                       name = NULL;
+                               break;
+                       case 0x0401:
+                               if (asprintf(&name, "ParallelPort(%x)%s",
+                                   acpi->UID, tail) < 0)
+                                       name = NULL;
+                               break;
+                       default:
+                               if (asprintf(&name, "Acpi(PNP%04x,%x)%s",
+                                   EISA_ID_TO_NUM(acpi->HID),
+                                   acpi->UID, tail) < 0)
+                                       name = NULL;
+                               break;
+                       }
+               } else {
+                       if (asprintf(&name, "Acpi(%08x,%x)%s",
+                           acpi->HID, acpi->UID, tail) < 0)
+                               name = NULL;
+               }
+               break;
+       case ACPI_EXTENDED_DP:
+       default:
+               if (asprintf(&name, "UnknownACPI(%x)%s", subtype, tail) < 0)
+                       name = NULL;
+               break;
+       }
+       free(tail);
+       return (name);
+}
+
+static char *
+efi_messaging_dev_path(EFI_DEVICE_PATH *node, char *suffix)
+{
+       uint8_t subtype = DevicePathSubType(node);
+       char *name;
+       char *tail;
+
+       tail = efi_make_tail(suffix);
+       switch (subtype) {
+       case MSG_ATAPI_DP:
+               if (asprintf(&name, "ATA(%s,%s,%x)%s",
+                   ((ATAPI_DEVICE_PATH *)node)->PrimarySecondary == 1 ?
+                   "Secondary" : "Primary",
+                   ((ATAPI_DEVICE_PATH *)node)->SlaveMaster == 1 ?
+                   "Slave" : "Master",
+                   ((ATAPI_DEVICE_PATH *)node)->Lun, tail) < 0)
+                       name = NULL;
+               break;
+       case MSG_SCSI_DP:
+               if (asprintf(&name, "SCSI(%x,%x)%s",
+                   ((SCSI_DEVICE_PATH *)node)->Pun,
+                   ((SCSI_DEVICE_PATH *)node)->Lun, tail) < 0)
+                       name = NULL;
+               break;
+       case MSG_FIBRECHANNEL_DP:
+               if (asprintf(&name, "Fibre(%" PRIx64 ",%" PRIx64 ")%s",
+                   ((FIBRECHANNEL_DEVICE_PATH *)node)->WWN,
+                   ((FIBRECHANNEL_DEVICE_PATH *)node)->Lun, tail) < 0)
+                       name = NULL;
+               break;
+       case MSG_1394_DP:
+               if (asprintf(&name, "I1394(%016" PRIx64 ")%s",
+                   ((F1394_DEVICE_PATH *)node)->Guid, tail) < 0)
+                       name = NULL;
+               break;
+       case MSG_USB_DP:
+               if (asprintf(&name, "USB(%x,%x)%s",
+                   ((USB_DEVICE_PATH *)node)->ParentPortNumber,
+                   ((USB_DEVICE_PATH *)node)->InterfaceNumber, tail) < 0)
+                       name = NULL;
+               break;
+       case MSG_USB_CLASS_DP:
+               if (asprintf(&name, "UsbClass(%x,%x,%x,%x,%x)%s",
+                   ((USB_CLASS_DEVICE_PATH *)node)->VendorId,
+                   ((USB_CLASS_DEVICE_PATH *)node)->ProductId,
+                   ((USB_CLASS_DEVICE_PATH *)node)->DeviceClass,
+                   ((USB_CLASS_DEVICE_PATH *)node)->DeviceSubClass,
+                   ((USB_CLASS_DEVICE_PATH *)node)->DeviceProtocol, tail) < 0)
+                       name = NULL;
+               break;
+       case MSG_MAC_ADDR_DP:
+               if (asprintf(&name, "MAC(%02x:%02x:%02x:%02x:%02x:%02x,%x)%s",
+                   ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[0],
+                   ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[1],
+                   ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[2],
+                   ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[3],
+                   ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[4],
+                   ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[5],
+                   ((MAC_ADDR_DEVICE_PATH *)node)->IfType, tail) < 0)
+                       name = NULL;
+               break;
+       case MSG_VENDOR_DP:
+               name = efi_vendor_path("Messaging",
+                   (VENDOR_DEVICE_PATH *)node, tail);
+               break;
+       case MSG_UART_DP:
+               if (asprintf(&name, "UART(%" PRIu64 ",%u,%x,%x)%s",
+                   ((UART_DEVICE_PATH *)node)->BaudRate,
+                   ((UART_DEVICE_PATH *)node)->DataBits,
+                   ((UART_DEVICE_PATH *)node)->Parity,
+                   ((UART_DEVICE_PATH *)node)->StopBits, tail) < 0)
+                       name = NULL;
+               break;
+       case MSG_SATA_DP:
+               if (asprintf(&name, "Sata(%x,%x,%x)%s",
+                   ((SATA_DEVICE_PATH *)node)->HBAPortNumber,
+                   ((SATA_DEVICE_PATH *)node)->PortMultiplierPortNumber,
+                   ((SATA_DEVICE_PATH *)node)->Lun, tail) < 0)
+                       name = NULL;
+               break;
+       default:
+               if (asprintf(&name, "UnknownMessaging(%x)%s",
+                   subtype, tail) < 0)
+                       name = NULL;
+               break;
+       }
+       free(tail);
+       return (name);
+}
+
+static char *
+efi_media_dev_path(EFI_DEVICE_PATH *node, char *suffix)
+{
+       uint8_t subtype = DevicePathSubType(node);
+       HARDDRIVE_DEVICE_PATH *hd;
+       char *name;
+       char *str;
+       char *tail;
+       int rv;
+
+       tail = efi_make_tail(suffix);
+       name = NULL;
+       switch (subtype) {
+       case MEDIA_HARDDRIVE_DP:
+               hd = (HARDDRIVE_DEVICE_PATH *)node;
+               switch (hd->SignatureType) {
+               case SIGNATURE_TYPE_MBR:
+                       if (asprintf(&name, "HD(%d,MBR,%08x,%" PRIx64
+                           ",%" PRIx64 ")%s",
+                           hd->PartitionNumber,
+                           *((uint32_t *)(uintptr_t)&hd->Signature[0]),
+                           hd->PartitionStart,
+                           hd->PartitionSize, tail) < 0)
+                               name = NULL;
+                       break;
+               case SIGNATURE_TYPE_GUID:
+                       name = NULL;
+                       uuid_to_string((const uuid_t *)(void *)
+                           &hd->Signature[0], &str, &rv);
+                       if (rv != uuid_s_ok)
+                               break;
+                       rv = asprintf(&name, "HD(%d,GPT,%s,%" PRIx64 ",%"
+                           PRIx64 ")%s",
+                           hd->PartitionNumber, str,
+                           hd->PartitionStart, hd->PartitionSize, tail);
+                       free(str);
+                       break;
+               default:
+                       if (asprintf(&name, "HD(%d,%d,0)%s",
+                           hd->PartitionNumber,
+                           hd->SignatureType, tail) < 0) {
+                               name = NULL;
+                       }
+                       break;
+               }
+               break;
+       case MEDIA_CDROM_DP:
+               if (asprintf(&name, "CD(%x,%" PRIx64 ",%" PRIx64 ")%s",
+                   ((CDROM_DEVICE_PATH *)node)->BootEntry,
+                   ((CDROM_DEVICE_PATH *)node)->PartitionStart,
+                   ((CDROM_DEVICE_PATH *)node)->PartitionSize, tail) < 0) {
+                       name = NULL;
+               }
+               break;
+       case MEDIA_VENDOR_DP:
+               name = efi_vendor_path("Media",
+                   (VENDOR_DEVICE_PATH *)node, tail);
+               break;
+       case MEDIA_FILEPATH_DP:
+               name = NULL;
+               str = NULL;
+               if (ucs2_to_utf8(((FILEPATH_DEVICE_PATH *)node)->PathName,
+                   &str) == 0) {
+                       (void)asprintf(&name, "%s%s", str, tail);
+                       free(str);
+               }
+               break;
+       case MEDIA_PROTOCOL_DP:
+               name = NULL;
+               uuid_to_string((const uuid_t *)(void *)
+                   &((MEDIA_PROTOCOL_DEVICE_PATH *)node)->Protocol,
+                   &str, &rv);
+               if (rv != uuid_s_ok)
+                       break;
+               rv = asprintf(&name, "Protocol(%s)%s", str, tail);
+               free(str);
+               break;
+       default:
+               if (asprintf(&name, "UnknownMedia(%x)%s",
+                   subtype, tail) < 0)
+                       name = NULL;
+       }
+       free(tail);
+       return (name);
+}
+
+static char *
+efi_translate_devpath(EFI_DEVICE_PATH *devpath)
+{
+       EFI_DEVICE_PATH *dp = NextDevicePathNode(devpath);
+       char *name, *ptr;
+       uint8_t type;
+
+       if (!IsDevicePathEnd(devpath))
+               name = efi_translate_devpath(dp);
+       else
+               return (NULL);
+
+       ptr = NULL;
+       type = DevicePathType(devpath);
+       switch (type) {
+       case HARDWARE_DEVICE_PATH:
+               ptr = efi_hw_dev_path(devpath, name);
+               break;
+       case ACPI_DEVICE_PATH:
+               ptr = efi_acpi_dev_path(devpath, name);
+               break;
+       case MESSAGING_DEVICE_PATH:
+               ptr = efi_messaging_dev_path(devpath, name);
+               break;
+       case MEDIA_DEVICE_PATH:
+               ptr = efi_media_dev_path(devpath, name);
+               break;
+       case BBS_DEVICE_PATH:
+       default:
+               if (asprintf(&ptr, "UnknownPath(%x)%s", type,
+                   name? name : "") < 0)
+                       ptr = NULL;
+               break;
+       }
+
+       if (ptr != NULL) {
+               free(name);
+               name = ptr;
+       }
+       return (name);
+}
+
+static CHAR16 *
+efi_devpath_to_name(EFI_DEVICE_PATH *devpath)
+{
+       char *name = NULL;
+       CHAR16 *ptr = NULL;
+       size_t len;
+       int rv;
+
+       name = efi_translate_devpath(devpath);
+       if (name == NULL)
+               return (NULL);
+
+       /*
+        * We need to return memory from AllocatePool, so it can be freed
+        * with FreePool() in efi_free_devpath_name().
+        */
+       rv = utf8_to_ucs2(name, &ptr, &len);
+       free(name);
+       if (rv == 0) {
+               CHAR16 *out = NULL;
+               EFI_STATUS status;
+
+               status = BS->AllocatePool(EfiLoaderData, len, (void **)&out);
+               if (EFI_ERROR(status)) {
+                       free(ptr);
+                       return (out);
+               }
+               memcpy(out, ptr, len);
+               free(ptr);
+               ptr = out;
+       }
+       
+       return (ptr);
+}
+
 CHAR16 *
 efi_devpath_name(EFI_DEVICE_PATH *devpath)
 {
@@ -78,7 +502,7 @@ efi_devpath_name(EFI_DEVICE_PATH *devpath)
                        toTextProtocol = NULL;
        }
        if (toTextProtocol == NULL)
-               return (NULL);
+               return (efi_devpath_to_name(devpath));
 
        return (toTextProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE));
 }
@@ -86,8 +510,8 @@ efi_devpath_name(EFI_DEVICE_PATH *devpath)
 void
 efi_free_devpath_name(CHAR16 *text)
 {
-
-       BS->FreePool(text);
+       if (text != NULL)
+               BS->FreePool(text);
 }
 
 EFI_DEVICE_PATH *
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to