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