[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