fastboot: Support defining raw partitions without a partition table
Add support for defining raw fastboot partitions in eMMC by specifying
the offset and size in an environment variable. Optionally, the eMMC
hardware partition number may also be specified.
This makes it possible to e.g. update only part of the eMMC boot
partition, instead of having to write the entire partition.
Signed-off-by: Filip Brozovic <fbrozovic@gmail.com>
diff --git a/doc/android/fastboot.rst b/doc/android/fastboot.rst
index de3f6c3..2877c3c 100644
--- a/doc/android/fastboot.rst
+++ b/doc/android/fastboot.rst
@@ -85,6 +85,25 @@
fastboot_partition_alias_boot=LNX
+Raw partition descriptors
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In cases where no partition table is present, a raw partition descriptor can be
+defined, specifying the offset, size, and optionally the MMC hardware partition
+number for a given partition name.
+
+This is useful when using fastboot to flash files (e.g. SPL or U-Boot) to a
+specific offset in the eMMC boot partition, without having to update the entire
+boot partition.
+
+To define a raw partition descriptor, add an environment variable similar to::
+
+ fastboot_raw_partition_<raw partition name>=<offset> <size> [mmcpart <num>]
+
+for example::
+
+ fastboot_raw_partition_boot=0x100 0x1f00 mmcpart 1
+
Variable overrides
^^^^^^^^^^^^^^^^^^
diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c
index b2f8932..ae8e8e5 100644
--- a/drivers/fastboot/fb_mmc.c
+++ b/drivers/fastboot/fb_mmc.c
@@ -50,6 +50,48 @@
return ret;
}
+static int raw_part_get_info_by_name(struct blk_desc *dev_desc,
+ const char *name, struct disk_partition *info, int *mmcpart)
+{
+ /* strlen("fastboot_raw_partition_") + PART_NAME_LEN + 1 */
+ char env_desc_name[23 + PART_NAME_LEN + 1];
+ char *raw_part_desc;
+ const char *argv[2];
+ const char **parg = argv;
+
+ /* check for raw partition descriptor */
+ strcpy(env_desc_name, "fastboot_raw_partition_");
+ strncat(env_desc_name, name, PART_NAME_LEN);
+ raw_part_desc = strdup(env_get(env_desc_name));
+ if (raw_part_desc == NULL)
+ return -ENODEV;
+
+ /*
+ * parse partition descriptor
+ *
+ * <lba_start> <lba_size> [mmcpart <num>]
+ */
+ for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) {
+ *parg = strsep(&raw_part_desc, " ");
+ if (*parg == NULL) {
+ pr_err("Invalid number of arguments.\n");
+ return -ENODEV;
+ }
+ }
+
+ info->start = simple_strtoul(argv[0], NULL, 0);
+ info->size = simple_strtoul(argv[1], NULL, 0);
+ info->blksz = dev_desc->blksz;
+ strncpy((char *)info->name, name, PART_NAME_LEN);
+
+ if (raw_part_desc) {
+ if (strcmp(strsep(&raw_part_desc, " "), "mmcpart") == 0)
+ *mmcpart = simple_strtoul(raw_part_desc, NULL, 0);
+ }
+
+ return 0;
+}
+
/**
* fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE
*
@@ -376,7 +418,8 @@
struct blk_desc **dev_desc,
struct disk_partition *part_info, char *response)
{
- int r;
+ int r = 0;
+ int mmcpart;
*dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!*dev_desc) {
@@ -388,10 +431,12 @@
return -ENOENT;
}
- r = part_get_info_by_name_or_alias(*dev_desc, part_name, part_info);
- if (r < 0) {
- fastboot_fail("partition not found", response);
- return r;
+ if (raw_part_get_info_by_name(*dev_desc, part_name, part_info, &mmcpart) < 0) {
+ r = part_get_info_by_name_or_alias(*dev_desc, part_name, part_info);
+ if (r < 0) {
+ fastboot_fail("partition not found", response);
+ return r;
+ }
}
return r;
@@ -410,6 +455,7 @@
{
struct blk_desc *dev_desc;
struct disk_partition info;
+ int mmcpart = 0;
dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
@@ -482,7 +528,13 @@
}
#endif
- if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) {
+ if (raw_part_get_info_by_name(dev_desc, cmd, &info, &mmcpart) == 0) {
+ if (blk_dselect_hwpart(dev_desc, mmcpart)) {
+ pr_err("Failed to select hwpart\n");
+ fastboot_fail("Failed to select hwpart", response);
+ return;
+ }
+ } else if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) {
pr_err("cannot find partition: '%s'\n", cmd);
fastboot_fail("cannot find partition", response);
return;
@@ -524,11 +576,11 @@
*/
void fastboot_mmc_erase(const char *cmd, char *response)
{
- int ret;
struct blk_desc *dev_desc;
struct disk_partition info;
lbaint_t blks, blks_start, blks_size, grp_size;
struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV);
+ int mmcpart = 0;
if (mmc == NULL) {
pr_err("invalid mmc device\n");
@@ -562,8 +614,13 @@
}
#endif
- ret = part_get_info_by_name_or_alias(dev_desc, cmd, &info);
- if (ret < 0) {
+ if (raw_part_get_info_by_name(dev_desc, cmd, &info, &mmcpart) == 0) {
+ if (blk_dselect_hwpart(dev_desc, mmcpart)) {
+ pr_err("Failed to select hwpart\n");
+ fastboot_fail("Failed to select hwpart", response);
+ return;
+ }
+ } else if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) {
pr_err("cannot find partition: '%s'\n", cmd);
fastboot_fail("cannot find partition", response);
return;