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