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 <fpar...@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; > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot