1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * EFI device path from u-boot device-model mapping 4 * 5 * (C) Copyright 2017 Rob Clark 6 */ 7 8 #define LOG_CATEGORY LOGL_ERR 9 10 #include <common.h> 11 #include <blk.h> 12 #include <dm.h> 13 #include <usb.h> 14 #include <mmc.h> 15 #include <efi_loader.h> 16 #include <inttypes.h> 17 #include <part.h> 18 19 /* template END node: */ 20 static const struct efi_device_path END = { 21 .type = DEVICE_PATH_TYPE_END, 22 .sub_type = DEVICE_PATH_SUB_TYPE_END, 23 .length = sizeof(END), 24 }; 25 26 #define U_BOOT_GUID \ 27 EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \ 28 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b) 29 30 /* template ROOT node: */ 31 static const struct efi_device_path_vendor ROOT = { 32 .dp = { 33 .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE, 34 .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR, 35 .length = sizeof(ROOT), 36 }, 37 .guid = U_BOOT_GUID, 38 }; 39 40 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) 41 /* 42 * Determine if an MMC device is an SD card. 43 * 44 * @desc block device descriptor 45 * @return true if the device is an SD card 46 */ 47 static bool is_sd(struct blk_desc *desc) 48 { 49 struct mmc *mmc = find_mmc_device(desc->devnum); 50 51 if (!mmc) 52 return false; 53 54 return IS_SD(mmc) != 0U; 55 } 56 #endif 57 58 static void *dp_alloc(size_t sz) 59 { 60 void *buf; 61 62 if (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) != 63 EFI_SUCCESS) { 64 debug("EFI: ERROR: out of memory in %s\n", __func__); 65 return NULL; 66 } 67 68 memset(buf, 0, sz); 69 return buf; 70 } 71 72 /* 73 * Iterate to next block in device-path, terminating (returning NULL) 74 * at /End* node. 75 */ 76 struct efi_device_path *efi_dp_next(const struct efi_device_path *dp) 77 { 78 if (dp == NULL) 79 return NULL; 80 if (dp->type == DEVICE_PATH_TYPE_END) 81 return NULL; 82 dp = ((void *)dp) + dp->length; 83 if (dp->type == DEVICE_PATH_TYPE_END) 84 return NULL; 85 return (struct efi_device_path *)dp; 86 } 87 88 /* 89 * Compare two device-paths, stopping when the shorter of the two hits 90 * an End* node. This is useful to, for example, compare a device-path 91 * representing a device with one representing a file on the device, or 92 * a device with a parent device. 93 */ 94 int efi_dp_match(const struct efi_device_path *a, 95 const struct efi_device_path *b) 96 { 97 while (1) { 98 int ret; 99 100 ret = memcmp(&a->length, &b->length, sizeof(a->length)); 101 if (ret) 102 return ret; 103 104 ret = memcmp(a, b, a->length); 105 if (ret) 106 return ret; 107 108 a = efi_dp_next(a); 109 b = efi_dp_next(b); 110 111 if (!a || !b) 112 return 0; 113 } 114 } 115 116 /* 117 * See UEFI spec (section 3.1.2, about short-form device-paths.. 118 * tl;dr: we can have a device-path that starts with a USB WWID 119 * or USB Class node, and a few other cases which don't encode 120 * the full device path with bus hierarchy: 121 * 122 * - MESSAGING:USB_WWID 123 * - MESSAGING:USB_CLASS 124 * - MEDIA:FILE_PATH 125 * - MEDIA:HARD_DRIVE 126 * - MESSAGING:URI 127 */ 128 static struct efi_device_path *shorten_path(struct efi_device_path *dp) 129 { 130 while (dp) { 131 /* 132 * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI.. 133 * in practice fallback.efi just uses MEDIA:HARD_DRIVE 134 * so not sure when we would see these other cases. 135 */ 136 if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) || 137 EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) || 138 EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH)) 139 return dp; 140 141 dp = efi_dp_next(dp); 142 } 143 144 return dp; 145 } 146 147 static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path, 148 struct efi_device_path **rem) 149 { 150 struct efi_object *efiobj; 151 efi_uintn_t dp_size = efi_dp_instance_size(dp); 152 153 list_for_each_entry(efiobj, &efi_obj_list, link) { 154 struct efi_handler *handler; 155 struct efi_device_path *obj_dp; 156 efi_status_t ret; 157 158 ret = efi_search_protocol(efiobj->handle, 159 &efi_guid_device_path, &handler); 160 if (ret != EFI_SUCCESS) 161 continue; 162 obj_dp = handler->protocol_interface; 163 164 do { 165 if (efi_dp_match(dp, obj_dp) == 0) { 166 if (rem) { 167 /* 168 * Allow partial matches, but inform 169 * the caller. 170 */ 171 *rem = ((void *)dp) + 172 efi_dp_instance_size(obj_dp); 173 return efiobj; 174 } else { 175 /* Only return on exact matches */ 176 if (efi_dp_instance_size(obj_dp) == 177 dp_size) 178 return efiobj; 179 } 180 } 181 182 obj_dp = shorten_path(efi_dp_next(obj_dp)); 183 } while (short_path && obj_dp); 184 } 185 186 return NULL; 187 } 188 189 /* 190 * Find an efiobj from device-path, if 'rem' is not NULL, returns the 191 * remaining part of the device path after the matched object. 192 */ 193 struct efi_object *efi_dp_find_obj(struct efi_device_path *dp, 194 struct efi_device_path **rem) 195 { 196 struct efi_object *efiobj; 197 198 /* Search for an exact match first */ 199 efiobj = find_obj(dp, false, NULL); 200 201 /* Then for a fuzzy match */ 202 if (!efiobj) 203 efiobj = find_obj(dp, false, rem); 204 205 /* And now for a fuzzy short match */ 206 if (!efiobj) 207 efiobj = find_obj(dp, true, rem); 208 209 return efiobj; 210 } 211 212 /* 213 * Determine the last device path node that is not the end node. 214 * 215 * @dp device path 216 * @return last node before the end node if it exists 217 * otherwise NULL 218 */ 219 const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp) 220 { 221 struct efi_device_path *ret; 222 223 if (!dp || dp->type == DEVICE_PATH_TYPE_END) 224 return NULL; 225 while (dp) { 226 ret = (struct efi_device_path *)dp; 227 dp = efi_dp_next(dp); 228 } 229 return ret; 230 } 231 232 /* get size of the first device path instance excluding end node */ 233 efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp) 234 { 235 efi_uintn_t sz = 0; 236 237 if (!dp || dp->type == DEVICE_PATH_TYPE_END) 238 return 0; 239 while (dp) { 240 sz += dp->length; 241 dp = efi_dp_next(dp); 242 } 243 244 return sz; 245 } 246 247 /* get size of multi-instance device path excluding end node */ 248 efi_uintn_t efi_dp_size(const struct efi_device_path *dp) 249 { 250 const struct efi_device_path *p = dp; 251 252 if (!p) 253 return 0; 254 while (p->type != DEVICE_PATH_TYPE_END || 255 p->sub_type != DEVICE_PATH_SUB_TYPE_END) 256 p = (void *)p + p->length; 257 258 return (void *)p - (void *)dp; 259 } 260 261 /* copy multi-instance device path */ 262 struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp) 263 { 264 struct efi_device_path *ndp; 265 size_t sz = efi_dp_size(dp) + sizeof(END); 266 267 if (!dp) 268 return NULL; 269 270 ndp = dp_alloc(sz); 271 if (!ndp) 272 return NULL; 273 memcpy(ndp, dp, sz); 274 275 return ndp; 276 } 277 278 struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1, 279 const struct efi_device_path *dp2) 280 { 281 struct efi_device_path *ret; 282 283 if (!dp1 && !dp2) { 284 /* return an end node */ 285 ret = efi_dp_dup(&END); 286 } else if (!dp1) { 287 ret = efi_dp_dup(dp2); 288 } else if (!dp2) { 289 ret = efi_dp_dup(dp1); 290 } else { 291 /* both dp1 and dp2 are non-null */ 292 unsigned sz1 = efi_dp_size(dp1); 293 unsigned sz2 = efi_dp_size(dp2); 294 void *p = dp_alloc(sz1 + sz2 + sizeof(END)); 295 if (!p) 296 return NULL; 297 memcpy(p, dp1, sz1); 298 /* the end node of the second device path has to be retained */ 299 memcpy(p + sz1, dp2, sz2 + sizeof(END)); 300 ret = p; 301 } 302 303 return ret; 304 } 305 306 struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp, 307 const struct efi_device_path *node) 308 { 309 struct efi_device_path *ret; 310 311 if (!node && !dp) { 312 ret = efi_dp_dup(&END); 313 } else if (!node) { 314 ret = efi_dp_dup(dp); 315 } else if (!dp) { 316 size_t sz = node->length; 317 void *p = dp_alloc(sz + sizeof(END)); 318 if (!p) 319 return NULL; 320 memcpy(p, node, sz); 321 memcpy(p + sz, &END, sizeof(END)); 322 ret = p; 323 } else { 324 /* both dp and node are non-null */ 325 size_t sz = efi_dp_size(dp); 326 void *p = dp_alloc(sz + node->length + sizeof(END)); 327 if (!p) 328 return NULL; 329 memcpy(p, dp, sz); 330 memcpy(p + sz, node, node->length); 331 memcpy(p + sz + node->length, &END, sizeof(END)); 332 ret = p; 333 } 334 335 return ret; 336 } 337 338 struct efi_device_path *efi_dp_create_device_node(const u8 type, 339 const u8 sub_type, 340 const u16 length) 341 { 342 struct efi_device_path *ret; 343 344 ret = dp_alloc(length); 345 if (!ret) 346 return ret; 347 ret->type = type; 348 ret->sub_type = sub_type; 349 ret->length = length; 350 return ret; 351 } 352 353 struct efi_device_path *efi_dp_append_instance( 354 const struct efi_device_path *dp, 355 const struct efi_device_path *dpi) 356 { 357 size_t sz, szi; 358 struct efi_device_path *p, *ret; 359 360 if (!dpi) 361 return NULL; 362 if (!dp) 363 return efi_dp_dup(dpi); 364 sz = efi_dp_size(dp); 365 szi = efi_dp_instance_size(dpi); 366 p = dp_alloc(sz + szi + 2 * sizeof(END)); 367 if (!p) 368 return NULL; 369 ret = p; 370 memcpy(p, dp, sz + sizeof(END)); 371 p = (void *)p + sz; 372 p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END; 373 p = (void *)p + sizeof(END); 374 memcpy(p, dpi, szi); 375 p = (void *)p + szi; 376 memcpy(p, &END, sizeof(END)); 377 return ret; 378 } 379 380 struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp, 381 efi_uintn_t *size) 382 { 383 size_t sz; 384 struct efi_device_path *p; 385 386 if (size) 387 *size = 0; 388 if (!dp || !*dp) 389 return NULL; 390 p = *dp; 391 sz = efi_dp_instance_size(*dp); 392 p = dp_alloc(sz + sizeof(END)); 393 if (!p) 394 return NULL; 395 memcpy(p, *dp, sz + sizeof(END)); 396 *dp = (void *)*dp + sz; 397 if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END) 398 *dp = (void *)*dp + sizeof(END); 399 else 400 *dp = NULL; 401 if (size) 402 *size = sz + sizeof(END); 403 return p; 404 } 405 406 bool efi_dp_is_multi_instance(const struct efi_device_path *dp) 407 { 408 const struct efi_device_path *p = dp; 409 410 if (!p) 411 return false; 412 while (p->type != DEVICE_PATH_TYPE_END) 413 p = (void *)p + p->length; 414 return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END; 415 } 416 417 #ifdef CONFIG_DM 418 /* size of device-path not including END node for device and all parents 419 * up to the root device. 420 */ 421 static unsigned dp_size(struct udevice *dev) 422 { 423 if (!dev || !dev->driver) 424 return sizeof(ROOT); 425 426 switch (dev->driver->id) { 427 case UCLASS_ROOT: 428 case UCLASS_SIMPLE_BUS: 429 /* stop traversing parents at this point: */ 430 return sizeof(ROOT); 431 case UCLASS_ETH: 432 return dp_size(dev->parent) + 433 sizeof(struct efi_device_path_mac_addr); 434 #ifdef CONFIG_BLK 435 case UCLASS_BLK: 436 switch (dev->parent->uclass->uc_drv->id) { 437 #ifdef CONFIG_IDE 438 case UCLASS_IDE: 439 return dp_size(dev->parent) + 440 sizeof(struct efi_device_path_atapi); 441 #endif 442 #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI) 443 case UCLASS_SCSI: 444 return dp_size(dev->parent) + 445 sizeof(struct efi_device_path_scsi); 446 #endif 447 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) 448 case UCLASS_MMC: 449 return dp_size(dev->parent) + 450 sizeof(struct efi_device_path_sd_mmc_path); 451 #endif 452 default: 453 return dp_size(dev->parent); 454 } 455 #endif 456 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) 457 case UCLASS_MMC: 458 return dp_size(dev->parent) + 459 sizeof(struct efi_device_path_sd_mmc_path); 460 #endif 461 case UCLASS_MASS_STORAGE: 462 case UCLASS_USB_HUB: 463 return dp_size(dev->parent) + 464 sizeof(struct efi_device_path_usb_class); 465 default: 466 /* just skip over unknown classes: */ 467 return dp_size(dev->parent); 468 } 469 } 470 471 /* 472 * Recursively build a device path. 473 * 474 * @buf pointer to the end of the device path 475 * @dev device 476 * @return pointer to the end of the device path 477 */ 478 static void *dp_fill(void *buf, struct udevice *dev) 479 { 480 if (!dev || !dev->driver) 481 return buf; 482 483 switch (dev->driver->id) { 484 case UCLASS_ROOT: 485 case UCLASS_SIMPLE_BUS: { 486 /* stop traversing parents at this point: */ 487 struct efi_device_path_vendor *vdp = buf; 488 *vdp = ROOT; 489 return &vdp[1]; 490 } 491 #ifdef CONFIG_DM_ETH 492 case UCLASS_ETH: { 493 struct efi_device_path_mac_addr *dp = 494 dp_fill(buf, dev->parent); 495 struct eth_pdata *pdata = dev->platdata; 496 497 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; 498 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR; 499 dp->dp.length = sizeof(*dp); 500 memset(&dp->mac, 0, sizeof(dp->mac)); 501 /* We only support IPv4 */ 502 memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN); 503 /* Ethernet */ 504 dp->if_type = 1; 505 return &dp[1]; 506 } 507 #endif 508 #ifdef CONFIG_BLK 509 case UCLASS_BLK: 510 switch (dev->parent->uclass->uc_drv->id) { 511 #ifdef CONFIG_IDE 512 case UCLASS_IDE: { 513 struct efi_device_path_atapi *dp = 514 dp_fill(buf, dev->parent); 515 struct blk_desc *desc = dev_get_uclass_platdata(dev); 516 517 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; 518 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI; 519 dp->dp.length = sizeof(*dp); 520 dp->logical_unit_number = desc->devnum; 521 dp->primary_secondary = IDE_BUS(desc->devnum); 522 dp->slave_master = desc->devnum % 523 (CONFIG_SYS_IDE_MAXDEVICE / 524 CONFIG_SYS_IDE_MAXBUS); 525 return &dp[1]; 526 } 527 #endif 528 #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI) 529 case UCLASS_SCSI: { 530 struct efi_device_path_scsi *dp = 531 dp_fill(buf, dev->parent); 532 struct blk_desc *desc = dev_get_uclass_platdata(dev); 533 534 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; 535 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI; 536 dp->dp.length = sizeof(*dp); 537 dp->logical_unit_number = desc->lun; 538 dp->target_id = desc->target; 539 return &dp[1]; 540 } 541 #endif 542 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) 543 case UCLASS_MMC: { 544 struct efi_device_path_sd_mmc_path *sddp = 545 dp_fill(buf, dev->parent); 546 struct blk_desc *desc = dev_get_uclass_platdata(dev); 547 548 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; 549 sddp->dp.sub_type = is_sd(desc) ? 550 DEVICE_PATH_SUB_TYPE_MSG_SD : 551 DEVICE_PATH_SUB_TYPE_MSG_MMC; 552 sddp->dp.length = sizeof(*sddp); 553 sddp->slot_number = dev->seq; 554 return &sddp[1]; 555 } 556 #endif 557 default: 558 debug("%s(%u) %s: unhandled parent class: %s (%u)\n", 559 __FILE__, __LINE__, __func__, 560 dev->name, dev->parent->uclass->uc_drv->id); 561 return dp_fill(buf, dev->parent); 562 } 563 #endif 564 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) 565 case UCLASS_MMC: { 566 struct efi_device_path_sd_mmc_path *sddp = 567 dp_fill(buf, dev->parent); 568 struct mmc *mmc = mmc_get_mmc_dev(dev); 569 struct blk_desc *desc = mmc_get_blk_desc(mmc); 570 571 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; 572 sddp->dp.sub_type = is_sd(desc) ? 573 DEVICE_PATH_SUB_TYPE_MSG_SD : 574 DEVICE_PATH_SUB_TYPE_MSG_MMC; 575 sddp->dp.length = sizeof(*sddp); 576 sddp->slot_number = dev->seq; 577 578 return &sddp[1]; 579 } 580 #endif 581 case UCLASS_MASS_STORAGE: 582 case UCLASS_USB_HUB: { 583 struct efi_device_path_usb_class *udp = 584 dp_fill(buf, dev->parent); 585 struct usb_device *udev = dev_get_parent_priv(dev); 586 struct usb_device_descriptor *desc = &udev->descriptor; 587 588 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; 589 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS; 590 udp->dp.length = sizeof(*udp); 591 udp->vendor_id = desc->idVendor; 592 udp->product_id = desc->idProduct; 593 udp->device_class = desc->bDeviceClass; 594 udp->device_subclass = desc->bDeviceSubClass; 595 udp->device_protocol = desc->bDeviceProtocol; 596 597 return &udp[1]; 598 } 599 default: 600 debug("%s(%u) %s: unhandled device class: %s (%u)\n", 601 __FILE__, __LINE__, __func__, 602 dev->name, dev->driver->id); 603 return dp_fill(buf, dev->parent); 604 } 605 } 606 607 /* Construct a device-path from a device: */ 608 struct efi_device_path *efi_dp_from_dev(struct udevice *dev) 609 { 610 void *buf, *start; 611 612 start = buf = dp_alloc(dp_size(dev) + sizeof(END)); 613 if (!buf) 614 return NULL; 615 buf = dp_fill(buf, dev); 616 *((struct efi_device_path *)buf) = END; 617 618 return start; 619 } 620 #endif 621 622 static unsigned dp_part_size(struct blk_desc *desc, int part) 623 { 624 unsigned dpsize; 625 626 #ifdef CONFIG_BLK 627 { 628 struct udevice *dev; 629 int ret = blk_find_device(desc->if_type, desc->devnum, &dev); 630 631 if (ret) 632 dev = desc->bdev->parent; 633 dpsize = dp_size(dev); 634 } 635 #else 636 dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb); 637 #endif 638 639 if (part == 0) /* the actual disk, not a partition */ 640 return dpsize; 641 642 if (desc->part_type == PART_TYPE_ISO) 643 dpsize += sizeof(struct efi_device_path_cdrom_path); 644 else 645 dpsize += sizeof(struct efi_device_path_hard_drive_path); 646 647 return dpsize; 648 } 649 650 /* 651 * Create a device node for a block device partition. 652 * 653 * @buf buffer to which the device path is wirtten 654 * @desc block device descriptor 655 * @part partition number, 0 identifies a block device 656 */ 657 static void *dp_part_node(void *buf, struct blk_desc *desc, int part) 658 { 659 disk_partition_t info; 660 661 part_get_info(desc, part, &info); 662 663 if (desc->part_type == PART_TYPE_ISO) { 664 struct efi_device_path_cdrom_path *cddp = buf; 665 666 cddp->boot_entry = part; 667 cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; 668 cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH; 669 cddp->dp.length = sizeof(*cddp); 670 cddp->partition_start = info.start; 671 cddp->partition_end = info.size; 672 673 buf = &cddp[1]; 674 } else { 675 struct efi_device_path_hard_drive_path *hddp = buf; 676 677 hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; 678 hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH; 679 hddp->dp.length = sizeof(*hddp); 680 hddp->partition_number = part; 681 hddp->partition_start = info.start; 682 hddp->partition_end = info.size; 683 if (desc->part_type == PART_TYPE_EFI) 684 hddp->partmap_type = 2; 685 else 686 hddp->partmap_type = 1; 687 688 switch (desc->sig_type) { 689 case SIG_TYPE_NONE: 690 default: 691 hddp->signature_type = 0; 692 memset(hddp->partition_signature, 0, 693 sizeof(hddp->partition_signature)); 694 break; 695 case SIG_TYPE_MBR: 696 hddp->signature_type = 1; 697 memset(hddp->partition_signature, 0, 698 sizeof(hddp->partition_signature)); 699 memcpy(hddp->partition_signature, &desc->mbr_sig, 700 sizeof(desc->mbr_sig)); 701 break; 702 case SIG_TYPE_GUID: 703 hddp->signature_type = 2; 704 memcpy(hddp->partition_signature, &desc->guid_sig, 705 sizeof(hddp->partition_signature)); 706 break; 707 } 708 709 buf = &hddp[1]; 710 } 711 712 return buf; 713 } 714 715 /* 716 * Create a device path for a block device or one of its partitions. 717 * 718 * @buf buffer to which the device path is wirtten 719 * @desc block device descriptor 720 * @part partition number, 0 identifies a block device 721 */ 722 static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) 723 { 724 #ifdef CONFIG_BLK 725 { 726 struct udevice *dev; 727 int ret = blk_find_device(desc->if_type, desc->devnum, &dev); 728 729 if (ret) 730 dev = desc->bdev->parent; 731 buf = dp_fill(buf, dev); 732 } 733 #else 734 /* 735 * We *could* make a more accurate path, by looking at if_type 736 * and handling all the different cases like we do for non- 737 * legacy (ie CONFIG_BLK=y) case. But most important thing 738 * is just to have a unique device-path for if_type+devnum. 739 * So map things to a fictitious USB device. 740 */ 741 struct efi_device_path_usb *udp; 742 743 memcpy(buf, &ROOT, sizeof(ROOT)); 744 buf += sizeof(ROOT); 745 746 udp = buf; 747 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; 748 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB; 749 udp->dp.length = sizeof(*udp); 750 udp->parent_port_number = desc->if_type; 751 udp->usb_interface = desc->devnum; 752 buf = &udp[1]; 753 #endif 754 755 if (part == 0) /* the actual disk, not a partition */ 756 return buf; 757 758 return dp_part_node(buf, desc, part); 759 } 760 761 /* Construct a device-path from a partition on a blk device: */ 762 struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part) 763 { 764 void *buf, *start; 765 766 start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END)); 767 if (!buf) 768 return NULL; 769 770 buf = dp_part_fill(buf, desc, part); 771 772 *((struct efi_device_path *)buf) = END; 773 774 return start; 775 } 776 777 /* 778 * Create a device node for a block device partition. 779 * 780 * @buf buffer to which the device path is wirtten 781 * @desc block device descriptor 782 * @part partition number, 0 identifies a block device 783 */ 784 struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part) 785 { 786 efi_uintn_t dpsize; 787 void *buf; 788 789 if (desc->part_type == PART_TYPE_ISO) 790 dpsize = sizeof(struct efi_device_path_cdrom_path); 791 else 792 dpsize = sizeof(struct efi_device_path_hard_drive_path); 793 buf = dp_alloc(dpsize); 794 795 dp_part_node(buf, desc, part); 796 797 return buf; 798 } 799 800 /* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */ 801 static void path_to_uefi(u16 *uefi, const char *path) 802 { 803 while (*path) { 804 char c = *(path++); 805 if (c == '/') 806 c = '\\'; 807 *(uefi++) = c; 808 } 809 *uefi = '\0'; 810 } 811 812 /* 813 * If desc is NULL, this creates a path with only the file component, 814 * otherwise it creates a full path with both device and file components 815 */ 816 struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part, 817 const char *path) 818 { 819 struct efi_device_path_file_path *fp; 820 void *buf, *start; 821 unsigned dpsize = 0, fpsize; 822 823 if (desc) 824 dpsize = dp_part_size(desc, part); 825 826 fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1); 827 dpsize += fpsize; 828 829 start = buf = dp_alloc(dpsize + sizeof(END)); 830 if (!buf) 831 return NULL; 832 833 if (desc) 834 buf = dp_part_fill(buf, desc, part); 835 836 /* add file-path: */ 837 fp = buf; 838 fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; 839 fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; 840 fp->dp.length = fpsize; 841 path_to_uefi(fp->str, path); 842 buf += fpsize; 843 844 *((struct efi_device_path *)buf) = END; 845 846 return start; 847 } 848 849 #ifdef CONFIG_NET 850 struct efi_device_path *efi_dp_from_eth(void) 851 { 852 #ifndef CONFIG_DM_ETH 853 struct efi_device_path_mac_addr *ndp; 854 #endif 855 void *buf, *start; 856 unsigned dpsize = 0; 857 858 assert(eth_get_dev()); 859 860 #ifdef CONFIG_DM_ETH 861 dpsize += dp_size(eth_get_dev()); 862 #else 863 dpsize += sizeof(ROOT); 864 dpsize += sizeof(*ndp); 865 #endif 866 867 start = buf = dp_alloc(dpsize + sizeof(END)); 868 if (!buf) 869 return NULL; 870 871 #ifdef CONFIG_DM_ETH 872 buf = dp_fill(buf, eth_get_dev()); 873 #else 874 memcpy(buf, &ROOT, sizeof(ROOT)); 875 buf += sizeof(ROOT); 876 877 ndp = buf; 878 ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; 879 ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR; 880 ndp->dp.length = sizeof(*ndp); 881 ndp->if_type = 1; /* Ethernet */ 882 memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN); 883 buf = &ndp[1]; 884 #endif 885 886 *((struct efi_device_path *)buf) = END; 887 888 return start; 889 } 890 #endif 891 892 /* Construct a device-path for memory-mapped image */ 893 struct efi_device_path *efi_dp_from_mem(uint32_t memory_type, 894 uint64_t start_address, 895 uint64_t end_address) 896 { 897 struct efi_device_path_memory *mdp; 898 void *buf, *start; 899 900 start = buf = dp_alloc(sizeof(*mdp) + sizeof(END)); 901 if (!buf) 902 return NULL; 903 904 mdp = buf; 905 mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; 906 mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY; 907 mdp->dp.length = sizeof(*mdp); 908 mdp->memory_type = memory_type; 909 mdp->start_address = start_address; 910 mdp->end_address = end_address; 911 buf = &mdp[1]; 912 913 *((struct efi_device_path *)buf) = END; 914 915 return start; 916 } 917 918 /* 919 * Helper to split a full device path (containing both device and file 920 * parts) into it's constituent parts. 921 */ 922 efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path, 923 struct efi_device_path **device_path, 924 struct efi_device_path **file_path) 925 { 926 struct efi_device_path *p, *dp, *fp; 927 928 *device_path = NULL; 929 *file_path = NULL; 930 dp = efi_dp_dup(full_path); 931 if (!dp) 932 return EFI_OUT_OF_RESOURCES; 933 p = dp; 934 while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) { 935 p = efi_dp_next(p); 936 if (!p) 937 return EFI_OUT_OF_RESOURCES; 938 } 939 fp = efi_dp_dup(p); 940 if (!fp) 941 return EFI_OUT_OF_RESOURCES; 942 p->type = DEVICE_PATH_TYPE_END; 943 p->sub_type = DEVICE_PATH_SUB_TYPE_END; 944 p->length = sizeof(*p); 945 946 *device_path = dp; 947 *file_path = fp; 948 return EFI_SUCCESS; 949 } 950