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 <env.h>
  11#include <flash.h>
  12#include <image.h>
  13#include <net.h>
  14#include <vsprintf.h>
  15#include <errno.h>
  16#include <dm.h>
  17
  18#include <spi_flash.h>
  19#include <spi.h>
  20#include <nand.h>
  21#include <usb.h>
  22#include <fs.h>
  23#include <mmc.h>
  24#ifdef CONFIG_BLK
  25#include <blk.h>
  26#endif
  27#include <u-boot/sha1.h>
  28#include <u-boot/sha256.h>
  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
  87
  88/* Structure of the main header, version 1 (Armada 370/XP/375/38x/39x) */
  89struct a38x_main_hdr_v1 {
  90        u8  blockid;               /* 0x0       */
  91        u8  flags;                 /* 0x1       */
  92        u16 nandpagesize;          /* 0x2-0x3   */
  93        u32 blocksize;             /* 0x4-0x7   */
  94        u8  version;               /* 0x8       */
  95        u8  headersz_msb;          /* 0x9       */
  96        u16 headersz_lsb;          /* 0xA-0xB   */
  97        u32 srcaddr;               /* 0xC-0xF   */
  98        u32 destaddr;              /* 0x10-0x13 */
  99        u32 execaddr;              /* 0x14-0x17 */
 100        u8  options;               /* 0x18      */
 101        u8  nandblocksize;         /* 0x19      */
 102        u8  nandbadblklocation;    /* 0x1A      */
 103        u8  reserved4;             /* 0x1B      */
 104        u16 reserved5;             /* 0x1C-0x1D */
 105        u8  ext;                   /* 0x1E      */
 106        u8  checksum;              /* 0x1F      */
 107};
 108
 109struct a38x_boot_mode {
 110        unsigned int id;
 111        const char *name;
 112};
 113
 114/* The blockid header field values used to indicate boot device of image */
 115struct a38x_boot_mode a38x_boot_modes[] = {
 116        { 0x4D, "i2c"  },
 117        { 0x5A, "spi"  },
 118        { 0x69, "uart" },
 119        { 0x78, "sata" },
 120        { 0x8B, "nand" },
 121        { 0x9C, "pex"  },
 122        { 0xAE, "mmc"  },
 123        {},
 124};
 125
 126struct bubt_dev {
 127        char name[8];
 128        size_t (*read)(const char *file_name);
 129        int (*write)(size_t image_size);
 130        int (*active)(void);
 131};
 132
 133static ulong get_load_addr(void)
 134{
 135        const char *addr_str;
 136        unsigned long addr;
 137
 138        addr_str = env_get("loadaddr");
 139        if (addr_str)
 140                addr = hextoul(addr_str, NULL);
 141        else
 142                addr = CONFIG_SYS_LOAD_ADDR;
 143
 144        return addr;
 145}
 146
 147/********************************************************************
 148 *     eMMC services
 149 ********************************************************************/
 150#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(MMC_WRITE)
 151static int mmc_burn_image(size_t image_size)
 152{
 153        struct mmc      *mmc;
 154        lbaint_t        start_lba;
 155        lbaint_t        blk_count;
 156        ulong           blk_written;
 157        int             err;
 158        const u8        mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
 159#ifdef CONFIG_BLK
 160        struct blk_desc *blk_desc;
 161#endif
 162        mmc = find_mmc_device(mmc_dev_num);
 163        if (!mmc) {
 164                printf("No SD/MMC/eMMC card found\n");
 165                return -ENOMEDIUM;
 166        }
 167
 168        err = mmc_init(mmc);
 169        if (err) {
 170                printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
 171                       mmc_dev_num);
 172                return err;
 173        }
 174
 175        /* SD reserves LBA-0 for MBR and boots from LBA-1,
 176         * MMC/eMMC boots from LBA-0
 177         */
 178        start_lba = IS_SD(mmc) ? 1 : 0;
 179#ifdef CONFIG_BLK
 180        blk_count = image_size / mmc->write_bl_len;
 181        if (image_size % mmc->write_bl_len)
 182                blk_count += 1;
 183
 184        blk_desc = mmc_get_blk_desc(mmc);
 185        if (!blk_desc) {
 186                printf("Error - failed to obtain block descriptor\n");
 187                return -ENODEV;
 188        }
 189        blk_written = blk_dwrite(blk_desc, start_lba, blk_count,
 190                                 (void *)get_load_addr());
 191#else
 192        blk_count = image_size / mmc->block_dev.blksz;
 193        if (image_size % mmc->block_dev.blksz)
 194                blk_count += 1;
 195
 196        blk_written = mmc->block_dev.block_write(mmc_dev_num,
 197                                                 start_lba, blk_count,
 198                                                 (void *)get_load_addr());
 199#endif /* CONFIG_BLK */
 200        if (blk_written != blk_count) {
 201                printf("Error - written %#lx blocks\n", blk_written);
 202                return -ENOSPC;
 203        }
 204        printf("Done!\n");
 205
 206        return 0;
 207}
 208
 209static size_t mmc_read_file(const char *file_name)
 210{
 211        loff_t          act_read = 0;
 212        int             rc;
 213        struct mmc      *mmc;
 214        const u8        mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
 215
 216        mmc = find_mmc_device(mmc_dev_num);
 217        if (!mmc) {
 218                printf("No SD/MMC/eMMC card found\n");
 219                return 0;
 220        }
 221
 222        if (mmc_init(mmc)) {
 223                printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
 224                       mmc_dev_num);
 225                return 0;
 226        }
 227
 228        /* Load from data partition (0) */
 229        if (fs_set_blk_dev("mmc", "0", FS_TYPE_ANY)) {
 230                printf("Error: MMC 0 not found\n");
 231                return 0;
 232        }
 233
 234        /* Perfrom file read */
 235        rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
 236        if (rc)
 237                return 0;
 238
 239        return act_read;
 240}
 241
 242static int is_mmc_active(void)
 243{
 244        return 1;
 245}
 246#else /* CONFIG_DM_MMC */
 247static int mmc_burn_image(size_t image_size)
 248{
 249        return -ENODEV;
 250}
 251
 252static size_t mmc_read_file(const char *file_name)
 253{
 254        return 0;
 255}
 256
 257static int is_mmc_active(void)
 258{
 259        return 0;
 260}
 261#endif /* CONFIG_DM_MMC */
 262
 263/********************************************************************
 264 *     SPI services
 265 ********************************************************************/
 266#ifdef CONFIG_SPI_FLASH
 267static int spi_burn_image(size_t image_size)
 268{
 269        int ret;
 270        struct spi_flash *flash;
 271        u32 erase_bytes;
 272
 273        /* Probe the SPI bus to get the flash device */
 274        flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
 275                                CONFIG_ENV_SPI_CS,
 276                                CONFIG_SF_DEFAULT_SPEED,
 277                                CONFIG_SF_DEFAULT_MODE);
 278        if (!flash) {
 279                printf("Failed to probe SPI Flash\n");
 280                return -ENOMEDIUM;
 281        }
 282
 283        erase_bytes = image_size +
 284                (flash->erase_size - image_size % flash->erase_size);
 285        printf("Erasing %d bytes (%d blocks) at offset 0 ...",
 286               erase_bytes, erase_bytes / flash->erase_size);
 287        ret = spi_flash_erase(flash, 0, erase_bytes);
 288        if (ret)
 289                printf("Error!\n");
 290        else
 291                printf("Done!\n");
 292
 293        printf("Writing %d bytes from 0x%lx to offset 0 ...",
 294               (int)image_size, get_load_addr());
 295        ret = spi_flash_write(flash, 0, image_size, (void *)get_load_addr());
 296        if (ret)
 297                printf("Error!\n");
 298        else
 299                printf("Done!\n");
 300
 301        return ret;
 302}
 303
 304static int is_spi_active(void)
 305{
 306        return 1;
 307}
 308
 309#else /* CONFIG_SPI_FLASH */
 310static int spi_burn_image(size_t image_size)
 311{
 312        return -ENODEV;
 313}
 314
 315static int is_spi_active(void)
 316{
 317        return 0;
 318}
 319#endif /* CONFIG_SPI_FLASH */
 320
 321/********************************************************************
 322 *     NAND services
 323 ********************************************************************/
 324#ifdef CONFIG_CMD_NAND
 325static int nand_burn_image(size_t image_size)
 326{
 327        int ret;
 328        uint32_t block_size;
 329        struct mtd_info *mtd;
 330
 331        mtd = get_nand_dev_by_index(nand_curr_device);
 332        if (!mtd) {
 333                puts("\nno devices available\n");
 334                return -ENOMEDIUM;
 335        }
 336        block_size = mtd->erasesize;
 337
 338        /* Align U-Boot size to currently used blocksize */
 339        image_size = ((image_size + (block_size - 1)) & (~(block_size - 1)));
 340
 341        /* Erase the U-Boot image space */
 342        printf("Erasing 0x%x - 0x%x:...", 0, (int)image_size);
 343        ret = nand_erase(mtd, 0, image_size);
 344        if (ret) {
 345                printf("Error!\n");
 346                goto error;
 347        }
 348        printf("Done!\n");
 349
 350        /* Write the image to flash */
 351        printf("Writing %d bytes from 0x%lx to offset 0 ... ",
 352               (int)image_size, get_load_addr());
 353        ret = nand_write(mtd, 0, &image_size, (void *)get_load_addr());
 354        if (ret)
 355                printf("Error!\n");
 356        else
 357                printf("Done!\n");
 358
 359error:
 360        return ret;
 361}
 362
 363static int is_nand_active(void)
 364{
 365        return 1;
 366}
 367
 368#else /* CONFIG_CMD_NAND */
 369static int nand_burn_image(size_t image_size)
 370{
 371        return -ENODEV;
 372}
 373
 374static int is_nand_active(void)
 375{
 376        return 0;
 377}
 378#endif /* CONFIG_CMD_NAND */
 379
 380/********************************************************************
 381 *     USB services
 382 ********************************************************************/
 383#if defined(CONFIG_USB_STORAGE) && defined(CONFIG_BLK)
 384static size_t usb_read_file(const char *file_name)
 385{
 386        loff_t act_read = 0;
 387        struct udevice *dev;
 388        int rc;
 389
 390        usb_stop();
 391
 392        if (usb_init() < 0) {
 393                printf("Error: usb_init failed\n");
 394                return 0;
 395        }
 396
 397        /* Try to recognize storage devices immediately */
 398        blk_first_device(IF_TYPE_USB, &dev);
 399        if (!dev) {
 400                printf("Error: USB storage device not found\n");
 401                return 0;
 402        }
 403
 404        /* Always load from usb 0 */
 405        if (fs_set_blk_dev("usb", "0", FS_TYPE_ANY)) {
 406                printf("Error: USB 0 not found\n");
 407                return 0;
 408        }
 409
 410        /* Perfrom file read */
 411        rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
 412        if (rc)
 413                return 0;
 414
 415        return act_read;
 416}
 417
 418static int is_usb_active(void)
 419{
 420        return 1;
 421}
 422
 423#else /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
 424static size_t usb_read_file(const char *file_name)
 425{
 426        return 0;
 427}
 428
 429static int is_usb_active(void)
 430{
 431        return 0;
 432}
 433#endif /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
 434
 435/********************************************************************
 436 *     Network services
 437 ********************************************************************/
 438#ifdef CONFIG_CMD_NET
 439static size_t tftp_read_file(const char *file_name)
 440{
 441        /*
 442         * update global variable image_load_addr before tftp file from network
 443         */
 444        image_load_addr = get_load_addr();
 445        return net_loop(TFTPGET);
 446}
 447
 448static int is_tftp_active(void)
 449{
 450        return 1;
 451}
 452
 453#else
 454static size_t tftp_read_file(const char *file_name)
 455{
 456        return 0;
 457}
 458
 459static int is_tftp_active(void)
 460{
 461        return 0;
 462}
 463#endif /* CONFIG_CMD_NET */
 464
 465enum bubt_devices {
 466        BUBT_DEV_NET = 0,
 467        BUBT_DEV_USB,
 468        BUBT_DEV_MMC,
 469        BUBT_DEV_SPI,
 470        BUBT_DEV_NAND,
 471
 472        BUBT_MAX_DEV
 473};
 474
 475struct bubt_dev bubt_devs[BUBT_MAX_DEV] = {
 476        {"tftp", tftp_read_file, NULL, is_tftp_active},
 477        {"usb",  usb_read_file,  NULL, is_usb_active},
 478        {"mmc",  mmc_read_file,  mmc_burn_image, is_mmc_active},
 479        {"spi",  NULL, spi_burn_image,  is_spi_active},
 480        {"nand", NULL, nand_burn_image, is_nand_active},
 481};
 482
 483static int bubt_write_file(struct bubt_dev *dst, size_t image_size)
 484{
 485        if (!dst->write) {
 486                printf("Error: Write not supported on device %s\n", dst->name);
 487                return -ENOTSUPP;
 488        }
 489
 490        return dst->write(image_size);
 491}
 492
 493#if defined(CONFIG_ARMADA_8K)
 494u32 do_checksum32(u32 *start, int32_t len)
 495{
 496        u32 sum = 0;
 497        u32 *startp = start;
 498
 499        do {
 500                sum += *startp;
 501                startp++;
 502                len -= 4;
 503        } while (len > 0);
 504
 505        return sum;
 506}
 507
 508static int check_image_header(void)
 509{
 510        struct mvebu_image_header *hdr =
 511                        (struct mvebu_image_header *)get_load_addr();
 512        u32 header_len = hdr->prolog_size;
 513        u32 checksum;
 514        u32 checksum_ref = hdr->prolog_checksum;
 515
 516        /*
 517         * For now compare checksum, and magic. Later we can
 518         * verify more stuff on the header like interface type, etc
 519         */
 520        if (hdr->magic != MAIN_HDR_MAGIC) {
 521                printf("ERROR: Bad MAGIC 0x%08x != 0x%08x\n",
 522                       hdr->magic, MAIN_HDR_MAGIC);
 523                return -ENOEXEC;
 524        }
 525
 526        /* The checksum value is discarded from checksum calculation */
 527        hdr->prolog_checksum = 0;
 528
 529        checksum = do_checksum32((u32 *)hdr, header_len);
 530        if (checksum != checksum_ref) {
 531                printf("Error: Bad Image checksum. 0x%x != 0x%x\n",
 532                       checksum, checksum_ref);
 533                return -ENOEXEC;
 534        }
 535
 536        /* Restore the checksum before writing */
 537        hdr->prolog_checksum = checksum_ref;
 538        printf("Image checksum...OK!\n");
 539
 540        return 0;
 541}
 542#elif defined(CONFIG_ARMADA_3700) /* Armada 3700 */
 543static int check_image_header(void)
 544{
 545        struct common_tim_data *hdr = (struct common_tim_data *)get_load_addr();
 546        int image_num;
 547        u8 hash_160_output[SHA1_SUM_LEN];
 548        u8 hash_256_output[SHA256_SUM_LEN];
 549        sha1_context hash1_text;
 550        sha256_context hash256_text;
 551        u8 *hash_output;
 552        u32 hash_algorithm_id;
 553        u32 image_size_to_hash;
 554        u32 flash_entry_addr;
 555        u32 *hash_value;
 556        u32 internal_hash[HASH_SUM_LEN];
 557        const u8 *buff;
 558        u32 num_of_image = hdr->num_images;
 559        u32 version = hdr->version;
 560        u32 trusted = hdr->trusted;
 561
 562        /* bubt checksum validation only supports nontrusted images */
 563        if (trusted == 1) {
 564                printf("bypass image validation, ");
 565                printf("only untrusted image is supported now\n");
 566                return 0;
 567        }
 568        /* only supports image version 3.5 and 3.6 */
 569        if (version != IMAGE_VERSION_3_5_0 && version != IMAGE_VERSION_3_6_0) {
 570                printf("Error: Unsupported Image version = 0x%08x\n", version);
 571                return -ENOEXEC;
 572        }
 573        /* validate images hash value */
 574        for (image_num = 0; image_num < num_of_image; image_num++) {
 575                struct mvebu_image_info *info =
 576                                (struct mvebu_image_info *)(get_load_addr() +
 577                                sizeof(struct common_tim_data) +
 578                                image_num * sizeof(struct mvebu_image_info));
 579                hash_algorithm_id = info->hash_algorithm_id;
 580                image_size_to_hash = info->image_size_to_hash;
 581                flash_entry_addr = info->flash_entry_addr;
 582                hash_value = info->hash;
 583                buff = (const u8 *)(get_load_addr() + flash_entry_addr);
 584
 585                if (image_num == 0) {
 586                        /*
 587                         * The first image includes hash values in its content.
 588                         * For hash calculation, we need to save the original
 589                         * hash values to a local variable that will be
 590                         * copied back for comparsion and set all zeros to
 591                         * the orignal hash values for calculating new value.
 592                         * First image original format :
 593                         * x...x (datum1) x...x(orig. hash values) x...x(datum2)
 594                         * Replaced first image format :
 595                         * x...x (datum1) 0...0(hash values) x...x(datum2)
 596                         */
 597                        memcpy(internal_hash, hash_value,
 598                               sizeof(internal_hash));
 599                        memset(hash_value, 0, sizeof(internal_hash));
 600                }
 601                if (image_size_to_hash == 0) {
 602                        printf("Warning: Image_%d hash checksum is disabled, ",
 603                               image_num);
 604                        printf("skip the image validation.\n");
 605                        continue;
 606                }
 607                switch (hash_algorithm_id) {
 608                case SHA1_SUM_LEN:
 609                        sha1_starts(&hash1_text);
 610                        sha1_update(&hash1_text, buff, image_size_to_hash);
 611                        sha1_finish(&hash1_text, hash_160_output);
 612                        hash_output = hash_160_output;
 613                        break;
 614                case SHA256_SUM_LEN:
 615                        sha256_starts(&hash256_text);
 616                        sha256_update(&hash256_text, buff, image_size_to_hash);
 617                        sha256_finish(&hash256_text, hash_256_output);
 618                        hash_output = hash_256_output;
 619                        break;
 620                default:
 621                        printf("Error: Unsupported hash_algorithm_id = %d\n",
 622                               hash_algorithm_id);
 623                        return -ENOEXEC;
 624                }
 625                if (image_num == 0)
 626                        memcpy(hash_value, internal_hash,
 627                               sizeof(internal_hash));
 628                if (memcmp(hash_value, hash_output, hash_algorithm_id) != 0) {
 629                        printf("Error: Image_%d checksum is not correct\n",
 630                               image_num);
 631                        return -ENOEXEC;
 632                }
 633        }
 634        printf("Image checksum...OK!\n");
 635
 636        return 0;
 637}
 638#elif defined(CONFIG_ARMADA_38X)
 639static size_t a38x_header_size(const struct a38x_main_hdr_v1 *h)
 640{
 641        if (h->version == 1)
 642                return (h->headersz_msb << 16) | le16_to_cpu(h->headersz_lsb);
 643
 644        printf("Error: Invalid A38x image (header version 0x%x unknown)!\n",
 645               h->version);
 646        return 0;
 647}
 648
 649static uint8_t image_checksum8(const void *start, size_t len)
 650{
 651        u8 csum = 0;
 652        const u8 *p = start;
 653
 654        while (len) {
 655                csum += *p;
 656                ++p;
 657                --len;
 658        }
 659
 660        return csum;
 661}
 662
 663static int check_image_header(void)
 664{
 665        u8 checksum;
 666        const struct a38x_main_hdr_v1 *hdr =
 667                (struct a38x_main_hdr_v1 *)get_load_addr();
 668        const size_t image_size = a38x_header_size(hdr);
 669
 670        if (!image_size)
 671                return -ENOEXEC;
 672
 673        checksum = image_checksum8(hdr, image_size);
 674        checksum -= hdr->checksum;
 675        if (checksum != hdr->checksum) {
 676                printf("Error: Bad A38x image checksum. 0x%x != 0x%x\n",
 677                       checksum, hdr->checksum);
 678                return -ENOEXEC;
 679        }
 680
 681        printf("Image checksum...OK!\n");
 682        return 0;
 683}
 684#else /* Not ARMADA? */
 685static int check_image_header(void)
 686{
 687        printf("bubt cmd does not support this SoC device or family!\n");
 688        return -ENOEXEC;
 689}
 690#endif
 691
 692static int bubt_check_boot_mode(const struct bubt_dev *dst)
 693{
 694        if (IS_ENABLED(CONFIG_ARMADA_38X)) {
 695                int mode;
 696                const struct a38x_main_hdr_v1 *hdr =
 697                        (struct a38x_main_hdr_v1 *)get_load_addr();
 698
 699                for (mode = 0; mode < ARRAY_SIZE(a38x_boot_modes); mode++) {
 700                        if (strcmp(a38x_boot_modes[mode].name, dst->name) == 0)
 701                                break;
 702                }
 703
 704                if (a38x_boot_modes[mode].id == hdr->blockid)
 705                        return 0;
 706
 707                for (int i = 0; i < ARRAY_SIZE(a38x_boot_modes); i++) {
 708                        if (a38x_boot_modes[i].id == hdr->blockid) {
 709                                printf("Error: A38x image meant to be booted from "
 710                                       "\"%s\", not \"%s\"!\n",
 711                                       a38x_boot_modes[i].name, dst->name);
 712                                return -ENOEXEC;
 713                        }
 714                }
 715
 716                printf("Error: unknown boot device in A38x image header: "
 717                       "0x%x\n", hdr->blockid);
 718                return -ENOEXEC;
 719        } else {
 720                return 0;
 721        }
 722}
 723
 724static int bubt_verify(const struct bubt_dev *dst)
 725{
 726        int err;
 727
 728        /* Check a correct image header exists */
 729        err = check_image_header();
 730        if (err) {
 731                printf("Error: Image header verification failed\n");
 732                return err;
 733        }
 734
 735        err = bubt_check_boot_mode(dst);
 736        if (err) {
 737                printf("Error: Image boot mode verification failed\n");
 738                return err;
 739        }
 740
 741        return 0;
 742}
 743
 744static int bubt_read_file(struct bubt_dev *src)
 745{
 746        size_t image_size;
 747
 748        if (!src->read) {
 749                printf("Error: Read not supported on device \"%s\"\n",
 750                       src->name);
 751                return 0;
 752        }
 753
 754        image_size = src->read(net_boot_file_name);
 755        if (image_size <= 0) {
 756                printf("Error: Failed to read file %s from %s\n",
 757                       net_boot_file_name, src->name);
 758                return 0;
 759        }
 760
 761        return image_size;
 762}
 763
 764static int bubt_is_dev_active(struct bubt_dev *dev)
 765{
 766        if (!dev->active) {
 767                printf("Device \"%s\" not supported by U-Boot image\n",
 768                       dev->name);
 769                return 0;
 770        }
 771
 772        if (!dev->active()) {
 773                printf("Device \"%s\" is inactive\n", dev->name);
 774                return 0;
 775        }
 776
 777        return 1;
 778}
 779
 780struct bubt_dev *find_bubt_dev(char *dev_name)
 781{
 782        int dev;
 783
 784        for (dev = 0; dev < BUBT_MAX_DEV; dev++) {
 785                if (strcmp(bubt_devs[dev].name, dev_name) == 0)
 786                        return &bubt_devs[dev];
 787        }
 788
 789        return 0;
 790}
 791
 792#define DEFAULT_BUBT_SRC "tftp"
 793
 794#ifndef DEFAULT_BUBT_DST
 795#ifdef CONFIG_MVEBU_SPI_BOOT
 796#define DEFAULT_BUBT_DST "spi"
 797#elif defined(CONFIG_MVEBU_NAND_BOOT)
 798#define DEFAULT_BUBT_DST "nand"
 799#elif defined(CONFIG_MVEBU_MMC_BOOT)
 800#define DEFAULT_BUBT_DST "mmc"
 801#else
 802#define DEFAULT_BUBT_DST "error"
 803#endif
 804#endif /* DEFAULT_BUBT_DST */
 805
 806int do_bubt_cmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 807{
 808        struct bubt_dev *src, *dst;
 809        size_t image_size;
 810        char src_dev_name[8];
 811        char dst_dev_name[8];
 812        char *name;
 813        int  err;
 814
 815        if (argc < 2)
 816                copy_filename(net_boot_file_name,
 817                              CONFIG_MVEBU_UBOOT_DFLT_NAME,
 818                              sizeof(net_boot_file_name));
 819        else
 820                copy_filename(net_boot_file_name, argv[1],
 821                              sizeof(net_boot_file_name));
 822
 823        if (argc >= 3) {
 824                strncpy(dst_dev_name, argv[2], 8);
 825        } else {
 826                name = DEFAULT_BUBT_DST;
 827                strncpy(dst_dev_name, name, 8);
 828        }
 829
 830        if (argc >= 4)
 831                strncpy(src_dev_name, argv[3], 8);
 832        else
 833                strncpy(src_dev_name, DEFAULT_BUBT_SRC, 8);
 834
 835        /* Figure out the destination device */
 836        dst = find_bubt_dev(dst_dev_name);
 837        if (!dst) {
 838                printf("Error: Unknown destination \"%s\"\n", dst_dev_name);
 839                return -EINVAL;
 840        }
 841
 842        if (!bubt_is_dev_active(dst))
 843                return -ENODEV;
 844
 845        /* Figure out the source device */
 846        src = find_bubt_dev(src_dev_name);
 847        if (!src) {
 848                printf("Error: Unknown source \"%s\"\n", src_dev_name);
 849                return 1;
 850        }
 851
 852        if (!bubt_is_dev_active(src))
 853                return -ENODEV;
 854
 855        printf("Burning U-Boot image \"%s\" from \"%s\" to \"%s\"\n",
 856               net_boot_file_name, src->name, dst->name);
 857
 858        image_size = bubt_read_file(src);
 859        if (!image_size)
 860                return -EIO;
 861
 862        err = bubt_verify(dst);
 863        if (err)
 864                return err;
 865
 866        err = bubt_write_file(dst, image_size);
 867        if (err)
 868                return err;
 869
 870        return 0;
 871}
 872
 873U_BOOT_CMD(
 874        bubt, 4, 0, do_bubt_cmd,
 875        "Burn a u-boot image to flash",
 876        "[file-name] [destination [source]]\n"
 877        "\t-file-name     The image file name to burn. Default = " CONFIG_MVEBU_UBOOT_DFLT_NAME "\n"
 878        "\t-destination   Flash to burn to [spi, nand, mmc]. Default = " DEFAULT_BUBT_DST "\n"
 879        "\t-source        The source to load image from [tftp, usb, mmc]. Default = " DEFAULT_BUBT_SRC "\n"
 880        "Examples:\n"
 881        "\tbubt - Burn flash-image.bin from tftp to active boot device\n"
 882        "\tbubt flash-image-new.bin nand - Burn flash-image-new.bin from tftp to NAND flash\n"
 883        "\tbubt backup-flash-image.bin mmc usb - Burn backup-flash-image.bin from usb to MMC\n"
 884
 885);
 886