[U-Boot] [PATCH 2/2 v2] fastboot: Flash command support

Steve Rae srae at broadcom.com
Mon Aug 11 21:52:11 CEST 2014



On 14-08-10 06:59 PM, Dileep Katta wrote:
> Flash command internally uses DFU, and Fastboot command initialization is modified to add DFU and partition initialization
> Added oem format functionality for GPT table creation
> partitioning code is added as disk/part_fastboot.c for better usability
>
> Fastboot flash command code is enabled and being tested on BeagleBone Black.
> OMAP3 Beagle configuration is modified to fix the build errors, but this configuration needs to be updated as per the flash functionality.
>
> Signed-off-by: Dileep Katta <dileep.katta at linaro.org>
> ---
> Changes for v2:
> 	- Fixed coding style issues
>
>   common/cmd_fastboot.c           |   5 +
>   common/cmd_mmc.c                |   2 +-
>   common/cmd_nvedit.c             |   2 +-
>   disk/Makefile                   |   1 +
>   disk/part_fastboot.c            | 379 ++++++++++++++++++++++++++++++++++++++++
>   doc/README.android-fastboot     |  26 +++
>   drivers/usb/gadget/f_fastboot.c | 178 ++++++++++++++++++-
>   include/configs/am335x_evm.h    |  23 ++-
>   include/configs/omap3_beagle.h  |  12 ++
>   include/usb/fastboot.h          | 182 +++++++++++++++++++
>   10 files changed, 796 insertions(+), 14 deletions(-)
>   create mode 100644 disk/part_fastboot.c
>   create mode 100644 include/usb/fastboot.h
>
> diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
> index 83fa7bd..6d0d0a4 100644
> --- a/common/cmd_fastboot.c
> +++ b/common/cmd_fastboot.c
> @@ -10,11 +10,15 @@
>   #include <common.h>
>   #include <command.h>
>   #include <g_dnl.h>
> +#include <dfu.h>
> +#include <usb/fastboot.h>
>
>   static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
>   {
>   	int ret;
>
> +	board_partition_init();
> +	dfu_init_env_entities("mmc", CONFIG_FB_MMCDEV);
>   	ret = g_dnl_register("usb_dnl_fastboot");
>   	if (ret)
>   		return ret;
> @@ -26,6 +30,7 @@ static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
>   	}
>
>   	g_dnl_unregister();
> +	dfu_free_entities();
>   	return CMD_RET_SUCCESS;
>   }
>
> diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
> index 1e40983..dd7170d 100644
> --- a/common/cmd_mmc.c
> +++ b/common/cmd_mmc.c
> @@ -612,7 +612,7 @@ static cmd_tbl_t cmd_mmc[] = {
>   	U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""),
>   };
>
> -static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>   {
>   	cmd_tbl_t *cp;
>
> diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
> index 855808c..a100109 100644
> --- a/common/cmd_nvedit.c
> +++ b/common/cmd_nvedit.c
> @@ -686,7 +686,7 @@ ulong getenv_ulong(const char *name, int base, ulong default_val)
>
>   #ifndef CONFIG_SPL_BUILD
>   #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
> -static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
> +int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
>   		       char * const argv[])
>   {
>   	printf("Saving Environment to %s...\n", env_name_spec);
> diff --git a/disk/Makefile b/disk/Makefile
> index 6970cec..4b7a9ef 100644
> --- a/disk/Makefile
> +++ b/disk/Makefile
> @@ -13,3 +13,4 @@ obj-$(CONFIG_DOS_PARTITION)   += part_dos.o
>   obj-$(CONFIG_ISO_PARTITION)   += part_iso.o
>   obj-$(CONFIG_AMIGA_PARTITION) += part_amiga.o
>   obj-$(CONFIG_EFI_PARTITION)   += part_efi.o
> +obj-$(CONFIG_CMD_FASTBOOT)    += part_fastboot.o
> diff --git a/disk/part_fastboot.c b/disk/part_fastboot.c
> new file mode 100644
> index 0000000..4fa9f85
> --- /dev/null
> +++ b/disk/part_fastboot.c
> @@ -0,0 +1,379 @@
> +/*
> + * Copyright (C) 2013 Texas Instruments
> + *
> + * Author : Pankaj Bharadiya <pankaj.bharadiya at ti.com>
> + *
> + * Tom Rix <Tom.Rix at windriver.com> and Sitara 2011 u-boot by
> + * Mohammed Afzal M A <afzal at ti.com>
> + *
> + * Copyright (C) 2008 The Android Open Source Project
> + * All rights reserved.
> + *
> + * Copyright 2014 Linaro, Ltd.
> + * Dileep Katta <dileep.katta at linaro.org>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <usb/fastboot.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include <environment.h>
> +#include <mmc.h>
> +#include <dfu.h>
> +
> +#define EFI_VERSION 0x00010000
> +#define EFI_ENTRIES 128
> +#define EFI_NAMELEN 36
> +
> +struct partition_emmc {
> +	const char *name;
> +	unsigned size_kb;
> +};
> +
> +/* eMMC partition layout (All sizes are in kB)
> + * Modify the below partition table to change the GPT configuration.
> + * The entry for each partition can be modified as per the requirement.
> + */
> +static struct partition_emmc partitions[] = {
> +	{ "-", 128 },	/* Master Boot Record and GUID Partition Table */
> +	{ "spl", 128 },	/* First stage bootloader */
> +	{ "bootloader", 512 },	/* Second stage bootloader */
> +	{ "misc", 128 },		/* Rserved for internal purpose */
> +	{ "-", 128 },			/* Reserved */
> +	{ "recovery", 8*1024 },	/* Recovery partition  */
> +	{ "boot", 8*1024 },	/* Partition contains kernel + ramdisk images */
> +	{ "system", 256*1024 },		/* Android file system */
> +	{ "cache", 256*1024 },		/* Store Application Cache */
> +	{ "userdata", 256*1024 },	/* User data */
> +	{ "media", 0 },			/* Media files */
> +	{ 0, 0 },

This hard-coded partition does not work for our boards -- what is your 
plan for supporting partition tables?
[ have you considered allowing the host to format, download and flash 
the partition table? (that is what we are doing...) ]

> +};
> +
> +
> +static const u8 partition_type[16] = {
> +	0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
> +	0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7,
> +};
> +
> +static const u8 random_uuid[16] = {
> +	0xff, 0x1f, 0xf2, 0xf9, 0xd4, 0xa8, 0x0e, 0x5f,
> +	0x97, 0x46, 0x59, 0x48, 0x69, 0xae, 0xc3, 0x4e,
> +};
> +
> +struct efi_entry {
> +	u8 type_uuid[16];
> +	u8 uniq_uuid[16];
> +	u64 first_lba;
> +	u64 last_lba;
> +	u64 attr;
> +	u16 name[EFI_NAMELEN];
> +};
> +
> +struct efi_header {
> +	u8 magic[8];
> +
> +	u32 version;
> +	u32 header_sz;
> +
> +	u32 crc32;
> +	u32 reserved;
> +
> +	u64 header_lba;
> +	u64 backup_lba;
> +	u64 first_lba;
> +	u64 last_lba;
> +
> +	u8 volume_uuid[16];
> +
> +	u64 entries_lba;
> +
> +	u32 entries_count;
> +	u32 entries_size;
> +	u32 entries_crc32;
> +} __packed;
> +
> +struct ptable {
> +	u8 mbr[512];
> +	union {
> +		struct efi_header header;
> +		u8 block[512];
> +	};
> +	struct efi_entry entry[EFI_ENTRIES];
> +};
> +
> +static void init_mbr(u8 *mbr, u32 blocks)
> +{
> +	mbr[0x1be] = 0x00; /* nonbootable */
> +	mbr[0x1bf] = 0xFF; /* bogus CHS */
> +	mbr[0x1c0] = 0xFF;
> +	mbr[0x1c1] = 0xFF;
> +
> +	mbr[0x1c2] = 0xEE; /* GPT partition */
> +	mbr[0x1c3] = 0xFF; /* bogus CHS */
> +	mbr[0x1c4] = 0xFF;
> +	mbr[0x1c5] = 0xFF;
> +
> +	mbr[0x1c6] = 0x01; /* start */
> +	mbr[0x1c7] = 0x00;
> +	mbr[0x1c8] = 0x00;
> +	mbr[0x1c9] = 0x00;
> +
> +	memcpy(mbr + 0x1ca, &blocks, sizeof(u32));
> +
> +	mbr[0x1fe] = 0x55;
> +	mbr[0x1ff] = 0xaa;
> +}
> +
> +
> +static void start_ptbl(struct ptable *ptbl, unsigned blocks)
> +{
> +	struct efi_header *hdr = &ptbl->header;
> +
> +	memset(ptbl, 0, sizeof(*ptbl));
> +
> +	init_mbr(ptbl->mbr, blocks - 1);
> +
> +	memcpy(hdr->magic, "EFI PART", 8);
> +	hdr->version = EFI_VERSION;
> +	hdr->header_sz = sizeof(struct efi_header);
> +	hdr->header_lba = 1;
> +	hdr->backup_lba = blocks - 1;
> +	hdr->first_lba = 34;
> +	hdr->last_lba = blocks - 1;
> +	memcpy(hdr->volume_uuid, random_uuid, 16);
> +	hdr->entries_lba = 2;
> +	hdr->entries_count = EFI_ENTRIES;
> +	hdr->entries_size = sizeof(struct efi_entry);
> +}
> +
> +static void end_ptbl(struct ptable *ptbl)
> +{
> +	struct efi_header *hdr = &ptbl->header;
> +	u32 n;
> +
> +	n = crc32(0, 0, 0);
> +	n = crc32(n, (void *)ptbl->entry, sizeof(ptbl->entry));
> +	hdr->entries_crc32 = n;
> +
> +	n = crc32(0, 0, 0);
> +	n = crc32(0, (void *)&ptbl->header, sizeof(ptbl->header));
> +	hdr->crc32 = n;
> +}
> +
> +int add_ptn(struct ptable *ptbl, u64 first, u64 last, const char *name)
> +{
> +	struct efi_header *hdr = &ptbl->header;
> +	struct efi_entry *entry = ptbl->entry;
> +	unsigned n;
> +
> +	if (first < 34) {
> +		printf("partition '%s' overlaps partition table\n", name);
> +		return -1;
> +	}
> +
> +	if (last > hdr->last_lba) {
> +		printf("partition '%s' does not fit\n", name);
> +		return -1;
> +	}
> +	for (n = 0; n < EFI_ENTRIES; n++, entry++) {
> +		if (entry->last_lba)
> +			continue;
> +		memcpy(entry->type_uuid, partition_type, 16);
> +		memcpy(entry->uniq_uuid, random_uuid, 16);
> +		entry->uniq_uuid[0] = n;
> +		entry->first_lba = first;
> +		entry->last_lba = last;
> +		for (n = 0; (n < EFI_NAMELEN) && *name; n++)
> +			entry->name[n] = *name++;
> +		return 0;
> +	}
> +	printf("out of partition table entries\n");
> +	return -1;
> +}
> +
> +void import_efi_partition(struct efi_entry *entry)
> +{
> +	struct fastboot_ptentry e;
> +	int n;
> +	if (memcmp(entry->type_uuid, partition_type, sizeof(partition_type)))
> +		return;
> +	for (n = 0; n < (sizeof(e.name)-1); n++)
> +		e.name[n] = entry->name[n];
> +	e.name[n] = 0;
> +	e.start = entry->first_lba;
> +	e.length = (entry->last_lba - entry->first_lba + 1) * 512;
> +	e.flags = 0;
> +
> +	if (!strcmp(e.name, "environment"))
> +		e.flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_ENV;
> +	fastboot_flash_add_ptn(&e);
> +
> +	if (e.length > 0x100000)
> +		printf("%8d %7dM %s\n", e.start, e.length/0x100000, e.name);
> +	else
> +		printf("%8d %7dK %s\n", e.start, e.length/0x400, e.name);
> +}
> +
> +static int load_ptbl(void)
> +{
> +	static unsigned char data[512];
> +	static struct efi_entry entry[4];
> +	int n, m;
> +	char source[32], dest[32], length[32];
> +
> +	char *mmc_read[5]  = {"mmc", "read", NULL, NULL, NULL};
> +
> +	/* read mbr */
> +	mmc_read[2] = source;
> +	mmc_read[3] = dest;
> +	mmc_read[4] = length;
> +
> +	sprintf(source, "%p", data);
> +	sprintf(dest, "0x%x", 0x1);
> +	sprintf(length, "0x%x", 1);
> +
> +	if (do_mmcops(NULL, 0, 5, mmc_read)) {
> +		printf("Reading boot magic FAILED!\n");
> +		return -1;
> +	}

REALLY -- building a string and passing to the command interpreter !?!?!

> +
> +	if (memcmp(data, "EFI PART", 8)) {
> +		printf("efi partition table not found\n");
> +		return -1;
> +	}
> +	for (n = 0; n < (128/4); n++) {
> +		/* read partition */
> +		source[0] = '\0';
> +		dest[0] = '\0';
> +		length[0] = '\0';
> +		mmc_read[2] = source;
> +		mmc_read[3] = dest;
> +		mmc_read[4] = length;
> +
> +		sprintf(source, "%p", entry);
> +		sprintf(dest, "0x%x", 0x1+n);
> +		sprintf(length, "0x%x", 1);
> +
> +		if (do_mmcops(NULL, 0, 5, mmc_read)) {
> +			printf("Reading boot magic FAILED!\n");
> +			return -1;
> +		}
> +		for (m = 0; m < 4; m++)
> +			import_efi_partition(entry + m);
> +	}
> +	return 0;
> +}
> +
> +int board_mmc_fbtptn_init(void)
> +{
> +	char *mmc_init[2] = {"mmc", "rescan",};
> +	char dev[2];
> +	char *mmc_dev[3] = {"mmc", "dev", NULL};
> +
> +	mmc_dev[2] = dev;
> +	sprintf(dev, "0x%x", CONFIG_FB_MMCDEV);
> +
> +	if (do_mmcops(NULL, 0, 3, mmc_dev)) {
> +		printf("MMC DEV: %d selection FAILED!\n", CONFIG_FB_MMCDEV);
> +		return -1;
> +	}
> +
> +	if (do_mmcops(NULL, 0, 2, mmc_init)) {
> +			printf("FAIL:Init of MMC card\n");
> +			return 1;
> +	}
> +
> +	printf("Loading efi partition table:\n");
> +	return load_ptbl();
> +}
> +
> +
> +static struct ptable the_ptable;
> +
> +int do_format(void)
> +{
> +	struct ptable *ptbl = &the_ptable;
> +	/* unsigned sector_sz; */
> +	unsigned blocks;
> +	unsigned next;
> +	int n;
> +
> +	printf("\ndo_format ..!!");
> +	/* get mmc info */
> +	struct mmc *mmc = find_mmc_device(CONFIG_FB_MMCDEV);
> +	if (mmc == 0) {
> +		printf("no mmc device at slot %d", CONFIG_FB_MMCDEV);
> +		return -1;
> +	}
> +
> +	mmc->has_init = 0;
> +	if (mmc_init(mmc)) {
> +		printf("\n mmc init FAILED");
> +		return -1;
> +	} else{
> +		printf("\nmmc capacity is: %llu", mmc->capacity);
> +		printf("\nmmc: number of blocks:0x%lx", mmc->block_dev.lba);
> +		printf("\nmmc: block size:0x%lx", mmc->block_dev.blksz);
> +	}
> +
> +	blocks = mmc->block_dev.lba;
> +	/* sector_sz = mmc->block_dev.blksz; */
> +
> +	start_ptbl(ptbl, blocks);
> +	n = 0;
> +	next = 0;
> +	for (n = 0, next = 0; partitions[n].name; n++) {
> +		/* 10/11 : below line change size from KB to no of blocks */
> +		unsigned sz = partitions[n].size_kb*2;
> +		if (!strcmp(partitions[n].name, "-")) {
> +			next += sz;
> +			continue;
> +		}
> +		if (sz == 0)
> +			sz = blocks - next;
> +		if (add_ptn(ptbl, next, next + sz - 1, partitions[n].name))
> +			return -1;
> +		next += sz;
> +	}
> +	end_ptbl(ptbl);
> +
> +	fastboot_flash_reset_ptn();
> +
> +	/* 10/11:modified as per PSP release support */
> +	char *mmc_write[5]  = {"mmc", "write", NULL, NULL, NULL};
> +	char source[32], dest[32], length[32];
> +
> +	char dev[2];
> +	char *mmc_dev[3] = {"mmc", "dev", NULL};
> +
> +	mmc_dev[2] = dev;
> +	sprintf(dev, "0x%x", CONFIG_FB_MMCDEV);
> +
> +	if (do_mmcops(NULL, 0, 3, mmc_dev)) {
> +		printf("MMC DEV: %d selection FAILED!\n", CONFIG_FB_MMCDEV);
> +		return -1;
> +	}
> +
> +	mmc_write[2] = source;
> +	mmc_write[3] = dest;
> +	mmc_write[4] = length;
> +
> +	sprintf(source, "%p", (void *)ptbl);
> +	sprintf(dest, "0x%x", 0x00);
> +	sprintf(length, "0x%x", (sizeof(struct ptable)/512)+1);
> +
> +	if (do_mmcops(NULL, 0, 5, mmc_write)) {
> +		printf("Writing mbr is FAILED!\n");
> +		return -1;
> +	} else {
> +		printf("Writing mbr is DONE!\n");
> +	}
> +
> +	printf("\nnew partition table:\n");
> +	load_ptbl();
> +
> +	return 0;
> +}
> diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
> index f1d128c..5420e5e 100644
> --- a/doc/README.android-fastboot
> +++ b/doc/README.android-fastboot
> @@ -46,6 +46,14 @@ buffer should be as large as possible for a platform. The location of the
>   buffer and size are set with CONFIG_USB_FASTBOOT_BUF_ADDR and
>   CONFIG_USB_FASTBOOT_BUF_SIZE.
>
> +Fastboot flash command uses DFU and storage(NAND/MMC) specific
> +functionality, and hence related definitions needs to be defined:
> +
> +DFU_ALT_INFO
> +CONFIG_STORAGE_EMMC
> +CONFIG_FB_MMCDEV
> +
> +
>   In Action
>   =========
>   Enter into fastboot by executing the fastboot command in u-boot and you
> @@ -89,3 +97,21 @@ and on the gadget side you should see:
>   |OK
>   |
>   |Starting kernel ...
> +
> +Flash command in action, on the client side:
> +
> +|>fastboot flash bootloader u-boot.img
> +|target reported max download size of 1835008 bytes
> +|sending 'bootloader' (395 KB)...
> +|OKAY [  0.144s]
> +|writing 'bootloader'...
> +|OKAY [  0.009s]
> +|finished. total time: 0.153s
> +
> +and on the gadget side you should see:
> +|Starting download of 405019 bytes
> +|...
> +|downloading of 405019 bytes finished
> +|download_bytes: 0x62e1b
> +|Writing 'bootloader'
> +|Writing 'bootloader' DONE!
> diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
> index 7a1acb9..da2117c 100644
> --- a/drivers/usb/gadget/f_fastboot.c
> +++ b/drivers/usb/gadget/f_fastboot.c
> @@ -19,6 +19,9 @@
>   #include <linux/compiler.h>
>   #include <version.h>
>   #include <g_dnl.h>
> +#include <usb/fastboot.h>
> +#include <command.h>
> +#include <dfu.h>
>
>   #define FASTBOOT_VERSION		"0.4"
>
> @@ -35,6 +38,15 @@
>
>   #define EP_BUFFER_SIZE			4096
>
> +static struct fastboot_config *fb_cfg;
> +static char *transfer_buffer = (void *)CONFIG_USB_FASTBOOT_BUF_ADDR;

is this "transfer_buffer" really needed?

> +
> +/* To support the Android-style naming of flash */
> +#define MAX_PTN 16
> +static fastboot_ptentry ptable[MAX_PTN];
> +static unsigned int pcount;
> +/* static int static_pcount = -1; */
> +
>   struct f_fastboot {
>   	struct usb_function usb_function;
>
> @@ -119,6 +131,39 @@ static struct usb_gadget_strings *fastboot_strings[] = {
>
>   static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
>
> +void set_fb_config(struct fastboot_config *cfg)
> +{
> +	fb_cfg = cfg;
> +}
> +
> +/*
> + * Android style flash utilties */
> +void fastboot_flash_reset_ptn(void)
> +{
> +#ifdef DEBUG
> +	printf("fastboot flash reset partition..!!");
> +#endif
> +	pcount = 0;
> +}
> +
> +void fastboot_flash_add_ptn(fastboot_ptentry *ptn)
> +{
> +	if (pcount < MAX_PTN) {
> +		memcpy((ptable + pcount), ptn, sizeof(*ptn));
> +		pcount++;
> +	}
> +}
> +
> +void fastboot_flash_dump_ptn(void)
> +{
> +	unsigned int n;
> +	for (n = 0; n < pcount; n++) {
> +		fastboot_ptentry *ptn = ptable + n;
> +		printf("ptn %d name='%s'", n, ptn->name);
> +		printf(" start=%d len=%d\n", ptn->start, ptn->length);
> +	}
> +}
> +
>   static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
>   {
>   	int status = req->status;
> @@ -308,6 +353,21 @@ static int fastboot_tx_write_str(const char *buffer)
>   	return fastboot_tx_write(buffer, strlen(buffer));
>   }
>
> +fastboot_ptentry *fastboot_flash_find_ptn(const char *name)
> +{
> +	unsigned int n;
> +
> +	for (n = 0; n < pcount; n++) {
> +		/* Make sure a substring is not accepted */
> +		if (strlen(name) == strlen(ptable[n].name)) {
> +			if (0 == strcmp(ptable[n].name, name))
> +				return ptable + n;
> +		}
> +	}
> +	return 0;
> +}
> +
> +
>   static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
>   {
>   	do_reset(NULL, 0, 0, NULL);
> @@ -346,7 +406,7 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
>   		strncat(response, FASTBOOT_VERSION, chars_left);
>   	} else if (!strcmp_l1("bootloader-version", cmd)) {
>   		strncat(response, U_BOOT_VERSION, chars_left);
> -	} else if (!strcmp_l1("downloadsize", cmd)) {
> +	} else if (!strcmp_l1("max-download-size", cmd)) {

why did this change?

>   		char str_num[12];
>
>   		sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE);
> @@ -380,6 +440,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
>   	unsigned int transfer_size = download_size - download_bytes;
>   	const unsigned char *buffer = req->buf;
>   	unsigned int buffer_size = req->actual;
> +	int dnl_complete = 0;

what is the purpose of this flag (and the code-change below) ???
>
>   	if (req->status != 0) {
>   		printf("Bad status: %d\n", req->status);
> @@ -389,11 +450,9 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
>   	if (buffer_size < transfer_size)
>   		transfer_size = buffer_size;
>
> -	memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,
> -	       buffer, transfer_size);
> +	memcpy((void *)transfer_buffer + download_bytes, buffer, transfer_size);
>
>   	download_bytes += transfer_size;
> -
>   	/* Check if transfer is done */
>   	if (download_bytes >= download_size) {
>   		/*
> @@ -403,9 +462,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
>   		download_size = 0;
>   		req->complete = rx_handler_command;
>   		req->length = EP_BUFFER_SIZE;
> -
> -		sprintf(response, "OKAY");
> -		fastboot_tx_write_str(response);
> +		dnl_complete = 1;
>
>   		printf("\ndownloading of %d bytes finished\n", download_bytes);
>   	} else {
> @@ -419,6 +476,11 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
>   		if (!(download_bytes % (74 * BYTES_PER_DOT)))
>   			putc('\n');
>   	}
> +
> +	if (dnl_complete) {
> +		sprintf(response, "OKAY");
> +		fastboot_tx_write_str(response);
> +	}
>   	req->actual = 0;
>   	usb_ep_queue(ep, req, 0);
>   }
> @@ -469,6 +531,37 @@ static void cb_boot(struct usb_ep *ep, struct usb_request *req)
>   	fastboot_tx_write_str("OKAY");
>   }
>
> +static void cb_flash(struct usb_ep *ep, struct usb_request *req)
> +{
> +	char *cmdbuf = req->buf;
> +	char response[32];
> +	char part_name[20] = {0,};
> +	strncpy(part_name, cmdbuf + 6, req->actual - 6);
> +	handle_flash(part_name, response, transfer_buffer);
> +	fastboot_tx_write_str(response);
> +}
> +
> +int fastboot_oem(const char *cmd)
> +{
> +	printf("fastboot_oem:%s", cmd);
> +	if (!strcmp(cmd, "format"))
> +		return do_format();
> +	return -1;
> +}
> +
> +static void cb_oem(struct usb_ep *ep, struct usb_request *req)
> +{
> +	char *cmd = req->buf;
> +
> +	printf("calling fastboot oem!! : %s\n", cmd);
> +	int r = fastboot_oem(cmd + 4);
> +	if (r < 0) {
> +		fastboot_tx_write_str("FAIL");
> +	} else {
> +		fastboot_tx_write_str("OKAY");
> +	}
> +}
> +
>   struct cmd_dispatch_info {
>   	char *cmd;
>   	void (*cb)(struct usb_ep *ep, struct usb_request *req);
> @@ -487,6 +580,12 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = {
>   	}, {
>   		.cmd = "boot",
>   		.cb = cb_boot,
> +	}, {
> +		.cmd = "flash",
> +		.cb = cb_flash,
> +	}, {
> +		.cmd = "oem",
> +		.cb = cb_oem,
>   	},
>   };
>
> @@ -496,6 +595,8 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
>   	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
>   	int i;
>
> +	*(cmdbuf + req->actual) = '\0';
> +
>   	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
>   		if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
>   			func_cb = cmd_dispatch_info[i].cb;
> @@ -514,3 +615,66 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
>   		usb_ep_queue(ep, req, 0);
>   	}
>   }
> +
> +static int alt_setting_num;
> +
> +int handle_flash(char *part_name, char *response, char *transfer_buffer)
> +{
> +	int status = 0;
> +	printf("download_bytes: 0x%x\n", download_bytes);
> +	if (download_bytes) {
> +		struct fastboot_ptentry *ptn;
> +
> +		/* Next is the partition name */
> +		ptn = fastboot_flash_find_ptn(part_name);

FYI - disk/part_efi.c provides:
          get_partition_info_efi_by_name()

> +
> +		if (ptn == 0) {
> +			printf("Partition:[%s] does not exist\n", part_name);
> +			sprintf(response, "FAILpartition does not exist");
> +		} else if ((download_bytes > ptn->length) &&
> +			!(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
> +			printf("Image too large for the partition\n");
> +			sprintf(response, "FAILimage too large for partition");
> +		} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
> +			/* Check if this is not really a flash write,
> +			 * but instead a saveenv
> +			 */
> +			unsigned int i = 0;
> +			/* Env file is expected with a NULL delimeter between
> +			 * env variables So replace New line Feeds(0x0a) with
> +			 * NULL (0x00)
> +			 */
> +			for (i = 0; i < download_bytes; i++) {
> +				if (transfer_buffer[i] == 0x0a)
> +					transfer_buffer[i] = 0x00;
> +			}
> +			memset(env_ptr->data, 0, ENV_SIZE);
> +			memcpy(env_ptr->data, transfer_buffer, download_bytes);
> +			do_env_save(NULL, 0, 1, NULL);
> +			printf("saveenv to '%s' DONE!\n", ptn->name);
> +			sprintf(response, "OKAY");
> +		} else {
> +			/* Normal case */
> +			alt_setting_num = dfu_get_alt(part_name);
> +			status = dfu_write(dfu_get_entity(alt_setting_num),
> +				transfer_buffer, download_bytes, 0);
> +			printf("Writing '%s'\n", ptn->name);
> +			if (status) {
> +				printf("Writing '%s' FAILED!\n", ptn->name);
> +				sprintf(response, "FAIL: Write partition");
> +			} else {
> +				printf("Writing '%s' DONE!\n", ptn->name);
> +				sprintf(response, "OKAY");
> +			}
> +		}
> +	} else {
> +			sprintf(response, "FAILno image downloaded");
> +	}
> +	return status;
> +}
> +
> +int board_partition_init(void)
> +{
> +	board_mmc_fbtptn_init();
> +	return 1;
> +}
> diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h
> index 3999405..2227a88 100644
> --- a/include/configs/am335x_evm.h
> +++ b/include/configs/am335x_evm.h
> @@ -87,6 +87,7 @@
>   		"uuid_disk=${uuid_gpt_disk};" \
>   		"name=rootfs,start=2MiB,size=-,uuid=${uuid_gpt_rootfs}\0" \
>   	"optargs=\0" \
> +	"dfu_alt_info=" DFU_ALT_INFO "\0" \
>   	"mmcdev=0\0" \
>   	"mmcroot=/dev/mmcblk0p2 ro\0" \
>   	"mmcrootfstype=ext4 rootwait\0" \
> @@ -303,6 +304,16 @@
>   #endif
>
>   #ifdef CONFIG_MUSB_GADGET
> +
> +#define CONFIG_FB_MMCDEV			1
> +
> +/*Uncomment this to enable NAND fastboot*/
> +/*#define CONFIG_NAND */
> +
> +/*Uncomment this to support eMMC booting*/
> +#define CONFIG_STORAGE_EMMC
> +
> +
>   #define CONFIG_USB_ETHER
>   #define CONFIG_USB_ETH_RNDIS
>   #define CONFIG_USBNET_HOST_ADDR	"de:ad:be:af:00:00"
> @@ -336,14 +347,13 @@
>   #define CONFIG_DFU_MMC
>   #define CONFIG_CMD_DFU
>   #define DFU_ALT_INFO_MMC \
> -	"dfu_alt_info_mmc=" \
>   	"boot part 0 1;" \
>   	"rootfs part 0 2;" \
>   	"MLO fat 0 1;" \
> -	"MLO.raw mmc 0x100 0x100;" \
> -	"u-boot.img.raw mmc 0x300 0x400;" \
> -	"spl-os-args.raw mmc 0x80 0x80;" \
> -	"spl-os-image.raw mmc 0x900 0x2000;" \
> +	"MLO.raw raw 0x100 0x100;" \
> +	"u-boot.img.raw raw 0x300 0x400;" \
> +	"spl-os-args.raw raw 0x80 0x80;" \
> +	"spl-os-image.raw raw 0x900 0x2000;" \
>   	"spl-os-args fat 0 1;" \
>   	"spl-os-image fat 0 1;" \
>   	"u-boot.img fat 0 1;" \
> @@ -374,6 +384,9 @@
>   	DFU_ALT_INFO_MMC \
>   	DFU_ALT_INFO_RAM \
>   	DFU_ALT_INFO_NAND
> +#ifdef CONFIG_DFU_MMC
> +#define DFU_ALT_INFO DFU_ALT_INFO_MMC
> +#endif
>   #endif
>
>   /*
> diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h
> index 644e97f..84594a0 100644
> --- a/include/configs/omap3_beagle.h
> +++ b/include/configs/omap3_beagle.h
> @@ -77,6 +77,18 @@
>   #define CONFIG_USB_FASTBOOT_BUF_ADDR	CONFIG_SYS_LOAD_ADDR
>   #define CONFIG_USB_FASTBOOT_BUF_SIZE	0x07000000
>
> +#ifdef CONFIG_CMD_FASTBOOT
> +#define CONFIG_FB_MMCDEV			1
> +#define CONFIG_DFU_FUNCTION
> +#define CONFIG_DFU_MMC
> +#define CONFIG_CMD_DFU
> +#define DFU_ALT_INFO_MMC ""
> +#endif
> +
> +#ifdef CONFIG_DFU_MMC
> +#define DFU_ALT_INFO DFU_ALT_INFO_MMC
> +#endif
> +
>   /* USB EHCI */
>   #define CONFIG_CMD_USB
>   #define CONFIG_USB_EHCI
> diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
> new file mode 100644
> index 0000000..a54778e
> --- /dev/null
> +++ b/include/usb/fastboot.h
> @@ -0,0 +1,182 @@
> +/*
> + * (C) Copyright 2008 - 2009
> + * Windriver, <www.windriver.com>
> + * Tom Rix <Tom.Rix at windriver.com>
> + *
> + * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy at linutronix.de>
> + *
> + *
> + * Copyright (C) 2008 The Android Open Source Project
> + * All rights reserved.
> + *
> + * Copyright 2014 Linaro, Ltd.
> + * Dileep Katta <dileep.katta at linaro.org>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef FASTBOOT_H
> +#define FASTBOOT_H
> +
> +#include <common.h>
> +#include <command.h>
> +#include <environment.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +
> +#ifdef DEBUG
> +#define FBTDBG(fmt, args...)\
> +		printf("DEBUG: [%s]: %d:\n"fmt, __func__, __LINE__, ##args)
> +#else
> +#define FBTDBG(fmt, args...) do {} while (0)
> +#endif
> +
> +#ifdef INFO
> +#define FBTINFO(fmt, args...)\
> +		printf("INFO: [%s]: "fmt, __func__, ##args)
> +#else
> +#define FBTINFO(fmt, args...) do {} while (0)
> +#endif
> +
> +#ifdef WARN
> +#define FBTWARN(fmt, args...)\
> +		printf("WARNING: [%s]: "fmt, __func__, ##args)
> +#else
> +#define FBTWARN(fmt, args...) do {} while (0)
> +#endif
> +
> +#ifdef ERR
> +#define FBTERR(fmt, args...)\
> +		printf("ERROR: [%s]: "fmt, __func__, ##args)
> +#else
> +#define FBTERR(fmt, args...) do {} while (0)
> +#endif
> +
> +struct fastboot_config {
> +	/*
> +	 * Transfer buffer for storing data sent by the client. It should be
> +	 * able to hold a kernel image and flash partitions. Care should be
> +	 * take so it does not overrun bootloader memory
> +	 */
> +	unsigned char *transfer_buffer;
> +
> +	/* Size of the buffer mentioned above */
> +	unsigned int transfer_buffer_size;
> +
> +	/* Total data to be downloaded */
> +	unsigned int download_size;
> +
> +	/* Data downloaded so far */
> +	unsigned int download_bytes;
> +
> +	unsigned int nand_block_size;
> +
> +	unsigned int nand_oob_size;
> +
> +	unsigned int download_bytes_unpadded;
> +};
> +
> +#define FB_STR_PRODUCT_IDX      1
> +#define FB_STR_SERIAL_IDX       2
> +#define FB_STR_CONFIG_IDX       3
> +#define FB_STR_INTERFACE_IDX    4
> +#define FB_STR_MANUFACTURER_IDX 5
> +#define FB_STR_PROC_REV_IDX     6
> +#define FB_STR_PROC_TYPE_IDX    7
> +
> +#ifdef CONFIG_CMD_FASTBOOT
> +
> +int fastboot_init(void);
> +void fastboot_shutdown(void);
> +int fastboot_poll(void);
> +
> +int fastboot_board_init(struct fastboot_config *interface,
> +		struct usb_gadget_strings **str);
> +
> +
> +/* Android-style flash naming */
> +typedef struct fastboot_ptentry fastboot_ptentry;
> +
> +/* flash partitions are defined in terms of blocks
> + ** (flash erase units)
> + */
> +struct fastboot_ptentry {
> +	/* The logical name for this partition, null terminated */
> +	char name[16];
> +	/* The start wrt the nand part, must be multiple of nand block size */
> +	unsigned int start;
> +	/* The length of the partition, must be multiple of nand block size */
> +	unsigned int length;
> +	/* Controls the details of how operations are done on the partition
> +	   See the FASTBOOT_PTENTRY_FLAGS_*'s defined below */
> +	unsigned int flags;
> +};
> +
> +/* Lower byte shows if the read/write/erase operation in
> +   repeated.  The base address is incremented.
> +   Either 0 or 1 is ok for a default */
> +
> +#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK(n)   (n & 0x0f)
> +#define FASTBOOT_PTENTRY_FLAGS_REPEAT_4         0x00000004
> +
> +/* Writes happen a block at a time.
> +   If the write fails, go to next block
> +   NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK  0x00000010
> +
> +/* Find a contiguous block big enough for a the whole file
> +   NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK 0x00000020
> +
> +/* Sets the ECC to software before writing
> +   HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC           0x00000040
> +
> +/* Sets the ECC to hardware before writing
> +   HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC           0x00000080
> +
> +/* Sets the ECC to hardware before writing
> +   HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH4_ECC      0x00000100
> +
> +/* Sets the ECC to hardware before writing
> +   HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC      0x00000200
> +
> +/* Sets the ECC to hardware before writing
> +   HW and SW ECC should not both be set. */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH16_ECC     0x00000400
> +
> +/* Write the file with write.i */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_I                0x00000800
> +
> +/* Write the file with write.jffs2 */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_JFFS2            0x00001000
> +
> +/* Write the file as a series of variable/value pairs
> +   using the setenv and saveenv commands */
> +#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV              0x00002000
> +
> +
> +/* The Android-style flash handling */
> +
> +/* tools to populate and query the partition table */
> +void fastboot_flash_add_ptn(fastboot_ptentry *ptn);
> +fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
> +fastboot_ptentry *fastboot_flash_get_ptn(unsigned n);
> +unsigned int fastboot_flash_get_ptn_count(void);
> +void fastboot_flash_dump_ptn(void);
> +int fastboot_oem(const char *cmd);
> +int do_format(void);
> +int board_mmc_fbtptn_init(void);
> +void fastboot_flash_reset_ptn(void);
> +int board_partition_init(void);
> +int handle_flash(char *part_name, char *response, char *transfer_buffer);
> +
> +extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
> +extern int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
> +extern env_t *env_ptr;
> +
> +#endif
> +#endif
>

My initial comments and questions
Thanks, Steve


More information about the U-Boot mailing list