[U-Boot] [PATCH v2 2/6] arm64: mvebu: Add bubt command for flash image burn

Kostya Porotchkin kostap at marvell.com
Tue Dec 6 08:50:20 CET 2016


Hi, Stefan,

Thank you for review and sorry for missing your earlier notes.
It was not intentional.
I will prepare a new patch version with all the fixes.

Regards
Kosta

-----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.

> +
> +/********************************************************************
> + *     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