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: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n", 194 mb_quot, mb_rem, 195 gb_quot, gb_rem, 196 lba, 197 dev_desc->blksz); 198 #else 199 printf (" Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\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 CONFIG_IS_ENABLED(MAC_PARTITION) || \ 238 CONFIG_IS_ENABLED(DOS_PARTITION) || \ 239 CONFIG_IS_ENABLED(ISO_PARTITION) || \ 240 CONFIG_IS_ENABLED(AMIGA_PARTITION) || \ 241 CONFIG_IS_ENABLED(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 #if CONFIG_IS_ENABLED(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 int blk_get_device_part_str(const char *ifname, const char *dev_part_str, 392 struct blk_desc **dev_desc, 393 disk_partition_t *info, int allow_whole_dev) 394 { 395 int ret = -1; 396 const char *part_str; 397 char *dup_str = NULL; 398 const char *dev_str; 399 int dev; 400 char *ep; 401 int p; 402 int part; 403 disk_partition_t tmpinfo; 404 405 #ifdef CONFIG_SANDBOX 406 /* 407 * Special-case a pseudo block device "hostfs", to allow access to the 408 * host's own filesystem. 409 */ 410 if (0 == strcmp(ifname, "hostfs")) { 411 *dev_desc = NULL; 412 info->start = 0; 413 info->size = 0; 414 info->blksz = 0; 415 info->bootable = 0; 416 strcpy((char *)info->type, BOOT_PART_TYPE); 417 strcpy((char *)info->name, "Sandbox host"); 418 #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 419 info->uuid[0] = 0; 420 #endif 421 #ifdef CONFIG_PARTITION_TYPE_GUID 422 info->type_guid[0] = 0; 423 #endif 424 425 return 0; 426 } 427 #endif 428 429 #ifdef CONFIG_CMD_UBIFS 430 /* 431 * Special-case ubi, ubi goes through a mtd, rathen then through 432 * a regular block device. 433 */ 434 if (0 == strcmp(ifname, "ubi")) { 435 if (!ubifs_is_mounted()) { 436 printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 437 return -1; 438 } 439 440 *dev_desc = NULL; 441 memset(info, 0, sizeof(*info)); 442 strcpy((char *)info->type, BOOT_PART_TYPE); 443 strcpy((char *)info->name, "UBI"); 444 #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 445 info->uuid[0] = 0; 446 #endif 447 return 0; 448 } 449 #endif 450 451 /* If no dev_part_str, use bootdevice environment variable */ 452 if (!dev_part_str || !strlen(dev_part_str) || 453 !strcmp(dev_part_str, "-")) 454 dev_part_str = getenv("bootdevice"); 455 456 /* If still no dev_part_str, it's an error */ 457 if (!dev_part_str) { 458 printf("** No device specified **\n"); 459 goto cleanup; 460 } 461 462 /* Separate device and partition ID specification */ 463 part_str = strchr(dev_part_str, ':'); 464 if (part_str) { 465 dup_str = strdup(dev_part_str); 466 dup_str[part_str - dev_part_str] = 0; 467 dev_str = dup_str; 468 part_str++; 469 } else { 470 dev_str = dev_part_str; 471 } 472 473 /* Look up the device */ 474 dev = blk_get_device_by_str(ifname, dev_str, dev_desc); 475 if (dev < 0) 476 goto cleanup; 477 478 /* Convert partition ID string to number */ 479 if (!part_str || !*part_str) { 480 part = PART_UNSPECIFIED; 481 } else if (!strcmp(part_str, "auto")) { 482 part = PART_AUTO; 483 } else { 484 /* Something specified -> use exactly that */ 485 part = (int)simple_strtoul(part_str, &ep, 16); 486 /* 487 * Less than whole string converted, 488 * or request for whole device, but caller requires partition. 489 */ 490 if (*ep || (part == 0 && !allow_whole_dev)) { 491 printf("** Bad partition specification %s %s **\n", 492 ifname, dev_part_str); 493 goto cleanup; 494 } 495 } 496 497 /* 498 * No partition table on device, 499 * or user requested partition 0 (entire device). 500 */ 501 if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 502 (part == 0)) { 503 if (!(*dev_desc)->lba) { 504 printf("** Bad device size - %s %s **\n", ifname, 505 dev_str); 506 goto cleanup; 507 } 508 509 /* 510 * If user specified a partition ID other than 0, 511 * or the calling command only accepts partitions, 512 * it's an error. 513 */ 514 if ((part > 0) || (!allow_whole_dev)) { 515 printf("** No partition table - %s %s **\n", ifname, 516 dev_str); 517 goto cleanup; 518 } 519 520 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 521 522 info->start = 0; 523 info->size = (*dev_desc)->lba; 524 info->blksz = (*dev_desc)->blksz; 525 info->bootable = 0; 526 strcpy((char *)info->type, BOOT_PART_TYPE); 527 strcpy((char *)info->name, "Whole Disk"); 528 #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 529 info->uuid[0] = 0; 530 #endif 531 #ifdef CONFIG_PARTITION_TYPE_GUID 532 info->type_guid[0] = 0; 533 #endif 534 535 ret = 0; 536 goto cleanup; 537 } 538 539 /* 540 * Now there's known to be a partition table, 541 * not specifying a partition means to pick partition 1. 542 */ 543 if (part == PART_UNSPECIFIED) 544 part = 1; 545 546 /* 547 * If user didn't specify a partition number, or did specify something 548 * other than "auto", use that partition number directly. 549 */ 550 if (part != PART_AUTO) { 551 ret = part_get_info(*dev_desc, part, info); 552 if (ret) { 553 printf("** Invalid partition %d **\n", part); 554 goto cleanup; 555 } 556 } else { 557 /* 558 * Find the first bootable partition. 559 * If none are bootable, fall back to the first valid partition. 560 */ 561 part = 0; 562 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 563 ret = part_get_info(*dev_desc, p, info); 564 if (ret) 565 continue; 566 567 /* 568 * First valid partition, or new better partition? 569 * If so, save partition ID. 570 */ 571 if (!part || info->bootable) 572 part = p; 573 574 /* Best possible partition? Stop searching. */ 575 if (info->bootable) 576 break; 577 578 /* 579 * We now need to search further for best possible. 580 * If we what we just queried was the best so far, 581 * save the info since we over-write it next loop. 582 */ 583 if (part == p) 584 tmpinfo = *info; 585 } 586 /* If we found any acceptable partition */ 587 if (part) { 588 /* 589 * If we searched all possible partition IDs, 590 * return the first valid partition we found. 591 */ 592 if (p == MAX_SEARCH_PARTITIONS + 1) 593 *info = tmpinfo; 594 } else { 595 printf("** No valid partitions found **\n"); 596 ret = -1; 597 goto cleanup; 598 } 599 } 600 if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 601 printf("** Invalid partition type \"%.32s\"" 602 " (expect \"" BOOT_PART_TYPE "\")\n", 603 info->type); 604 ret = -1; 605 goto cleanup; 606 } 607 608 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 609 610 ret = part; 611 goto cleanup; 612 613 cleanup: 614 free(dup_str); 615 return ret; 616 } 617 618 int part_get_info_by_name(struct blk_desc *dev_desc, const char *name, 619 disk_partition_t *info) 620 { 621 struct part_driver *first_drv = 622 ll_entry_start(struct part_driver, part_driver); 623 const int n_drvs = ll_entry_count(struct part_driver, part_driver); 624 struct part_driver *part_drv; 625 626 for (part_drv = first_drv; part_drv != first_drv + n_drvs; part_drv++) { 627 int ret; 628 int i; 629 for (i = 1; i < part_drv->max_entries; i++) { 630 ret = part_drv->get_info(dev_desc, i, info); 631 if (ret != 0) { 632 /* no more entries in table */ 633 break; 634 } 635 if (strcmp(name, (const char *)info->name) == 0) { 636 /* matched */ 637 return i; 638 } 639 } 640 } 641 return -1; 642 } 643 644 void part_set_generic_name(const struct blk_desc *dev_desc, 645 int part_num, char *name) 646 { 647 char *devtype; 648 649 switch (dev_desc->if_type) { 650 case IF_TYPE_IDE: 651 case IF_TYPE_SATA: 652 case IF_TYPE_ATAPI: 653 devtype = "hd"; 654 break; 655 case IF_TYPE_SCSI: 656 devtype = "sd"; 657 break; 658 case IF_TYPE_USB: 659 devtype = "usbd"; 660 break; 661 case IF_TYPE_DOC: 662 devtype = "docd"; 663 break; 664 case IF_TYPE_MMC: 665 case IF_TYPE_SD: 666 devtype = "mmcsd"; 667 break; 668 default: 669 devtype = "xx"; 670 break; 671 } 672 673 sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num); 674 } 675