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 EFI_DEVICE_PATH * 579 efi_devpath_trim(EFI_DEVICE_PATH *devpath) 580 { 581 EFI_DEVICE_PATH *node, *copy; 582 size_t prefix, len; 583 584 if ((node = efi_devpath_last_node(devpath)) == NULL) 585 return (NULL); 586 prefix = (UINT8 *)node - (UINT8 *)devpath; 587 if (prefix == 0) 588 return (NULL); 589 len = prefix + DevicePathNodeLength(NextDevicePathNode(node)); 590 copy = malloc(len); 591 if (copy != NULL) { 592 memcpy(copy, devpath, prefix); 593 node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix); 594 SetDevicePathEndNode(node); 595 } 596 return (copy); 597 } 598 599 EFI_HANDLE 600 efi_devpath_handle(EFI_DEVICE_PATH *devpath) 601 { 602 EFI_STATUS status; 603 EFI_HANDLE h; 604 605 /* 606 * There isn't a standard way to locate a handle for a given 607 * device path. However, querying the EFI_DEVICE_PATH protocol 608 * for a given device path should give us a handle for the 609 * closest node in the path to the end that is valid. 610 */ 611 status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h); 612 if (EFI_ERROR(status)) 613 return (NULL); 614 return (h); 615 } 616 617 bool 618 efi_devpath_match_node(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) 619 { 620 size_t len; 621 622 if (devpath1 == NULL || devpath2 == NULL) 623 return (false); 624 if (DevicePathType(devpath1) != DevicePathType(devpath2) || 625 DevicePathSubType(devpath1) != DevicePathSubType(devpath2)) 626 return (false); 627 len = DevicePathNodeLength(devpath1); 628 if (len != DevicePathNodeLength(devpath2)) 629 return (false); 630 if (memcmp(devpath1, devpath2, len) != 0) 631 return (false); 632 return (true); 633 } 634 635 static bool 636 _efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2, 637 bool ignore_media) 638 { 639 640 if (devpath1 == NULL || devpath2 == NULL) 641 return (false); 642 643 while (true) { 644 if (ignore_media && 645 IsDevicePathType(devpath1, MEDIA_DEVICE_PATH) && 646 IsDevicePathType(devpath2, MEDIA_DEVICE_PATH)) 647 return (true); 648 if (!efi_devpath_match_node(devpath1, devpath2)) 649 return false; 650 if (IsDevicePathEnd(devpath1)) 651 break; 652 devpath1 = NextDevicePathNode(devpath1); 653 devpath2 = NextDevicePathNode(devpath2); 654 } 655 return (true); 656 } 657 /* 658 * Are two devpaths identical? 659 */ 660 bool 661 efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) 662 { 663 return _efi_devpath_match(devpath1, devpath2, false); 664 } 665 666 /* 667 * Like efi_devpath_match, but stops at when we hit the media device 668 * path node that specifies the partition information. If we match 669 * up to that point, then we're on the same disk. 670 */ 671 bool 672 efi_devpath_same_disk(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) 673 { 674 return _efi_devpath_match(devpath1, devpath2, true); 675 } 676 677 bool 678 efi_devpath_is_prefix(EFI_DEVICE_PATH *prefix, EFI_DEVICE_PATH *path) 679 { 680 size_t len; 681 682 if (prefix == NULL || path == NULL) 683 return (false); 684 685 while (1) { 686 if (IsDevicePathEnd(prefix)) 687 break; 688 689 if (DevicePathType(prefix) != DevicePathType(path) || 690 DevicePathSubType(prefix) != DevicePathSubType(path)) 691 return (false); 692 693 len = DevicePathNodeLength(prefix); 694 if (len != DevicePathNodeLength(path)) 695 return (false); 696 697 if (memcmp(prefix, path, len) != 0) 698 return (false); 699 700 prefix = NextDevicePathNode(prefix); 701 path = NextDevicePathNode(path); 702 } 703 return (true); 704 } 705 706 /* 707 * Skip over the 'prefix' part of path and return the part of the path 708 * that starts with the first node that's a MEDIA_DEVICE_PATH. 709 */ 710 EFI_DEVICE_PATH * 711 efi_devpath_to_media_path(EFI_DEVICE_PATH *path) 712 { 713 714 while (!IsDevicePathEnd(path)) { 715 if (DevicePathType(path) == MEDIA_DEVICE_PATH) 716 return (path); 717 path = NextDevicePathNode(path); 718 } 719 return (NULL); 720 } 721 722 UINTN 723 efi_devpath_length(EFI_DEVICE_PATH *path) 724 { 725 EFI_DEVICE_PATH *start = path; 726 727 while (!IsDevicePathEnd(path)) 728 path = NextDevicePathNode(path); 729 return ((UINTN)path - (UINTN)start) + DevicePathNodeLength(path); 730 } 731 732 EFI_HANDLE 733 efi_devpath_to_handle(EFI_DEVICE_PATH *path, EFI_HANDLE *handles, unsigned nhandles) 734 { 735 unsigned i; 736 EFI_DEVICE_PATH *media, *devpath; 737 EFI_HANDLE h; 738 739 media = efi_devpath_to_media_path(path); 740 if (media == NULL) 741 return (NULL); 742 for (i = 0; i < nhandles; i++) { 743 h = handles[i]; 744 devpath = efi_lookup_devpath(h); 745 if (devpath == NULL) 746 continue; 747 if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath))) 748 continue; 749 return (h); 750 } 751 return (NULL); 752 } 753