[RFC PATCH 11/14] FWU: Add FWU Multi Bank Update on SPI Flash
AKASHI Takahiro
takahiro.akashi at linaro.org
Fri Jan 21 03:20:25 CET 2022
On Fri, Jan 21, 2022 at 12:31:10AM +0900, Masami Hiramatsu wrote:
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu at linaro.org>
> ---
> include/fwu.h | 13 ++
> lib/fwu_updates/Kconfig | 34 ++++++
> lib/fwu_updates/Makefile | 5 -
> lib/fwu_updates/fwu_mdata_sf.c | 241 ++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 288 insertions(+), 5 deletions(-)
> create mode 100644 lib/fwu_updates/fwu_mdata_sf.c
>
> diff --git a/include/fwu.h b/include/fwu.h
> index 7af94988b7..a013170321 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -64,9 +64,18 @@ int fwu_accept_image(efi_guid_t *img_type_id, u32 bank);
> int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank);
>
> int fwu_plat_get_update_index(u32 *update_idx);
> -int fwu_plat_get_blk_desc(struct blk_desc **desc);
> -int fwu_plat_get_alt_num(void *identifier);
> int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr);
> void fwu_plat_get_bootidx(void *boot_idx);
>
> +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE_GPT_BLK
> +int fwu_plat_get_blk_desc(struct blk_desc **desc);
> +int fwu_plat_get_alt_num(void *identifier);
> +#endif
We can (and should) remove "#ifdef ..." from headers.
-Takahiro Akashi
> +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE_SF
> +struct fwu_mdata_ops *fwu_sf_get_fwu_mdata_ops(void);
> +int fwu_plat_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
> + int *alt_no);
> +#endif
> +
> #endif /* _FWU_H_ */
> diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
> index 0940a90747..8a369b9872 100644
> --- a/lib/fwu_updates/Kconfig
> +++ b/lib/fwu_updates/Kconfig
> @@ -38,3 +38,37 @@ config FWU_REBOOT_AFTER_UPDATE
> Reboot the machine soon after installing a new firmware
> and start trial boot. You can disable this option for
> debugging or FWU development, but recommended to enable it.
> +
> +config FWU_MULTI_BANK_UPDATE_GPT_BLK
> + bool "Enable FWU Multi Bank Update for GPT on blockdev"
> + depends on FWU_MULTI_BANK_UPDATE
> + select EFI_PARTITION
> + help
> + Enable FWU Multi Bank Update for GPT on a block device. This
> + driver depends on GPT and the block device. FWU meatadata and
> + firmware will be stored on a block device with GPT.
> +
> +config FWU_MULTI_BANK_UPDATE_SF
> + bool "Enable FWU Multi Bank Update for SPI Flash"
> + depends on FWU_MULTI_BANK_UPDATE
> + help
> + Enable FWU Multi Bank Update for SPI flash driver. This
> + driver does not depend on GPT. Instead, the platform must
> + provide some APIs and define the offset of the primary and
> + the secondary metadata.
> +
> +config FWU_SF_PRIMARY_MDATA_OFFSET
> + hex "The offset of the primary metadata"
> + depends on FWU_MULTI_BANK_UPDATE_SF
> + help
> + The offset of the primary metadata on SPI Flash in
> + hexadecimal.
> +
> +config FWU_SF_SECONDARY_MDATA_OFFSET
> + hex "The offset of the secondary metadata"
> + depends on FWU_MULTI_BANK_UPDATE_SF
> + help
> + The offset of the secondary metadata on SPI Flash in
> + hexadecimal.
> + This must NOT be the same offset of the primary
> + metadata.
> diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile
> index 73099a30cb..80669344f2 100644
> --- a/lib/fwu_updates/Makefile
> +++ b/lib/fwu_updates/Makefile
> @@ -6,6 +6,5 @@
> obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_mdata.o
> obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o
>
> -ifdef CONFIG_EFI_PARTITION
> -obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_mdata_gpt_blk.o
> -endif
> +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE_GPT_BLK) += fwu_mdata_gpt_blk.o
> +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE_SF) += fwu_mdata_sf.o
> diff --git a/lib/fwu_updates/fwu_mdata_sf.c b/lib/fwu_updates/fwu_mdata_sf.c
> new file mode 100644
> index 0000000000..9e3cae7b68
> --- /dev/null
> +++ b/lib/fwu_updates/fwu_mdata_sf.c
> @@ -0,0 +1,241 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2021, Linaro Limited
> + */
> +
> +#include <efi_loader.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <malloc.h>
> +#include <memalign.h>
> +#include <spi.h>
> +#include <spi_flash.h>
> +#include <flash.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <u-boot/crc.h>
> +
> +/*
> + * For the FWU SPI flash driver, the platform must define below functions
> + * according to its dfu_alt_info.
> + */
> +extern int fwu_plat_get_image_alt_num(efi_guid_t image_type_id,
> + u32 update_bank, int *alt_no);
> +
> +static struct spi_flash *fwu_spi_flash;
> +
> +static int __fwu_sf_get_flash(void)
> +{
> + if (IS_ENABLED(CONFIG_DM_SPI_FLASH)) {
> + struct udevice *new;
> + int ret;
> +
> + ret = spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS,
> + CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE,
> + &new);
> + if (ret)
> + return ret;
> +
> + fwu_spi_flash = dev_get_uclass_priv(new);
> + } else {
> + fwu_spi_flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS,
> + CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE);
> + if (!fwu_spi_flash)
> + return -EIO;
> + }
> + return 0;
> +}
> +
> +static int fwu_sf_get_flash(struct spi_flash **flash)
> +{
> + int ret = 0;
> +
> + if (!fwu_spi_flash)
> + ret = __fwu_sf_get_flash();
> +
> + *flash = fwu_spi_flash;
> +
> + return ret;
> +}
> +
> +static int sf_load_data(u32 offs, u32 size, void **data)
> +{
> + struct spi_flash *flash;
> + int ret;
> +
> + ret = fwu_sf_get_flash(&flash);
> + if (ret < 0)
> + return ret;
> +
> + *data = memalign(ARCH_DMA_MINALIGN, size);
> + if (!*data)
> + return -ENOMEM;
> +
> + ret = spi_flash_read(flash, offs, size, *data);
> + if (ret < 0) {
> + free(*data);
> + *data = NULL;
> + }
> +
> + return ret;
> +}
> +
> +static int sf_save_data(u32 offs, u32 size, void *data)
> +{
> + struct spi_flash *flash;
> + u32 sect_size, nsect;
> + void *buf;
> + int ret;
> +
> + ret = fwu_sf_get_flash(&flash);
> + if (ret < 0)
> + return ret;
> +
> + sect_size = flash->mtd.erasesize;
> + nsect = DIV_ROUND_UP(size, sect_size);
> + ret = spi_flash_erase(flash, offs, nsect * sect_size);
> + if (ret < 0)
> + return ret;
> +
> + buf = memalign(ARCH_DMA_MINALIGN, size);
> + if (!buf)
> + return -ENOMEM;
> + memcpy(buf, data, size);
> +
> + ret = spi_flash_write(flash, offs, size, buf);
> +
> + free(buf);
> +
> + return ret;
> +}
> +
> +static int fwu_sf_load_mdata(struct fwu_mdata **mdata, u32 offs)
> +{
> + int ret;
> +
> + ret = sf_load_data(offs, sizeof(struct fwu_mdata), (void **)mdata);
> +
> + if (ret >= 0) {
> + ret = fwu_verify_mdata(*mdata,
> + offs == CONFIG_FWU_SF_PRIMARY_MDATA_OFFSET);
> + if (ret < 0) {
> + free(*mdata);
> + *mdata = NULL;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static int fwu_sf_load_primary_mdata(struct fwu_mdata **mdata)
> +{
> + return fwu_sf_load_mdata(mdata, CONFIG_FWU_SF_PRIMARY_MDATA_OFFSET);
> +}
> +
> +static int fwu_sf_load_secondary_mdata(struct fwu_mdata **mdata)
> +{
> + return fwu_sf_load_mdata(mdata, CONFIG_FWU_SF_SECONDARY_MDATA_OFFSET);
> +}
> +
> +static int fwu_sf_save_primary_mdata(struct fwu_mdata *mdata)
> +{
> + return sf_save_data(CONFIG_FWU_SF_PRIMARY_MDATA_OFFSET,
> + sizeof(struct fwu_mdata), mdata);
> +}
> +
> +static int fwu_sf_save_secondary_mdata(struct fwu_mdata *mdata)
> +{
> + return sf_save_data(CONFIG_FWU_SF_SECONDARY_MDATA_OFFSET,
> + sizeof(struct fwu_mdata), mdata);
> +}
> +
> +static int fwu_sf_get_valid_mdata(struct fwu_mdata **mdata)
> +{
> + if (fwu_sf_load_primary_mdata(mdata) == 0)
> + return 0;
> +
> + log_err("Failed to load/verify primary mdata. Try secondary.\n");
> +
> + if (fwu_sf_load_secondary_mdata(mdata) == 0)
> + return 0;
> +
> + log_err("Failed to load/verify secondary mdata.\n");
> +
> + return -1;
> +}
> +
> +static int fwu_sf_update_mdata(struct fwu_mdata *mdata)
> +{
> + int ret;
> +
> + /* Update mdata crc32 field */
> + mdata->crc32 = crc32(0, (void *)&mdata->version,
> + sizeof(*mdata) - sizeof(u32));
> +
> + /* First write the primary mdata */
> + ret = fwu_sf_save_primary_mdata(mdata);
> + if (ret < 0) {
> + log_err("Failed to update the primary mdata.\n");
> + return ret;
> + }
> +
> + /* And now the replica */
> + ret = fwu_sf_save_secondary_mdata(mdata);
> + if (ret < 0) {
> + log_err("Failed to update the secondary mdata.\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int fwu_sf_mdata_check(void)
> +{
> + struct fwu_mdata *primary = NULL, *secondary = NULL;
> + int ret;
> +
> + ret = fwu_sf_load_primary_mdata(&primary);
> + if (ret < 0)
> + log_err("Failed to read the primary mdata: %d\n", ret);
> +
> + ret = fwu_sf_load_secondary_mdata(&secondary);
> + if (ret < 0)
> + log_err("Failed to read the secondary mdata: %d\n", ret);
> +
> + if (primary && secondary) {
> + if (memcmp(primary, secondary, sizeof(struct fwu_mdata))) {
> + log_err("The primary and the secondary mdata are different\n");
> + ret = -1;
> + }
> + } else if (primary) {
> + ret = fwu_sf_save_secondary_mdata(primary);
> + if (ret < 0)
> + log_err("Restoring secondary mdata partition failed\n");
> + } else if (secondary) {
> + ret = fwu_sf_save_primary_mdata(secondary);
> + if (ret < 0)
> + log_err("Restoring primary mdata partition failed\n");
> + }
> +
> + free(primary);
> + free(secondary);
> + return ret;
> +}
> +
> +static int fwu_sf_get_mdata(struct fwu_mdata **mdata)
> +{
> + return fwu_sf_get_valid_mdata(mdata);
> +}
> +
> +static struct fwu_mdata_ops fwu_sf_mdata_ops = {
> + .get_image_alt_num = fwu_plat_get_image_alt_num,
> + .mdata_check = fwu_sf_mdata_check,
> + .get_mdata = fwu_sf_get_mdata,
> + .update_mdata = fwu_sf_update_mdata,
> +};
> +
> +struct fwu_mdata_ops *fwu_sf_get_fwu_mdata_ops(void)
> +{
> + return &fwu_sf_mdata_ops;
> +}
>
More information about the U-Boot
mailing list