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 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 mb = lba512_muldiv(lba512, 10, 2048); /* 2048 = (1024 * 1024) / 512 MB */ 219 220 mb_quot = mb / 10; 221 mb_rem = mb - (10 * mb_quot); 222 223 gb = mb / 1024; 224 gb_quot = gb / 10; 225 gb_rem = gb - (10 * gb_quot); 226 #ifdef CONFIG_LBA48 227 if (dev_desc->lba48) 228 printf (" Supports 48-bit addressing\n"); 229 #endif 230 #if defined(CONFIG_SYS_64BIT_LBA) 231 printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n", 232 mb_quot, mb_rem, 233 gb_quot, gb_rem, 234 lba, 235 dev_desc->blksz); 236 #else 237 printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n", 238 mb_quot, mb_rem, 239 gb_quot, gb_rem, 240 (ulong)lba, 241 dev_desc->blksz); 242 #endif 243 } else { 244 puts (" Capacity: not available\n"); 245 } 246 } 247 #endif 248 249 #ifdef HAVE_BLOCK_DEVICE 250 251 void init_part (block_dev_desc_t * dev_desc) 252 { 253 #ifdef CONFIG_ISO_PARTITION 254 if (test_part_iso(dev_desc) == 0) { 255 dev_desc->part_type = PART_TYPE_ISO; 256 return; 257 } 258 #endif 259 260 #ifdef CONFIG_MAC_PARTITION 261 if (test_part_mac(dev_desc) == 0) { 262 dev_desc->part_type = PART_TYPE_MAC; 263 return; 264 } 265 #endif 266 267 /* must be placed before DOS partition detection */ 268 #ifdef CONFIG_EFI_PARTITION 269 if (test_part_efi(dev_desc) == 0) { 270 dev_desc->part_type = PART_TYPE_EFI; 271 return; 272 } 273 #endif 274 275 #ifdef CONFIG_DOS_PARTITION 276 if (test_part_dos(dev_desc) == 0) { 277 dev_desc->part_type = PART_TYPE_DOS; 278 return; 279 } 280 #endif 281 282 #ifdef CONFIG_AMIGA_PARTITION 283 if (test_part_amiga(dev_desc) == 0) { 284 dev_desc->part_type = PART_TYPE_AMIGA; 285 return; 286 } 287 #endif 288 dev_desc->part_type = PART_TYPE_UNKNOWN; 289 } 290 291 292 #if defined(CONFIG_MAC_PARTITION) || \ 293 defined(CONFIG_DOS_PARTITION) || \ 294 defined(CONFIG_ISO_PARTITION) || \ 295 defined(CONFIG_AMIGA_PARTITION) || \ 296 defined(CONFIG_EFI_PARTITION) 297 298 static void print_part_header (const char *type, block_dev_desc_t * dev_desc) 299 { 300 puts ("\nPartition Map for "); 301 switch (dev_desc->if_type) { 302 case IF_TYPE_IDE: 303 puts ("IDE"); 304 break; 305 case IF_TYPE_SATA: 306 puts ("SATA"); 307 break; 308 case IF_TYPE_SCSI: 309 puts ("SCSI"); 310 break; 311 case IF_TYPE_ATAPI: 312 puts ("ATAPI"); 313 break; 314 case IF_TYPE_USB: 315 puts ("USB"); 316 break; 317 case IF_TYPE_DOC: 318 puts ("DOC"); 319 break; 320 case IF_TYPE_MMC: 321 puts ("MMC"); 322 break; 323 case IF_TYPE_HOST: 324 puts("HOST"); 325 break; 326 default: 327 puts ("UNKNOWN"); 328 break; 329 } 330 printf (" device %d -- Partition Type: %s\n\n", 331 dev_desc->dev, type); 332 } 333 334 #endif /* any CONFIG_..._PARTITION */ 335 336 void print_part(block_dev_desc_t * dev_desc) 337 { 338 339 switch (dev_desc->part_type) { 340 #ifdef CONFIG_MAC_PARTITION 341 case PART_TYPE_MAC: 342 PRINTF ("## Testing for valid MAC partition ##\n"); 343 print_part_header ("MAC", dev_desc); 344 print_part_mac (dev_desc); 345 return; 346 #endif 347 #ifdef CONFIG_DOS_PARTITION 348 case PART_TYPE_DOS: 349 PRINTF ("## Testing for valid DOS partition ##\n"); 350 print_part_header ("DOS", dev_desc); 351 print_part_dos (dev_desc); 352 return; 353 #endif 354 355 #ifdef CONFIG_ISO_PARTITION 356 case PART_TYPE_ISO: 357 PRINTF ("## Testing for valid ISO Boot partition ##\n"); 358 print_part_header ("ISO", dev_desc); 359 print_part_iso (dev_desc); 360 return; 361 #endif 362 363 #ifdef CONFIG_AMIGA_PARTITION 364 case PART_TYPE_AMIGA: 365 PRINTF ("## Testing for a valid Amiga partition ##\n"); 366 print_part_header ("AMIGA", dev_desc); 367 print_part_amiga (dev_desc); 368 return; 369 #endif 370 371 #ifdef CONFIG_EFI_PARTITION 372 case PART_TYPE_EFI: 373 PRINTF ("## Testing for valid EFI partition ##\n"); 374 print_part_header ("EFI", dev_desc); 375 print_part_efi (dev_desc); 376 return; 377 #endif 378 } 379 puts ("## Unknown partition table\n"); 380 } 381 382 #endif /* HAVE_BLOCK_DEVICE */ 383 384 int get_partition_info(block_dev_desc_t *dev_desc, int part, 385 disk_partition_t *info) 386 { 387 #ifdef HAVE_BLOCK_DEVICE 388 389 #ifdef CONFIG_PARTITION_UUIDS 390 /* The common case is no UUID support */ 391 info->uuid[0] = 0; 392 #endif 393 394 switch (dev_desc->part_type) { 395 #ifdef CONFIG_MAC_PARTITION 396 case PART_TYPE_MAC: 397 if (get_partition_info_mac(dev_desc, part, info) == 0) { 398 PRINTF("## Valid MAC partition found ##\n"); 399 return 0; 400 } 401 break; 402 #endif 403 404 #ifdef CONFIG_DOS_PARTITION 405 case PART_TYPE_DOS: 406 if (get_partition_info_dos(dev_desc, part, info) == 0) { 407 PRINTF("## Valid DOS partition found ##\n"); 408 return 0; 409 } 410 break; 411 #endif 412 413 #ifdef CONFIG_ISO_PARTITION 414 case PART_TYPE_ISO: 415 if (get_partition_info_iso(dev_desc, part, info) == 0) { 416 PRINTF("## Valid ISO boot partition found ##\n"); 417 return 0; 418 } 419 break; 420 #endif 421 422 #ifdef CONFIG_AMIGA_PARTITION 423 case PART_TYPE_AMIGA: 424 if (get_partition_info_amiga(dev_desc, part, info) == 0) { 425 PRINTF("## Valid Amiga partition found ##\n"); 426 return 0; 427 } 428 break; 429 #endif 430 431 #ifdef CONFIG_EFI_PARTITION 432 case PART_TYPE_EFI: 433 if (get_partition_info_efi(dev_desc, part, info) == 0) { 434 PRINTF("## Valid EFI partition found ##\n"); 435 return 0; 436 } 437 break; 438 #endif 439 default: 440 break; 441 } 442 #endif /* HAVE_BLOCK_DEVICE */ 443 444 return -1; 445 } 446 447 int get_device(const char *ifname, const char *dev_hwpart_str, 448 block_dev_desc_t **dev_desc) 449 { 450 char *ep; 451 char *dup_str = NULL; 452 const char *dev_str, *hwpart_str; 453 int dev, hwpart; 454 455 hwpart_str = strchr(dev_hwpart_str, '.'); 456 if (hwpart_str) { 457 dup_str = strdup(dev_hwpart_str); 458 dup_str[hwpart_str - dev_hwpart_str] = 0; 459 dev_str = dup_str; 460 hwpart_str++; 461 } else { 462 dev_str = dev_hwpart_str; 463 hwpart = 0; 464 } 465 466 dev = simple_strtoul(dev_str, &ep, 16); 467 if (*ep) { 468 printf("** Bad device specification %s %s **\n", 469 ifname, dev_str); 470 dev = -1; 471 goto cleanup; 472 } 473 474 if (hwpart_str) { 475 hwpart = simple_strtoul(hwpart_str, &ep, 16); 476 if (*ep) { 477 printf("** Bad HW partition specification %s %s **\n", 478 ifname, hwpart_str); 479 dev = -1; 480 goto cleanup; 481 } 482 } 483 484 *dev_desc = get_dev_hwpart(ifname, dev, hwpart); 485 if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { 486 printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); 487 dev = -1; 488 goto cleanup; 489 } 490 491 cleanup: 492 free(dup_str); 493 return dev; 494 } 495 496 #define PART_UNSPECIFIED -2 497 #define PART_AUTO -1 498 #define MAX_SEARCH_PARTITIONS 16 499 int get_device_and_partition(const char *ifname, const char *dev_part_str, 500 block_dev_desc_t **dev_desc, 501 disk_partition_t *info, int allow_whole_dev) 502 { 503 int ret = -1; 504 const char *part_str; 505 char *dup_str = NULL; 506 const char *dev_str; 507 int dev; 508 char *ep; 509 int p; 510 int part; 511 disk_partition_t tmpinfo; 512 513 /* 514 * Special-case a pseudo block device "hostfs", to allow access to the 515 * host's own filesystem. 516 */ 517 if (0 == strcmp(ifname, "hostfs")) { 518 *dev_desc = NULL; 519 info->start = 0; 520 info->size = 0; 521 info->blksz = 0; 522 info->bootable = 0; 523 strcpy((char *)info->type, BOOT_PART_TYPE); 524 strcpy((char *)info->name, "Sandbox host"); 525 #ifdef CONFIG_PARTITION_UUIDS 526 info->uuid[0] = 0; 527 #endif 528 529 return 0; 530 } 531 532 /* If no dev_part_str, use bootdevice environment variable */ 533 if (!dev_part_str || !strlen(dev_part_str) || 534 !strcmp(dev_part_str, "-")) 535 dev_part_str = getenv("bootdevice"); 536 537 /* If still no dev_part_str, it's an error */ 538 if (!dev_part_str) { 539 printf("** No device specified **\n"); 540 goto cleanup; 541 } 542 543 /* Separate device and partition ID specification */ 544 part_str = strchr(dev_part_str, ':'); 545 if (part_str) { 546 dup_str = strdup(dev_part_str); 547 dup_str[part_str - dev_part_str] = 0; 548 dev_str = dup_str; 549 part_str++; 550 } else { 551 dev_str = dev_part_str; 552 } 553 554 /* Look up the device */ 555 dev = get_device(ifname, dev_str, dev_desc); 556 if (dev < 0) 557 goto cleanup; 558 559 /* Convert partition ID string to number */ 560 if (!part_str || !*part_str) { 561 part = PART_UNSPECIFIED; 562 } else if (!strcmp(part_str, "auto")) { 563 part = PART_AUTO; 564 } else { 565 /* Something specified -> use exactly that */ 566 part = (int)simple_strtoul(part_str, &ep, 16); 567 /* 568 * Less than whole string converted, 569 * or request for whole device, but caller requires partition. 570 */ 571 if (*ep || (part == 0 && !allow_whole_dev)) { 572 printf("** Bad partition specification %s %s **\n", 573 ifname, dev_part_str); 574 goto cleanup; 575 } 576 } 577 578 /* 579 * No partition table on device, 580 * or user requested partition 0 (entire device). 581 */ 582 if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 583 (part == 0)) { 584 if (!(*dev_desc)->lba) { 585 printf("** Bad device size - %s %s **\n", ifname, 586 dev_str); 587 goto cleanup; 588 } 589 590 /* 591 * If user specified a partition ID other than 0, 592 * or the calling command only accepts partitions, 593 * it's an error. 594 */ 595 if ((part > 0) || (!allow_whole_dev)) { 596 printf("** No partition table - %s %s **\n", ifname, 597 dev_str); 598 goto cleanup; 599 } 600 601 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 602 603 info->start = 0; 604 info->size = (*dev_desc)->lba; 605 info->blksz = (*dev_desc)->blksz; 606 info->bootable = 0; 607 strcpy((char *)info->type, BOOT_PART_TYPE); 608 strcpy((char *)info->name, "Whole Disk"); 609 #ifdef CONFIG_PARTITION_UUIDS 610 info->uuid[0] = 0; 611 #endif 612 613 ret = 0; 614 goto cleanup; 615 } 616 617 /* 618 * Now there's known to be a partition table, 619 * not specifying a partition means to pick partition 1. 620 */ 621 if (part == PART_UNSPECIFIED) 622 part = 1; 623 624 /* 625 * If user didn't specify a partition number, or did specify something 626 * other than "auto", use that partition number directly. 627 */ 628 if (part != PART_AUTO) { 629 ret = get_partition_info(*dev_desc, part, info); 630 if (ret) { 631 printf("** Invalid partition %d **\n", part); 632 goto cleanup; 633 } 634 } else { 635 /* 636 * Find the first bootable partition. 637 * If none are bootable, fall back to the first valid partition. 638 */ 639 part = 0; 640 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 641 ret = get_partition_info(*dev_desc, p, info); 642 if (ret) 643 continue; 644 645 /* 646 * First valid partition, or new better partition? 647 * If so, save partition ID. 648 */ 649 if (!part || info->bootable) 650 part = p; 651 652 /* Best possible partition? Stop searching. */ 653 if (info->bootable) 654 break; 655 656 /* 657 * We now need to search further for best possible. 658 * If we what we just queried was the best so far, 659 * save the info since we over-write it next loop. 660 */ 661 if (part == p) 662 tmpinfo = *info; 663 } 664 /* If we found any acceptable partition */ 665 if (part) { 666 /* 667 * If we searched all possible partition IDs, 668 * return the first valid partition we found. 669 */ 670 if (p == MAX_SEARCH_PARTITIONS + 1) 671 *info = tmpinfo; 672 } else { 673 printf("** No valid partitions found **\n"); 674 ret = -1; 675 goto cleanup; 676 } 677 } 678 if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 679 printf("** Invalid partition type \"%.32s\"" 680 " (expect \"" BOOT_PART_TYPE "\")\n", 681 info->type); 682 ret = -1; 683 goto cleanup; 684 } 685 686 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 687 688 ret = part; 689 goto cleanup; 690 691 cleanup: 692 free(dup_str); 693 return ret; 694 } 695