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