2 * Copyright (c) 2016 John Baldwin <jhb@FreeBSD.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
33 #include <machine/_inttypes.h>
35 static EFI_GUID ImageDevicePathGUID =
36 EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID;
37 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
38 static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
39 static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *toTextProtocol;
40 static EFI_GUID DevicePathFromTextGUID =
41 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID;
42 static EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *fromTextProtocol;
45 efi_lookup_image_devpath(EFI_HANDLE handle)
47 EFI_DEVICE_PATH *devpath;
50 status = OpenProtocolByHandle(handle, &ImageDevicePathGUID,
52 if (EFI_ERROR(status))
58 efi_lookup_devpath(EFI_HANDLE handle)
60 EFI_DEVICE_PATH *devpath;
63 status = OpenProtocolByHandle(handle, &DevicePathGUID,
65 if (EFI_ERROR(status))
71 efi_make_tail(char *suffix)
77 (void)asprintf(&tail, "/%s", suffix);
84 EFI_DEVICE_PATH Header;
86 UINT8 VendorDefinedData[1];
87 } __packed VENDOR_DEVICE_PATH_WITH_DATA;
90 efi_vendor_path(const char *type, VENDOR_DEVICE_PATH *node, char *suffix)
92 uint32_t size = DevicePathNodeLength(&node->Header) - sizeof(*node);
93 VENDOR_DEVICE_PATH_WITH_DATA *dp = (VENDOR_DEVICE_PATH_WITH_DATA *)node;
94 char *name, *tail, *head;
98 uuid_to_string((const uuid_t *)(void *)&node->Guid, &uuid, &rv);
102 tail = efi_make_tail(suffix);
103 rv = asprintf(&head, "%sVendor(%s)[%x:", type, uuid, size);
108 if (DevicePathNodeLength(&node->Header) > sizeof(*node)) {
109 for (uint32_t i = 0; i < size; i++) {
110 rv = asprintf(&name, "%s%02x", head,
111 dp->VendorDefinedData[i]);
122 if (asprintf(&name, "%s]%s", head, tail) < 0)
130 efi_hw_dev_path(EFI_DEVICE_PATH *node, char *suffix)
132 uint8_t subtype = DevicePathSubType(node);
135 tail = efi_make_tail(suffix);
138 if (asprintf(&name, "Pci(%x,%x)%s",
139 ((PCI_DEVICE_PATH *)node)->Function,
140 ((PCI_DEVICE_PATH *)node)->Device, tail) < 0)
144 if (asprintf(&name, "PCCARD(%x)%s",
145 ((PCCARD_DEVICE_PATH *)node)->FunctionNumber, tail) < 0)
149 if (asprintf(&name, "MMap(%x,%" PRIx64 ",%" PRIx64 ")%s",
150 ((MEMMAP_DEVICE_PATH *)node)->MemoryType,
151 ((MEMMAP_DEVICE_PATH *)node)->StartingAddress,
152 ((MEMMAP_DEVICE_PATH *)node)->EndingAddress, tail) < 0)
156 name = efi_vendor_path("Hardware",
157 (VENDOR_DEVICE_PATH *)node, tail);
159 case HW_CONTROLLER_DP:
160 if (asprintf(&name, "Ctrl(%x)%s",
161 ((CONTROLLER_DEVICE_PATH *)node)->Controller, tail) < 0)
165 if (asprintf(&name, "UnknownHW(%x)%s", subtype, tail) < 0)
174 efi_acpi_dev_path(EFI_DEVICE_PATH *node, char *suffix)
176 uint8_t subtype = DevicePathSubType(node);
177 ACPI_HID_DEVICE_PATH *acpi = (ACPI_HID_DEVICE_PATH *)node;
180 tail = efi_make_tail(suffix);
183 if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
184 switch (EISA_ID_TO_NUM (acpi->HID)) {
186 if (asprintf(&name, "PciRoot(%x)%s",
187 acpi->UID, tail) < 0)
191 if (asprintf(&name, "PcieRoot(%x)%s",
192 acpi->UID, tail) < 0)
196 if (asprintf(&name, "Floppy(%x)%s",
197 acpi->UID, tail) < 0)
201 if (asprintf(&name, "Keyboard(%x)%s",
202 acpi->UID, tail) < 0)
206 if (asprintf(&name, "Serial(%x)%s",
207 acpi->UID, tail) < 0)
211 if (asprintf(&name, "ParallelPort(%x)%s",
212 acpi->UID, tail) < 0)
216 if (asprintf(&name, "Acpi(PNP%04x,%x)%s",
217 EISA_ID_TO_NUM(acpi->HID),
218 acpi->UID, tail) < 0)
223 if (asprintf(&name, "Acpi(%08x,%x)%s",
224 acpi->HID, acpi->UID, tail) < 0)
228 case ACPI_EXTENDED_DP:
230 if (asprintf(&name, "UnknownACPI(%x)%s", subtype, tail) < 0)
239 efi_messaging_dev_path(EFI_DEVICE_PATH *node, char *suffix)
241 uint8_t subtype = DevicePathSubType(node);
245 tail = efi_make_tail(suffix);
248 if (asprintf(&name, "ATA(%s,%s,%x)%s",
249 ((ATAPI_DEVICE_PATH *)node)->PrimarySecondary == 1 ?
250 "Secondary" : "Primary",
251 ((ATAPI_DEVICE_PATH *)node)->SlaveMaster == 1 ?
253 ((ATAPI_DEVICE_PATH *)node)->Lun, tail) < 0)
257 if (asprintf(&name, "SCSI(%x,%x)%s",
258 ((SCSI_DEVICE_PATH *)node)->Pun,
259 ((SCSI_DEVICE_PATH *)node)->Lun, tail) < 0)
262 case MSG_FIBRECHANNEL_DP:
263 if (asprintf(&name, "Fibre(%" PRIx64 ",%" PRIx64 ")%s",
264 ((FIBRECHANNEL_DEVICE_PATH *)node)->WWN,
265 ((FIBRECHANNEL_DEVICE_PATH *)node)->Lun, tail) < 0)
269 if (asprintf(&name, "I1394(%016" PRIx64 ")%s",
270 ((F1394_DEVICE_PATH *)node)->Guid, tail) < 0)
274 if (asprintf(&name, "USB(%x,%x)%s",
275 ((USB_DEVICE_PATH *)node)->ParentPortNumber,
276 ((USB_DEVICE_PATH *)node)->InterfaceNumber, tail) < 0)
279 case MSG_USB_CLASS_DP:
280 if (asprintf(&name, "UsbClass(%x,%x,%x,%x,%x)%s",
281 ((USB_CLASS_DEVICE_PATH *)node)->VendorId,
282 ((USB_CLASS_DEVICE_PATH *)node)->ProductId,
283 ((USB_CLASS_DEVICE_PATH *)node)->DeviceClass,
284 ((USB_CLASS_DEVICE_PATH *)node)->DeviceSubClass,
285 ((USB_CLASS_DEVICE_PATH *)node)->DeviceProtocol, tail) < 0)
288 case MSG_MAC_ADDR_DP:
289 if (asprintf(&name, "MAC(%02x:%02x:%02x:%02x:%02x:%02x,%x)%s",
290 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[0],
291 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[1],
292 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[2],
293 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[3],
294 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[4],
295 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[5],
296 ((MAC_ADDR_DEVICE_PATH *)node)->IfType, tail) < 0)
300 name = efi_vendor_path("Messaging",
301 (VENDOR_DEVICE_PATH *)node, tail);
304 if (asprintf(&name, "UART(%" PRIu64 ",%u,%x,%x)%s",
305 ((UART_DEVICE_PATH *)node)->BaudRate,
306 ((UART_DEVICE_PATH *)node)->DataBits,
307 ((UART_DEVICE_PATH *)node)->Parity,
308 ((UART_DEVICE_PATH *)node)->StopBits, tail) < 0)
312 if (asprintf(&name, "Sata(%x,%x,%x)%s",
313 ((SATA_DEVICE_PATH *)node)->HBAPortNumber,
314 ((SATA_DEVICE_PATH *)node)->PortMultiplierPortNumber,
315 ((SATA_DEVICE_PATH *)node)->Lun, tail) < 0)
319 if (asprintf(&name, "UnknownMessaging(%x)%s",
329 efi_media_dev_path(EFI_DEVICE_PATH *node, char *suffix)
331 uint8_t subtype = DevicePathSubType(node);
332 HARDDRIVE_DEVICE_PATH *hd;
338 tail = efi_make_tail(suffix);
341 case MEDIA_HARDDRIVE_DP:
342 hd = (HARDDRIVE_DEVICE_PATH *)node;
343 switch (hd->SignatureType) {
344 case SIGNATURE_TYPE_MBR:
345 if (asprintf(&name, "HD(%d,MBR,%08x,%" PRIx64
348 *((uint32_t *)(uintptr_t)&hd->Signature[0]),
350 hd->PartitionSize, tail) < 0)
353 case SIGNATURE_TYPE_GUID:
355 uuid_to_string((const uuid_t *)(void *)
356 &hd->Signature[0], &str, &rv);
359 rv = asprintf(&name, "HD(%d,GPT,%s,%" PRIx64 ",%"
361 hd->PartitionNumber, str,
362 hd->PartitionStart, hd->PartitionSize, tail);
366 if (asprintf(&name, "HD(%d,%d,0)%s",
368 hd->SignatureType, tail) < 0) {
375 if (asprintf(&name, "CD(%x,%" PRIx64 ",%" PRIx64 ")%s",
376 ((CDROM_DEVICE_PATH *)node)->BootEntry,
377 ((CDROM_DEVICE_PATH *)node)->PartitionStart,
378 ((CDROM_DEVICE_PATH *)node)->PartitionSize, tail) < 0) {
382 case MEDIA_VENDOR_DP:
383 name = efi_vendor_path("Media",
384 (VENDOR_DEVICE_PATH *)node, tail);
386 case MEDIA_FILEPATH_DP:
389 if (ucs2_to_utf8(((FILEPATH_DEVICE_PATH *)node)->PathName,
391 (void)asprintf(&name, "%s%s", str, tail);
395 case MEDIA_PROTOCOL_DP:
397 uuid_to_string((const uuid_t *)(void *)
398 &((MEDIA_PROTOCOL_DEVICE_PATH *)node)->Protocol,
402 rv = asprintf(&name, "Protocol(%s)%s", str, tail);
406 if (asprintf(&name, "UnknownMedia(%x)%s",
415 efi_translate_devpath(EFI_DEVICE_PATH *devpath)
417 EFI_DEVICE_PATH *dp = NextDevicePathNode(devpath);
421 if (!IsDevicePathEnd(devpath))
422 name = efi_translate_devpath(dp);
427 type = DevicePathType(devpath);
429 case HARDWARE_DEVICE_PATH:
430 ptr = efi_hw_dev_path(devpath, name);
432 case ACPI_DEVICE_PATH:
433 ptr = efi_acpi_dev_path(devpath, name);
435 case MESSAGING_DEVICE_PATH:
436 ptr = efi_messaging_dev_path(devpath, name);
438 case MEDIA_DEVICE_PATH:
439 ptr = efi_media_dev_path(devpath, name);
441 case BBS_DEVICE_PATH:
443 if (asprintf(&ptr, "UnknownPath(%x)%s", type,
444 name? name : "") < 0)
457 efi_devpath_to_name(EFI_DEVICE_PATH *devpath)
464 name = efi_translate_devpath(devpath);
469 * We need to return memory from AllocatePool, so it can be freed
470 * with FreePool() in efi_free_devpath_name().
472 rv = utf8_to_ucs2(name, &ptr, &len);
478 status = BS->AllocatePool(EfiLoaderData, len, (void **)&out);
479 if (EFI_ERROR(status)) {
483 memcpy(out, ptr, len);
492 efi_devpath_name(EFI_DEVICE_PATH *devpath)
498 if (toTextProtocol == NULL) {
499 status = BS->LocateProtocol(&DevicePathToTextGUID, NULL,
500 (VOID **)&toTextProtocol);
501 if (EFI_ERROR(status))
502 toTextProtocol = NULL;
504 if (toTextProtocol == NULL)
505 return (efi_devpath_to_name(devpath));
507 return (toTextProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE));
511 efi_free_devpath_name(CHAR16 *text)
518 efi_name_to_devpath(const char *path)
520 EFI_DEVICE_PATH *devpath;
525 if (utf8_to_ucs2(path, &uv, &ul) != 0)
527 devpath = efi_name_to_devpath16(uv);
533 efi_name_to_devpath16(CHAR16 *path)
539 if (fromTextProtocol == NULL) {
540 status = BS->LocateProtocol(&DevicePathFromTextGUID, NULL,
541 (VOID **)&fromTextProtocol);
542 if (EFI_ERROR(status))
543 fromTextProtocol = NULL;
545 if (fromTextProtocol == NULL)
548 return (fromTextProtocol->ConvertTextToDevicePath(path));
551 void efi_devpath_free(EFI_DEVICE_PATH *devpath)
554 BS->FreePool(devpath);
558 efi_devpath_last_node(EFI_DEVICE_PATH *devpath)
561 if (IsDevicePathEnd(devpath))
563 while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
564 devpath = NextDevicePathNode(devpath);
569 efi_devpath_trim(EFI_DEVICE_PATH *devpath)
571 EFI_DEVICE_PATH *node, *copy;
574 if ((node = efi_devpath_last_node(devpath)) == NULL)
576 prefix = (UINT8 *)node - (UINT8 *)devpath;
579 len = prefix + DevicePathNodeLength(NextDevicePathNode(node));
582 memcpy(copy, devpath, prefix);
583 node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix);
584 SetDevicePathEndNode(node);
590 efi_devpath_handle(EFI_DEVICE_PATH *devpath)
596 * There isn't a standard way to locate a handle for a given
597 * device path. However, querying the EFI_DEVICE_PATH protocol
598 * for a given device path should give us a handle for the
599 * closest node in the path to the end that is valid.
601 status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h);
602 if (EFI_ERROR(status))
608 efi_devpath_match_node(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
612 if (devpath1 == NULL || devpath2 == NULL)
614 if (DevicePathType(devpath1) != DevicePathType(devpath2) ||
615 DevicePathSubType(devpath1) != DevicePathSubType(devpath2))
617 len = DevicePathNodeLength(devpath1);
618 if (len != DevicePathNodeLength(devpath2))
620 if (memcmp(devpath1, devpath2, len) != 0)
626 _efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2,
630 if (devpath1 == NULL || devpath2 == NULL)
635 IsDevicePathType(devpath1, MEDIA_DEVICE_PATH) &&
636 IsDevicePathType(devpath2, MEDIA_DEVICE_PATH))
638 if (!efi_devpath_match_node(devpath1, devpath2))
640 if (IsDevicePathEnd(devpath1))
642 devpath1 = NextDevicePathNode(devpath1);
643 devpath2 = NextDevicePathNode(devpath2);
648 * Are two devpaths identical?
651 efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
653 return _efi_devpath_match(devpath1, devpath2, false);
657 * Like efi_devpath_match, but stops at when we hit the media device
658 * path node that specifies the partition information. If we match
659 * up to that point, then we're on the same disk.
662 efi_devpath_same_disk(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
664 return _efi_devpath_match(devpath1, devpath2, true);
668 efi_devpath_is_prefix(EFI_DEVICE_PATH *prefix, EFI_DEVICE_PATH *path)
672 if (prefix == NULL || path == NULL)
676 if (IsDevicePathEnd(prefix))
679 if (DevicePathType(prefix) != DevicePathType(path) ||
680 DevicePathSubType(prefix) != DevicePathSubType(path))
683 len = DevicePathNodeLength(prefix);
684 if (len != DevicePathNodeLength(path))
687 if (memcmp(prefix, path, len) != 0)
690 prefix = NextDevicePathNode(prefix);
691 path = NextDevicePathNode(path);
697 * Skip over the 'prefix' part of path and return the part of the path
698 * that starts with the first node that's a MEDIA_DEVICE_PATH.
701 efi_devpath_to_media_path(EFI_DEVICE_PATH *path)
704 while (!IsDevicePathEnd(path)) {
705 if (DevicePathType(path) == MEDIA_DEVICE_PATH)
707 path = NextDevicePathNode(path);
713 efi_devpath_length(EFI_DEVICE_PATH *path)
715 EFI_DEVICE_PATH *start = path;
717 while (!IsDevicePathEnd(path))
718 path = NextDevicePathNode(path);
719 return ((UINTN)path - (UINTN)start) + DevicePathNodeLength(path);
723 efi_devpath_to_handle(EFI_DEVICE_PATH *path, EFI_HANDLE *handles, unsigned nhandles)
726 EFI_DEVICE_PATH *media, *devpath;
729 media = efi_devpath_to_media_path(path);
732 for (i = 0; i < nhandles; i++) {
734 devpath = efi_lookup_devpath(h);
737 if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath)))