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