[U-Boot] [PATCH v1 1/1] fastboot: oem format command implementation
Dileep Katta
dileep.katta at linaro.org
Fri Jan 30 12:54:51 CET 2015
This is the Modified version of http://patchwork.ozlabs.org/patch/388084/
- As flash support is already in mainline, it is removed
- 'oem' command support is present
- 'oem format' command is implemented
- Handled review comments of the original patch
Signed-off-by: Dileep Katta <dileep.katta at linaro.org>
---
common/cmd_fastboot.c | 4 +
common/cmd_mmc.c | 2 +-
disk/Makefile | 1 +
disk/part_fastboot.c | 363 ++++++++++++++++++++++++++++++++++++++++
doc/README.android-fastboot | 5 +-
drivers/usb/gadget/f_fastboot.c | 85 ++++++++++
include/usb/fastboot.h | 108 ++++++++++++
7 files changed, 564 insertions(+), 4 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 b72f4f3..efdf461 100644
--- a/common/cmd_fastboot.c
+++ b/common/cmd_fastboot.c
@@ -10,12 +10,16 @@
#include <common.h>
#include <command.h>
#include <g_dnl.h>
+#include <usb/fastboot.h>
static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
int ret;
g_dnl_clear_detach();
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+ board_partition_init();
+#endif
ret = g_dnl_register("usb_dnl_fastboot");
if (ret)
return ret;
diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
index 4e28c9d..0ce747b 100644
--- a/common/cmd_mmc.c
+++ b/common/cmd_mmc.c
@@ -809,7 +809,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/disk/Makefile b/disk/Makefile
index 6970cec..4969656 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_FASTBOOT_FLASH_MMC_DEV) +=part_fastboot.o
diff --git a/disk/part_fastboot.c b/disk/part_fastboot.c
new file mode 100644
index 0000000..adf37af
--- /dev/null
+++ b/disk/part_fastboot.c
@@ -0,0 +1,363 @@
+/*
+ * 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>
+#include <asm/arch/mmc_host_def.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 },
+};
+
+
+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;
+
+ /* Get the initial checksum by passing buf as NULL */
+ n = crc32(0, NULL, 0);
+ n = crc32(n, (void *)ptbl->entry, sizeof(ptbl->entry));
+ hdr->entries_crc32 = n;
+
+ 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)
+{
+ u64 ptbl_sectors = 0;
+ int i = 0, r = 0;
+
+ struct ptable gpt[sizeof(struct ptable)];
+ struct mmc *mmc = NULL;
+
+ mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV);
+ if (mmc == NULL) {
+ printf("No MMC in slot 1\n");
+ return -1;
+ }
+
+ int gpt_size = sizeof(struct ptable);
+
+ ptbl_sectors = (u64)(gpt_size / MMCSD_SECTOR_SIZE);
+
+ r = mmc->block_dev.block_read(1, 0, ptbl_sectors, (void *)gpt);
+ if (r == -1) {
+ printf("error reading GPT\n");
+ goto fail;
+ }
+
+ if (memcmp(gpt->header.magic, "EFI PART", 8)) {
+ printf("efi partition table not found\n");
+ r = -1;
+ goto fail;
+ }
+
+ for (i = 0; i < EFI_ENTRIES; i++)
+ import_efi_partition(&gpt->entry[i]);
+
+fail:
+ return r;
+}
+
+int board_mmc_fbtptn_init(void)
+{
+ char *mmc_init[2] = {"mmc", "rescan",};
+ char dev[2];
+ char *mmc_dev[3] = {"mmc", "dev", dev};
+ unsigned fb_mmcdev = CONFIG_FASTBOOT_FLASH_MMC_DEV;
+
+ sprintf(dev, "0x%x", fb_mmcdev);
+
+ if (do_mmcops(NULL, 0, 3, mmc_dev)) {
+ printf("MMC DEV: %d selection FAILED!\n", fb_mmcdev);
+ return -1;
+ }
+
+ if (do_mmcops(NULL, 0, 2, mmc_init)) {
+ printf("FAIL:Init of MMC card\n");
+ return -1;
+ }
+
+ return load_ptbl();
+}
+
+
+static struct ptable the_ptable;
+
+int do_format(void)
+{
+ struct ptable *ptbl = &the_ptable;
+ struct mmc *mmc = NULL;
+ unsigned blocks;
+ unsigned next;
+ unsigned sz;
+ int n;
+ unsigned fb_mmcdev = CONFIG_FASTBOOT_FLASH_MMC_DEV;
+
+ /* get mmc info */
+ mmc = find_mmc_device(fb_mmcdev);
+ if (mmc == 0) {
+ printf("no mmc device at slot %d", fb_mmcdev);
+ return -1;
+ }
+
+ mmc->has_init = 0;
+ if (mmc_init(mmc)) {
+ printf("\n mmc init FAILED");
+ return -1;
+ }
+
+ 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;
+
+ start_ptbl(ptbl, blocks);
+ n = 0;
+ next = 0;
+ for (n = 0, next = 0; partitions[n].name; n++) {
+ /* below line change size from KB to no of blocks */
+ 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();
+
+ 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", fb_mmcdev);
+
+ if (do_mmcops(NULL, 0, 3, mmc_dev)) {
+ printf("MMC DEV: %d selection FAILED!\n", 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("mbr write FAILED!\n");
+ return -1;
+ }
+
+ printf("\nnew partition table:\n");
+ load_ptbl();
+
+ return 0;
+}
diff --git a/doc/README.android-fastboot b/doc/README.android-fastboot
index 1677609..77cce8e 100644
--- a/doc/README.android-fastboot
+++ b/doc/README.android-fastboot
@@ -6,9 +6,8 @@ Overview
The protocol that is used over USB is described in
README.android-fastboot-protocol in same directory.
-The current implementation does not yet support the erase command or the
-"oem format" command, and there is minimal support for the flash command;
-it only supports eMMC devices.
+The current implementation does not yet support the erase command, and
+there is minimal support for the flash command;it only supports eMMC devices.
Client installation
===================
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 310175a..76ccc55 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -23,6 +23,8 @@
#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
#include <fb_mmc.h>
#endif
+#include <usb/fastboot.h>
+#include <command.h>
#define FASTBOOT_VERSION "0.4"
@@ -39,6 +41,12 @@
#define EP_BUFFER_SIZE 4096
+/* To support the Android-style naming of flash */
+#define MAX_PTN 16
+static struct fastboot_ptentry ptable[MAX_PTN];
+static unsigned int pcount;
+/* static int static_pcount = -1; */
+
struct f_fastboot {
struct usb_function usb_function;
@@ -123,6 +131,33 @@ static struct usb_gadget_strings *fastboot_strings[] = {
static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+/* 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(struct 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++) {
+ struct 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;
@@ -312,6 +347,21 @@ static int fastboot_tx_write_str(const char *buffer)
return fastboot_tx_write(buffer, strlen(buffer));
}
+struct 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);
@@ -513,6 +563,27 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req)
}
#endif
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+int fastboot_oem(const char *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;
+
+ int r = fastboot_oem(cmd + 4);
+ if (r < 0) {
+ fastboot_tx_write_str("FAIL");
+ } else {
+ fastboot_tx_write_str("OKAY");
+ }
+}
+#endif
+
struct cmd_dispatch_info {
char *cmd;
void (*cb)(struct usb_ep *ep, struct usb_request *req);
@@ -541,6 +612,12 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = {
.cb = cb_flash,
},
#endif
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+ {
+ .cmd = "oem",
+ .cb = cb_oem,
+ },
+#endif
};
static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
@@ -576,3 +653,11 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
usb_ep_queue(ep, req, 0);
}
}
+
+#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
+int board_partition_init(void)
+{
+ board_mmc_fbtptn_init();
+ return 1;
+}
+#endif
diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
new file mode 100644
index 0000000..8fee6fc
--- /dev/null
+++ b/include/usb/fastboot.h
@@ -0,0 +1,108 @@
+/*
+ * (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 CONFIG_CMD_FASTBOOT
+
+/* Android-style flash naming */
+
+/* flash partitions are defined in blocks (flash erase units) */
+struct fastboot_ptentry {
+ /* The logical name for this partition, null terminated */
+ char name[16];
+ /* start wrt the nand part, must be multiple of nand block size */
+ unsigned int start;
+ /* 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 is 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
+
+/*
+ * Following definitions are to set the ECC to software/Hardware
+ * before writing. HW and SW ECC should not both be set.
+ */
+
+
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC 0x00000040
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC 0x00000080
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH4_ECC 0x00000100
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC 0x00000200
+#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(struct fastboot_ptentry *ptn);
+struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
+struct 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 do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+#endif
+#endif
--
1.8.3.2
More information about the U-Boot
mailing list