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