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 == -1) 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, -1); 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 = -1; 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 /* If no dev_part_str, use bootdevice environment variable */ 514 if (!dev_part_str || !strlen(dev_part_str) || 515 !strcmp(dev_part_str, "-")) 516 dev_part_str = getenv("bootdevice"); 517 518 /* If still no dev_part_str, it's an error */ 519 if (!dev_part_str) { 520 printf("** No device specified **\n"); 521 goto cleanup; 522 } 523 524 /* Separate device and partition ID specification */ 525 part_str = strchr(dev_part_str, ':'); 526 if (part_str) { 527 dup_str = strdup(dev_part_str); 528 dup_str[part_str - dev_part_str] = 0; 529 dev_str = dup_str; 530 part_str++; 531 } else { 532 dev_str = dev_part_str; 533 } 534 535 /* Look up the device */ 536 dev = get_device(ifname, dev_str, dev_desc); 537 if (dev < 0) 538 goto cleanup; 539 540 /* Convert partition ID string to number */ 541 if (!part_str || !*part_str) { 542 part = PART_UNSPECIFIED; 543 } else if (!strcmp(part_str, "auto")) { 544 part = PART_AUTO; 545 } else { 546 /* Something specified -> use exactly that */ 547 part = (int)simple_strtoul(part_str, &ep, 16); 548 /* 549 * Less than whole string converted, 550 * or request for whole device, but caller requires partition. 551 */ 552 if (*ep || (part == 0 && !allow_whole_dev)) { 553 printf("** Bad partition specification %s %s **\n", 554 ifname, dev_part_str); 555 goto cleanup; 556 } 557 } 558 559 /* 560 * No partition table on device, 561 * or user requested partition 0 (entire device). 562 */ 563 if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 564 (part == 0)) { 565 if (!(*dev_desc)->lba) { 566 printf("** Bad device size - %s %s **\n", ifname, 567 dev_str); 568 goto cleanup; 569 } 570 571 /* 572 * If user specified a partition ID other than 0, 573 * or the calling command only accepts partitions, 574 * it's an error. 575 */ 576 if ((part > 0) || (!allow_whole_dev)) { 577 printf("** No partition table - %s %s **\n", ifname, 578 dev_str); 579 goto cleanup; 580 } 581 582 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 583 584 info->start = 0; 585 info->size = (*dev_desc)->lba; 586 info->blksz = (*dev_desc)->blksz; 587 info->bootable = 0; 588 strcpy((char *)info->type, BOOT_PART_TYPE); 589 strcpy((char *)info->name, "Whole Disk"); 590 #ifdef CONFIG_PARTITION_UUIDS 591 info->uuid[0] = 0; 592 #endif 593 594 ret = 0; 595 goto cleanup; 596 } 597 598 /* 599 * Now there's known to be a partition table, 600 * not specifying a partition means to pick partition 1. 601 */ 602 if (part == PART_UNSPECIFIED) 603 part = 1; 604 605 /* 606 * If user didn't specify a partition number, or did specify something 607 * other than "auto", use that partition number directly. 608 */ 609 if (part != PART_AUTO) { 610 ret = get_partition_info(*dev_desc, part, info); 611 if (ret) { 612 printf("** Invalid partition %d **\n", part); 613 goto cleanup; 614 } 615 } else { 616 /* 617 * Find the first bootable partition. 618 * If none are bootable, fall back to the first valid partition. 619 */ 620 part = 0; 621 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 622 ret = get_partition_info(*dev_desc, p, info); 623 if (ret) 624 continue; 625 626 /* 627 * First valid partition, or new better partition? 628 * If so, save partition ID. 629 */ 630 if (!part || info->bootable) 631 part = p; 632 633 /* Best possible partition? Stop searching. */ 634 if (info->bootable) 635 break; 636 637 /* 638 * We now need to search further for best possible. 639 * If we what we just queried was the best so far, 640 * save the info since we over-write it next loop. 641 */ 642 if (part == p) 643 tmpinfo = *info; 644 } 645 /* If we found any acceptable partition */ 646 if (part) { 647 /* 648 * If we searched all possible partition IDs, 649 * return the first valid partition we found. 650 */ 651 if (p == MAX_SEARCH_PARTITIONS + 1) 652 *info = tmpinfo; 653 } else { 654 printf("** No valid partitions found **\n"); 655 ret = -1; 656 goto cleanup; 657 } 658 } 659 if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 660 printf("** Invalid partition type \"%.32s\"" 661 " (expect \"" BOOT_PART_TYPE "\")\n", 662 info->type); 663 ret = -1; 664 goto cleanup; 665 } 666 667 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 668 669 ret = part; 670 goto cleanup; 671 672 cleanup: 673 free(dup_str); 674 return ret; 675 } 676