Message ID | 164269267060.39378.17392247605833481024.stgit@localhost |
---|---|
State | New |
Headers | show |
Series | FWU: Add FWU Multi Bank Update for DeveloerBox | expand |
On Fri, Jan 21, 2022 at 12:31:10AM +0900, Masami Hiramatsu wrote: > Signed-off-by: Masami Hiramatsu <masami.hiramatsu@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; > +} >
2022年1月21日(金) 11:20 AKASHI Takahiro <takahiro.akashi@linaro.org>: > > On Fri, Jan 21, 2022 at 12:31:10AM +0900, Masami Hiramatsu wrote: > > Signed-off-by: Masami Hiramatsu <masami.hiramatsu@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. Oops, indeed. We just need some comments for those platform dependent functions. Thank you! > > -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; > > +} > > -- Masami Hiramatsu
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 + +#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; +}
Signed-off-by: Masami Hiramatsu <masami.hiramatsu@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