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