uboot/disk/part.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2001
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 */
   6
   7#include <common.h>
   8#include <command.h>
   9#include <errno.h>
  10#include <ide.h>
  11#include <malloc.h>
  12#include <part.h>
  13#include <ubifs_uboot.h>
  14
  15#undef  PART_DEBUG
  16
  17#ifdef  PART_DEBUG
  18#define PRINTF(fmt,args...)     printf (fmt ,##args)
  19#else
  20#define PRINTF(fmt,args...)
  21#endif
  22
  23/* Check all partition types */
  24#define PART_TYPE_ALL           -1
  25
  26static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc)
  27{
  28        struct part_driver *drv =
  29                ll_entry_start(struct part_driver, part_driver);
  30        const int n_ents = ll_entry_count(struct part_driver, part_driver);
  31        struct part_driver *entry;
  32
  33        if (dev_desc->part_type == PART_TYPE_UNKNOWN) {
  34                for (entry = drv; entry != drv + n_ents; entry++) {
  35                        int ret;
  36
  37                        ret = entry->test(dev_desc);
  38                        if (!ret) {
  39                                dev_desc->part_type = entry->part_type;
  40                                return entry;
  41                        }
  42                }
  43        } else {
  44                for (entry = drv; entry != drv + n_ents; entry++) {
  45                        if (dev_desc->part_type == entry->part_type)
  46                                return entry;
  47                }
  48        }
  49
  50        /* Not found */
  51        return NULL;
  52}
  53
  54#ifdef CONFIG_HAVE_BLOCK_DEVICE
  55static 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
  76struct blk_desc *blk_get_dev(const char *ifname, int dev)
  77{
  78        return get_dev_hwpart(ifname, dev, 0);
  79}
  80#else
  81struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
  82{
  83        return NULL;
  84}
  85
  86struct blk_desc *blk_get_dev(const char *ifname, int dev)
  87{
  88        return NULL;
  89}
  90#endif
  91
  92#ifdef CONFIG_HAVE_BLOCK_DEVICE
  93
  94/* ------------------------------------------------------------------------- */
  95/*
  96 * reports device info to the user
  97 */
  98
  99#ifdef CONFIG_LBA48
 100typedef uint64_t lba512_t;
 101#else
 102typedef 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 */
 109static 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
 119void 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                printf ("Vendor: %s Rev: %s Prod: %s\n",
 149                        dev_desc->vendor,
 150                        dev_desc->revision,
 151                        dev_desc->product);
 152                break;
 153        case IF_TYPE_VIRTIO:
 154                printf("%s VirtIO Block Device\n", dev_desc->vendor);
 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 CONFIG_HAVE_BLOCK_DEVICE
 228
 229void 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
 251static 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_VIRTIO:
 288                puts("VirtIO");
 289                break;
 290        default:
 291                puts ("UNKNOWN");
 292                break;
 293        }
 294        printf (" device %d  --   Partition Type: %s\n\n",
 295                        dev_desc->devnum, type);
 296#endif /* any CONFIG_..._PARTITION */
 297}
 298
 299void part_print(struct blk_desc *dev_desc)
 300{
 301        struct part_driver *drv;
 302
 303        drv = part_driver_lookup_type(dev_desc);
 304        if (!drv) {
 305                printf("## Unknown partition table type %x\n",
 306                       dev_desc->part_type);
 307                return;
 308        }
 309
 310        PRINTF("## Testing for valid %s partition ##\n", drv->name);
 311        print_part_header(drv->name, dev_desc);
 312        if (drv->print)
 313                drv->print(dev_desc);
 314}
 315
 316#endif /* CONFIG_HAVE_BLOCK_DEVICE */
 317
 318int part_get_info(struct blk_desc *dev_desc, int part,
 319                       disk_partition_t *info)
 320{
 321#ifdef CONFIG_HAVE_BLOCK_DEVICE
 322        struct part_driver *drv;
 323
 324#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 325        /* The common case is no UUID support */
 326        info->uuid[0] = 0;
 327#endif
 328#ifdef CONFIG_PARTITION_TYPE_GUID
 329        info->type_guid[0] = 0;
 330#endif
 331
 332        drv = part_driver_lookup_type(dev_desc);
 333        if (!drv) {
 334                debug("## Unknown partition table type %x\n",
 335                      dev_desc->part_type);
 336                return -EPROTONOSUPPORT;
 337        }
 338        if (!drv->get_info) {
 339                PRINTF("## Driver %s does not have the get_info() method\n",
 340                       drv->name);
 341                return -ENOSYS;
 342        }
 343        if (drv->get_info(dev_desc, part, info) == 0) {
 344                PRINTF("## Valid %s partition found ##\n", drv->name);
 345                return 0;
 346        }
 347#endif /* CONFIG_HAVE_BLOCK_DEVICE */
 348
 349        return -1;
 350}
 351
 352int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info)
 353{
 354        info->start = 0;
 355        info->size = dev_desc->lba;
 356        info->blksz = dev_desc->blksz;
 357        info->bootable = 0;
 358        strcpy((char *)info->type, BOOT_PART_TYPE);
 359        strcpy((char *)info->name, "Whole Disk");
 360#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 361        info->uuid[0] = 0;
 362#endif
 363#ifdef CONFIG_PARTITION_TYPE_GUID
 364        info->type_guid[0] = 0;
 365#endif
 366
 367        return 0;
 368}
 369
 370int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
 371                          struct blk_desc **dev_desc)
 372{
 373        char *ep;
 374        char *dup_str = NULL;
 375        const char *dev_str, *hwpart_str;
 376        int dev, hwpart;
 377
 378        hwpart_str = strchr(dev_hwpart_str, '.');
 379        if (hwpart_str) {
 380                dup_str = strdup(dev_hwpart_str);
 381                dup_str[hwpart_str - dev_hwpart_str] = 0;
 382                dev_str = dup_str;
 383                hwpart_str++;
 384        } else {
 385                dev_str = dev_hwpart_str;
 386                hwpart = 0;
 387        }
 388
 389        dev = simple_strtoul(dev_str, &ep, 16);
 390        if (*ep) {
 391                printf("** Bad device specification %s %s **\n",
 392                       ifname, dev_str);
 393                dev = -EINVAL;
 394                goto cleanup;
 395        }
 396
 397        if (hwpart_str) {
 398                hwpart = simple_strtoul(hwpart_str, &ep, 16);
 399                if (*ep) {
 400                        printf("** Bad HW partition specification %s %s **\n",
 401                            ifname, hwpart_str);
 402                        dev = -EINVAL;
 403                        goto cleanup;
 404                }
 405        }
 406
 407        *dev_desc = get_dev_hwpart(ifname, dev, hwpart);
 408        if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
 409                debug("** Bad device %s %s **\n", ifname, dev_hwpart_str);
 410                dev = -ENOENT;
 411                goto cleanup;
 412        }
 413
 414#ifdef CONFIG_HAVE_BLOCK_DEVICE
 415        /*
 416         * Updates the partition table for the specified hw partition.
 417         * Does not need to be done for hwpart 0 since it is default and
 418         * already loaded.
 419         */
 420        if(hwpart != 0)
 421                part_init(*dev_desc);
 422#endif
 423
 424cleanup:
 425        free(dup_str);
 426        return dev;
 427}
 428
 429#define PART_UNSPECIFIED -2
 430#define PART_AUTO -1
 431int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 432                             struct blk_desc **dev_desc,
 433                             disk_partition_t *info, int allow_whole_dev)
 434{
 435        int ret = -1;
 436        const char *part_str;
 437        char *dup_str = NULL;
 438        const char *dev_str;
 439        int dev;
 440        char *ep;
 441        int p;
 442        int part;
 443        disk_partition_t tmpinfo;
 444
 445#ifdef CONFIG_SANDBOX
 446        /*
 447         * Special-case a pseudo block device "hostfs", to allow access to the
 448         * host's own filesystem.
 449         */
 450        if (0 == strcmp(ifname, "hostfs")) {
 451                *dev_desc = NULL;
 452                info->start = 0;
 453                info->size = 0;
 454                info->blksz = 0;
 455                info->bootable = 0;
 456                strcpy((char *)info->type, BOOT_PART_TYPE);
 457                strcpy((char *)info->name, "Sandbox host");
 458#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 459                info->uuid[0] = 0;
 460#endif
 461#ifdef CONFIG_PARTITION_TYPE_GUID
 462                info->type_guid[0] = 0;
 463#endif
 464
 465                return 0;
 466        }
 467#endif
 468
 469#ifdef CONFIG_CMD_UBIFS
 470        /*
 471         * Special-case ubi, ubi goes through a mtd, rathen then through
 472         * a regular block device.
 473         */
 474        if (0 == strcmp(ifname, "ubi")) {
 475                if (!ubifs_is_mounted()) {
 476                        printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
 477                        return -1;
 478                }
 479
 480                *dev_desc = NULL;
 481                memset(info, 0, sizeof(*info));
 482                strcpy((char *)info->type, BOOT_PART_TYPE);
 483                strcpy((char *)info->name, "UBI");
 484#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 485                info->uuid[0] = 0;
 486#endif
 487                return 0;
 488        }
 489#endif
 490
 491        /* If no dev_part_str, use bootdevice environment variable */
 492        if (!dev_part_str || !strlen(dev_part_str) ||
 493            !strcmp(dev_part_str, "-"))
 494                dev_part_str = env_get("bootdevice");
 495
 496        /* If still no dev_part_str, it's an error */
 497        if (!dev_part_str) {
 498                printf("** No device specified **\n");
 499                goto cleanup;
 500        }
 501
 502        /* Separate device and partition ID specification */
 503        part_str = strchr(dev_part_str, ':');
 504        if (part_str) {
 505                dup_str = strdup(dev_part_str);
 506                dup_str[part_str - dev_part_str] = 0;
 507                dev_str = dup_str;
 508                part_str++;
 509        } else {
 510                dev_str = dev_part_str;
 511        }
 512
 513        /* Look up the device */
 514        dev = blk_get_device_by_str(ifname, dev_str, dev_desc);
 515        if (dev < 0)
 516                goto cleanup;
 517
 518        /* Convert partition ID string to number */
 519        if (!part_str || !*part_str) {
 520                part = PART_UNSPECIFIED;
 521        } else if (!strcmp(part_str, "auto")) {
 522                part = PART_AUTO;
 523        } else {
 524                /* Something specified -> use exactly that */
 525                part = (int)simple_strtoul(part_str, &ep, 16);
 526                /*
 527                 * Less than whole string converted,
 528                 * or request for whole device, but caller requires partition.
 529                 */
 530                if (*ep || (part == 0 && !allow_whole_dev)) {
 531                        printf("** Bad partition specification %s %s **\n",
 532                            ifname, dev_part_str);
 533                        goto cleanup;
 534                }
 535        }
 536
 537        /*
 538         * No partition table on device,
 539         * or user requested partition 0 (entire device).
 540         */
 541        if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
 542            (part == 0)) {
 543                if (!(*dev_desc)->lba) {
 544                        printf("** Bad device size - %s %s **\n", ifname,
 545                               dev_str);
 546                        goto cleanup;
 547                }
 548
 549                /*
 550                 * If user specified a partition ID other than 0,
 551                 * or the calling command only accepts partitions,
 552                 * it's an error.
 553                 */
 554                if ((part > 0) || (!allow_whole_dev)) {
 555                        printf("** No partition table - %s %s **\n", ifname,
 556                               dev_str);
 557                        goto cleanup;
 558                }
 559
 560                (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
 561
 562                part_get_info_whole_disk(*dev_desc, info);
 563
 564                ret = 0;
 565                goto cleanup;
 566        }
 567
 568        /*
 569         * Now there's known to be a partition table,
 570         * not specifying a partition means to pick partition 1.
 571         */
 572        if (part == PART_UNSPECIFIED)
 573                part = 1;
 574
 575        /*
 576         * If user didn't specify a partition number, or did specify something
 577         * other than "auto", use that partition number directly.
 578         */
 579        if (part != PART_AUTO) {
 580                ret = part_get_info(*dev_desc, part, info);
 581                if (ret) {
 582                        printf("** Invalid partition %d **\n", part);
 583                        goto cleanup;
 584                }
 585        } else {
 586                /*
 587                 * Find the first bootable partition.
 588                 * If none are bootable, fall back to the first valid partition.
 589                 */
 590                part = 0;
 591                for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 592                        ret = part_get_info(*dev_desc, p, info);
 593                        if (ret)
 594                                continue;
 595
 596                        /*
 597                         * First valid partition, or new better partition?
 598                         * If so, save partition ID.
 599                         */
 600                        if (!part || info->bootable)
 601                                part = p;
 602
 603                        /* Best possible partition? Stop searching. */
 604                        if (info->bootable)
 605                                break;
 606
 607                        /*
 608                         * We now need to search further for best possible.
 609                         * If we what we just queried was the best so far,
 610                         * save the info since we over-write it next loop.
 611                         */
 612                        if (part == p)
 613                                tmpinfo = *info;
 614                }
 615                /* If we found any acceptable partition */
 616                if (part) {
 617                        /*
 618                         * If we searched all possible partition IDs,
 619                         * return the first valid partition we found.
 620                         */
 621                        if (p == MAX_SEARCH_PARTITIONS + 1)
 622                                *info = tmpinfo;
 623                } else {
 624                        printf("** No valid partitions found **\n");
 625                        ret = -1;
 626                        goto cleanup;
 627                }
 628        }
 629        if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
 630                printf("** Invalid partition type \"%.32s\""
 631                        " (expect \"" BOOT_PART_TYPE "\")\n",
 632                        info->type);
 633                ret  = -1;
 634                goto cleanup;
 635        }
 636
 637        (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
 638
 639        ret = part;
 640        goto cleanup;
 641
 642cleanup:
 643        free(dup_str);
 644        return ret;
 645}
 646
 647int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
 648                               disk_partition_t *info, int part_type)
 649{
 650        struct part_driver *part_drv;
 651        int ret;
 652        int i;
 653
 654        part_drv = part_driver_lookup_type(dev_desc);
 655        if (!part_drv)
 656                return -1;
 657        for (i = 1; i < part_drv->max_entries; i++) {
 658                ret = part_drv->get_info(dev_desc, i, info);
 659                if (ret != 0) {
 660                        /* no more entries in table */
 661                        break;
 662                }
 663                if (strcmp(name, (const char *)info->name) == 0) {
 664                        /* matched */
 665                        return i;
 666                }
 667        }
 668
 669        return -1;
 670}
 671
 672int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
 673                          disk_partition_t *info)
 674{
 675        return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
 676}
 677
 678void part_set_generic_name(const struct blk_desc *dev_desc,
 679        int part_num, char *name)
 680{
 681        char *devtype;
 682
 683        switch (dev_desc->if_type) {
 684        case IF_TYPE_IDE:
 685        case IF_TYPE_SATA:
 686        case IF_TYPE_ATAPI:
 687                devtype = "hd";
 688                break;
 689        case IF_TYPE_SCSI:
 690                devtype = "sd";
 691                break;
 692        case IF_TYPE_USB:
 693                devtype = "usbd";
 694                break;
 695        case IF_TYPE_DOC:
 696                devtype = "docd";
 697                break;
 698        case IF_TYPE_MMC:
 699        case IF_TYPE_SD:
 700                devtype = "mmcsd";
 701                break;
 702        default:
 703                devtype = "xx";
 704                break;
 705        }
 706
 707        sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num);
 708}
 709