uboot/disk/part.c
<<
>>
Prefs
   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
  27DECLARE_GLOBAL_DATA_PTR;
  28
  29#ifdef HAVE_BLOCK_DEVICE
  30static 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
  46static 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
  67struct blk_desc *blk_get_dev(const char *ifname, int dev)
  68{
  69        return get_dev_hwpart(ifname, dev, 0);
  70}
  71#else
  72struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
  73{
  74        return NULL;
  75}
  76
  77struct 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
  91typedef uint64_t lba512_t;
  92#else
  93typedef 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 */
 100static 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
 110void 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
 217void 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
 239static 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
 284void 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
 303int 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
 337int 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
 355int 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
 409cleanup:
 410        free(dup_str);
 411        return dev;
 412}
 413
 414#define PART_UNSPECIFIED -2
 415#define PART_AUTO -1
 416int 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
 627cleanup:
 628        free(dup_str);
 629        return ret;
 630}
 631
 632int 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
 660int 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
 666void 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