[U-Boot] [PATCH v2 2/6] arm64: mvebu: Add bubt command for flash image burn
Kostya Porotchkin
kostap at marvell.com
Tue Dec 6 10:06:18 CET 2016
Hi, Stefan,
> -----Original Message-----
> From: Stefan Roese [mailto:sr at denx.de]
> Sent: Tuesday, December 06, 2016 08:22
> To: Kostya Porotchkin; u-boot at lists.denx.de
> Cc: Nadav Haklai; Neta Zur Hershkovits; Omri Itach; Igal Liberman; Haim
> Boot; Hanna Hawa
> Subject: Re: [PATCH v2 2/6] arm64: mvebu: Add bubt command for flash
> image burn
>
> On 04.12.2016 17:12, kostap at marvell.com wrote:
> > From: Konstantin Porotchkin <kostap at marvell.com>
> >
> > Add support for mvebu bubt command for flash image load, check and
> > burn on boot device.
> >
> > Changes for v2:
> > - Add "bubt" documentation
> > - Fix code syntax
> >
> > Signed-off-by: Konstantin Porotchkin <kostap at marvell.com>
> > Cc: Stefan Roese <sr at denx.de>
> > Cc: Nadav Haklai <nadavh at marvell.com>
> > Cc: Neta Zur Hershkovits <neta at marvell.com>
> > Cc: Omri Itach <omrii at marvell.com>
> > Cc: Igal Liberman <igall at marvell.com>
> > Cc: Haim Boot <hayim at marvell.com>
> > Cc: Hanna Hawa <hannah at marvell.com>
> > ---
>
> Again, please move the patch version history.
>
> It seems that you missed to address most of my last review comments.
> I've added them again below. Please either address them or give me a
> short notice why not. Thanks.
>
> > arch/arm/mach-mvebu/Kconfig | 34 +++
> > cmd/Kconfig | 3 +
> > cmd/Makefile | 2 +
> > cmd/mvebu/Kconfig | 10 +
> > cmd/mvebu/Makefile | 8 +
> > cmd/mvebu/bubt.c | 726
> ++++++++++++++++++++++++++++++++++++++++++++
> > doc/mvebu/cmd/bubt.txt | 64 ++++
> > 7 files changed, 847 insertions(+)
> > create mode 100644 cmd/mvebu/Kconfig
> > create mode 100644 cmd/mvebu/Makefile create mode 100644
> > cmd/mvebu/bubt.c create mode 100644 doc/mvebu/cmd/bubt.txt
> >
> > diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
> > index 7248fd7..dba5c98 100644
> > --- a/arch/arm/mach-mvebu/Kconfig
> > +++ b/arch/arm/mach-mvebu/Kconfig
> > @@ -99,6 +99,40 @@ config TARGET_THEADORABLE
> >
> > endchoice
> >
> > +choice
> > + prompt "Flash for image"
> > + default MVEBU_SPI_BOOT
> > +
> > +config MVEBU_NAND_BOOT
> > + bool "NAND flash boot"
> > + depends on NAND_PXA3XX
> > + help
> > + Enable boot from NAND flash.
> > + Use NAND flash as a target for "bubt" command
> > +
> > +config MVEBU_SPI_BOOT
> > + bool "SPI flash boot"
> > + depends on SPI_FLASH
> > + help
> > + Enable boot from SPI flash.
> > + Use SPI flash as a target for "bubt" command
> > +
> > +config MVEBU_MMC_BOOT
> > + bool "eMMC flash boot"
> > + depends on MVEBU_MMC
> > + help
> > + Enable boot from eMMC boot partition
> > + Use eMMC/SD device as a target for "bubt" command
> > +
> > +endchoice
> > +
> > +config MVEBU_UBOOT_DFLT_NAME
> > + string "Default image name for bubt command"
> > + default "flash-image.bin"
> > + help
> > + This option should contain a default file name to be used with
> > + MVEBU "bubt" command if the source file name is omitted
> > +
>
> Again my question on this location of these Kconfig options. Wouldn't it
> be better, to move all Kconfig option into cmd/mvebu/Kconfig instead of
> having most of them in the mach-mvebu file?
>
> > config SYS_BOARD
> > default "clearfog" if TARGET_CLEARFOG
> > default "mvebu_db-88f3720" if TARGET_MVEBU_DB_88F3720 diff --git
> > a/cmd/Kconfig b/cmd/Kconfig index b16c603..b38d285 100644
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -632,6 +632,9 @@ config CMD_QFW
> > This provides access to the QEMU firmware interface. The main
> > feature is to allow easy loading of files passed to qemu-system
> > via -kernel / -initrd
> > +
> > +source "cmd/mvebu/Kconfig"
> > +
> > endmenu
> >
> > config CMD_BOOTSTAGE
> > diff --git a/cmd/Makefile b/cmd/Makefile index 9c9a9d1..34bc544 100644
> > --- a/cmd/Makefile
> > +++ b/cmd/Makefile
> > @@ -163,3 +163,5 @@ obj-$(CONFIG_CMD_BLOB) += blob.o
> >
> > # core command
> > obj-y += nvedit.o
> > +
> > +obj-$(CONFIG_ARCH_MVEBU) += mvebu/
> > diff --git a/cmd/mvebu/Kconfig b/cmd/mvebu/Kconfig new file mode
> > 100644 index 0000000..e7fbd20
> > --- /dev/null
> > +++ b/cmd/mvebu/Kconfig
> > @@ -0,0 +1,10 @@
> > +menu "MVEBU commands"
> > +depends on ARCH_MVEBU
> > +
> > +config CMD_MVEBU_BUBT
> > + bool "bubt"
> > + default n
> > + help
> > + bubt - Burn a u-boot image to flash
> > +
> > +endmenu
> > diff --git a/cmd/mvebu/Makefile b/cmd/mvebu/Makefile new file mode
> > 100644 index 0000000..03de53e
> > --- /dev/null
> > +++ b/cmd/mvebu/Makefile
> > @@ -0,0 +1,8 @@
> > +#
> > +# Copyright (C) 2016 Marvell International Ltd.
> > +#
> > +# SPDX-License-Identifier: GPL-2.0
> > +# https://spdx.org/licenses
> > +
> > +
> > +obj-$(CONFIG_CMD_MVEBU_BUBT) += bubt.o
> > diff --git a/cmd/mvebu/bubt.c b/cmd/mvebu/bubt.c new file mode 100644
> > index 0000000..1aee728
> > --- /dev/null
> > +++ b/cmd/mvebu/bubt.c
> > @@ -0,0 +1,726 @@
> > +/*
> > + * Copyright (C) 2016 Marvell International Ltd.
> > + *
> > + * SPDX-License-Identifier: GPL-2.0
> > + * https://spdx.org/licenses
> > + */
> > +
> > +#include <config.h>
> > +#include <common.h>
> > +#include <command.h>
> > +#include <vsprintf.h>
> > +#include <errno.h>
> > +#include <dm.h>
> > +
> > +#include <spi_flash.h>
> > +#include <spi.h>
> > +#include <nand.h>
> > +#include <usb.h>
> > +#include <fs.h>
> > +#include <mmc.h>
> > +#include <u-boot/sha1.h>
> > +#include <u-boot/sha256.h>
> > +
> > +#if defined(CONFIG_TARGET_MVEBU_ARMADA_8K)
>
> Please use CONFIG_ARMADA_8K instead. So below...
>
> > +#define MAIN_HDR_MAGIC 0xB105B002
> > +
> > +struct mvebu_image_header {
> > + u32 magic; /* 0-3 */
> > + u32 prolog_size; /* 4-7 */
> > + u32 prolog_checksum; /* 8-11 */
> > + u32 boot_image_size; /* 12-15 */
> > + u32 boot_image_checksum; /* 16-19 */
> > + u32 rsrvd0; /* 20-23 */
> > + u32 load_addr; /* 24-27 */
> > + u32 exec_addr; /* 28-31 */
> > + u8 uart_cfg; /* 32 */
> > + u8 baudrate; /* 33 */
> > + u8 ext_count; /* 34 */
> > + u8 aux_flags; /* 35 */
> > + u32 io_arg_0; /* 36-39 */
> > + u32 io_arg_1; /* 40-43 */
> > + u32 io_arg_2; /* 43-47 */
> > + u32 io_arg_3; /* 48-51 */
> > + u32 rsrvd1; /* 52-55 */
> > + u32 rsrvd2; /* 56-59 */
> > + u32 rsrvd3; /* 60-63 */
> > +};
> > +#elif defined(CONFIG_TARGET_MVEBU_DB_88F3720) /* A3700 */
>
> Please use CONFIG_ARMADA_3700 as this is most likely not board specific
> but platform (SoC) specific.
>
> > +#define HASH_SUM_LEN 16
> > +#define IMAGE_VERSION_3_6_0 0x030600
> > +#define IMAGE_VERSION_3_5_0 0x030500
> > +
> > +struct common_tim_data {
> > + u32 version;
> > + u32 identifier;
> > + u32 trusted;
> > + u32 issue_date;
> > + u32 oem_unique_id;
> > + u32 reserved[5]; /* Reserve 20 bytes */
> > + u32 boot_flash_sign;
> > + u32 num_images;
> > + u32 num_keys;
> > + u32 size_of_reserved;
> > +};
> > +
> > +struct mvebu_image_info {
> > + u32 image_id;
> > + u32 next_image_id;
> > + u32 flash_entry_addr;
> > + u32 load_addr;
> > + u32 image_size;
> > + u32 image_size_to_hash;
> > + u32 hash_algorithm_id;
> > + u32 hash[HASH_SUM_LEN]; /* Reserve 512 bits for the hash */
> > + u32 partition_number;
> > + u32 enc_algorithm_id;
> > + u32 encrypt_start_offset;
> > + u32 encrypt_size;
> > +};
> > +#endif
> > +
> > +struct bubt_dev {
> > + char name[8];
> > + size_t (*read)(const char *file_name);
> > + int (*write)(size_t image_size);
> > + int (*active)(void);
> > +};
> > +
> > +static ulong get_load_addr(void)
> > +{
> > + const char *addr_str;
> > + unsigned long addr;
> > +
> > + addr_str = getenv("loadaddr");
> > + if (addr_str)
> > + addr = simple_strtoul(addr_str, NULL, 16);
> > + else
> > + addr = CONFIG_SYS_LOAD_ADDR;
> > +
> > + return addr;
> > +}
> > +
> > +/********************************************************************
> > + * eMMC services
> > +
> > +********************************************************************/
> > +#ifdef CONFIG_DM_MMC
> > +static int mmc_burn_image(size_t image_size) {
> > + struct mmc *mmc;
> > + lbaint_t start_lba;
> > + lbaint_t blk_count;
> > + ulong blk_written;
> > + int err;
> > +#ifdef CONFIG_SYS_MMC_ENV_DEV
> > + const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
> > +#else
> > + const u8 mmc_dev_num = 0;
> > +#endif
>
> I suggest to move this one up in this file to make the code look a bit
> "cleaner", like this:
>
> #ifndef CONFIG_SYS_MMC_ENV_DEV
> #define CONFIG_SYS_MMC_ENV_DEV 0
> #endif
>
> Then you can remove the #ifdef from the code here.
>
> > +
> > + mmc = find_mmc_device(mmc_dev_num);
> > + if (!mmc) {
> > + printf("No SD/MMC/eMMC card found\n");
> > + return -ENOMEDIUM;
> > + }
> > +
> > + err = mmc_init(mmc);
> > + if (err) {
> > + printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
> > + mmc_dev_num);
> > + return err;
> > + }
> > +
> > +#ifdef CONFIG_SYS_MMC_ENV_PART
> > + if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART) {
> > + err = mmc_switch_part(mmc_dev_num, CONFIG_SYS_MMC_ENV_PART);
> > + if (err) {
> > + printf("MMC partition switch failed\n");
> > + return err;
> > + }
> > + }
> > +#endif
> > +
> > + /* SD reserves LBA-0 for MBR and boots from LBA-1,
> > + * MMC/eMMC boots from LBA-0
> > + */
> > + start_lba = IS_SD(mmc) ? 1 : 0;
> > + blk_count = image_size / mmc->block_dev.blksz;
> > + if (image_size % mmc->block_dev.blksz)
> > + blk_count += 1;
> > +
> > + blk_written = mmc->block_dev.block_write(mmc_dev_num,
> > + start_lba, blk_count,
> > + (void *)get_load_addr());
> > + if (blk_written != blk_count) {
> > + printf("Error - written %#lx blocks\n", blk_written);
> > + return -ENOSPC;
> > + }
> > + printf("Done!\n");
> > +
> > +#ifdef CONFIG_SYS_MMC_ENV_PART
> > + if (mmc->part_num != CONFIG_SYS_MMC_ENV_PART)
> > + mmc_switch_part(mmc_dev_num, mmc->part_num); #endif
> > +
> > + return 0;
> > +}
> > +
> > +static size_t mmc_read_file(const char *file_name) {
> > + loff_t act_read = 0;
> > + int rc;
> > + struct mmc *mmc;
> > +#ifdef CONFIG_SYS_MMC_ENV_DEV
> > + const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
> > +#else
> > + const u8 mmc_dev_num = 0;
> > +#endif
>
> Same comment here.
>
> > +
> > + mmc = find_mmc_device(mmc_dev_num);
> > + if (!mmc) {
> > + printf("No SD/MMC/eMMC card found\n");
> > + return 0;
> > + }
> > +
> > + if (mmc_init(mmc)) {
> > + printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
> > + mmc_dev_num);
> > + return 0;
> > + }
> > +
> > + /* Load from data partition (0) */
> > + if (fs_set_blk_dev("mmc", "0", FS_TYPE_ANY)) {
> > + printf("Error: MMC 0 not found\n");
> > + return 0;
> > + }
> > +
> > + /* Perfrom file read */
> > + rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
> > + if (rc)
> > + return 0;
> > +
> > + return act_read;
> > +}
> > +
> > +int is_mmc_active(void)
> > +{
> > + return 1;
> > +}
> > +#else /* CONFIG_DM_MMC */
> > +#define mmc_burn_image 0
> > +#define mmc_read_file 0
> > +#define is_mmc_active 0
> > +#endif /* CONFIG_DM_MMC */
>
> Please use empty functions instead.
[Konstantin Porotchkin]
Do you mean defining it in this way?
#define mmc_burn_image(a) 0
Or like below?
int mmc_burn_image(size_t image_size)
{
return -1;
}
Thanks
Kosta
>
> > +
> > +/********************************************************************
> > + * SPI services
> > +
> > +********************************************************************/
> > +#ifdef CONFIG_SPI_FLASH
> > +static int spi_burn_image(size_t image_size) {
> > + int ret;
> > + struct spi_flash *flash;
> > + u32 erase_bytes;
> > +
> > + /* Probe the SPI bus to get the flash device */
> > + flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
> > + CONFIG_ENV_SPI_CS,
> > + CONFIG_SF_DEFAULT_SPEED,
> > + CONFIG_SF_DEFAULT_MODE);
> > + if (!flash) {
> > + printf("Failed to probe SPI Flash\n");
> > + return -ENOMEDIUM;
> > + }
> > +
> > +#ifdef CONFIG_SPI_FLASH_PROTECTION
> > + spi_flash_protect(flash, 0);
> > +#endif
> > + erase_bytes = image_size +
> > + (flash->erase_size - image_size % flash->erase_size);
> > + printf("Erasing %d bytes (%d blocks) at offset 0 ...",
> > + erase_bytes, erase_bytes / flash->erase_size);
> > + ret = spi_flash_erase(flash, 0, erase_bytes);
> > + if (ret)
> > + printf("Error!\n");
> > + else
> > + printf("Done!\n");
> > +
> > + printf("Writing %d bytes from 0x%lx to offset 0 ...",
> > + (int)image_size, get_load_addr());
> > + ret = spi_flash_write(flash, 0, image_size, (void
> *)get_load_addr());
> > + if (ret)
> > + printf("Error!\n");
> > + else
> > + printf("Done!\n");
> > +
> > +#ifdef CONFIG_SPI_FLASH_PROTECTION
> > + spi_flash_protect(flash, 1);
> > +#endif
> > +
> > + return ret;
> > +}
> > +
> > +int is_spi_active(void)
> > +{
> > + return 1;
> > +}
> > +#else /* CONFIG_SPI_FLASH */
> > +#define spi_burn_image 0
> > +#define is_spi_active 0
> > +#endif /* CONFIG_SPI_FLASH */
>
> Empty functions please.
>
> > +
> > +/********************************************************************
> > + * NAND services
> > +
> > +********************************************************************/
> > +#ifdef CONFIG_CMD_NAND
> > +static int nand_burn_image(size_t image_size) {
> > + int ret, block_size;
> > + nand_info_t *nand;
> > + int dev = nand_curr_device;
> > +
> > + if ((dev < 0) || (dev >= CONFIG_SYS_MAX_NAND_DEVICE) ||
> > + (!nand_info[dev].name)) {
> > + puts("\nno devices available\n");
> > + return -ENOMEDIUM;
> > + }
> > + nand = &nand_info[dev];
> > + block_size = nand->erasesize;
> > +
> > + /* Align U-Boot size to currently used blocksize */
> > + image_size = ((image_size + (block_size - 1)) & (~(block_size -
> > +1)));
> > +
> > + /* Erase the U-BOOT image space */
> > + printf("Erasing 0x%x - 0x%x:...", 0, (int)image_size);
> > + ret = nand_erase(nand, 0, image_size);
> > + if (ret) {
> > + printf("Error!\n");
> > + goto error;
> > + }
> > + printf("Done!\n");
> > +
> > + /* Write the image to flash */
> > + printf("Writing image:...");
> > + printf("&image_size = 0x%p\n", (void *)&image_size);
> > + ret = nand_write(nand, 0, &image_size, (void *)get_load_addr());
> > + if (ret)
> > + printf("Error!\n");
> > + else
> > + printf("Done!\n");
> > +
> > +error:
> > + return ret;
> > +}
> > +
> > +int is_nand_active(void)
> > +{
> > + return 1;
> > +}
> > +#else /* CONFIG_CMD_NAND */
> > +#define nand_burn_image 0
> > +#define is_nand_active 0
> > +#endif /* CONFIG_CMD_NAND */
>
> Empty functions please.
>
> > +
> > +/********************************************************************
> > + * USB services
> > +
> > +********************************************************************/
> > +#if defined(CONFIG_USB_STORAGE) && defined(CONFIG_BLK) static size_t
> > +usb_read_file(const char *file_name) {
> > + loff_t act_read = 0;
> > + struct udevice *dev;
> > + int rc;
> > +
> > + usb_stop();
> > +
> > + if (usb_init() < 0) {
> > + printf("Error: usb_init failed\n");
> > + return 0;
> > + }
> > +
> > + /* Try to recognize storage devices immediately */
> > + blk_first_device(IF_TYPE_USB, &dev);
> > + if (!dev) {
> > + printf("Error: USB storage device not found\n");
> > + return 0;
> > + }
> > +
> > + /* Always load from usb 0 */
> > + if (fs_set_blk_dev("usb", "0", FS_TYPE_ANY)) {
> > + printf("Error: USB 0 not found\n");
> > + return 0;
> > + }
> > +
> > + /* Perfrom file read */
> > + rc = fs_read(file_name, get_load_addr(), 0, 0, &act_read);
> > + if (rc)
> > + return 0;
> > +
> > + return act_read;
> > +}
> > +
> > +int is_usb_active(void)
> > +{
> > + return 1;
> > +}
> > +#else /* defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
> > +#define usb_read_file 0 #define is_usb_active 0 #endif /*
> > +defined(CONFIG_USB_STORAGE) && defined (CONFIG_BLK) */
> > +
> > +/********************************************************************
> > + * Network services
> > +
> > +********************************************************************/
> > +#ifdef CONFIG_CMD_NET
> > +static size_t tftp_read_file(const char *file_name) {
> > + /* update global variable load_addr before tftp file from network
> */
> > + load_addr = get_load_addr();
> > + return net_loop(TFTPGET);
> > +}
> > +
> > +int is_tftp_active(void)
> > +{
> > + return 1;
> > +}
> > +#else
> > +#define tftp_read_file 0
> > +#define is_tftp_active 0
> > +#endif /* CONFIG_CMD_NET */
> > +
> > +enum bubt_devices {
> > + BUBT_DEV_NET = 0,
> > + BUBT_DEV_USB,
> > + BUBT_DEV_MMC,
> > + BUBT_DEV_SPI,
> > + BUBT_DEV_NAND,
> > +
> > + BUBT_MAX_DEV
> > +};
> > +
> > +struct bubt_dev bubt_devs[BUBT_MAX_DEV] = {
> > + {"tftp", tftp_read_file, NULL, is_tftp_active},
> > + {"usb", usb_read_file, NULL, is_usb_active},
> > + {"mmc", mmc_read_file, mmc_burn_image, is_mmc_active},
> > + {"spi", NULL, spi_burn_image, is_spi_active},
> > + {"nand", NULL, nand_burn_image, is_nand_active}, };
> > +
> > +static int bubt_write_file(struct bubt_dev *dst, size_t image_size) {
> > + if (!dst->write) {
> > + printf("Error: Write not supported on device %s\n", dst-
> >name);
> > + return -ENOTSUPP;
> > + }
> > +
> > + return dst->write(image_size);
> > +}
> > +
> > +#if defined(CONFIG_TARGET_MVEBU_ARMADA_8K)
> > +u32 do_checksum32(u32 *start, int32_t len) {
> > + u32 sum = 0;
> > + u32 *startp = start;
> > +
> > + do {
> > + sum += *startp;
> > + startp++;
> > + len -= 4;
> > + } while (len > 0);
> > +
> > + return sum;
> > +}
> > +
> > +static int check_image_header(void)
> > +{
> > + struct mvebu_image_header *hdr =
> > + (struct mvebu_image_header *)get_load_addr();
> > + u32 header_len = hdr->prolog_size;
> > + u32 checksum;
> > + u32 checksum_ref = hdr->prolog_checksum;
> > +
> > + /*
> > + * For now compare checksum, and magic. Later we can
> > + * verify more stuff on the header like interface type, etc
> > + */
> > + if (hdr->magic != MAIN_HDR_MAGIC) {
> > + printf("ERROR: Bad MAGIC 0x%08x != 0x%08x\n",
> > + hdr->magic, MAIN_HDR_MAGIC);
> > + return -ENOEXEC;
> > + }
> > +
> > + /* The checksum value is discarded from checksum calculation */
> > + hdr->prolog_checksum = 0;
> > +
> > + checksum = do_checksum32((u32 *)hdr, header_len);
> > + if (checksum != checksum_ref) {
> > + printf("Error: Bad Image checksum. 0x%x != 0x%x\n",
> > + checksum, checksum_ref);
> > + return -ENOEXEC;
> > + }
> > +
> > + /* Restore the checksum before writing */
> > + hdr->prolog_checksum = checksum_ref;
> > + printf("Image checksum...OK!\n");
> > +
> > + return 0;
> > +}
> > +#elif defined(CONFIG_TARGET_MVEBU_DB_88F3720) /* Armada 3700 */
> > +static int check_image_header(void) {
> > + struct common_tim_data *hdr = (struct common_tim_data
> *)get_load_addr();
> > + int image_num;
> > + u8 hash_160_output[SHA1_SUM_LEN];
> > + u8 hash_256_output[SHA256_SUM_LEN];
> > + sha1_context hash1_text;
> > + sha256_context hash256_text;
> > + u8 *hash_output;
> > + u32 hash_algorithm_id;
> > + u32 image_size_to_hash;
> > + u32 flash_entry_addr;
> > + u32 *hash_value;
> > + u32 internal_hash[HASH_SUM_LEN];
> > + const u8 *buff;
> > + u32 num_of_image = hdr->num_images;
> > + u32 version = hdr->version;
> > + u32 trusted = hdr->trusted;
> > +
> > + /* bubt checksum validation only supports nontrusted images */
> > + if (trusted == 1) {
> > + printf("bypass image validation, ");
> > + printf("only untrusted image is supported now\n");
> > + return 0;
> > + }
> > + /* only supports image version 3.5 and 3.6 */
> > + if (version != IMAGE_VERSION_3_5_0 && version !=
> IMAGE_VERSION_3_6_0) {
> > + printf("Error: Unsupported Image version = 0x%08x\n",
> version);
> > + return -ENOEXEC;
> > + }
> > + /* validate images hash value */
> > + for (image_num = 0; image_num < num_of_image; image_num++) {
> > + struct mvebu_image_info *info =
> > + (struct mvebu_image_info *)(get_load_addr() +
> > + sizeof(struct common_tim_data) +
> > + image_num * sizeof(struct mvebu_image_info));
> > + hash_algorithm_id = info->hash_algorithm_id;
> > + image_size_to_hash = info->image_size_to_hash;
> > + flash_entry_addr = info->flash_entry_addr;
> > + hash_value = info->hash;
> > + buff = (const u8 *)(get_load_addr() + flash_entry_addr);
> > +
> > + if (image_num == 0) {
> > + /* The first image includes hash values in its content.
> > + * For hash calculation, we need to save the original
> > + * hash values to a local variable that will be
> > + * copied back for comparsion and set all zeros to
> > + * the orignal hash values for calculating new value.
> > + * First image original format :
> > + * x...x (datum1) x...x(orig. hash values) x...x(datum2)
> > + * Replaced first image format :
> > + * x...x (datum1) 0...0(hash values) x...x(datum2)
> > + */
>
> Multicomment style is:
>
> /*
> *
> */
>
> > + memcpy(internal_hash, hash_value,
> > + sizeof(internal_hash));
> > + memset(hash_value, 0, sizeof(internal_hash));
> > + }
> > + if (image_size_to_hash == 0) {
> > + printf("Warning: Image_%d hash checksum is disabled, ",
> > + image_num);
> > + printf("skip the image validation.\n");
> > + continue;
> > + }
> > + switch (hash_algorithm_id) {
> > + case SHA1_SUM_LEN:
> > + sha1_starts(&hash1_text);
> > + sha1_update(&hash1_text, buff, image_size_to_hash);
> > + sha1_finish(&hash1_text, hash_160_output);
> > + hash_output = hash_160_output;
> > + break;
> > + case SHA256_SUM_LEN:
> > + sha256_starts(&hash256_text);
> > + sha256_update(&hash256_text, buff, image_size_to_hash);
> > + sha256_finish(&hash256_text, hash_256_output);
> > + hash_output = hash_256_output;
> > + break;
> > + default:
> > + printf("Error: Unsupported hash_algorithm_id = %d\n",
> > + hash_algorithm_id);
> > + return -ENOEXEC;
> > + }
> > + if (image_num == 0)
> > + memcpy(hash_value, internal_hash,
> > + sizeof(internal_hash));
> > + if (memcmp(hash_value, hash_output, hash_algorithm_id) != 0) {
> > + printf("Error: Image_%d checksum is not correct\n",
> > + image_num);
> > + return -ENOEXEC;
> > + }
> > + }
> > + printf("Image checksum...OK!\n");
> > +
> > + return 0;
> > +}
> > +#else
> > +static int check_image_header(void)
> > +{
> > + printf("bubt cmd does not support this SoC device or family!\n");
> > + return -ENOEXEC;
> > +}
> > +#endif
> > +
> > +static int bubt_verify(size_t image_size) {
> > + int err;
> > +
> > + /* Check a correct image header exists */
> > + err = check_image_header();
> > + if (err) {
> > + printf("Error: Image header verification failed\n");
> > + return err;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int bubt_read_file(struct bubt_dev *src) {
> > + size_t image_size;
> > +
> > + if (!src->read) {
> > + printf("Error: Read not supported on device \"%s\"\n",
> > + src->name);
> > + return 0;
> > + }
> > +
> > + image_size = src->read(net_boot_file_name);
> > + if (image_size <= 0) {
> > + printf("Error: Failed to read file %s from %s\n",
> > + net_boot_file_name, src->name);
> > + return 0;
> > + }
> > +
> > + return image_size;
> > +}
> > +
> > +static int bubt_is_dev_active(struct bubt_dev *dev) {
> > + if (!dev->active) {
> > + printf("Device \"%s\" not supported by U-BOOT image\n",
> > + dev->name);
> > + return 0;
> > + }
> > +
> > + if (!dev->active()) {
> > + printf("Device \"%s\" is inactive\n", dev->name);
> > + return 0;
> > + }
> > +
> > + return 1;
> > +}
> > +
> > +struct bubt_dev *find_bubt_dev(char *dev_name) {
> > + int dev;
> > +
> > + for (dev = 0; dev < BUBT_MAX_DEV; dev++) {
> > + if (strcmp(bubt_devs[dev].name, dev_name) == 0)
> > + return &bubt_devs[dev];
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +#define DEFAULT_BUBT_SRC "tftp"
> > +
> > +#ifndef DEFAULT_BUBT_DST
> > +#ifdef CONFIG_MVEBU_SPI_BOOT
> > +#define DEFAULT_BUBT_DST "spi"
> > +#elif defined(CONFIG_MVEBU_NAND_BOOT) #define DEFAULT_BUBT_DST "nand"
> > +#elif defined(CONFIG_MVEBU_MMC_BOOT)
> > +#define DEFAULT_BUBT_DST "mmc"
> > +else
> > +#define DEFAULT_BUBT_DST "error"
> > +#endif
> > +#endif /* DEFAULT_BUBT_DST */
> > +
> > +int do_bubt_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const
> > +argv[]) {
> > + struct bubt_dev *src, *dst;
> > + size_t image_size;
> > + char src_dev_name[8];
> > + char dst_dev_name[8];
> > + char *name;
> > + int err;
> > +
> > + if (argc < 2)
> > + copy_filename(net_boot_file_name,
> > + CONFIG_MVEBU_UBOOT_DFLT_NAME,
> > + sizeof(net_boot_file_name));
> > + else
> > + copy_filename(net_boot_file_name, argv[1],
> > + sizeof(net_boot_file_name));
> > +
> > + if (argc >= 3) {
> > + strncpy(dst_dev_name, argv[2], 8);
> > + } else {
> > + name = DEFAULT_BUBT_DST;
> > + strncpy(dst_dev_name, name, 8);
> > + }
> > +
> > + if (argc >= 4)
> > + strncpy(src_dev_name, argv[3], 8);
> > + else
> > + strncpy(src_dev_name, DEFAULT_BUBT_SRC, 8);
> > +
> > + /* Figure out the destination device */
> > + dst = find_bubt_dev(dst_dev_name);
> > + if (!dst) {
> > + printf("Error: Unknown destination \"%s\"\n", dst_dev_name);
> > + return -EINVAL;
> > + }
> > +
> > + if (!bubt_is_dev_active(dst))
> > + return -ENODEV;
> > +
> > + /* Figure out the source device */
> > + src = find_bubt_dev(src_dev_name);
> > + if (!src) {
> > + printf("Error: Unknown source \"%s\"\n", src_dev_name);
> > + return 1;
> > + }
> > +
> > + if (!bubt_is_dev_active(src))
> > + return -ENODEV;
> > +
> > + printf("Burning U-BOOT image \"%s\" from \"%s\" to \"%s\"\n",
> > + net_boot_file_name, src->name, dst->name);
> > +
> > + image_size = bubt_read_file(src);
> > + if (!image_size)
> > + return -EIO;
> > +
> > + err = bubt_verify(image_size);
> > + if (err)
> > + return err;
> > +
> > + err = bubt_write_file(dst, image_size);
> > + if (err)
> > + return err;
> > +
> > + return 0;
> > +}
> > +
> > +U_BOOT_CMD(
> > + bubt, 4, 0, do_bubt_cmd,
> > + "Burn a u-boot image to flash",
> > + "[file-name] [destination [source]]\n"
> > + "\t-file-name The image file name to burn. Default = flash-
> image.bin\n"
> > + "\t-destination Flash to burn to [spi, nand, mmc]. Default =
> active boot device\n"
> > + "\t-source The source to load image from [tftp, usb, mmc].
> Default = tftp\n"
> > + "Examples:\n"
> > + "\tbubt - Burn flash-image.bin from tftp to active boot device\n"
> > + "\tbubt flash-image-new.bin nand - Burn flash-image-new.bin from
> tftp to NAND flash\n"
> > + "\tbubt backup-flash-image.bin mmc usb - Burn backup-flash-
> image.bin from usb to MMC\n"
> > +
> > +);
> > diff --git a/doc/mvebu/cmd/bubt.txt b/doc/mvebu/cmd/bubt.txt new file
> > mode 100644 index 0000000..6f9f525
> > --- /dev/null
> > +++ b/doc/mvebu/cmd/bubt.txt
> > @@ -0,0 +1,64 @@
> > +BUBT (Burn ATF) command
> > +--------------------------
> > +Bubt command is used to burn a new ATF image to flash device.
> > +
> > +The bubt command gets the following parameters: ATF file name,
> destination device and source device.
> > +bubt [file-name] [destination [source]]
> > + - file-name Image file name to burn. default = flash-
> image.bin
> > + - destination Flash to burn to [spi, nand, mmc]. default =
> active flash
> > + - source Source to load image from [tftp, usb]. default =
> tftp
> > +
> > +Examples:
> > + bubt - Burn flash-image.bin from tftp to active
> flash
> > + bubt latest-spi.bin nand - Burn latest-spi.bin from tftp to NAND
> flash
> > +
> > +Notes:
> > +- For the TFTP interface set serverip and ipaddr.
> > +- To burn image to SD/eMMC device, the target is defined
> > + by parameters CONFIG_SYS_MMC_ENV_DEV and CONFIG_SYS_MMC_ENV_PART.
> > +
> > +Bubt command details (burn image step by-step)
> > +----------------------------------------------
> > +This section describes bubt command flow:
> > +
> > +1. Fetch the requested ATF image from an available interface
> (USB/SD/SATA/XDB, etc.)
> > + into the DRAM, and place it at <load_address>
> > + Example: when using the FAT file system on USB flash device:
> > + # usb reset
> > + # fatls usb 0 (see files in device)
> > + # fatload usb 0 <load_address> <file_name>
> > +
> > +2. Erase the target device:
> > + - NAND: # nand erase 0 100000
> > + - SPI: # sf probe 0
> > + # sf erase 0 100000
> > + - SD/eMMC: # mmc dev <dev_id> <boot_partition>
> > +
> > +Notes:
> > +- The eMMC has 2 boot partitions (BOOT0 and BOOT1) and a user data
> partition (DATA).
> > + The boot partitions are numbered as partition 1 and 2 in MMC
> driver.
> > + Number 0 is used for user data partition and should not be utilized
> > +for storing
> > + boot images and U-Boot environment in RAW mode since it will break
> > +file system
> > + structures usually located here.
> > + The default boot partition is BOOT0. It is selected by the
> following parameter:
> > + CONFIG_SYS_MMC_ENV_PART=1
> > + Valid values for this parameter are 1 for BOOT0 and 2 for BOOT1.
> > + Please never use partition number 0 here!
> > + The eMMC has 2 boot partitions (BOOT0 and BOOT1) and a user data
> partition (DATA).
> > + The boot partitions are numbered as partition 1 and 2 in MMC
> driver.
> > + Number 0 is used for user data partition and should not be utilized
> > +for storing
> > + boot images and U-Boot environment in RAW mode since it will break
> > +file system
> > + structures usually located here.
> > + The default boot partition is BOOT0. It is selected by the
> following parameter:
> > + CONFIG_SYS_MMC_ENV_PART=1
> > + Valid values for this parameter are 1 for BOOT0 and 2 for BOOT1.
> > + Please never use partition number 0 here!
> > +- The partition number is ignored if the target device is SD card.
> > +- The boot image offset starts at block 0 for eMMC and block 1 for SD
> devices.
> > + The block 0 on SD devices is left for MBR storage.
> > +
> > +3. Write the ATF image:
> > + - NAND: # nand write <load_address> 0 <ATF Size>
> > + - SPI: # sf write <load_address> 0 <ATF Size>
> > + - SD/eMMC: # mmc write <load_address> [0|1] <ATF Size>/<block_size>
> > +
> >
>
> Thanks,
> Stefan
More information about the U-Boot
mailing list