Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Nov 2019 11:17:03 +0000 (UTC)
From:      Toomas Soome <tsoome@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r354435 - head/stand/efi/libefi
Message-ID:  <201911071117.xA7BH390010873@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 *



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201911071117.xA7BH390010873>