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