svn commit: r354435 - head/stand/efi/libefi

Warner Losh imp at bsdimp.com
Thu Nov 7 16:23:16 UTC 2019


On Thu, Nov 7, 2019 at 8:39 AM Toomas Soome <tsoome at me.com> wrote:

>
>
> 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> wrote:
>
>> 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.
>>
>
> 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…
>

Yea, that's surprising... The initial reports we'd received were only from
super-old macbooks. We'd also been told that newer versions were newer UEFI
revisions, so not to worry...  Guess there's some disconnect here. If
there's modern gear that still use this old revision, that's quite useful
to know... we've made other decisions that would exclude 1.2-level
implementations as well...

Warner


> 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