"Das U-Boot" Source Tree
at master 819 lines 20 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2001 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 */ 6 7#include <blk.h> 8#include <command.h> 9#include <env.h> 10#include <errno.h> 11#include <ide.h> 12#include <log.h> 13#include <malloc.h> 14#include <part.h> 15#include <ubifs_uboot.h> 16#include <dm/uclass.h> 17 18#undef PART_DEBUG 19 20#ifdef PART_DEBUG 21#define PRINTF(fmt,args...) printf (fmt ,##args) 22#else 23#define PRINTF(fmt,args...) 24#endif 25 26/* Check all partition types */ 27#define PART_TYPE_ALL -1 28 29/** 30 * part_driver_get_type() - Get a driver given its type 31 * 32 * @part_type: Partition type to find the driver for 33 * Return: Driver for that type, or NULL if none 34 */ 35static struct part_driver *part_driver_get_type(int part_type) 36{ 37 struct part_driver *drv = 38 ll_entry_start(struct part_driver, part_driver); 39 const int n_ents = ll_entry_count(struct part_driver, part_driver); 40 struct part_driver *entry; 41 42 for (entry = drv; entry != drv + n_ents; entry++) { 43 if (part_type == entry->part_type) 44 return entry; 45 } 46 47 /* Not found */ 48 return NULL; 49} 50 51/** 52 * part_driver_lookup_type() - Look up the partition driver for a blk device 53 * 54 * If @desc->part_type is PART_TYPE_UNKNOWN, this checks each parition driver 55 * against the blk device to see if there is a valid partition table acceptable 56 * to that driver. 57 * 58 * If @desc->part_type is already set, it just returns the driver for that 59 * type, without testing if the driver can find a valid partition on the 60 * descriptor. 61 * 62 * On success it updates @desc->part_type if set to PART_TYPE_UNKNOWN on entry 63 * 64 * @dev_desc: Device descriptor 65 * Return: Driver found, or NULL if none 66 */ 67static struct part_driver *part_driver_lookup_type(struct blk_desc *desc) 68{ 69 struct part_driver *drv = 70 ll_entry_start(struct part_driver, part_driver); 71 const int n_ents = ll_entry_count(struct part_driver, part_driver); 72 struct part_driver *entry; 73 74 if (desc->part_type == PART_TYPE_UNKNOWN) { 75 for (entry = drv; entry != drv + n_ents; entry++) { 76 int ret; 77 78 ret = entry->test(desc); 79 if (!ret) { 80 desc->part_type = entry->part_type; 81 return entry; 82 } 83 } 84 } else { 85 return part_driver_get_type(desc->part_type); 86 } 87 88 /* Not found */ 89 return NULL; 90} 91 92int part_get_type_by_name(const char *name) 93{ 94 struct part_driver *drv = 95 ll_entry_start(struct part_driver, part_driver); 96 const int n_ents = ll_entry_count(struct part_driver, part_driver); 97 struct part_driver *entry; 98 99 for (entry = drv; entry != drv + n_ents; entry++) { 100 if (!strcasecmp(name, entry->name)) 101 return entry->part_type; 102 } 103 104 /* Not found */ 105 return PART_TYPE_UNKNOWN; 106} 107 108/** 109 * get_dev_hwpart() - Get the descriptor for a device with hardware partitions 110 * 111 * @ifname: Interface name (e.g. "ide", "scsi") 112 * @dev: Device number (0 for first device on that interface, 1 for 113 * second, etc. 114 * @hwpart: Hardware partition, or 0 if none (used for MMC) 115 * Return: pointer to the block device, or NULL if not available, or an 116 * error occurred. 117 */ 118static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 119{ 120 struct blk_desc *desc; 121 int ret; 122 123 if (!blk_enabled()) 124 return NULL; 125 desc = blk_get_devnum_by_uclass_idname(ifname, dev); 126 if (!desc) { 127 debug("%s: No device for iface '%s', dev %d\n", __func__, 128 ifname, dev); 129 return NULL; 130 } 131 ret = blk_dselect_hwpart(desc, hwpart); 132 if (ret) { 133 debug("%s: Failed to select h/w partition: err-%d\n", __func__, 134 ret); 135 return NULL; 136 } 137 138 return desc; 139} 140 141struct blk_desc *blk_get_dev(const char *ifname, int dev) 142{ 143 if (!blk_enabled()) 144 return NULL; 145 146 return get_dev_hwpart(ifname, dev, 0); 147} 148 149/* ------------------------------------------------------------------------- */ 150/* 151 * reports device info to the user 152 */ 153 154#ifdef CONFIG_LBA48 155typedef uint64_t lba512_t; 156#else 157typedef lbaint_t lba512_t; 158#endif 159 160/* 161 * Overflowless variant of (block_count * mul_by / 2**right_shift) 162 * when 2**right_shift > mul_by 163 */ 164static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, 165 int right_shift) 166{ 167 lba512_t bc_quot, bc_rem; 168 169 /* x * m / d == x / d * m + (x % d) * m / d */ 170 bc_quot = block_count >> right_shift; 171 bc_rem = block_count - (bc_quot << right_shift); 172 return bc_quot * mul_by + ((bc_rem * mul_by) >> right_shift); 173} 174 175void dev_print(struct blk_desc *desc) 176{ 177 lba512_t lba512; /* number of blocks if 512bytes block size */ 178 179 if (desc->type == DEV_TYPE_UNKNOWN) { 180 puts ("not available\n"); 181 return; 182 } 183 184 switch (desc->uclass_id) { 185 case UCLASS_SCSI: 186 printf("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n", desc->target, 187 desc->lun, desc->vendor, desc->product, desc->revision); 188 break; 189 case UCLASS_IDE: 190 case UCLASS_AHCI: 191 printf("Model: %s Firm: %s Ser#: %s\n", desc->vendor, 192 desc->revision, desc->product); 193 break; 194 case UCLASS_MMC: 195 case UCLASS_USB: 196 case UCLASS_NVME: 197 case UCLASS_PVBLOCK: 198 case UCLASS_HOST: 199 case UCLASS_BLKMAP: 200 case UCLASS_RKMTD: 201 printf ("Vendor: %s Rev: %s Prod: %s\n", 202 desc->vendor, 203 desc->revision, 204 desc->product); 205 break; 206 case UCLASS_VIRTIO: 207 printf("%s VirtIO Block Device\n", desc->vendor); 208 break; 209 case UCLASS_EFI_MEDIA: 210 printf("EFI media Block Device %d\n", desc->devnum); 211 break; 212 case UCLASS_INVALID: 213 puts("device type unknown\n"); 214 return; 215 default: 216 printf("Unhandled device type: %i\n", desc->uclass_id); 217 return; 218 } 219 puts (" Type: "); 220 if (desc->removable) 221 puts ("Removable "); 222 switch (desc->type & 0x1F) { 223 case DEV_TYPE_HARDDISK: 224 puts ("Hard Disk"); 225 break; 226 case DEV_TYPE_CDROM: 227 puts ("CD ROM"); 228 break; 229 case DEV_TYPE_OPDISK: 230 puts ("Optical Device"); 231 break; 232 case DEV_TYPE_TAPE: 233 puts ("Tape"); 234 break; 235 default: 236 printf("# %02X #", desc->type & 0x1F); 237 break; 238 } 239 puts ("\n"); 240 if (desc->lba > 0L && desc->blksz > 0L) { 241 ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem; 242 lbaint_t lba; 243 244 lba = desc->lba; 245 246 lba512 = lba * (desc->blksz / 512); 247 /* round to 1 digit */ 248 /* 2048 = (1024 * 1024) / 512 MB */ 249 mb = lba512_muldiv(lba512, 10, 11); 250 251 mb_quot = mb / 10; 252 mb_rem = mb - (10 * mb_quot); 253 254 gb = mb / 1024; 255 gb_quot = gb / 10; 256 gb_rem = gb - (10 * gb_quot); 257#ifdef CONFIG_LBA48 258 if (desc->lba48) 259 printf (" Supports 48-bit addressing\n"); 260#endif 261#if defined(CONFIG_SYS_64BIT_LBA) 262 printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n", 263 mb_quot, mb_rem, 264 gb_quot, gb_rem, 265 lba, 266 desc->blksz); 267#else 268 printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n", 269 mb_quot, mb_rem, 270 gb_quot, gb_rem, 271 (ulong)lba, 272 desc->blksz); 273#endif 274 } else { 275 puts (" Capacity: not available\n"); 276 } 277} 278 279void part_init(struct blk_desc *desc) 280{ 281 struct part_driver *drv = 282 ll_entry_start(struct part_driver, part_driver); 283 const int n_ents = ll_entry_count(struct part_driver, part_driver); 284 struct part_driver *entry; 285 286 blkcache_invalidate(desc->uclass_id, desc->devnum); 287 288 if (desc->part_type != PART_TYPE_UNKNOWN) { 289 for (entry = drv; entry != drv + n_ents; entry++) { 290 if (entry->part_type == desc->part_type && !entry->test(desc)) 291 return; 292 } 293 } 294 295 desc->part_type = PART_TYPE_UNKNOWN; 296 for (entry = drv; entry != drv + n_ents; entry++) { 297 int ret; 298 299 ret = entry->test(desc); 300 debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret); 301 if (!ret) { 302 desc->part_type = entry->part_type; 303 break; 304 } 305 } 306} 307 308static void print_part_header(const char *type, struct blk_desc *desc) 309{ 310#if CONFIG_IS_ENABLED(MAC_PARTITION) || \ 311 CONFIG_IS_ENABLED(DOS_PARTITION) || \ 312 CONFIG_IS_ENABLED(ISO_PARTITION) || \ 313 CONFIG_IS_ENABLED(AMIGA_PARTITION) || \ 314 CONFIG_IS_ENABLED(EFI_PARTITION) || \ 315 CONFIG_IS_ENABLED(MTD_PARTITIONS) 316 printf("\nPartition Map for %s device %d -- Partition Type: %s\n\n", 317 uclass_get_name(desc->uclass_id), desc->devnum, type); 318#endif /* any CONFIG_..._PARTITION */ 319} 320 321void part_print(struct blk_desc *desc) 322{ 323 struct part_driver *drv; 324 325 drv = part_driver_lookup_type(desc); 326 if (!drv) { 327 printf("## Unknown partition table type %x\n", 328 desc->part_type); 329 return; 330 } 331 332 PRINTF("## Testing for valid %s partition ##\n", drv->name); 333 print_part_header(drv->name, desc); 334 if (drv->print) 335 drv->print(desc); 336} 337 338int part_get_info_by_type(struct blk_desc *desc, int part, int part_type, 339 struct disk_partition *info) 340{ 341 struct part_driver *drv; 342 343 if (blk_enabled()) { 344 /* The common case is no UUID support */ 345 disk_partition_clr_uuid(info); 346 disk_partition_clr_type_guid(info); 347 348 if (part_type == PART_TYPE_UNKNOWN) { 349 drv = part_driver_lookup_type(desc); 350 } else { 351 drv = part_driver_get_type(part_type); 352 } 353 354 if (!drv) { 355 debug("## Unknown partition table type %x\n", 356 desc->part_type); 357 return -EPROTONOSUPPORT; 358 } 359 if (!drv->get_info) { 360 PRINTF("## Driver %s does not have the get_info() method\n", 361 drv->name); 362 return -ENOSYS; 363 } 364 if (drv->get_info(desc, part, info) == 0) { 365 PRINTF("## Valid %s partition found ##\n", drv->name); 366 return 0; 367 } 368 } 369 370 return -ENOENT; 371} 372 373int part_get_info(struct blk_desc *desc, int part, 374 struct disk_partition *info) 375{ 376 return part_get_info_by_type(desc, part, PART_TYPE_UNKNOWN, info); 377} 378 379int part_get_info_whole_disk(struct blk_desc *desc, 380 struct disk_partition *info) 381{ 382 info->start = 0; 383 info->size = desc->lba; 384 info->blksz = desc->blksz; 385 info->bootable = 0; 386 strcpy((char *)info->type, BOOT_PART_TYPE); 387 strcpy((char *)info->name, "Whole Disk"); 388 disk_partition_clr_uuid(info); 389 disk_partition_clr_type_guid(info); 390 391 return 0; 392} 393 394int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, 395 struct blk_desc **desc) 396{ 397 char *ep; 398 char *dup_str = NULL; 399 const char *dev_str, *hwpart_str; 400 int dev, hwpart; 401 402 hwpart_str = strchr(dev_hwpart_str, '.'); 403 if (hwpart_str) { 404 dup_str = strdup(dev_hwpart_str); 405 dup_str[hwpart_str - dev_hwpart_str] = 0; 406 dev_str = dup_str; 407 hwpart_str++; 408 } else { 409 dev_str = dev_hwpart_str; 410 hwpart = 0; 411 } 412 413 dev = hextoul(dev_str, &ep); 414 if (*ep) { 415 printf("** Bad device specification %s %s **\n", 416 ifname, dev_str); 417 dev = -EINVAL; 418 goto cleanup; 419 } 420 421 if (hwpart_str) { 422 hwpart = hextoul(hwpart_str, &ep); 423 if (*ep) { 424 printf("** Bad HW partition specification %s %s **\n", 425 ifname, hwpart_str); 426 dev = -EINVAL; 427 goto cleanup; 428 } 429 } 430 431 *desc = get_dev_hwpart(ifname, dev, hwpart); 432 if (!(*desc) || ((*desc)->type == DEV_TYPE_UNKNOWN)) { 433 debug("** Bad device %s %s **\n", ifname, dev_hwpart_str); 434 dev = -ENODEV; 435 goto cleanup; 436 } 437 438 if (blk_enabled()) { 439 /* 440 * Updates the partition table for the specified hw partition. 441 * Always should be done, otherwise hw partition 0 will return 442 * stale data after displaying a non-zero hw partition. 443 */ 444 if ((*desc)->uclass_id == UCLASS_MMC) 445 part_init(*desc); 446 } 447 448cleanup: 449 free(dup_str); 450 return dev; 451} 452 453#define PART_UNSPECIFIED -2 454#define PART_AUTO -1 455int blk_get_device_part_str(const char *ifname, const char *dev_part_str, 456 struct blk_desc **desc, 457 struct disk_partition *info, int allow_whole_dev) 458{ 459 int ret; 460 const char *part_str; 461 char *dup_str = NULL; 462 const char *dev_str; 463 int dev; 464 char *ep; 465 int p; 466 int part; 467 struct disk_partition tmpinfo; 468 469 *desc = NULL; 470 memset(info, 0, sizeof(*info)); 471 472#if IS_ENABLED(CONFIG_SANDBOX) || IS_ENABLED(CONFIG_SEMIHOSTING) 473 /* 474 * Special-case a pseudo block device "hostfs", to allow access to the 475 * host's own filesystem. 476 */ 477 if (!strcmp(ifname, "hostfs")) { 478 strcpy((char *)info->type, BOOT_PART_TYPE); 479 strcpy((char *)info->name, "Host filesystem"); 480 481 return 0; 482 } 483#endif 484 485#if IS_ENABLED(CONFIG_CMD_UBIFS) && !IS_ENABLED(CONFIG_XPL_BUILD) 486 /* 487 * Special-case ubi, ubi goes through a mtd, rather than through 488 * a regular block device. 489 */ 490 if (!strcmp(ifname, "ubi")) { 491 if (!ubifs_is_mounted()) { 492 printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 493 return -EINVAL; 494 } 495 496 strcpy((char *)info->type, BOOT_PART_TYPE); 497 strcpy((char *)info->name, "UBI"); 498 return 0; 499 } 500#endif 501 502 /* If no dev_part_str, use bootdevice environment variable */ 503 if (CONFIG_IS_ENABLED(ENV_SUPPORT)) { 504 if (!dev_part_str || !strlen(dev_part_str) || 505 !strcmp(dev_part_str, "-")) 506 dev_part_str = env_get("bootdevice"); 507 } 508 509 /* If still no dev_part_str, it's an error */ 510 if (!dev_part_str) { 511 printf("** No device specified **\n"); 512 ret = -ENODEV; 513 goto cleanup; 514 } 515 516 /* Separate device and partition ID specification */ 517 part_str = strchr(dev_part_str, ':'); 518 if (part_str) { 519 dup_str = strdup(dev_part_str); 520 dup_str[part_str - dev_part_str] = 0; 521 dev_str = dup_str; 522 part_str++; 523 } else { 524 dev_str = dev_part_str; 525 } 526 527 /* Look up the device */ 528 dev = blk_get_device_by_str(ifname, dev_str, desc); 529 if (dev < 0) { 530 printf("** Bad device specification %s %s **\n", 531 ifname, dev_str); 532 ret = dev; 533 goto cleanup; 534 } 535 536 /* Convert partition ID string to number */ 537 if (!part_str || !*part_str) { 538 part = PART_UNSPECIFIED; 539 } else if (!strcmp(part_str, "auto")) { 540 part = PART_AUTO; 541 } else { 542 /* Something specified -> use exactly that */ 543 part = (int)hextoul(part_str, &ep); 544 /* 545 * Less than whole string converted, 546 * or request for whole device, but caller requires partition. 547 */ 548 if (*ep || (part == 0 && !allow_whole_dev)) { 549 printf("** Bad partition specification %s %s **\n", 550 ifname, dev_part_str); 551 ret = -ENOENT; 552 goto cleanup; 553 } 554 } 555 556 /* 557 * No partition table on device, 558 * or user requested partition 0 (entire device). 559 */ 560 if (((*desc)->part_type == PART_TYPE_UNKNOWN) || !part) { 561 if (!(*desc)->lba) { 562 printf("** Bad device size - %s %s **\n", ifname, 563 dev_str); 564 ret = -EINVAL; 565 goto cleanup; 566 } 567 568 /* 569 * If user specified a partition ID other than 0, 570 * or the calling command only accepts partitions, 571 * it's an error. 572 */ 573 if ((part > 0) || (!allow_whole_dev)) { 574 printf("** No partition table - %s %s **\n", ifname, 575 dev_str); 576 ret = -EPROTONOSUPPORT; 577 goto cleanup; 578 } 579 580 (*desc)->log2blksz = LOG2((*desc)->blksz); 581 582 part_get_info_whole_disk(*desc, info); 583 584 ret = 0; 585 goto cleanup; 586 } 587 588 /* 589 * Now there's known to be a partition table, 590 * not specifying a partition means to pick partition 1. 591 */ 592 if (part == PART_UNSPECIFIED) 593 part = 1; 594 595 /* 596 * If user didn't specify a partition number, or did specify something 597 * other than "auto", use that partition number directly. 598 */ 599 if (part != PART_AUTO) { 600 ret = part_get_info(*desc, part, info); 601 if (ret) { 602 printf("** Invalid partition %d **\n", part); 603 goto cleanup; 604 } 605 } else { 606 /* 607 * Find the first bootable partition. 608 * If none are bootable, fall back to the first valid partition. 609 */ 610 part = 0; 611 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 612 ret = part_get_info(*desc, p, info); 613 if (ret) 614 continue; 615 616 /* 617 * First valid partition, or new better partition? 618 * If so, save partition ID. 619 */ 620 if (!part || info->bootable) 621 part = p; 622 623 /* Best possible partition? Stop searching. */ 624 if (info->bootable) 625 break; 626 627 /* 628 * We now need to search further for best possible. 629 * If we what we just queried was the best so far, 630 * save the info since we over-write it next loop. 631 */ 632 if (part == p) 633 tmpinfo = *info; 634 } 635 /* If we found any acceptable partition */ 636 if (part) { 637 /* 638 * If we searched all possible partition IDs, 639 * return the first valid partition we found. 640 */ 641 if (p == MAX_SEARCH_PARTITIONS + 1) 642 *info = tmpinfo; 643 } else { 644 printf("** No valid partitions found **\n"); 645 goto cleanup; 646 } 647 } 648 if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 649 printf("** Invalid partition type \"%.32s\"" 650 " (expect \"" BOOT_PART_TYPE "\")\n", 651 info->type); 652 ret = -EINVAL; 653 goto cleanup; 654 } 655 656 (*desc)->log2blksz = LOG2((*desc)->blksz); 657 658 ret = part; 659 goto cleanup; 660 661cleanup: 662 free(dup_str); 663 return ret; 664} 665 666int part_get_info_by_name(struct blk_desc *desc, const char *name, 667 struct disk_partition *info) 668{ 669 struct part_driver *part_drv; 670 int ret; 671 int i; 672 673 part_drv = part_driver_lookup_type(desc); 674 if (!part_drv) 675 return -1; 676 677 if (!part_drv->get_info) { 678 log_debug("## Driver %s does not have the get_info() method\n", 679 part_drv->name); 680 return -ENOSYS; 681 } 682 683 for (i = 1; i < part_drv->max_entries; i++) { 684 ret = part_drv->get_info(desc, i, info); 685 if (ret != 0) { 686 /* 687 * Partition with this index can't be obtained, but 688 * further partitions might be, so keep checking. 689 */ 690 continue; 691 } 692 if (strcmp(name, (const char *)info->name) == 0) { 693 /* matched */ 694 return i; 695 } 696 } 697 698 return -ENOENT; 699} 700 701/** 702 * Get partition info from device number and partition name. 703 * 704 * Parse a device number and partition name string in the form of 705 * "devicenum.hwpartnum#partition_name", for example "0.1#misc". devicenum and 706 * hwpartnum are both optional, defaulting to 0. If the partition is found, 707 * sets desc and part_info accordingly with the information of the 708 * partition with the given partition_name. 709 * 710 * @param[in] dev_iface Device interface 711 * @param[in] dev_part_str Input string argument, like "0.1#misc" 712 * @param[out] desc Place to store the device description pointer 713 * @param[out] part_info Place to store the partition information 714 * Return: 0 on success, or a negative on error 715 */ 716static int part_get_info_by_dev_and_name(const char *dev_iface, 717 const char *dev_part_str, 718 struct blk_desc **desc, 719 struct disk_partition *part_info) 720{ 721 char *dup_str = NULL; 722 const char *dev_str, *part_str; 723 int ret; 724 725 /* Separate device and partition name specification */ 726 if (dev_part_str) 727 part_str = strchr(dev_part_str, '#'); 728 else 729 part_str = NULL; 730 731 if (part_str) { 732 dup_str = strdup(dev_part_str); 733 dup_str[part_str - dev_part_str] = 0; 734 dev_str = dup_str; 735 part_str++; 736 } else { 737 return -EINVAL; 738 } 739 740 ret = blk_get_device_by_str(dev_iface, dev_str, desc); 741 if (ret < 0) 742 goto cleanup; 743 744 ret = part_get_info_by_name(*desc, part_str, part_info); 745 if (ret < 0) 746 printf("Could not find \"%s\" partition\n", part_str); 747 748cleanup: 749 free(dup_str); 750 return ret; 751} 752 753int part_get_info_by_dev_and_name_or_num(const char *dev_iface, 754 const char *dev_part_str, 755 struct blk_desc **desc, 756 struct disk_partition *part_info, 757 int allow_whole_dev) 758{ 759 int ret; 760 761 /* Split the part_name if passed as "$dev_num#part_name". */ 762 ret = part_get_info_by_dev_and_name(dev_iface, dev_part_str, desc, 763 part_info); 764 if (ret >= 0) 765 return ret; 766 /* 767 * Couldn't lookup by name, try looking up the partition description 768 * directly. 769 */ 770 ret = blk_get_device_part_str(dev_iface, dev_part_str, desc, part_info, 771 allow_whole_dev); 772 if (ret < 0) 773 printf("Couldn't find partition %s %s\n", 774 dev_iface, dev_part_str); 775 return ret; 776} 777 778void part_set_generic_name(const struct blk_desc *desc, int part_num, 779 char *name) 780{ 781 char *devtype; 782 783 switch (desc->uclass_id) { 784 case UCLASS_IDE: 785 case UCLASS_AHCI: 786 devtype = "hd"; 787 break; 788 case UCLASS_SCSI: 789 devtype = "sd"; 790 break; 791 case UCLASS_USB: 792 devtype = "usbd"; 793 break; 794 case UCLASS_MMC: 795 devtype = "mmcsd"; 796 break; 797 default: 798 devtype = "xx"; 799 break; 800 } 801 802 sprintf(name, "%s%c%d", devtype, 'a' + desc->devnum, part_num); 803} 804 805int part_get_bootable(struct blk_desc *desc) 806{ 807 struct disk_partition info; 808 int p; 809 810 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 811 int ret; 812 813 ret = part_get_info(desc, p, &info); 814 if (!ret && info.bootable) 815 return p; 816 } 817 818 return 0; 819}