1 /* 2 * (C) Copyright 2001 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <command.h> 10 #include <ide.h> 11 #include <malloc.h> 12 #include <part.h> 13 #include <ubifs_uboot.h> 14 15 #undef PART_DEBUG 16 17 #ifdef PART_DEBUG 18 #define PRINTF(fmt,args...) printf (fmt ,##args) 19 #else 20 #define PRINTF(fmt,args...) 21 #endif 22 23 struct block_drvr { 24 char *name; 25 block_dev_desc_t* (*get_dev)(int dev); 26 int (*select_hwpart)(int dev_num, int hwpart); 27 }; 28 29 static const struct block_drvr block_drvr[] = { 30 #if defined(CONFIG_CMD_IDE) 31 { .name = "ide", .get_dev = ide_get_dev, }, 32 #endif 33 #if defined(CONFIG_CMD_SATA) 34 {.name = "sata", .get_dev = sata_get_dev, }, 35 #endif 36 #if defined(CONFIG_CMD_SCSI) 37 { .name = "scsi", .get_dev = scsi_get_dev, }, 38 #endif 39 #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) 40 { .name = "usb", .get_dev = usb_stor_get_dev, }, 41 #endif 42 #if defined(CONFIG_MMC) 43 { 44 .name = "mmc", 45 .get_dev = mmc_get_dev, 46 .select_hwpart = mmc_select_hwpart, 47 }, 48 #endif 49 #if defined(CONFIG_SYSTEMACE) 50 { .name = "ace", .get_dev = systemace_get_dev, }, 51 #endif 52 #if defined(CONFIG_SANDBOX) 53 { .name = "host", .get_dev = host_get_dev, }, 54 #endif 55 { }, 56 }; 57 58 DECLARE_GLOBAL_DATA_PTR; 59 60 #ifdef HAVE_BLOCK_DEVICE 61 static block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart) 62 { 63 const struct block_drvr *drvr = block_drvr; 64 block_dev_desc_t* (*reloc_get_dev)(int dev); 65 int (*select_hwpart)(int dev_num, int hwpart); 66 char *name; 67 int ret; 68 69 if (!ifname) 70 return NULL; 71 72 name = drvr->name; 73 #ifdef CONFIG_NEEDS_MANUAL_RELOC 74 name += gd->reloc_off; 75 #endif 76 while (drvr->name) { 77 name = drvr->name; 78 reloc_get_dev = drvr->get_dev; 79 select_hwpart = drvr->select_hwpart; 80 #ifdef CONFIG_NEEDS_MANUAL_RELOC 81 name += gd->reloc_off; 82 reloc_get_dev += gd->reloc_off; 83 if (select_hwpart) 84 select_hwpart += gd->reloc_off; 85 #endif 86 if (strncmp(ifname, name, strlen(name)) == 0) { 87 block_dev_desc_t *dev_desc = reloc_get_dev(dev); 88 if (!dev_desc) 89 return NULL; 90 if (hwpart == 0 && !select_hwpart) 91 return dev_desc; 92 if (!select_hwpart) 93 return NULL; 94 ret = select_hwpart(dev_desc->dev, hwpart); 95 if (ret < 0) 96 return NULL; 97 return dev_desc; 98 } 99 drvr++; 100 } 101 return NULL; 102 } 103 104 block_dev_desc_t *get_dev(const char *ifname, int dev) 105 { 106 return get_dev_hwpart(ifname, dev, 0); 107 } 108 #else 109 block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart) 110 { 111 return NULL; 112 } 113 114 block_dev_desc_t *get_dev(const char *ifname, int dev) 115 { 116 return NULL; 117 } 118 #endif 119 120 #ifdef HAVE_BLOCK_DEVICE 121 122 /* ------------------------------------------------------------------------- */ 123 /* 124 * reports device info to the user 125 */ 126 127 #ifdef CONFIG_LBA48 128 typedef uint64_t lba512_t; 129 #else 130 typedef lbaint_t lba512_t; 131 #endif 132 133 /* 134 * Overflowless variant of (block_count * mul_by / div_by) 135 * when div_by > mul_by 136 */ 137 static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by) 138 { 139 lba512_t bc_quot, bc_rem; 140 141 /* x * m / d == x / d * m + (x % d) * m / d */ 142 bc_quot = block_count / div_by; 143 bc_rem = block_count - div_by * bc_quot; 144 return bc_quot * mul_by + (bc_rem * mul_by) / div_by; 145 } 146 147 void dev_print (block_dev_desc_t *dev_desc) 148 { 149 lba512_t lba512; /* number of blocks if 512bytes block size */ 150 151 if (dev_desc->type == DEV_TYPE_UNKNOWN) { 152 puts ("not available\n"); 153 return; 154 } 155 156 switch (dev_desc->if_type) { 157 case IF_TYPE_SCSI: 158 printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n", 159 dev_desc->target,dev_desc->lun, 160 dev_desc->vendor, 161 dev_desc->product, 162 dev_desc->revision); 163 break; 164 case IF_TYPE_ATAPI: 165 case IF_TYPE_IDE: 166 case IF_TYPE_SATA: 167 printf ("Model: %s Firm: %s Ser#: %s\n", 168 dev_desc->vendor, 169 dev_desc->revision, 170 dev_desc->product); 171 break; 172 case IF_TYPE_SD: 173 case IF_TYPE_MMC: 174 case IF_TYPE_USB: 175 printf ("Vendor: %s Rev: %s Prod: %s\n", 176 dev_desc->vendor, 177 dev_desc->revision, 178 dev_desc->product); 179 break; 180 case IF_TYPE_DOC: 181 puts("device type DOC\n"); 182 return; 183 case IF_TYPE_UNKNOWN: 184 puts("device type unknown\n"); 185 return; 186 default: 187 printf("Unhandled device type: %i\n", dev_desc->if_type); 188 return; 189 } 190 puts (" Type: "); 191 if (dev_desc->removable) 192 puts ("Removable "); 193 switch (dev_desc->type & 0x1F) { 194 case DEV_TYPE_HARDDISK: 195 puts ("Hard Disk"); 196 break; 197 case DEV_TYPE_CDROM: 198 puts ("CD ROM"); 199 break; 200 case DEV_TYPE_OPDISK: 201 puts ("Optical Device"); 202 break; 203 case DEV_TYPE_TAPE: 204 puts ("Tape"); 205 break; 206 default: 207 printf ("# %02X #", dev_desc->type & 0x1F); 208 break; 209 } 210 puts ("\n"); 211 if (dev_desc->lba > 0L && dev_desc->blksz > 0L) { 212 ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem; 213 lbaint_t lba; 214 215 lba = dev_desc->lba; 216 217 lba512 = (lba * (dev_desc->blksz/512)); 218 /* round to 1 digit */ 219 /* 2048 = (1024 * 1024) / 512 MB */ 220 mb = lba512_muldiv(lba512, 10, 2048); 221 222 mb_quot = mb / 10; 223 mb_rem = mb - (10 * mb_quot); 224 225 gb = mb / 1024; 226 gb_quot = gb / 10; 227 gb_rem = gb - (10 * gb_quot); 228 #ifdef CONFIG_LBA48 229 if (dev_desc->lba48) 230 printf (" Supports 48-bit addressing\n"); 231 #endif 232 #if defined(CONFIG_SYS_64BIT_LBA) 233 printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n", 234 mb_quot, mb_rem, 235 gb_quot, gb_rem, 236 lba, 237 dev_desc->blksz); 238 #else 239 printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n", 240 mb_quot, mb_rem, 241 gb_quot, gb_rem, 242 (ulong)lba, 243 dev_desc->blksz); 244 #endif 245 } else { 246 puts (" Capacity: not available\n"); 247 } 248 } 249 #endif 250 251 #ifdef HAVE_BLOCK_DEVICE 252 253 void init_part(block_dev_desc_t *dev_desc) 254 { 255 #ifdef CONFIG_ISO_PARTITION 256 if (test_part_iso(dev_desc) == 0) { 257 dev_desc->part_type = PART_TYPE_ISO; 258 return; 259 } 260 #endif 261 262 #ifdef CONFIG_MAC_PARTITION 263 if (test_part_mac(dev_desc) == 0) { 264 dev_desc->part_type = PART_TYPE_MAC; 265 return; 266 } 267 #endif 268 269 /* must be placed before DOS partition detection */ 270 #ifdef CONFIG_EFI_PARTITION 271 if (test_part_efi(dev_desc) == 0) { 272 dev_desc->part_type = PART_TYPE_EFI; 273 return; 274 } 275 #endif 276 277 #ifdef CONFIG_DOS_PARTITION 278 if (test_part_dos(dev_desc) == 0) { 279 dev_desc->part_type = PART_TYPE_DOS; 280 return; 281 } 282 #endif 283 284 #ifdef CONFIG_AMIGA_PARTITION 285 if (test_part_amiga(dev_desc) == 0) { 286 dev_desc->part_type = PART_TYPE_AMIGA; 287 return; 288 } 289 #endif 290 dev_desc->part_type = PART_TYPE_UNKNOWN; 291 } 292 293 294 #if defined(CONFIG_MAC_PARTITION) || \ 295 defined(CONFIG_DOS_PARTITION) || \ 296 defined(CONFIG_ISO_PARTITION) || \ 297 defined(CONFIG_AMIGA_PARTITION) || \ 298 defined(CONFIG_EFI_PARTITION) 299 300 static void print_part_header(const char *type, block_dev_desc_t *dev_desc) 301 { 302 puts ("\nPartition Map for "); 303 switch (dev_desc->if_type) { 304 case IF_TYPE_IDE: 305 puts ("IDE"); 306 break; 307 case IF_TYPE_SATA: 308 puts ("SATA"); 309 break; 310 case IF_TYPE_SCSI: 311 puts ("SCSI"); 312 break; 313 case IF_TYPE_ATAPI: 314 puts ("ATAPI"); 315 break; 316 case IF_TYPE_USB: 317 puts ("USB"); 318 break; 319 case IF_TYPE_DOC: 320 puts ("DOC"); 321 break; 322 case IF_TYPE_MMC: 323 puts ("MMC"); 324 break; 325 case IF_TYPE_HOST: 326 puts("HOST"); 327 break; 328 default: 329 puts ("UNKNOWN"); 330 break; 331 } 332 printf (" device %d -- Partition Type: %s\n\n", 333 dev_desc->dev, type); 334 } 335 336 #endif /* any CONFIG_..._PARTITION */ 337 338 void print_part(block_dev_desc_t * dev_desc) 339 { 340 341 switch (dev_desc->part_type) { 342 #ifdef CONFIG_MAC_PARTITION 343 case PART_TYPE_MAC: 344 PRINTF ("## Testing for valid MAC partition ##\n"); 345 print_part_header ("MAC", dev_desc); 346 print_part_mac (dev_desc); 347 return; 348 #endif 349 #ifdef CONFIG_DOS_PARTITION 350 case PART_TYPE_DOS: 351 PRINTF ("## Testing for valid DOS partition ##\n"); 352 print_part_header ("DOS", dev_desc); 353 print_part_dos (dev_desc); 354 return; 355 #endif 356 357 #ifdef CONFIG_ISO_PARTITION 358 case PART_TYPE_ISO: 359 PRINTF ("## Testing for valid ISO Boot partition ##\n"); 360 print_part_header ("ISO", dev_desc); 361 print_part_iso (dev_desc); 362 return; 363 #endif 364 365 #ifdef CONFIG_AMIGA_PARTITION 366 case PART_TYPE_AMIGA: 367 PRINTF ("## Testing for a valid Amiga partition ##\n"); 368 print_part_header ("AMIGA", dev_desc); 369 print_part_amiga (dev_desc); 370 return; 371 #endif 372 373 #ifdef CONFIG_EFI_PARTITION 374 case PART_TYPE_EFI: 375 PRINTF ("## Testing for valid EFI partition ##\n"); 376 print_part_header ("EFI", dev_desc); 377 print_part_efi (dev_desc); 378 return; 379 #endif 380 } 381 puts ("## Unknown partition table\n"); 382 } 383 384 #endif /* HAVE_BLOCK_DEVICE */ 385 386 int get_partition_info(block_dev_desc_t *dev_desc, int part, 387 disk_partition_t *info) 388 { 389 #ifdef HAVE_BLOCK_DEVICE 390 391 #ifdef CONFIG_PARTITION_UUIDS 392 /* The common case is no UUID support */ 393 info->uuid[0] = 0; 394 #endif 395 396 switch (dev_desc->part_type) { 397 #ifdef CONFIG_MAC_PARTITION 398 case PART_TYPE_MAC: 399 if (get_partition_info_mac(dev_desc, part, info) == 0) { 400 PRINTF("## Valid MAC partition found ##\n"); 401 return 0; 402 } 403 break; 404 #endif 405 406 #ifdef CONFIG_DOS_PARTITION 407 case PART_TYPE_DOS: 408 if (get_partition_info_dos(dev_desc, part, info) == 0) { 409 PRINTF("## Valid DOS partition found ##\n"); 410 return 0; 411 } 412 break; 413 #endif 414 415 #ifdef CONFIG_ISO_PARTITION 416 case PART_TYPE_ISO: 417 if (get_partition_info_iso(dev_desc, part, info) == 0) { 418 PRINTF("## Valid ISO boot partition found ##\n"); 419 return 0; 420 } 421 break; 422 #endif 423 424 #ifdef CONFIG_AMIGA_PARTITION 425 case PART_TYPE_AMIGA: 426 if (get_partition_info_amiga(dev_desc, part, info) == 0) { 427 PRINTF("## Valid Amiga partition found ##\n"); 428 return 0; 429 } 430 break; 431 #endif 432 433 #ifdef CONFIG_EFI_PARTITION 434 case PART_TYPE_EFI: 435 if (get_partition_info_efi(dev_desc, part, info) == 0) { 436 PRINTF("## Valid EFI partition found ##\n"); 437 return 0; 438 } 439 break; 440 #endif 441 default: 442 break; 443 } 444 #endif /* HAVE_BLOCK_DEVICE */ 445 446 return -1; 447 } 448 449 int get_device(const char *ifname, const char *dev_hwpart_str, 450 block_dev_desc_t **dev_desc) 451 { 452 char *ep; 453 char *dup_str = NULL; 454 const char *dev_str, *hwpart_str; 455 int dev, hwpart; 456 457 hwpart_str = strchr(dev_hwpart_str, '.'); 458 if (hwpart_str) { 459 dup_str = strdup(dev_hwpart_str); 460 dup_str[hwpart_str - dev_hwpart_str] = 0; 461 dev_str = dup_str; 462 hwpart_str++; 463 } else { 464 dev_str = dev_hwpart_str; 465 hwpart = 0; 466 } 467 468 dev = simple_strtoul(dev_str, &ep, 16); 469 if (*ep) { 470 printf("** Bad device specification %s %s **\n", 471 ifname, dev_str); 472 dev = -1; 473 goto cleanup; 474 } 475 476 if (hwpart_str) { 477 hwpart = simple_strtoul(hwpart_str, &ep, 16); 478 if (*ep) { 479 printf("** Bad HW partition specification %s %s **\n", 480 ifname, hwpart_str); 481 dev = -1; 482 goto cleanup; 483 } 484 } 485 486 *dev_desc = get_dev_hwpart(ifname, dev, hwpart); 487 if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { 488 printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); 489 dev = -1; 490 goto cleanup; 491 } 492 493 cleanup: 494 free(dup_str); 495 return dev; 496 } 497 498 #define PART_UNSPECIFIED -2 499 #define PART_AUTO -1 500 #define MAX_SEARCH_PARTITIONS 16 501 int get_device_and_partition(const char *ifname, const char *dev_part_str, 502 block_dev_desc_t **dev_desc, 503 disk_partition_t *info, int allow_whole_dev) 504 { 505 int ret = -1; 506 const char *part_str; 507 char *dup_str = NULL; 508 const char *dev_str; 509 int dev; 510 char *ep; 511 int p; 512 int part; 513 disk_partition_t tmpinfo; 514 515 #if defined CONFIG_SANDBOX && defined CONFIG_CMD_UBIFS 516 #error Only one of CONFIG_SANDBOX and CONFIG_CMD_UBIFS may be selected 517 #endif 518 519 #ifdef CONFIG_SANDBOX 520 /* 521 * Special-case a pseudo block device "hostfs", to allow access to the 522 * host's own filesystem. 523 */ 524 if (0 == strcmp(ifname, "hostfs")) { 525 *dev_desc = NULL; 526 info->start = 0; 527 info->size = 0; 528 info->blksz = 0; 529 info->bootable = 0; 530 strcpy((char *)info->type, BOOT_PART_TYPE); 531 strcpy((char *)info->name, "Sandbox host"); 532 #ifdef CONFIG_PARTITION_UUIDS 533 info->uuid[0] = 0; 534 #endif 535 536 return 0; 537 } 538 #endif 539 540 #ifdef CONFIG_CMD_UBIFS 541 /* 542 * Special-case ubi, ubi goes through a mtd, rathen then through 543 * a regular block device. 544 */ 545 if (0 == strcmp(ifname, "ubi")) { 546 if (!ubifs_is_mounted()) { 547 printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 548 return -1; 549 } 550 551 *dev_desc = NULL; 552 memset(info, 0, sizeof(*info)); 553 strcpy((char *)info->type, BOOT_PART_TYPE); 554 strcpy((char *)info->name, "UBI"); 555 #ifdef CONFIG_PARTITION_UUIDS 556 info->uuid[0] = 0; 557 #endif 558 return 0; 559 } 560 #endif 561 562 /* If no dev_part_str, use bootdevice environment variable */ 563 if (!dev_part_str || !strlen(dev_part_str) || 564 !strcmp(dev_part_str, "-")) 565 dev_part_str = getenv("bootdevice"); 566 567 /* If still no dev_part_str, it's an error */ 568 if (!dev_part_str) { 569 printf("** No device specified **\n"); 570 goto cleanup; 571 } 572 573 /* Separate device and partition ID specification */ 574 part_str = strchr(dev_part_str, ':'); 575 if (part_str) { 576 dup_str = strdup(dev_part_str); 577 dup_str[part_str - dev_part_str] = 0; 578 dev_str = dup_str; 579 part_str++; 580 } else { 581 dev_str = dev_part_str; 582 } 583 584 /* Look up the device */ 585 dev = get_device(ifname, dev_str, dev_desc); 586 if (dev < 0) 587 goto cleanup; 588 589 /* Convert partition ID string to number */ 590 if (!part_str || !*part_str) { 591 part = PART_UNSPECIFIED; 592 } else if (!strcmp(part_str, "auto")) { 593 part = PART_AUTO; 594 } else { 595 /* Something specified -> use exactly that */ 596 part = (int)simple_strtoul(part_str, &ep, 16); 597 /* 598 * Less than whole string converted, 599 * or request for whole device, but caller requires partition. 600 */ 601 if (*ep || (part == 0 && !allow_whole_dev)) { 602 printf("** Bad partition specification %s %s **\n", 603 ifname, dev_part_str); 604 goto cleanup; 605 } 606 } 607 608 /* 609 * No partition table on device, 610 * or user requested partition 0 (entire device). 611 */ 612 if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 613 (part == 0)) { 614 if (!(*dev_desc)->lba) { 615 printf("** Bad device size - %s %s **\n", ifname, 616 dev_str); 617 goto cleanup; 618 } 619 620 /* 621 * If user specified a partition ID other than 0, 622 * or the calling command only accepts partitions, 623 * it's an error. 624 */ 625 if ((part > 0) || (!allow_whole_dev)) { 626 printf("** No partition table - %s %s **\n", ifname, 627 dev_str); 628 goto cleanup; 629 } 630 631 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 632 633 info->start = 0; 634 info->size = (*dev_desc)->lba; 635 info->blksz = (*dev_desc)->blksz; 636 info->bootable = 0; 637 strcpy((char *)info->type, BOOT_PART_TYPE); 638 strcpy((char *)info->name, "Whole Disk"); 639 #ifdef CONFIG_PARTITION_UUIDS 640 info->uuid[0] = 0; 641 #endif 642 643 ret = 0; 644 goto cleanup; 645 } 646 647 /* 648 * Now there's known to be a partition table, 649 * not specifying a partition means to pick partition 1. 650 */ 651 if (part == PART_UNSPECIFIED) 652 part = 1; 653 654 /* 655 * If user didn't specify a partition number, or did specify something 656 * other than "auto", use that partition number directly. 657 */ 658 if (part != PART_AUTO) { 659 ret = get_partition_info(*dev_desc, part, info); 660 if (ret) { 661 printf("** Invalid partition %d **\n", part); 662 goto cleanup; 663 } 664 } else { 665 /* 666 * Find the first bootable partition. 667 * If none are bootable, fall back to the first valid partition. 668 */ 669 part = 0; 670 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 671 ret = get_partition_info(*dev_desc, p, info); 672 if (ret) 673 continue; 674 675 /* 676 * First valid partition, or new better partition? 677 * If so, save partition ID. 678 */ 679 if (!part || info->bootable) 680 part = p; 681 682 /* Best possible partition? Stop searching. */ 683 if (info->bootable) 684 break; 685 686 /* 687 * We now need to search further for best possible. 688 * If we what we just queried was the best so far, 689 * save the info since we over-write it next loop. 690 */ 691 if (part == p) 692 tmpinfo = *info; 693 } 694 /* If we found any acceptable partition */ 695 if (part) { 696 /* 697 * If we searched all possible partition IDs, 698 * return the first valid partition we found. 699 */ 700 if (p == MAX_SEARCH_PARTITIONS + 1) 701 *info = tmpinfo; 702 } else { 703 printf("** No valid partitions found **\n"); 704 ret = -1; 705 goto cleanup; 706 } 707 } 708 if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 709 printf("** Invalid partition type \"%.32s\"" 710 " (expect \"" BOOT_PART_TYPE "\")\n", 711 info->type); 712 ret = -1; 713 goto cleanup; 714 } 715 716 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 717 718 ret = part; 719 goto cleanup; 720 721 cleanup: 722 free(dup_str); 723 return ret; 724 } 725