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