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
  24DECLARE_GLOBAL_DATA_PTR;
  25
  26#ifdef HAVE_BLOCK_DEVICE
  27static 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
  43static 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
  64struct blk_desc *blk_get_dev(const char *ifname, int dev)
  65{
  66        return get_dev_hwpart(ifname, dev, 0);
  67}
  68#else
  69struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
  70{
  71        return NULL;
  72}
  73
  74struct 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
  88typedef uint64_t lba512_t;
  89#else
  90typedef 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 */
  97static 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
 107void 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
 213void 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
 235static 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
 277void 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
 296int 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
 330int 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
 384cleanup:
 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
 392int 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
 614cleanup:
 615        free(dup_str);
 616        return ret;
 617}
 618