svn commit: r354435 - head/stand/efi/libefi
Toomas Soome
tsoome at me.com
Thu Nov 7 15:39:29 UTC 2019
> On 7. Nov 2019, at 17:29, Warner Losh <imp at bsdimp.com> wrote:
>
>
>
> On Thu, Nov 7, 2019 at 4:17 AM Toomas Soome <tsoome at freebsd.org <mailto:tsoome at freebsd.org>> wrote:
> Author: tsoome
> Date: Thu Nov 7 11:17:03 2019
> New Revision: 354435
> URL: https://svnweb.freebsd.org/changeset/base/354435 <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.
>
> We specifically deleted our own version of this function (it was wrong in many ways too) because we thought we could require a minimum UEFI 2.0 for full functionality... This sort of function is a total pain to maintain.
>
> I'd prefer the fallback was "you don't get this" rather than bloating the code, especially for devices that we don't care about and will never care about for booting...
>
> Warner
I can see why, but then again, try to debug such system… btw, that particular one I debug is MacBookPro11,4 with quad core i7…. not even that old hw anyhow.
I’d rather keep some bloat than spend 2-3 days to write code just to get any idea what is going on in the machine…
rgds,
toomas
>
> 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 *
More information about the svn-src-head
mailing list