uboot/cmd/mvebu/bubt.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 Marvell International Ltd.
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0
   5 * https://spdx.org/licenses
   6 */
   7
   8#include <config.h>
   9#include <common.h>
  10#include <command.h>
  11#include <vsprintf.h>
  12#include <errno.h>
  13#include <dm.h>
  14
  15#include <spi_flash.h>
  16#include <spi.h>
  17#include <nand.h>
  18#include <usb.h>
  19#include <fs.h>
  20#include <mmc.h>
  21#include <u-boot/sha1.h>
  22#include <u-boot/sha256.h>
  23
  24#ifndef CONFIG_SYS_MMC_ENV_DEV
  25#define CONFIG_SYS_MMC_ENV_DEV  0
  26#endif
  27
  28#if defined(CONFIG_ARMADA_8K)
  29#define MAIN_HDR_MAGIC          0xB105B002
  30
  31struct mvebu_image_header {
  32        u32     magic;                  /*  0-3  */
  33        u32     prolog_size;            /*  4-7  */
  34        u32     prolog_checksum;        /*  8-11 */
  35        u32     boot_image_size;        /* 12-15 */
  36        u32     boot_image_checksum;    /* 16-19 */
  37        u32     rsrvd0;                 /* 20-23 */
  38        u32     load_addr;              /* 24-27 */
  39        u32     exec_addr;              /* 28-31 */
  40        u8      uart_cfg;               /*  32   */
  41        u8      baudrate;               /*  33   */
  42        u8      ext_count;              /*  34   */
  43        u8      aux_flags;              /*  35   */
  44        u32     io_arg_0;               /* 36-39 */
  45        u32     io_arg_1;               /* 40-43 */
  46        u32     io_arg_2;               /* 43-47 */
  47        u32     io_arg_3;               /* 48-51 */
  48        u32     rsrvd1;                 /* 52-55 */
  49        u32     rsrvd2;                 /* 56-59 */
  50        u32     rsrvd3;                 /* 60-63 */
  51};
  52#elif defined(CONFIG_ARMADA_3700)       /* A3700 */
  53#define HASH_SUM_LEN            16
  54#define IMAGE_VERSION_3_6_0     0x030600
  55#define IMAGE_VERSION_3_5_0     0x030500
  56
  57struct common_tim_data {
  58        u32     version;
  59        u32     identifier;
  60        u32     trusted;
  61        u32     issue_date;
  62        u32     oem_unique_id;
  63        u32     reserved[5];            /* Reserve 20 bytes */
  64        u32     boot_flash_sign;
  65        u32     num_images;
  66        u32     num_keys;
  67        u32     size_of_reserved;
  68};
  69
  70struct mvebu_image_info {
  71        u32     image_id;
  72        u32     next_image_id;
  73        u32     flash_entry_addr;
  74        u32     load_addr;
  75        u32     image_size;
  76        u32     image_size_to_hash;
  77        u32     hash_algorithm_id;
  78        u32     hash[HASH_SUM_LEN];     /* Reserve 512 bits for the hash */
  79        u32     partition_number;
  80        u32     enc_algorithm_id;
  81        u32     encrypt_start_offset;
  82        u32     encrypt_size;
  83};
  84#endif /* CONFIG_ARMADA_XXX */
  85
  86struct bubt_dev {
  87        char name[8];
  88        size_t (*read)(const char *file_name);
  89        int (*write)(size_t image_size);
  90        int (*active)(void);
  91};
  92
  93static ulong get_load_addr(void)
  94{
  95        const char *addr_str;
  96        unsigned long addr;
  97
  98        addr_str = getenv("loadaddr");
  99        if (addr_str)
 100                addr = simple_strtoul(addr_str, NULL, 16);
 101        else
 102                addr = CONFIG_SYS_LOAD_ADDR;
 103
 104        return addr;
 105}
 106
 107/********************************************************************
 108 *     eMMC services
 109 ********************************************************************/
 110#ifdef CONFIG_DM_MMC
 111static int mmc_burn_image(size_t image_size)
 112{
 113        struct mmc      *mmc;
 114        lbaint_t        start_lba;
 115        lbaint_t        blk_count;
 116        ulong           blk_written;
 117        int             err;
 118        const u8        mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
 119
 120        mmc = find_mmc_device(mmc_dev_num);
 121        if (!mmc) {
 122                printf("No SD/MMC/eMMC card found\n");
 123                return -ENOMEDIUM;
 124        }
 125
 126        err = mmc_init(mmc);
 127        if (err) {
 128                printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
 129                       mmc_dev_num);
 130                return err;
 131        }
 132
 133#ifdef CONFIG_SYS_MMC_ENV_PART
 134        if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART) {
 135                err = mmc_switch_part(mmc_dev_num, CONFIG_SYS_MMC_ENV_PART);
 136                if (err) {
 137                        printf("MMC partition switch failed\n");
 138                        return err;
 139                }
 140        }
 141#endif
 142
 143        /* SD reserves LBA-0 for MBR and boots from LBA-1,
 144         * MMC/eMMC boots from LBA-0
 145         */
 146        start_lba = IS_SD(mmc) ? 1 : 0;
 147        blk_count = image_size / mmc->block_dev.blksz;
 148        if (image_size % mmc->block_dev.blksz)
 149                blk_count += 1;
 150
 151        blk_written = mmc->block_dev.block_write(mmc_dev_num,
 152                                                start_lba, blk_count,
 153                                                (void *)get_load_addr());
 154        if (blk_written != blk_count) {
 155                printf("Error - written %#lx blocks\n", blk_written);
 156                return -ENOSPC;
 157        }
 158        printf("Done!\n");
 159
 160#ifdef CONFIG_SYS_MMC_ENV_PART
 161        if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART)
 162                mmc_switch_part(mmc_dev_num, mmc->part_num);
 163#endif
 164
 165        return 0;
 166}
 167
 168static size_t mmc_read_file(const char *file_name)
 169{
 170        loff_t          act_read = 0;
 171        int             rc;
 172        struct mmc      *mmc;
 173        const u8        mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
 174
 175        mmc = find_mmc_device(mmc_dev_num);
 176        if (!mmc) {
 177                printf("No SD/MMC/eMMC card found\n");
 178                return 0;
 179        }
 180
 181        if (mmc_init(mmc)) {
 182                printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
 183                       mmc_dev_num);
 184                return 0;
 185        }
 186
 187        /* Load from data partition (0) */
 188        if (fs_set_blk_dev("mmc", "0", FS_TYPE_ANY)) {
 189                printf("Error: MMC 0 not found\n");
 190                return 0;
 191        }
 192
 193        /* Perfrom file read */
 194        rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
 195        if (rc)
 196                return 0;
 197
 198        return act_read;
 199}
 200
 201static int is_mmc_active(void)
 202{
 203        return 1;
 204}
 205#else /* CONFIG_DM_MMC */
 206static int mmc_burn_image(size_t image_size)
 207{
 208        return -ENODEV;
 209}
 210
 211static size_t mmc_read_file(const char *file_name)
 212{
 213        return 0;
 214}
 215
 216static int is_mmc_active(void)
 217{
 218        return 0;
 219}
 220#endif /* CONFIG_DM_MMC */
 221
 222/********************************************************************
 223 *     SPI services
 224 ********************************************************************/
 225#ifdef CONFIG_SPI_FLASH
 226static int spi_burn_image(size_t image_size)
 227{
 228        int ret;
 229        struct spi_flash *flash;
 230        u32 erase_bytes;
 231
 232        /* Probe the SPI bus to get the flash device */
 233        flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
 234                                CONFIG_ENV_SPI_CS,
 235                                CONFIG_SF_DEFAULT_SPEED,
 236                                CONFIG_SF_DEFAULT_MODE);
 237        if (!flash) {
 238                printf("Failed to probe SPI Flash\n");
 239                return -ENOMEDIUM;
 240        }
 241
 242#ifdef CONFIG_SPI_FLASH_PROTECTION
 243        spi_flash_protect(flash, 0);
 244#endif
 245        erase_bytes = image_size +
 246                (flash->erase_size - image_size % flash->erase_size);
 247        printf("Erasing %d bytes (%d blocks) at offset 0 ...",
 248               erase_bytes, erase_bytes / flash->erase_size);
 249        ret = spi_flash_erase(flash, 0, erase_bytes);
 250        if (ret)
 251                printf("Error!\n");
 252        else
 253                printf("Done!\n");
 254
 255        printf("Writing %d bytes from 0x%lx to offset 0 ...",
 256               (int)image_size, get_load_addr());
 257        ret = spi_flash_write(flash, 0, image_size, (void *)get_load_addr());
 258        if (ret)
 259                printf("Error!\n");
 260        else
 261                printf("Done!\n");
 262
 263#ifdef CONFIG_SPI_FLASH_PROTECTION
 264        spi_flash_protect(flash, 1);
 265#endif
 266
 267        return ret;
 268}
 269
 270static int is_spi_active(void)
 271{
 272        return 1;
 273}
 274
 275#else /* CONFIG_SPI_FLASH */
 276static int spi_burn_image(size_t image_size)
 277{
 278        return -ENODEV;
 279}
 280
 281static int is_spi_active(void)
 282{
 283        return 0;
 284}
 285#endif /* CONFIG_SPI_FLASH */
 286
 287/********************************************************************
 288 *     NAND services
 289 ********************************************************************/
 290#ifdef CONFIG_CMD_NAND
 291static int nand_burn_image(size_t image_size)
 292{
 293        int ret, block_size;
 294        nand_info_t *nand;
 295        int dev = nand_curr_device;
 296
 297        if ((dev < 0) || (dev >= CONFIG_SYS_MAX_NAND_DEVICE) ||
 298            (!nand_info[dev].name)) {
 299                puts("\nno devices available\n");
 300                return -ENOMEDIUM;
 301        }
 302        nand = &nand_info[dev];
 303        block_size = nand->erasesize;
 304
 305        /* Align U-Boot size to currently used blocksize */
 306        image_size = ((image_size + (block_size - 1)) & (~(block_size - 1)));
 307
 308        /* Erase the U-BOOT image space */
 309        printf("Erasing 0x%x - 0x%x:...", 0, (int)image_size);
 310        ret = nand_erase(nand, 0, image_size);
 311        if (ret) {
 312                printf("Error!\n");
 313                goto error;
 314        }
 315        printf("Done!\n");
 316
 317        /* Write the image to flash */
 318        printf("Writing image:...");
 319        printf("&image_size = 0x%p\n", (void *)&image_size);
 320        ret = nand_write(nand, 0, &image_size, (void *)get_load_addr());
 321        if (ret)
 322                printf("Error!\n");
 323        else
 324                printf("Done!\n");
 325
 326error:
 327        return ret;
 328}
 329
 330static int is_nand_active(void)
 331{
 332        return 1;
 333}
 334
 335#else /* CONFIG_CMD_NAND */
 336static int nand_burn_image(size_t image_size)
 337{
 338        return -ENODEV;
 339}
 340
 341static int is_nand_active(void)
 342{
 343        return 0;
 344}
 345#endif /* CONFIG_CMD_NAND */
 346
 347/********************************************************************
 348 *     USB services
 349 ********************************************************************/
 350#if defined(CONFIG_USB_STORAGE) && defined(CONFIG_BLK)
 351static size_t usb_read_file(const char *file_name)
 352{
 353        loff_t act_read = 0;
 354        struct udevice *dev;
 355        int rc;
 356
 357        usb_stop();
 358
 359        if (usb_init() < 0) {
 360                printf("Error: usb_init failed\n");
 361                return 0;
 362        }
 363
 364        /* Try to recognize storage devices immediately */
 365        blk_first_device(IF_TYPE_USB, &dev);
 366        if (!dev) {
 367                printf("Error: USB storage device not found\n");
 368                return 0;
 369        }
 370
 371        /* Always load from usb 0 */
 372        if (fs_set_blk_dev("usb", "0", FS_TYPE_ANY)) {
 373                printf("Error: USB 0 not found\n");
 374                return 0;
 375        }
 376
 377        /* Perfrom file read */
 378        rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
 379        if (rc)
 380                return 0;
 381
 382        return act_read;
 383}
 384
 385static int is_usb_active(void)
 386{
 387        return 1;
 388}
 389
 390#else /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
 391static size_t usb_read_file(const char *file_name)
 392{
 393        return 0;
 394}
 395
 396static int is_usb_active(void)
 397{
 398        return 0;
 399}
 400#endif /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
 401
 402/********************************************************************
 403 *     Network services
 404 ********************************************************************/
 405#ifdef CONFIG_CMD_NET
 406static size_t tftp_read_file(const char *file_name)
 407{
 408        /* update global variable load_addr before tftp file from network */
 409        load_addr = get_load_addr();
 410        return net_loop(TFTPGET);
 411}
 412
 413static int is_tftp_active(void)
 414{
 415        return 1;
 416}
 417
 418#else
 419static size_t tftp_read_file(const char *file_name)
 420{
 421        return 0;
 422}
 423
 424static int is_tftp_active(void)
 425{
 426        return 0;
 427}
 428#endif /* CONFIG_CMD_NET */
 429
 430enum bubt_devices {
 431        BUBT_DEV_NET = 0,
 432        BUBT_DEV_USB,
 433        BUBT_DEV_MMC,
 434        BUBT_DEV_SPI,
 435        BUBT_DEV_NAND,
 436
 437        BUBT_MAX_DEV
 438};
 439
 440struct bubt_dev bubt_devs[BUBT_MAX_DEV] = {
 441        {"tftp", tftp_read_file, NULL, is_tftp_active},
 442        {"usb",  usb_read_file,  NULL, is_usb_active},
 443        {"mmc",  mmc_read_file,  mmc_burn_image, is_mmc_active},
 444        {"spi",  NULL, spi_burn_image,  is_spi_active},
 445        {"nand", NULL, nand_burn_image, is_nand_active},
 446};
 447
 448static int bubt_write_file(struct bubt_dev *dst, size_t image_size)
 449{
 450        if (!dst->write) {
 451                printf("Error: Write not supported on device %s\n", dst->name);
 452                return -ENOTSUPP;
 453        }
 454
 455        return dst->write(image_size);
 456}
 457
 458#if defined(CONFIG_ARMADA_8K)
 459u32 do_checksum32(u32 *start, int32_t len)
 460{
 461        u32 sum = 0;
 462        u32 *startp = start;
 463
 464        do {
 465                sum += *startp;
 466                startp++;
 467                len -= 4;
 468        } while (len > 0);
 469
 470        return sum;
 471}
 472
 473static int check_image_header(void)
 474{
 475        struct mvebu_image_header *hdr =
 476                        (struct mvebu_image_header *)get_load_addr();
 477        u32 header_len = hdr->prolog_size;
 478        u32 checksum;
 479        u32 checksum_ref = hdr->prolog_checksum;
 480
 481        /*
 482         * For now compare checksum, and magic. Later we can
 483         * verify more stuff on the header like interface type, etc
 484         */
 485        if (hdr->magic != MAIN_HDR_MAGIC) {
 486                printf("ERROR: Bad MAGIC 0x%08x != 0x%08x\n",
 487                       hdr->magic, MAIN_HDR_MAGIC);
 488                return -ENOEXEC;
 489        }
 490
 491        /* The checksum value is discarded from checksum calculation */
 492        hdr->prolog_checksum = 0;
 493
 494        checksum = do_checksum32((u32 *)hdr, header_len);
 495        if (checksum != checksum_ref) {
 496                printf("Error: Bad Image checksum. 0x%x != 0x%x\n",
 497                       checksum, checksum_ref);
 498                return -ENOEXEC;
 499        }
 500
 501        /* Restore the checksum before writing */
 502        hdr->prolog_checksum = checksum_ref;
 503        printf("Image checksum...OK!\n");
 504
 505        return 0;
 506}
 507#elif defined(CONFIG_ARMADA_3700) /* Armada 3700 */
 508static int check_image_header(void)
 509{
 510        struct common_tim_data *hdr = (struct common_tim_data *)get_load_addr();
 511        int image_num;
 512        u8 hash_160_output[SHA1_SUM_LEN];
 513        u8 hash_256_output[SHA256_SUM_LEN];
 514        sha1_context hash1_text;
 515        sha256_context hash256_text;
 516        u8 *hash_output;
 517        u32 hash_algorithm_id;
 518        u32 image_size_to_hash;
 519        u32 flash_entry_addr;
 520        u32 *hash_value;
 521        u32 internal_hash[HASH_SUM_LEN];
 522        const u8 *buff;
 523        u32 num_of_image = hdr->num_images;
 524        u32 version = hdr->version;
 525        u32 trusted = hdr->trusted;
 526
 527        /* bubt checksum validation only supports nontrusted images */
 528        if (trusted == 1) {
 529                printf("bypass image validation, ");
 530                printf("only untrusted image is supported now\n");
 531                return 0;
 532        }
 533        /* only supports image version 3.5 and 3.6 */
 534        if (version != IMAGE_VERSION_3_5_0 && version != IMAGE_VERSION_3_6_0) {
 535                printf("Error: Unsupported Image version = 0x%08x\n", version);
 536                return -ENOEXEC;
 537        }
 538        /* validate images hash value */
 539        for (image_num = 0; image_num < num_of_image; image_num++) {
 540                struct mvebu_image_info *info =
 541                                (struct mvebu_image_info *)(get_load_addr() +
 542                                sizeof(struct common_tim_data) +
 543                                image_num * sizeof(struct mvebu_image_info));
 544                hash_algorithm_id = info->hash_algorithm_id;
 545                image_size_to_hash = info->image_size_to_hash;
 546                flash_entry_addr = info->flash_entry_addr;
 547                hash_value = info->hash;
 548                buff = (const u8 *)(get_load_addr() + flash_entry_addr);
 549
 550                if (image_num == 0) {
 551                        /*
 552                         * The first image includes hash values in its content.
 553                         * For hash calculation, we need to save the original
 554                         * hash values to a local variable that will be
 555                         * copied back for comparsion and set all zeros to
 556                         * the orignal hash values for calculating new value.
 557                         * First image original format :
 558                         * x...x (datum1) x...x(orig. hash values) x...x(datum2)
 559                         * Replaced first image format :
 560                         * x...x (datum1) 0...0(hash values) x...x(datum2)
 561                         */
 562                        memcpy(internal_hash, hash_value,
 563                               sizeof(internal_hash));
 564                        memset(hash_value, 0, sizeof(internal_hash));
 565                }
 566                if (image_size_to_hash == 0) {
 567                        printf("Warning: Image_%d hash checksum is disabled, ",
 568                               image_num);
 569                        printf("skip the image validation.\n");
 570                        continue;
 571                }
 572                switch (hash_algorithm_id) {
 573                case SHA1_SUM_LEN:
 574                        sha1_starts(&hash1_text);
 575                        sha1_update(&hash1_text, buff, image_size_to_hash);
 576                        sha1_finish(&hash1_text, hash_160_output);
 577                        hash_output = hash_160_output;
 578                        break;
 579                case SHA256_SUM_LEN:
 580                        sha256_starts(&hash256_text);
 581                        sha256_update(&hash256_text, buff, image_size_to_hash);
 582                        sha256_finish(&hash256_text, hash_256_output);
 583                        hash_output = hash_256_output;
 584                        break;
 585                default:
 586                        printf("Error: Unsupported hash_algorithm_id = %d\n",
 587                               hash_algorithm_id);
 588                        return -ENOEXEC;
 589                }
 590                if (image_num == 0)
 591                        memcpy(hash_value, internal_hash,
 592                               sizeof(internal_hash));
 593                if (memcmp(hash_value, hash_output, hash_algorithm_id) != 0) {
 594                        printf("Error: Image_%d checksum is not correct\n",
 595                               image_num);
 596                        return -ENOEXEC;
 597                }
 598        }
 599        printf("Image checksum...OK!\n");
 600
 601        return 0;
 602}
 603
 604#else /* Not ARMADA? */
 605static int check_image_header(void)
 606{
 607        printf("bubt cmd does not support this SoC device or family!\n");
 608        return -ENOEXEC;
 609}
 610#endif
 611
 612static int bubt_verify(size_t image_size)
 613{
 614        int err;
 615
 616        /* Check a correct image header exists */
 617        err = check_image_header();
 618        if (err) {
 619                printf("Error: Image header verification failed\n");
 620                return err;
 621        }
 622
 623        return 0;
 624}
 625
 626static int bubt_read_file(struct bubt_dev *src)
 627{
 628        size_t image_size;
 629
 630        if (!src->read) {
 631                printf("Error: Read not supported on device \"%s\"\n",
 632                       src->name);
 633                return 0;
 634        }
 635
 636        image_size = src->read(net_boot_file_name);
 637        if (image_size <= 0) {
 638                printf("Error: Failed to read file %s from %s\n",
 639                       net_boot_file_name, src->name);
 640                return 0;
 641        }
 642
 643        return image_size;
 644}
 645
 646static int bubt_is_dev_active(struct bubt_dev *dev)
 647{
 648        if (!dev->active) {
 649                printf("Device \"%s\" not supported by U-BOOT image\n",
 650                       dev->name);
 651                return 0;
 652        }
 653
 654        if (!dev->active()) {
 655                printf("Device \"%s\" is inactive\n", dev->name);
 656                return 0;
 657        }
 658
 659        return 1;
 660}
 661
 662struct bubt_dev *find_bubt_dev(char *dev_name)
 663{
 664        int dev;
 665
 666        for (dev = 0; dev < BUBT_MAX_DEV; dev++) {
 667                if (strcmp(bubt_devs[dev].name, dev_name) == 0)
 668                        return &bubt_devs[dev];
 669        }
 670
 671        return 0;
 672}
 673
 674#define DEFAULT_BUBT_SRC "tftp"
 675
 676#ifndef DEFAULT_BUBT_DST
 677#ifdef CONFIG_MVEBU_SPI_BOOT
 678#define DEFAULT_BUBT_DST "spi"
 679#elif defined(CONFIG_MVEBU_NAND_BOOT)
 680#define DEFAULT_BUBT_DST "nand"
 681#elif defined(CONFIG_MVEBU_MMC_BOOT)
 682#define DEFAULT_BUBT_DST "mmc"
 683else
 684#define DEFAULT_BUBT_DST "error"
 685#endif
 686#endif /* DEFAULT_BUBT_DST */
 687
 688int do_bubt_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 689{
 690        struct bubt_dev *src, *dst;
 691        size_t image_size;
 692        char src_dev_name[8];
 693        char dst_dev_name[8];
 694        char *name;
 695        int  err;
 696
 697        if (argc < 2)
 698                copy_filename(net_boot_file_name,
 699                              CONFIG_MVEBU_UBOOT_DFLT_NAME,
 700                              sizeof(net_boot_file_name));
 701        else
 702                copy_filename(net_boot_file_name, argv[1],
 703                              sizeof(net_boot_file_name));
 704
 705        if (argc >= 3) {
 706                strncpy(dst_dev_name, argv[2], 8);
 707        } else {
 708                name = DEFAULT_BUBT_DST;
 709                strncpy(dst_dev_name, name, 8);
 710        }
 711
 712        if (argc >= 4)
 713                strncpy(src_dev_name, argv[3], 8);
 714        else
 715                strncpy(src_dev_name, DEFAULT_BUBT_SRC, 8);
 716
 717        /* Figure out the destination device */
 718        dst = find_bubt_dev(dst_dev_name);
 719        if (!dst) {
 720                printf("Error: Unknown destination \"%s\"\n", dst_dev_name);
 721                return -EINVAL;
 722        }
 723
 724        if (!bubt_is_dev_active(dst))
 725                return -ENODEV;
 726
 727        /* Figure out the source device */
 728        src = find_bubt_dev(src_dev_name);
 729        if (!src) {
 730                printf("Error: Unknown source \"%s\"\n", src_dev_name);
 731                return 1;
 732        }
 733
 734        if (!bubt_is_dev_active(src))
 735                return -ENODEV;
 736
 737        printf("Burning U-BOOT image \"%s\" from \"%s\" to \"%s\"\n",
 738               net_boot_file_name, src->name, dst->name);
 739
 740        image_size = bubt_read_file(src);
 741        if (!image_size)
 742                return -EIO;
 743
 744        err = bubt_verify(image_size);
 745        if (err)
 746                return err;
 747
 748        err = bubt_write_file(dst, image_size);
 749        if (err)
 750                return err;
 751
 752        return 0;
 753}
 754
 755U_BOOT_CMD(
 756        bubt, 4, 0, do_bubt_cmd,
 757        "Burn a u-boot image to flash",
 758        "[file-name] [destination [source]]\n"
 759        "\t-file-name     The image file name to burn. Default = flash-image.bin\n"
 760        "\t-destination   Flash to burn to [spi, nand, mmc]. Default = active boot device\n"
 761        "\t-source        The source to load image from [tftp, usb, mmc]. Default = tftp\n"
 762        "Examples:\n"
 763        "\tbubt - Burn flash-image.bin from tftp to active boot device\n"
 764        "\tbubt flash-image-new.bin nand - Burn flash-image-new.bin from tftp to NAND flash\n"
 765        "\tbubt backup-flash-image.bin mmc usb - Burn backup-flash-image.bin from usb to MMC\n"
 766
 767);
 768