diff mbox series

[RFC,11/14] FWU: Add FWU Multi Bank Update on SPI Flash

Message ID 164269267060.39378.17392247605833481024.stgit@localhost
State New
Headers show
Series FWU: Add FWU Multi Bank Update for DeveloerBox | expand

Commit Message

Masami Hiramatsu Jan. 20, 2022, 3:31 p.m. UTC
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

Comments

AKASHI Takahiro Jan. 21, 2022, 2:20 a.m. UTC | #1
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;
> +}
>
Masami Hiramatsu Jan. 21, 2022, 4:41 a.m. UTC | #2
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 mbox series

Patch

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;
+}