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