[U-Boot] [PATCH] fastboot: mmc: add support for flashing boot partitions
Neil Armstrong
narmstrong at baylibre.com
Fri Jun 28 09:24:22 UTC 2019
Hi Fabien,
On 25/06/2019 18:43, Fabien Parent wrote:
> MMC storage supports 4 hardware partitions:
> * User partition
> * 2 boot partitions
> * RPMB partition
>
> Flashing to the User partition is already supported, and this commit
> adds support for flashing to the 2 boot partitions.
I find it quite dansgerous to expose the whole boot0/boot1 partitions
via fastboot, usually a bootloader or environment will use only a small
area of these HW partitions, like SPI or other non volatile storages.
I implemented a way to handle "vendor" partitions instead since bootloader.
envs, ... on boot HW partitions is heavily vendor/board specific.
Here is the fastboot code I added :
=======><===========================================
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index d63ecdd27e..9c914d4842 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -86,6 +86,10 @@ config FASTBOOT_FLASH_NAND
endchoice
+config FASTBOOT_FLASH_CUSTOM
+ bool "FASTBOOT on custom board partitions"
+ depends on FASTBOOT_FLASH
+
config FASTBOOT_FLASH_MMC_DEV
int "Define FASTBOOT MMC FLASH default device"
depends on FASTBOOT_FLASH_MMC
diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c
index 200f9910c5..57e14cdbde 100644
--- a/drivers/fastboot/fb_command.c
+++ b/drivers/fastboot/fb_command.c
@@ -8,6 +8,7 @@
#include <fastboot-internal.h>
#include <fb_mmc.h>
#include <fb_nand.h>
+#include <fb_board.h>
#include <part.h>
#include <stdlib.h>
@@ -266,6 +267,11 @@ void fastboot_data_complete(char *response)
*/
static void flash(char *cmd_parameter, char *response)
{
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_CUSTOM)
+ if (fastboot_board_flash_write(cmd_parameter, fastboot_buf_addr,
+ image_size, response))
+ return;
+#endif
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
response);
@@ -287,6 +293,10 @@ static void flash(char *cmd_parameter, char *response)
*/
static void erase(char *cmd_parameter, char *response)
{
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_CUSTOM)
+ if (fastboot_board_erase(cmd_parameter, response))
+ return;
+#endif
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
fastboot_mmc_erase(cmd_parameter, response);
#endif
diff --git a/include/fb_board.h b/include/fb_board.h
new file mode 100644
index 0000000000..c5d6f59fc6
--- /dev/null
+++ b/include/fb_board.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 BayLibre SAS
+ */
+
+#ifndef _FB_BOARD_H_
+#define _FB_BOARD_H_
+
+/**
+ * fastboot_board_flash_write() - Write image to board partition for fastboot
+ *
+ * @cmd: Named partition to write image to
+ * @download_buffer: Pointer to image data
+ * @download_bytes: Size of image data
+ * @response: Pointer to fastboot response buffer
+ * @return true if write was handled, false if was not handled
+ */
+bool fastboot_board_flash_write(const char *cmd, void *download_buffer,
+ u32 download_bytes, char *response);
+/**
+ * fastboot_board_flash_erase() - Erase board partition for fastboot
+ *
+ * @cmd: Named partition to erase
+ * @response: Pointer to fastboot response buffer
+ * @return true if erase was handled, false if was not handled
+ */
+bool fastboot_board_erase(const char *cmd, char *response);
+#endif
========><=============================================================
This could handle any virtual partitions on any device (SPI, eeprom, mmc HW, eFuses, NVMEM.....)
is a generic way from the fastboot code, but protecting the whole memory zone from being
re-written if it contains sensible data like factory data, keys, ....
Then you can add the following (not optimal at all) in a board support :
========><=============================================================
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_CUSTOM) && CONFIG_IS_ENABLED(MMC_WRITE)
+
+#include <malloc.h>
+#include <blk.h>
+#include <fastboot.h>
+#include <fastboot-internal.h>
+#include <fb_board.h>
+#include <image-sparse.h>
+#include <mmc.h>
+#include <div64.h>
+#include <linux/compat.h>
+
+#define FASBOOT_HWPART_MMC_ENV_DEV CONFIG_SYS_MMC_ENV_DEV
+#define FASBOOT_HWPART_MMC_ENV_PART CONFIG_SYS_MMC_ENV_PART
+#define FASBOOT_HWPART_BOOTLOADER_OFFSET 0x200 /* Block 1 */
+#define FASBOOT_HWPART_BOOTLOADER_LENGTH 0xffe00 /* 1MiB */
+#define FASBOOT_HWPART_BOOTENV_OFFSET CONFIG_ENV_OFFSET
+#define FASBOOT_HWPART_BOOTENV_LENGTH CONFIG_ENV_SIZE
+
+#define FASTBOOT_MAX_BLK_WRITE 16384
+
+static bool fastboot_board_hwpart_process(const char *cmd, void *buffer,
+ u32 bytes, char *response)
+{
+ struct blk_desc *desc;
+ void *blk_ptr = NULL;
+ int offset, length;
+ struct mmc *mmc;
+ lbaint_t blkcnt;
+ lbaint_t blk;
+ lbaint_t blks_written;
+ lbaint_t cur_blkcnt;
+ lbaint_t blks = 0;
+ int ret, i;
+
+ /* Check if we handle these partitions */
+ if (strcmp(cmd, "bootloader") == 0) {
+ offset = FASBOOT_HWPART_BOOTLOADER_OFFSET;
+ length = FASBOOT_HWPART_BOOTLOADER_LENGTH;
+ } else if (strcmp(cmd, "bootenv") == 0) {
+ offset = FASBOOT_HWPART_BOOTENV_OFFSET;
+ length = FASBOOT_HWPART_BOOTENV_LENGTH;
+ } else
+ return false;
+
+ if (buffer && is_sparse_image(buffer)) {
+ pr_err("sparse buffer not supported");
+ fastboot_fail("sparse buffer not supported", response);
+ return true;
+ }
+
+ mmc = find_mmc_device(FASBOOT_HWPART_MMC_ENV_DEV);
+ if (!mmc) {
+ pr_err("invalid mmc device\n");
+ fastboot_fail("invalid mmc device", response);
+ return true;
+ }
+
+ ret = mmc_switch_part(mmc, FASBOOT_HWPART_MMC_ENV_PART);
+ if (ret) {
+ pr_err("invalid mmc hwpart\n");
+ fastboot_fail("invalid mmc hwpart", response);
+ return true;
+ }
+
+ desc = mmc_get_blk_desc(mmc);
+
+ if (offset < 0)
+ offset += mmc->capacity;
+
+ printf("using custom hwpart %s at offset 0x%x and length %d bytes\n",
+ cmd, offset, length);
+
+ /* Use full length in erase mode */
+ if (!buffer)
+ bytes = length;
+
+ /* determine number of blocks to write */
+ blkcnt = ((bytes + (desc->blksz - 1)) & ~(desc->blksz - 1));
+ blkcnt = lldiv(blkcnt, desc->blksz);
+
+ if ((blkcnt * desc->blksz) > length) {
+ pr_err("too large for partition: '%s'\n", cmd);
+ fastboot_fail("too large for partition", response);
+ return true;
+ }
+
+ blk = offset / desc->blksz;
+
+ printf("writing " LBAFU " blocks starting at %ld...\n", blkcnt, blk);
+
+ for (i = 0; i < blkcnt; i += FASTBOOT_MAX_BLK_WRITE) {
+ cur_blkcnt = min((int)blkcnt - i, FASTBOOT_MAX_BLK_WRITE);
+ if (buffer) {
+ if (fastboot_progress_callback)
+ fastboot_progress_callback("writing");
+ blks_written = blk_dwrite(desc, blk, cur_blkcnt,
+ buffer + (i * desc->blksz));
+ } else if ((blk % mmc->erase_grp_size) == 0 &&
+ (cur_blkcnt % mmc->erase_grp_size) == 0) {
+ /* Only call erase if multiple of erase group */
+ if (fastboot_progress_callback)
+ fastboot_progress_callback("erasing");
+ blks_written = blk_derase(desc, blk, cur_blkcnt);
+ } else {
+ /* Write 0s if not aligned */
+ if (!blk_ptr) {
+ blk_ptr = malloc(desc->blksz);
+ if (!blk_ptr) {
+ pr_err("failed to allocate\n");
+ fastboot_fail("failed to allocate",
+ response);
+ return true;
+ }
+ memset(blk_ptr, 0, desc->blksz);
+ }
+ if (fastboot_progress_callback)
+ fastboot_progress_callback("erasing");
+ blks_written = 0;
+ do {
+ blks_written += blk_dwrite(desc, blk, 1,
+ blk_ptr);
+ } while (--cur_blkcnt);
+ }
+ blk += blks_written;
+ blks += blks_written;
+ }
+
+ if (blk_ptr)
+ free(blk_ptr);
+
+ if (blks != blkcnt) {
+ pr_err("failed writing to device %d\n", desc->devnum);
+ fastboot_fail("failed writing to device", response);
+ return true;
+ }
+
+ printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * desc->blksz,
+ cmd);
+ fastboot_okay(NULL, response);
+
+ return true;
+}
+
+
+bool fastboot_board_flash_write(const char *cmd, void *download_buffer,
+ u32 download_bytes, char *response)
+{
+ return fastboot_board_hwpart_process(cmd, download_buffer,
+ download_bytes, response);
+}
+
+bool fastboot_board_erase(const char *cmd, char *response)
+{
+ return fastboot_board_hwpart_process(cmd, NULL, 0, response);
+}
+#endif
========><=============================================================
>
> User can run the following commands to flash to the boot partitions:
> fastboot flash mmcboot0 myfile
> fastboot flash mmcboot1 myfile
>
> "mmcboot" is the default name of the partition and can be changed via
> a Kconfig option.
>
> Signed-off-by: Fabien Parent <fparent at baylibre.com>
> ---
> drivers/fastboot/Kconfig | 17 +++++++++++++++++
> drivers/fastboot/fb_mmc.c | 36 +++++++++++++++++++++++++++++++++++-
> 2 files changed, 52 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
> index d63ecdd27e..f481d7596c 100644
> --- a/drivers/fastboot/Kconfig
> +++ b/drivers/fastboot/Kconfig
> @@ -126,6 +126,23 @@ config FASTBOOT_MBR_NAME
> specified on the "fastboot flash" command line matches the value
> defined here. The default target name for updating MBR is "mbr".
>
> +config FASTBOOT_MMC_BOOT_PART_NAME
> + string "Target name for updating MMC's boot partitions"
> + depends on FASTBOOT_FLASH_MMC
> + default "mmcboot"
> + help
> + The fastboot "flash" command supports writing the downloaded
> + image to the MMC's boot partitions.
> + This occurs when the specified "partition name" on the
> + "fastboot flash" command line is starts with the value defined here,
> + and ends with '0' or '1' to specify which boot partition is being
> + targeted.
> + The default name for updating the boot partitions is "mmcboot".
> + For example the two partitions can be flashed using the following
> + commands if the default name is used:
> + - "fastboot flash mmcboot0 myfile",
> + - "fastboot flash mmcboot1 myfile".
> +
> config FASTBOOT_CMD_OEM_FORMAT
> bool "Enable the 'oem format' command"
> depends on FASTBOOT_FLASH_MMC && CMD_GPT
> diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c
> index 90ca81da9b..c2451200f7 100644
> --- a/drivers/fastboot/fb_mmc.c
> +++ b/drivers/fastboot/fb_mmc.c
> @@ -46,6 +46,28 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc,
> return ret;
> }
>
> +static int part_get_mmc_boot_info(int hwpart, disk_partition_t *info)
> +{
> + struct mmc *mmc;
> + int ret;
> +
> + mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV);
> + if (!mmc)
> + return -EINVAL;
> +
> + ret = blk_select_hwpart_devnum(IF_TYPE_MMC,
> + CONFIG_FASTBOOT_FLASH_MMC_DEV, hwpart);
> + if (ret < 0)
> + return ret;
> +
> + memset(info, 0, sizeof(*info));
> + info->start = 0;
> + info->size = mmc->capacity_boot;
> + info->blksz = mmc->write_bl_len;
> +
> + return 0;
> +}
> +
> /**
> * fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE
> *
> @@ -394,7 +416,19 @@ 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 (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT_PART_NAME "0") == 0) {
> + if (part_get_mmc_boot_info(1, &info) < 0) {
> + pr_err("cannot find partition: '%s'\n", cmd);
> + fastboot_fail("cannot find partition", response);
> + return;
> + }
> + } else if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT_PART_NAME "1") == 0) {
> + if (part_get_mmc_boot_info(2, &info) < 0) {
> + pr_err("cannot find partition: '%s'\n", cmd);
> + fastboot_fail("cannot find partition", 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;
>
More information about the U-Boot
mailing list