diff mbox series

fastboot: Support defining raw partitions without a partition table

Message ID 20200629111437.106839-1-fbrozovic@gmail.com
State Accepted
Commit a17c0cb85e3abe8601efaadbb287116d1142fefd
Headers show
Series fastboot: Support defining raw partitions without a partition table | expand

Commit Message

=?UTF-8?Q?Filip_Brozovi=C4=87?= June 29, 2020, 11:14 a.m. UTC
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 at gmail.com>
---
 doc/android/fastboot.rst  | 19 ++++++++++
 drivers/fastboot/fb_mmc.c | 75 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 85 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/doc/android/fastboot.rst b/doc/android/fastboot.rst
index de3f6c37d7..2877c3cbaa 100644
--- a/doc/android/fastboot.rst
+++ b/doc/android/fastboot.rst
@@ -85,6 +85,25 @@  for example::
 
     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 b2f8932e1c..ae8e8e512f 100644
--- a/drivers/fastboot/fb_mmc.c
+++ b/drivers/fastboot/fb_mmc.c
@@ -50,6 +50,48 @@  static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc,
 	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 @@  int fastboot_mmc_get_part_info(const char *part_name,
 			       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 @@  int fastboot_mmc_get_part_info(const char *part_name,
 		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 @@  void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
 {
 	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 @@  void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
 	}
 #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_flash_write(const char *cmd, void *download_buffer,
  */
 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 @@  void fastboot_mmc_erase(const char *cmd, char *response)
 	}
 #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;