1 /*- 2 * Copyright (c) 2016 John Baldwin <jhb@FreeBSD.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 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. 12 * 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 23 * SUCH DAMAGE. 24 */ 25 26 #include <efi.h> 27 #include <efilib.h> 28 #include <efichar.h> 29 #include <uuid.h> 30 #include <machine/_inttypes.h> 31 #include <Protocol/DevicePathToText.h> 32 #include <Protocol/DevicePathFromText.h> 33 34 static EFI_GUID ImageDevicePathGUID = 35 EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; 36 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 37 static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; 38 static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *toTextProtocol; 39 static EFI_GUID DevicePathFromTextGUID = 40 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID; 41 static EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *fromTextProtocol; 42 43 EFI_DEVICE_PATH * 44 efi_lookup_image_devpath(EFI_HANDLE handle) 45 { 46 EFI_DEVICE_PATH *devpath; 47 EFI_STATUS status; 48 49 status = OpenProtocolByHandle(handle, &ImageDevicePathGUID, 50 (void **)&devpath); 51 if (EFI_ERROR(status)) 52 devpath = NULL; 53 return (devpath); 54 } 55 56 EFI_DEVICE_PATH * 57 efi_lookup_devpath(EFI_HANDLE handle) 58 { 59 EFI_DEVICE_PATH *devpath; 60 EFI_STATUS status; 61 62 status = OpenProtocolByHandle(handle, &DevicePathGUID, 63 (void **)&devpath); 64 if (EFI_ERROR(status)) 65 devpath = NULL; 66 return (devpath); 67 } 68 69 void 70 efi_close_devpath(EFI_HANDLE handle) 71 { 72 EFI_STATUS status; 73 74 status = BS->CloseProtocol(handle, &DevicePathGUID, IH, NULL); 75 if (EFI_ERROR(status)) 76 printf("CloseProtocol error: %lu\n", DECODE_ERROR(status)); 77 } 78 79 static char * 80 efi_make_tail(char *suffix) 81 { 82 char *tail; 83 84 tail = NULL; 85 if (suffix != NULL) 86 (void)asprintf(&tail, "/%s", suffix); 87 else 88 tail = strdup(""); 89 return (tail); 90 } 91 92 typedef struct { 93 EFI_DEVICE_PATH Header; 94 EFI_GUID Guid; 95 UINT8 VendorDefinedData[1]; 96 } __packed VENDOR_DEVICE_PATH_WITH_DATA; 97 98 static char * 99 efi_vendor_path(const char *type, VENDOR_DEVICE_PATH *node, char *suffix) 100 { 101 uint32_t size = DevicePathNodeLength(&node->Header) - sizeof(*node); 102 VENDOR_DEVICE_PATH_WITH_DATA *dp = (VENDOR_DEVICE_PATH_WITH_DATA *)node; 103 char *name, *tail, *head; 104 char *uuid; 105 int rv; 106 107 uuid_to_string((const uuid_t *)(void *)&node->Guid, &uuid, &rv); 108 if (rv != uuid_s_ok) 109 return (NULL); 110 111 tail = efi_make_tail(suffix); 112 rv = asprintf(&head, "%sVendor(%s)[%x:", type, uuid, size); 113 free(uuid); 114 if (rv < 0) 115 return (NULL); 116 117 if (DevicePathNodeLength(&node->Header) > sizeof(*node)) { 118 for (uint32_t i = 0; i < size; i++) { 119 rv = asprintf(&name, "%s%02x", head, 120 dp->VendorDefinedData[i]); 121 if (rv < 0) { 122 free(tail); 123 free(head); 124 return (NULL); 125 } 126 free(head); 127 head = name; 128 } 129 } 130 131 if (asprintf(&name, "%s]%s", head, tail) < 0) 132 name = NULL; 133 free(head); 134 free(tail); 135 return (name); 136 } 137 138 static char * 139 efi_hw_dev_path(EFI_DEVICE_PATH *node, char *suffix) 140 { 141 uint8_t subtype = DevicePathSubType(node); 142 char *name, *tail; 143 144 tail = efi_make_tail(suffix); 145 switch (subtype) { 146 case HW_PCI_DP: 147 if (asprintf(&name, "Pci(%x,%x)%s", 148 ((PCI_DEVICE_PATH *)node)->Device, 149 ((PCI_DEVICE_PATH *)node)->Function, tail) < 0) 150 name = NULL; 151 break; 152 case HW_PCCARD_DP: 153 if (asprintf(&name, "PCCARD(%x)%s", 154 ((PCCARD_DEVICE_PATH *)node)->FunctionNumber, tail) < 0) 155 name = NULL; 156 break; 157 case HW_MEMMAP_DP: 158 if (asprintf(&name, "MMap(%x,%" PRIx64 ",%" PRIx64 ")%s", 159 ((MEMMAP_DEVICE_PATH *)node)->MemoryType, 160 ((MEMMAP_DEVICE_PATH *)node)->StartingAddress, 161 ((MEMMAP_DEVICE_PATH *)node)->EndingAddress, tail) < 0) 162 name = NULL; 163 break; 164 case HW_VENDOR_DP: 165 name = efi_vendor_path("Hardware", 166 (VENDOR_DEVICE_PATH *)node, tail); 167 break; 168 case HW_CONTROLLER_DP: 169 if (asprintf(&name, "Ctrl(%x)%s", 170 ((CONTROLLER_DEVICE_PATH *)node)->ControllerNumber, tail) < 0) 171 name = NULL; 172 break; 173 default: 174 if (asprintf(&name, "UnknownHW(%x)%s", subtype, tail) < 0) 175 name = NULL; 176 break; 177 } 178 free(tail); 179 return (name); 180 } 181 182 static char * 183 efi_acpi_dev_path(EFI_DEVICE_PATH *node, char *suffix) 184 { 185 uint8_t subtype = DevicePathSubType(node); 186 ACPI_HID_DEVICE_PATH *acpi = (ACPI_HID_DEVICE_PATH *)node; 187 char *name, *tail; 188 189 tail = efi_make_tail(suffix); 190 switch (subtype) { 191 case ACPI_DP: 192 if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { 193 switch (EISA_ID_TO_NUM (acpi->HID)) { 194 case 0x0a03: 195 if (asprintf(&name, "PciRoot(%x)%s", 196 acpi->UID, tail) < 0) 197 name = NULL; 198 break; 199 case 0x0a08: 200 if (asprintf(&name, "PcieRoot(%x)%s", 201 acpi->UID, tail) < 0) 202 name = NULL; 203 break; 204 case 0x0604: 205 if (asprintf(&name, "Floppy(%x)%s", 206 acpi->UID, tail) < 0) 207 name = NULL; 208 break; 209 case 0x0301: 210 if (asprintf(&name, "Keyboard(%x)%s", 211 acpi->UID, tail) < 0) 212 name = NULL; 213 break; 214 case 0x0501: 215 if (asprintf(&name, "Serial(%x)%s", 216 acpi->UID, tail) < 0) 217 name = NULL; 218 break; 219 case 0x0401: 220 if (asprintf(&name, "ParallelPort(%x)%s", 221 acpi->UID, tail) < 0) 222 name = NULL; 223 break; 224 default: 225 if (asprintf(&name, "Acpi(PNP%04x,%x)%s", 226 EISA_ID_TO_NUM(acpi->HID), 227 acpi->UID, tail) < 0) 228 name = NULL; 229 break; 230 } 231 } else { 232 if (asprintf(&name, "Acpi(%08x,%x)%s", 233 acpi->HID, acpi->UID, tail) < 0) 234 name = NULL; 235 } 236 break; 237 case ACPI_EXTENDED_DP: 238 default: 239 if (asprintf(&name, "UnknownACPI(%x)%s", subtype, tail) < 0) 240 name = NULL; 241 break; 242 } 243 free(tail); 244 return (name); 245 } 246 247 static char * 248 efi_messaging_dev_path(EFI_DEVICE_PATH *node, char *suffix) 249 { 250 uint8_t subtype = DevicePathSubType(node); 251 char *name; 252 char *tail; 253 254 tail = efi_make_tail(suffix); 255 switch (subtype) { 256 case MSG_ATAPI_DP: 257 if (asprintf(&name, "ATA(%s,%s,%x)%s", 258 ((ATAPI_DEVICE_PATH *)node)->PrimarySecondary == 1 ? 259 "Secondary" : "Primary", 260 ((ATAPI_DEVICE_PATH *)node)->SlaveMaster == 1 ? 261 "Slave" : "Master", 262 ((ATAPI_DEVICE_PATH *)node)->Lun, tail) < 0) 263 name = NULL; 264 break; 265 case MSG_SCSI_DP: 266 if (asprintf(&name, "SCSI(%x,%x)%s", 267 ((SCSI_DEVICE_PATH *)node)->Pun, 268 ((SCSI_DEVICE_PATH *)node)->Lun, tail) < 0) 269 name = NULL; 270 break; 271 case MSG_FIBRECHANNEL_DP: 272 if (asprintf(&name, "Fibre(%" PRIx64 ",%" PRIx64 ")%s", 273 ((FIBRECHANNEL_DEVICE_PATH *)node)->WWN, 274 ((FIBRECHANNEL_DEVICE_PATH *)node)->Lun, tail) < 0) 275 name = NULL; 276 break; 277 case MSG_1394_DP: 278 if (asprintf(&name, "I1394(%016" PRIx64 ")%s", 279 ((F1394_DEVICE_PATH *)node)->Guid, tail) < 0) 280 name = NULL; 281 break; 282 case MSG_USB_DP: 283 if (asprintf(&name, "USB(%x,%x)%s", 284 ((USB_DEVICE_PATH *)node)->ParentPortNumber, 285 ((USB_DEVICE_PATH *)node)->InterfaceNumber, tail) < 0) 286 name = NULL; 287 break; 288 case MSG_USB_CLASS_DP: 289 if (asprintf(&name, "UsbClass(%x,%x,%x,%x,%x)%s", 290 ((USB_CLASS_DEVICE_PATH *)node)->VendorId, 291 ((USB_CLASS_DEVICE_PATH *)node)->ProductId, 292 ((USB_CLASS_DEVICE_PATH *)node)->DeviceClass, 293 ((USB_CLASS_DEVICE_PATH *)node)->DeviceSubClass, 294 ((USB_CLASS_DEVICE_PATH *)node)->DeviceProtocol, tail) < 0) 295 name = NULL; 296 break; 297 case MSG_MAC_ADDR_DP: 298 if (asprintf(&name, "MAC(%02x:%02x:%02x:%02x:%02x:%02x,%x)%s", 299 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[0], 300 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[1], 301 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[2], 302 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[3], 303 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[4], 304 ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[5], 305 ((MAC_ADDR_DEVICE_PATH *)node)->IfType, tail) < 0) 306 name = NULL; 307 break; 308 case MSG_VENDOR_DP: 309 name = efi_vendor_path("Messaging", 310 (VENDOR_DEVICE_PATH *)node, tail); 311 break; 312 case MSG_UART_DP: 313 if (asprintf(&name, "UART(%" PRIu64 ",%u,%x,%x)%s", 314 ((UART_DEVICE_PATH *)node)->BaudRate, 315 ((UART_DEVICE_PATH *)node)->DataBits, 316 ((UART_DEVICE_PATH *)node)->Parity, 317 ((UART_DEVICE_PATH *)node)->StopBits, tail) < 0) 318 name = NULL; 319 break; 320 case MSG_SATA_DP: 321 if (asprintf(&name, "Sata(%x,%x,%x)%s", 322 ((SATA_DEVICE_PATH *)node)->HBAPortNumber, 323 ((SATA_DEVICE_PATH *)node)->PortMultiplierPortNumber, 324 ((SATA_DEVICE_PATH *)node)->Lun, tail) < 0) 325 name = NULL; 326 break; 327 default: 328 if (asprintf(&name, "UnknownMessaging(%x)%s", 329 subtype, tail) < 0) 330 name = NULL; 331 break; 332 } 333 free(tail); 334 return (name); 335 } 336 337 static char * 338 efi_media_dev_path(EFI_DEVICE_PATH *node, char *suffix) 339 { 340 uint8_t subtype = DevicePathSubType(node); 341 HARDDRIVE_DEVICE_PATH *hd; 342 char *name; 343 char *str; 344 char *tail; 345 int rv; 346 347 tail = efi_make_tail(suffix); 348 name = NULL; 349 switch (subtype) { 350 case MEDIA_HARDDRIVE_DP: 351 hd = (HARDDRIVE_DEVICE_PATH *)node; 352 switch (hd->SignatureType) { 353 case SIGNATURE_TYPE_MBR: 354 if (asprintf(&name, "HD(%d,MBR,%08x,%" PRIx64 355 ",%" PRIx64 ")%s", 356 hd->PartitionNumber, 357 *((uint32_t *)(uintptr_t)&hd->Signature[0]), 358 hd->PartitionStart, 359 hd->PartitionSize, tail) < 0) 360 name = NULL; 361 break; 362 case SIGNATURE_TYPE_GUID: 363 name = NULL; 364 uuid_to_string((const uuid_t *)(void *) 365 &hd->Signature[0], &str, &rv); 366 if (rv != uuid_s_ok) 367 break; 368 rv = asprintf(&name, "HD(%d,GPT,%s,%" PRIx64 ",%" 369 PRIx64 ")%s", 370 hd->PartitionNumber, str, 371 hd->PartitionStart, hd->PartitionSize, tail); 372 free(str); 373 break; 374 default: 375 if (asprintf(&name, "HD(%d,%d,0)%s", 376 hd->PartitionNumber, 377 hd->SignatureType, tail) < 0) { 378 name = NULL; 379 } 380 break; 381 } 382 break; 383 case MEDIA_CDROM_DP: 384 if (asprintf(&name, "CD(%x,%" PRIx64 ",%" PRIx64 ")%s", 385 ((CDROM_DEVICE_PATH *)node)->BootEntry, 386 ((CDROM_DEVICE_PATH *)node)->PartitionStart, 387 ((CDROM_DEVICE_PATH *)node)->PartitionSize, tail) < 0) { 388 name = NULL; 389 } 390 break; 391 case MEDIA_VENDOR_DP: 392 name = efi_vendor_path("Media", 393 (VENDOR_DEVICE_PATH *)node, tail); 394 break; 395 case MEDIA_FILEPATH_DP: 396 name = NULL; 397 str = NULL; 398 if (ucs2_to_utf8(((FILEPATH_DEVICE_PATH *)node)->PathName, 399 &str) == 0) { 400 (void)asprintf(&name, "%s%s", str, tail); 401 free(str); 402 } 403 break; 404 case MEDIA_PROTOCOL_DP: 405 name = NULL; 406 uuid_to_string((const uuid_t *)(void *) 407 &((MEDIA_PROTOCOL_DEVICE_PATH *)node)->Protocol, 408 &str, &rv); 409 if (rv != uuid_s_ok) 410 break; 411 rv = asprintf(&name, "Protocol(%s)%s", str, tail); 412 free(str); 413 break; 414 default: 415 if (asprintf(&name, "UnknownMedia(%x)%s", 416 subtype, tail) < 0) 417 name = NULL; 418 } 419 free(tail); 420 return (name); 421 } 422 423 static char * 424 efi_translate_devpath(EFI_DEVICE_PATH *devpath) 425 { 426 EFI_DEVICE_PATH *dp = NextDevicePathNode(devpath); 427 char *name, *ptr; 428 uint8_t type; 429 430 if (!IsDevicePathEnd(devpath)) 431 name = efi_translate_devpath(dp); 432 else 433 return (NULL); 434 435 ptr = NULL; 436 type = DevicePathType(devpath); 437 switch (type) { 438 case HARDWARE_DEVICE_PATH: 439 ptr = efi_hw_dev_path(devpath, name); 440 break; 441 case ACPI_DEVICE_PATH: 442 ptr = efi_acpi_dev_path(devpath, name); 443 break; 444 case MESSAGING_DEVICE_PATH: 445 ptr = efi_messaging_dev_path(devpath, name); 446 break; 447 case MEDIA_DEVICE_PATH: 448 ptr = efi_media_dev_path(devpath, name); 449 break; 450 case BBS_DEVICE_PATH: 451 default: 452 if (asprintf(&ptr, "UnknownPath(%x)%s", type, 453 name? name : "") < 0) 454 ptr = NULL; 455 break; 456 } 457 458 if (ptr != NULL) { 459 free(name); 460 name = ptr; 461 } 462 return (name); 463 } 464 465 static CHAR16 * 466 efi_devpath_to_name(EFI_DEVICE_PATH *devpath) 467 { 468 char *name = NULL; 469 CHAR16 *ptr = NULL; 470 size_t len; 471 int rv; 472 473 name = efi_translate_devpath(devpath); 474 if (name == NULL) 475 return (NULL); 476 477 /* 478 * We need to return memory from AllocatePool, so it can be freed 479 * with FreePool() in efi_free_devpath_name(). 480 */ 481 rv = utf8_to_ucs2(name, &ptr, &len); 482 free(name); 483 if (rv == 0) { 484 CHAR16 *out = NULL; 485 EFI_STATUS status; 486 487 status = BS->AllocatePool(EfiLoaderData, len, (void **)&out); 488 if (EFI_ERROR(status)) { 489 free(ptr); 490 return (out); 491 } 492 memcpy(out, ptr, len); 493 free(ptr); 494 ptr = out; 495 } 496 497 return (ptr); 498 } 499 500 CHAR16 * 501 efi_devpath_name(EFI_DEVICE_PATH *devpath) 502 { 503 EFI_STATUS status; 504 505 if (devpath == NULL) 506 return (NULL); 507 if (toTextProtocol == NULL) { 508 status = BS->LocateProtocol(&DevicePathToTextGUID, NULL, 509 (VOID **)&toTextProtocol); 510 if (EFI_ERROR(status)) 511 toTextProtocol = NULL; 512 } 513 if (toTextProtocol == NULL) 514 return (efi_devpath_to_name(devpath)); 515 516 return (toTextProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE)); 517 } 518 519 void 520 efi_free_devpath_name(CHAR16 *text) 521 { 522 if (text != NULL) 523 BS->FreePool(text); 524 } 525 526 EFI_DEVICE_PATH * 527 efi_name_to_devpath(const char *path) 528 { 529 EFI_DEVICE_PATH *devpath; 530 CHAR16 *uv; 531 size_t ul; 532 533 uv = NULL; 534 if (utf8_to_ucs2(path, &uv, &ul) != 0) 535 return (NULL); 536 devpath = efi_name_to_devpath16(uv); 537 free(uv); 538 return (devpath); 539 } 540 541 EFI_DEVICE_PATH * 542 efi_name_to_devpath16(CHAR16 *path) 543 { 544 EFI_STATUS status; 545 546 if (path == NULL) 547 return (NULL); 548 if (fromTextProtocol == NULL) { 549 status = BS->LocateProtocol(&DevicePathFromTextGUID, NULL, 550 (VOID **)&fromTextProtocol); 551 if (EFI_ERROR(status)) 552 fromTextProtocol = NULL; 553 } 554 if (fromTextProtocol == NULL) 555 return (NULL); 556 557 return (fromTextProtocol->ConvertTextToDevicePath(path)); 558 } 559 560 void efi_devpath_free(EFI_DEVICE_PATH *devpath) 561 { 562 563 BS->FreePool(devpath); 564 } 565 566 EFI_DEVICE_PATH * 567 efi_devpath_last_node(EFI_DEVICE_PATH *devpath) 568 { 569 570 if (IsDevicePathEnd(devpath)) 571 return (NULL); 572 while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 573 devpath = NextDevicePathNode(devpath); 574 return (devpath); 575 } 576 577 /* 578 * Walk device path nodes, return next instance or end node. 579 */ 580 EFI_DEVICE_PATH * 581 efi_devpath_next_instance(EFI_DEVICE_PATH *devpath) 582 { 583 while (!IsDevicePathEnd(devpath)) { 584 devpath = NextDevicePathNode(devpath); 585 if (IsDevicePathEndType(devpath) && 586 devpath->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) { 587 devpath = NextDevicePathNode(devpath); 588 break; 589 } 590 } 591 return (devpath); 592 } 593 594 EFI_DEVICE_PATH * 595 efi_devpath_trim(EFI_DEVICE_PATH *devpath) 596 { 597 EFI_DEVICE_PATH *node, *copy; 598 size_t prefix, len; 599 600 if ((node = efi_devpath_last_node(devpath)) == NULL) 601 return (NULL); 602 prefix = (UINT8 *)node - (UINT8 *)devpath; 603 if (prefix == 0) 604 return (NULL); 605 len = prefix + DevicePathNodeLength(NextDevicePathNode(node)); 606 copy = malloc(len); 607 if (copy != NULL) { 608 memcpy(copy, devpath, prefix); 609 node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix); 610 SetDevicePathEndNode(node); 611 } 612 return (copy); 613 } 614 615 EFI_HANDLE 616 efi_devpath_handle(EFI_DEVICE_PATH *devpath) 617 { 618 EFI_STATUS status; 619 EFI_HANDLE h; 620 621 /* 622 * There isn't a standard way to locate a handle for a given 623 * device path. However, querying the EFI_DEVICE_PATH protocol 624 * for a given device path should give us a handle for the 625 * closest node in the path to the end that is valid. 626 */ 627 status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h); 628 if (EFI_ERROR(status)) 629 return (NULL); 630 return (h); 631 } 632 633 bool 634 efi_devpath_match_node(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) 635 { 636 size_t len; 637 638 if (devpath1 == NULL || devpath2 == NULL) 639 return (false); 640 if (DevicePathType(devpath1) != DevicePathType(devpath2) || 641 DevicePathSubType(devpath1) != DevicePathSubType(devpath2)) 642 return (false); 643 len = DevicePathNodeLength(devpath1); 644 if (len != DevicePathNodeLength(devpath2)) 645 return (false); 646 if (memcmp(devpath1, devpath2, len) != 0) 647 return (false); 648 return (true); 649 } 650 651 static bool 652 _efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2, 653 bool ignore_media) 654 { 655 656 if (devpath1 == NULL || devpath2 == NULL) 657 return (false); 658 659 while (true) { 660 if (ignore_media && 661 IsDevicePathType(devpath1, MEDIA_DEVICE_PATH) && 662 IsDevicePathType(devpath2, MEDIA_DEVICE_PATH)) 663 return (true); 664 if (!efi_devpath_match_node(devpath1, devpath2)) 665 return false; 666 if (IsDevicePathEnd(devpath1)) 667 break; 668 devpath1 = NextDevicePathNode(devpath1); 669 devpath2 = NextDevicePathNode(devpath2); 670 } 671 return (true); 672 } 673 /* 674 * Are two devpaths identical? 675 */ 676 bool 677 efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) 678 { 679 return _efi_devpath_match(devpath1, devpath2, false); 680 } 681 682 /* 683 * Like efi_devpath_match, but stops at when we hit the media device 684 * path node that specifies the partition information. If we match 685 * up to that point, then we're on the same disk. 686 */ 687 bool 688 efi_devpath_same_disk(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) 689 { 690 return _efi_devpath_match(devpath1, devpath2, true); 691 } 692 693 bool 694 efi_devpath_is_prefix(EFI_DEVICE_PATH *prefix, EFI_DEVICE_PATH *path) 695 { 696 size_t len; 697 698 if (prefix == NULL || path == NULL) 699 return (false); 700 701 while (1) { 702 if (IsDevicePathEnd(prefix)) 703 break; 704 705 if (DevicePathType(prefix) != DevicePathType(path) || 706 DevicePathSubType(prefix) != DevicePathSubType(path)) 707 return (false); 708 709 len = DevicePathNodeLength(prefix); 710 if (len != DevicePathNodeLength(path)) 711 return (false); 712 713 if (memcmp(prefix, path, len) != 0) 714 return (false); 715 716 prefix = NextDevicePathNode(prefix); 717 path = NextDevicePathNode(path); 718 } 719 return (true); 720 } 721 722 /* 723 * Skip over the 'prefix' part of path and return the part of the path 724 * that starts with the first node that's a MEDIA_DEVICE_PATH. 725 */ 726 EFI_DEVICE_PATH * 727 efi_devpath_to_media_path(EFI_DEVICE_PATH *path) 728 { 729 730 while (!IsDevicePathEnd(path)) { 731 if (DevicePathType(path) == MEDIA_DEVICE_PATH) 732 return (path); 733 path = NextDevicePathNode(path); 734 } 735 return (NULL); 736 } 737 738 UINTN 739 efi_devpath_length(EFI_DEVICE_PATH *path) 740 { 741 EFI_DEVICE_PATH *start = path; 742 743 while (!IsDevicePathEnd(path)) 744 path = NextDevicePathNode(path); 745 return ((UINTN)path - (UINTN)start) + DevicePathNodeLength(path); 746 } 747 748 EFI_HANDLE 749 efi_devpath_to_handle(EFI_DEVICE_PATH *path, EFI_HANDLE *handles, unsigned nhandles) 750 { 751 unsigned i; 752 EFI_DEVICE_PATH *media, *devpath; 753 EFI_HANDLE h; 754 755 media = efi_devpath_to_media_path(path); 756 if (media == NULL) 757 return (NULL); 758 for (i = 0; i < nhandles; i++) { 759 h = handles[i]; 760 devpath = efi_lookup_devpath(h); 761 if (devpath == NULL) 762 continue; 763 if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath))) 764 continue; 765 return (h); 766 } 767 return (NULL); 768 } 769