All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support
@ 2022-06-09 12:29 Sughosh Ganu
  2022-06-09 12:29 ` [PATCH v5 01/23] dt/bindings: Add bindings for FWU Metadata storage device Sughosh Ganu
                   ` (23 more replies)
  0 siblings, 24 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar


The patchset adds support for the FWU Multi Bank Update[1]
feature. Certain aspects of the Dependable Boot[2] specification have
also been implemented.

The FWU multi bank update feature is used for supporting multiple
sets(also called banks) of firmware image(s), allowing the platform to
boot from a different bank, in case it fails to boot from the active
bank. This functionality is supported by keeping the relevant
information in a structure called metadata, which provides information
on the images. Among other parameters, the metadata structure contains
information on the currect active bank that is being used to boot
image(s).

Functionality is being added to work with the UEFI capsule driver in
u-boot. The metadata is read to gather information on the update bank,
which is the bank to which the firmware images would be flashed to. On
a successful completion of the update of all components, the active
bank field in the metadata is updated, to reflect the bank from which
the platform will boot on the subsequent boots.

Currently, the feature is being enabled on the STM32MP157C-DK2 and
Synquacer boards. The DK2 board boots a FIP image from a uSD card
partitioned with the GPT partioning scheme, while the Synquacer board
boots a FIP image from a MTD partitioned SPI NOR flash device.

This feature also requires changes in a previous stage of
bootloader, which parses the metadata and selects the bank to boot the
image(s) from. Support has being added in tf-a(BL2 stage) for the
STM32MP157C-DK2 board to boot the active bank images. These changes 
have been merged to the upstream tf-a repository.

Earlier, two separate patchsets were being sent. The patchset sent by
me was adding support for the feature, and enabling the feature on the
ST board. The other set of patches were being sent by Masami
Hiramatsu, which were enabling the feature on the Synquacer
platform. This patchset contains both set of patches, along with the
associated documentation and the python test script for testing the
feature.

The upstreaming effort for this feature had been put on a temporary
hold to address the fixing of some issues in the capsule update code,
primarily using a per platform image GUID for the updatable
images. Now that the series has been merged, upstreaming effort for
the FWU update feature is being resumed. Hence, this version does not
have any review comments being addressed.


[1] - https://developer.arm.com/documentation/den0118/a
[2] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf

Jassi Brar (1):
  developerbox: synquacer: Use FIP as the updatable image

Masami Hiramatsu (9):
  FWU: Add FWU metadata access driver for non-GPT MTD devices
  dt/bindings: firmware: Add FWU metadata on MTD devices binding
  tools: Add mkfwumdata tool for FWU metadata image
  FWU: doc: Update documentation for the FWU non-GPT MTD
  synquacer: Update for TBBR (BL2) based new FIP layout
  FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  FWU: synquacer: Generate dfu_alt_info from devicetree partition
  doc: synquacer: Add how to enable FWU Multi Bank Update
  [TEMP]configs: synquacer: Add FWU support for DeveloperBox

Sughosh Ganu (13):
  dt/bindings: Add bindings for FWU Metadata storage device
  FWU: Add FWU metadata structure and driver for accessing metadata
  FWU: Add FWU metadata access driver for GPT partitioned block devices
  stm32mp1: dk2: Add a node for the FWU metadata device
  stm32mp1: dk2: Add image information for capsule updates
  FWU: stm32mp1: Add helper functions for accessing FWU metadata
  FWU: STM32MP1: Add support to read boot index from backup register
  FWU: Add boot time checks as highlighted by the FWU specification
  FWU: Add support for the FWU Multi Bank Update feature
  FWU: cmd: Add a command to read FWU metadata
  mkeficapsule: Add support for generating empty capsules
  FWU: doc: Add documentation for the FWU feature
  sandbox: fwu: Add support for testing FWU feature on sandbox

 arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi      |   7 +
 .../synquacer-sc2a11-developerbox-u-boot.dtsi |  40 +-
 arch/arm/mach-stm32mp/include/mach/stm32.h    |   4 +
 arch/sandbox/Kconfig                          |   6 +
 arch/sandbox/dts/test.dts                     |  45 +-
 board/sandbox/sandbox.c                       |  49 ++
 board/socionext/developerbox/Kconfig          |  14 +
 board/socionext/developerbox/Makefile         |   1 +
 board/socionext/developerbox/developerbox.c   |  17 +-
 board/socionext/developerbox/fwu_plat.c       | 200 ++++++++
 board/st/stm32mp1/stm32mp1.c                  | 141 ++++++
 cmd/Kconfig                                   |   7 +
 cmd/Makefile                                  |   1 +
 cmd/fwu_mdata.c                               |  74 +++
 common/board_r.c                              |   5 +
 configs/sandbox64_defconfig                   |  12 +-
 configs/synquacer_developerbox_defconfig      |  10 +-
 doc/board/socionext/developerbox.rst          | 110 +++++
 doc/develop/uefi/fwu_updates.rst              | 200 ++++++++
 doc/develop/uefi/index.rst                    |   1 +
 doc/develop/uefi/uefi.rst                     |   2 +
 .../firmware/fwu-mdata.txt                    |  18 +
 .../firmware/uboot,fwu-mdata-mtd.yaml         |  38 ++
 doc/mkeficapsule.1                            |  29 +-
 drivers/Kconfig                               |   2 +
 drivers/Makefile                              |   1 +
 drivers/fwu-mdata/Kconfig                     |  24 +
 drivers/fwu-mdata/Makefile                    |   8 +
 drivers/fwu-mdata/fwu-mdata-uclass.c          | 459 ++++++++++++++++++
 drivers/fwu-mdata/fwu_mdata_gpt_blk.c         | 404 +++++++++++++++
 drivers/fwu-mdata/fwu_mdata_mtd.c             | 308 ++++++++++++
 include/configs/stm32mp15_common.h            |   4 +
 include/configs/synquacer.h                   |  21 +-
 include/dm/uclass-id.h                        |   1 +
 include/fwu.h                                 |  74 +++
 include/fwu_mdata.h                           |  67 +++
 lib/Kconfig                                   |   6 +
 lib/Makefile                                  |   1 +
 lib/efi_loader/efi_capsule.c                  | 231 ++++++++-
 lib/efi_loader/efi_setup.c                    |   3 +-
 lib/fwu_updates/Kconfig                       |  31 ++
 lib/fwu_updates/Makefile                      |   7 +
 lib/fwu_updates/fwu.c                         | 206 ++++++++
 lib/fwu_updates/fwu_mtd.c                     | 173 +++++++
 .../test_capsule_firmware_fit.py              |   1 -
 .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
 test/py/tests/test_fwu_updates/conftest.py    |  78 +++
 .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++
 tools/Kconfig                                 |   9 +
 tools/Makefile                                |   4 +
 tools/eficapsule.h                            |   8 +
 tools/mkeficapsule.c                          | 139 +++++-
 tools/mkfwumdata.c                            | 298 ++++++++++++
 53 files changed, 3903 insertions(+), 73 deletions(-)
 create mode 100644 board/socionext/developerbox/fwu_plat.c
 create mode 100644 cmd/fwu_mdata.c
 create mode 100644 doc/develop/uefi/fwu_updates.rst
 create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt
 create mode 100644 doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
 create mode 100644 drivers/fwu-mdata/Kconfig
 create mode 100644 drivers/fwu-mdata/Makefile
 create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
 create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c
 create mode 100644 drivers/fwu-mdata/fwu_mdata_mtd.c
 create mode 100644 include/fwu.h
 create mode 100644 include/fwu_mdata.h
 create mode 100644 lib/fwu_updates/Kconfig
 create mode 100644 lib/fwu_updates/Makefile
 create mode 100644 lib/fwu_updates/fwu.c
 create mode 100644 lib/fwu_updates/fwu_mtd.c
 create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
 create mode 100644 test/py/tests/test_fwu_updates/conftest.py
 create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
 create mode 100644 tools/mkfwumdata.c

-- 
2.25.1



^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH v5 01/23] dt/bindings: Add bindings for FWU Metadata storage device
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-16 13:34   ` Michal Simek
  2022-06-09 12:29 ` [PATCH v5 02/23] FWU: Add FWU metadata structure and driver for accessing metadata Sughosh Ganu
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

Add bindings needed for accessing the FWU metadata partitions. These
include the compatible string which point to the access method and the
actual device which stores the FWU metadata.

The current patch adds basic bindings needed for accessing the
metadata structure on GPT partitioned block devices.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 .../firmware/fwu-mdata.txt                     | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt

diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt
new file mode 100644
index 0000000000..2d8ed056a5
--- /dev/null
+++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt
@@ -0,0 +1,18 @@
+FWU Metadata Access Devicetree Binding
+
+The FWU Multi Bank Update feature uses a metadata structure, stored on
+a separate partition for keeping information on the set of updatable
+images. The device tree node provides information on the storage
+device that contains the FWU metadata.
+
+Required properties :
+
+- compatible : "u-boot,fwu-mdata-gpt";
+- fwu-mdata-store : should point to the storage device which contains
+		    the FWU metadata partition.
+
+Example :
+	fwu-mdata {
+		compatible = "u-boot,fwu-mdata-gpt";
+		fwu-mdata-store = <&sdmmc1>;
+	};
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 02/23] FWU: Add FWU metadata structure and driver for accessing metadata
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
  2022-06-09 12:29 ` [PATCH v5 01/23] dt/bindings: Add bindings for FWU Metadata storage device Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-21 10:54   ` Etienne Carriere
  2022-06-09 12:29 ` [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices Sughosh Ganu
                   ` (21 subsequent siblings)
  23 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

In the FWU Multi Bank Update feature, the information about the
updatable images is stored as part of the metadata, which is stored on
a dedicated partition. Add the metadata structure, and a driver model
uclass which provides functions to access the metadata. These are
generic API's, and implementations can be added based on parameters
like how the metadata partition is accessed and what type of storage
device houses the metadata.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 drivers/Kconfig                      |   2 +
 drivers/Makefile                     |   1 +
 drivers/fwu-mdata/Kconfig            |   7 +
 drivers/fwu-mdata/Makefile           |   6 +
 drivers/fwu-mdata/fwu-mdata-uclass.c | 459 +++++++++++++++++++++++++++
 include/dm/uclass-id.h               |   1 +
 include/fwu.h                        |  49 +++
 include/fwu_mdata.h                  |  67 ++++
 8 files changed, 592 insertions(+)
 create mode 100644 drivers/fwu-mdata/Kconfig
 create mode 100644 drivers/fwu-mdata/Makefile
 create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
 create mode 100644 include/fwu.h
 create mode 100644 include/fwu_mdata.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index b26ca8cf70..adc6079ecf 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig"
 
 source "drivers/fpga/Kconfig"
 
+source "drivers/fwu-mdata/Kconfig"
+
 source "drivers/gpio/Kconfig"
 
 source "drivers/hwspinlock/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 67c8af7442..901150bb35 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -83,6 +83,7 @@ obj-y += cache/
 obj-$(CONFIG_CPU) += cpu/
 obj-y += crypto/
 obj-$(CONFIG_FASTBOOT) += fastboot/
+obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/
 obj-y += misc/
 obj-$(CONFIG_MMC) += mmc/
 obj-$(CONFIG_NVME) += nvme/
diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
new file mode 100644
index 0000000000..d6a21c8e19
--- /dev/null
+++ b/drivers/fwu-mdata/Kconfig
@@ -0,0 +1,7 @@
+config DM_FWU_MDATA
+	bool "Driver support for accessing FWU Metadata"
+	depends on DM
+	help
+	  Enable support for accessing FWU Metadata partitions. The
+	  FWU Metadata partitions reside on the same storage device
+	  which contains the other FWU updatable firmware images.
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
new file mode 100644
index 0000000000..7fec7171f4
--- /dev/null
+++ b/drivers/fwu-mdata/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2022, Linaro Limited
+#
+
+obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c
new file mode 100644
index 0000000000..1530ceb01d
--- /dev/null
+++ b/drivers/fwu-mdata/fwu-mdata-uclass.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <efi_loader.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+#include <malloc.h>
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <u-boot/crc.h>
+
+#define IMAGE_ACCEPT_SET	BIT(0)
+#define IMAGE_ACCEPT_CLEAR	BIT(1)
+
+static int fwu_get_dev_ops(struct udevice **dev,
+			   const struct fwu_mdata_ops **ops)
+{
+	int ret;
+
+	ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev);
+	if (ret) {
+		log_debug("Cannot find fwu device\n");
+		return ret;
+	}
+
+	if ((*ops = device_get_ops(*dev)) == NULL) {
+		log_debug("Cannot get fwu device ops\n");
+		return -ENOSYS;
+	}
+
+	return 0;
+}
+
+/**
+ * fwu_verify_mdata() - Verify the FWU metadata
+ * @mdata: FWU metadata structure
+ * @pri_part: FWU metadata partition is primary or secondary
+ *
+ * Verify the FWU metadata by computing the CRC32 for the metadata
+ * structure and comparing it against the CRC32 value stored as part
+ * of the structure.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part)
+{
+	u32 calc_crc32;
+	void *buf;
+
+	buf = &mdata->version;
+	calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
+
+	if (calc_crc32 != mdata->crc32) {
+		log_err("crc32 check failed for %s FWU metadata partition\n",
+			pri_part ? "primary" : "secondary");
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * fwu_get_active_index() - Get active_index from the FWU metadata
+ * @active_idx: active_index value to be read
+ *
+ * Read the active_index field from the FWU metadata and place it in
+ * the variable pointed to be the function argument.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_get_active_index(u32 *active_idx)
+{
+	int ret;
+	struct fwu_mdata *mdata = NULL;
+
+	ret = fwu_get_mdata(&mdata);
+	if (ret < 0) {
+		log_err("Unable to get valid FWU metadata\n");
+		goto out;
+	}
+
+	/*
+	 * Found the FWU metadata partition, now read the active_index
+	 * value
+	 */
+	*active_idx = mdata->active_index;
+	if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
+		log_err("Active index value read is incorrect\n");
+		ret = -EINVAL;
+	}
+
+out:
+	free(mdata);
+
+	return ret;
+}
+
+/**
+ * fwu_update_active_index() - Update active_index from the FWU metadata
+ * @active_idx: active_index value to be updated
+ *
+ * Update the active_index field in the FWU metadata
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_update_active_index(u32 active_idx)
+{
+	int ret;
+	struct fwu_mdata *mdata = NULL;
+
+	if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
+		log_err("Active index value to be updated is incorrect\n");
+		return -1;
+	}
+
+	ret = fwu_get_mdata(&mdata);
+	if (ret < 0) {
+		log_err("Unable to get valid FWU metadata\n");
+		goto out;
+	}
+
+	/*
+	 * Update the active index and previous_active_index fields
+	 * in the FWU metadata
+	 */
+	mdata->previous_active_index = mdata->active_index;
+	mdata->active_index = active_idx;
+
+	/*
+	 * Now write this updated FWU metadata to both the
+	 * FWU metadata partitions
+	 */
+	ret = fwu_update_mdata(mdata);
+	if (ret < 0) {
+		log_err("Failed to update FWU metadata partitions\n");
+		ret = -EIO;
+	}
+
+out:
+	free(mdata);
+
+	return ret;
+}
+
+/**
+ * fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update
+ * @image_type_id: pointer to the image guid as passed in the capsule
+ * @update_bank: Bank to which the update is to be made
+ * @alt_num: The alt_num for the image
+ *
+ * Based on the guid value passed in the capsule, along with the bank to which the
+ * image needs to be updated, get the dfu alt number which will be used for the
+ * capsule update
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
+			  int *alt_num)
+{
+	int ret, i;
+	efi_guid_t *image_guid;
+	struct udevice *dev = NULL;
+	struct fwu_mdata *mdata = NULL;
+	struct fwu_image_entry *img_entry;
+	const struct fwu_mdata_ops *ops = NULL;
+	struct fwu_image_bank_info *img_bank_info;
+
+	ret = fwu_get_dev_ops(&dev, &ops);
+	if (ret)
+		return ret;
+
+	ret = fwu_get_mdata(&mdata);
+	if (ret) {
+		log_err("Unable to get valid FWU metadata\n");
+		goto out;
+	}
+
+	/*
+	 * The FWU metadata has been read. Now get the image_uuid for the
+	 * image with the update_bank.
+	 */
+	for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
+		if (!guidcmp(image_type_id,
+			     &mdata->img_entry[i].image_type_uuid)) {
+			img_entry = &mdata->img_entry[i];
+			img_bank_info = &img_entry->img_bank_info[update_bank];
+			image_guid = &img_bank_info->image_uuid;
+			ret = fwu_plat_get_alt_num(dev_get_priv(dev),
+						   image_guid, alt_num);
+			break;
+		}
+	}
+
+	if (i == CONFIG_FWU_NUM_IMAGES_PER_BANK) {
+		log_err("Partition with the image type %pUs not found\n",
+			image_type_id);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!ret) {
+		log_debug("alt_num %d for partition %pUs\n",
+			  *alt_num, &image_guid);
+	} else {
+		log_err("alt_num not found for partition with GUID %pUs\n",
+			&image_guid);
+		ret = -EINVAL;
+	}
+
+out:
+	free(mdata);
+
+	return ret;
+}
+
+/**
+ * fwu_mdata_check() - Check if the FWU metadata is valid
+ *
+ * Validate both copies of the FWU metadata. If one of the copies
+ * has gone bad, restore it from the other bad copy.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_mdata_check(void)
+{
+	int ret;
+	struct udevice *dev = NULL;
+	const struct fwu_mdata_ops *ops = NULL;
+
+	ret = fwu_get_dev_ops(&dev, &ops);
+	if (ret)
+		return ret;
+
+	if (!ops->mdata_check) {
+		log_err("mdata_check() method not defined\n");
+		return -ENOSYS;
+	}
+
+	return ops->mdata_check(dev);
+}
+
+/**
+ * fwu_revert_boot_index() - Revert the active index in the FWU metadata
+ *
+ * Revert the active_index value in the FWU metadata, by swapping the values
+ * of active_index and previous_active_index in both copies of the
+ * FWU metadata.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_revert_boot_index(void)
+{
+	int ret;
+	u32 cur_active_index;
+	struct fwu_mdata *mdata = NULL;
+
+	ret = fwu_get_mdata(&mdata);
+	if (ret < 0) {
+		log_err("Unable to get valid FWU metadata\n");
+		goto out;
+	}
+
+	/*
+	 * Swap the active index and previous_active_index fields
+	 * in the FWU metadata
+	 */
+	cur_active_index = mdata->active_index;
+	mdata->active_index = mdata->previous_active_index;
+	mdata->previous_active_index = cur_active_index;
+
+	/*
+	 * Now write this updated FWU metadata to both the
+	 * FWU metadata partitions
+	 */
+	ret = fwu_update_mdata(mdata);
+	if (ret < 0) {
+		log_err("Failed to update FWU metadata partitions\n");
+		ret = -EIO;
+	}
+
+out:
+	free(mdata);
+
+	return ret;
+}
+
+/**
+ * fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image
+ * @img_type_id: Guid of the image type for which the accepted bit is to be
+ *               set or cleared
+ * @bank: Bank of which the image's Accept bit is to be set or cleared
+ * @action: Action which specifies whether image's Accept bit is to be set or
+ *          cleared
+ *
+ * Set/Clear the accepted bit for the image specified by the img_guid parameter.
+ * This indicates acceptance or rejection of image for subsequent boots by some
+ * governing component like OS(or firmware).
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+static int fwu_set_clear_image_accept(efi_guid_t *img_type_id,
+				      u32 bank, u8 action)
+{
+	int ret, i;
+	u32 nimages;
+	struct fwu_mdata *mdata = NULL;
+	struct fwu_image_entry *img_entry;
+	struct fwu_image_bank_info *img_bank_info;
+
+	ret = fwu_get_mdata(&mdata);
+	if (ret < 0) {
+		log_err("Unable to get valid FWU metadata\n");
+		goto out;
+	}
+
+	nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
+	img_entry = &mdata->img_entry[0];
+	for (i = 0; i < nimages; i++) {
+		if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
+			img_bank_info = &img_entry[i].img_bank_info[bank];
+			if (action == IMAGE_ACCEPT_SET)
+				img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
+			else
+				img_bank_info->accepted = 0;
+
+			ret = fwu_update_mdata(mdata);
+			goto out;
+		}
+	}
+
+	/* Image not found */
+	ret = -EINVAL;
+
+out:
+	free(mdata);
+
+	return ret;
+}
+
+/**
+ * fwu_accept_image() - Set the Acceptance bit for the image
+ * @img_type_id: Guid of the image type for which the accepted bit is to be
+ *               cleared
+ * @bank: Bank of which the image's Accept bit is to be set
+ *
+ * Set the accepted bit for the image specified by the img_guid parameter. This
+ * indicates acceptance of image for subsequent boots by some governing component
+ * like OS(or firmware).
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_accept_image(efi_guid_t *img_type_id, u32 bank)
+{
+	return fwu_set_clear_image_accept(img_type_id, bank,
+					  IMAGE_ACCEPT_SET);
+}
+
+/**
+ * fwu_clear_accept_image() - Clear the Acceptance bit for the image
+ * @img_type_id: Guid of the image type for which the accepted bit is to be
+ *               cleared
+ * @bank: Bank of which the image's Accept bit is to be cleared
+ *
+ * Clear the accepted bit for the image type specified by the img_type_id parameter.
+ * This function is called after the image has been updated. The accepted bit is
+ * cleared to be set subsequently after passing the image acceptance criteria, by
+ * either the OS(or firmware)
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank)
+{
+	return fwu_set_clear_image_accept(img_type_id, bank,
+					  IMAGE_ACCEPT_CLEAR);
+}
+
+/**
+ * fwu_get_mdata() - Get a FWU metadata copy
+ * @mdata: Copy of the FWU metadata
+ *
+ * Get a valid copy of the FWU metadata.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_get_mdata(struct fwu_mdata **mdata)
+{
+	int ret;
+	struct udevice *dev = NULL;
+	const struct fwu_mdata_ops *ops = NULL;
+
+	ret = fwu_get_dev_ops(&dev, &ops);
+	if (ret)
+		return ret;
+
+	if (!ops->get_mdata) {
+		log_err("get_mdata() method not defined\n");
+		return -ENOSYS;
+	}
+
+	return ops->get_mdata(dev, mdata);
+}
+
+/**
+ * fwu_update_mdata() - Update the FWU metadata
+ * @mdata: Copy of the FWU metadata
+ *
+ * Update the FWU metadata structure by writing to the
+ * FWU metadata partitions.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_update_mdata(struct fwu_mdata *mdata)
+{
+	int ret;
+	void *buf;
+	struct udevice *dev = NULL;
+	const struct fwu_mdata_ops *ops = NULL;
+
+	ret = fwu_get_dev_ops(&dev, &ops);
+	if (ret)
+		return ret;
+
+	if (!ops->update_mdata) {
+		log_err("get_mdata() method not defined\n");
+		return -ENOSYS;
+	}
+
+	/*
+	 * Calculate the crc32 for the updated FWU metadata
+	 * and put the updated value in the FWU metadata crc32
+	 * field
+	 */
+	buf = &mdata->version;
+	mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
+
+	return ops->update_mdata(dev, mdata);
+}
+
+UCLASS_DRIVER(fwu_mdata) = {
+	.id		= UCLASS_FWU_MDATA,
+	.name		= "fwu-mdata",
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 3ba69ad9a0..7da719c048 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -57,6 +57,7 @@ enum uclass_id {
 	UCLASS_ETH_PHY,		/* Ethernet PHY device */
 	UCLASS_FIRMWARE,	/* Firmware */
 	UCLASS_FS_FIRMWARE_LOADER,		/* Generic loader */
+	UCLASS_FWU_MDATA,	/* FWU Metadata Access */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
 	UCLASS_HASH,		/* Hash device */
 	UCLASS_HWSPINLOCK,	/* Hardware semaphores */
diff --git a/include/fwu.h b/include/fwu.h
new file mode 100644
index 0000000000..f9e44e7b39
--- /dev/null
+++ b/include/fwu.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#if !defined _FWU_H_
+#define _FWU_H_
+
+#include <blk.h>
+#include <efi.h>
+
+#include <linux/types.h>
+
+struct fwu_mdata;
+struct udevice;
+
+/**
+ * @mdata_check: check the validity of the FWU metadata partitions
+ * @get_mdata() - Get a FWU metadata copy
+ * @update_mdata() - Update the FWU metadata copy
+ */
+struct fwu_mdata_ops {
+	int (*mdata_check)(struct udevice *dev);
+
+	int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata);
+
+	int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
+};
+
+#define FWU_MDATA_VERSION	0x1
+
+#define FWU_MDATA_GUID \
+	EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
+		 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+
+int fwu_get_mdata(struct fwu_mdata **mdata);
+int fwu_update_mdata(struct fwu_mdata *mdata);
+int fwu_get_active_index(u32 *active_idx);
+int fwu_update_active_index(u32 active_idx);
+int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
+			  int *alt_num);
+int fwu_mdata_check(void);
+int fwu_revert_boot_index(void);
+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_alt_num(struct udevice *dev, efi_guid_t *image_guid,
+			 int *alt_num);
+#endif /* _FWU_H_ */
diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h
new file mode 100644
index 0000000000..701efbba03
--- /dev/null
+++ b/include/fwu_mdata.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#if !defined _FWU_MDATA_H_
+#define _FWU_MDATA_H_
+
+#include <efi.h>
+
+/**
+ * struct fwu_image_bank_info - firmware image information
+ * @image_uuid: Guid value of the image in this bank
+ * @accepted: Acceptance status of the image
+ * @reserved: Reserved
+ *
+ * The structure contains image specific fields which are
+ * used to identify the image and to specify the image's
+ * acceptance status
+ */
+struct fwu_image_bank_info {
+	efi_guid_t  image_uuid;
+	uint32_t accepted;
+	uint32_t reserved;
+} __attribute__((__packed__));
+
+/**
+ * struct fwu_image_entry - information for a particular type of image
+ * @image_type_uuid: Guid value for identifying the image type
+ * @location_uuid: Guid of the storage volume where the image is located
+ * @img_bank_info: Array containing properties of images
+ *
+ * This structure contains information on various types of updatable
+ * firmware images. Each image type then contains an array of image
+ * information per bank.
+ */
+struct fwu_image_entry {
+	efi_guid_t image_type_uuid;
+	efi_guid_t location_uuid;
+	struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+} __attribute__((__packed__));
+
+/**
+ * struct fwu_mdata - FWU metadata structure for multi-bank updates
+ * @crc32: crc32 value for the FWU metadata
+ * @version: FWU metadata version
+ * @active_index: Index of the bank currently used for booting images
+ * @previous_active_inde: Index of the bank used before the current bank
+ *                        being used for booting
+ * @img_entry: Array of information on various firmware images that can
+ *             be updated
+ *
+ * This structure is used to store all the needed information for performing
+ * multi bank updates on the platform. This contains info on the bank being
+ * used to boot along with the information needed for identification of
+ * individual images
+ */
+struct fwu_mdata {
+	uint32_t crc32;
+	uint32_t version;
+	uint32_t active_index;
+	uint32_t previous_active_index;
+
+	struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+} __attribute__((__packed__));
+
+#endif /* _FWU_MDATA_H_ */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
  2022-06-09 12:29 ` [PATCH v5 01/23] dt/bindings: Add bindings for FWU Metadata storage device Sughosh Ganu
  2022-06-09 12:29 ` [PATCH v5 02/23] FWU: Add FWU metadata structure and driver for accessing metadata Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-21  9:34   ` Patrick DELAUNAY
  2022-06-21 10:55   ` Etienne Carriere
  2022-06-09 12:29 ` [PATCH v5 04/23] stm32mp1: dk2: Add a node for the FWU metadata device Sughosh Ganu
                   ` (20 subsequent siblings)
  23 siblings, 2 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

In the FWU Multi Bank Update feature, the information about the
updatable images is stored as part of the metadata, on a separate
partition. Add a driver for reading from and writing to the metadata
when the updatable images and the metadata are stored on a block
device which is formated with GPT based partition scheme.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 drivers/fwu-mdata/Kconfig             |   9 +
 drivers/fwu-mdata/Makefile            |   1 +
 drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 404 ++++++++++++++++++++++++++
 include/fwu.h                         |   2 +
 4 files changed, 416 insertions(+)
 create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c

diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
index d6a21c8e19..d5edef19d6 100644
--- a/drivers/fwu-mdata/Kconfig
+++ b/drivers/fwu-mdata/Kconfig
@@ -5,3 +5,12 @@ config DM_FWU_MDATA
 	  Enable support for accessing FWU Metadata partitions. The
 	  FWU Metadata partitions reside on the same storage device
 	  which contains the other FWU updatable firmware images.
+
+config FWU_MDATA_GPT_BLK
+	bool "FWU Metadata access for GPT partitioned Block devices"
+	select PARTITION_TYPE_GUID
+	select PARTITION_UUIDS
+	depends on DM && HAVE_BLOCK_DEVICE && EFI_PARTITION
+	help
+	  Enable support for accessing FWU Metadata on GPT partitioned
+	  block devices.
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
index 7fec7171f4..12a5b4fe04 100644
--- a/drivers/fwu-mdata/Makefile
+++ b/drivers/fwu-mdata/Makefile
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
+obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o
diff --git a/drivers/fwu-mdata/fwu_mdata_gpt_blk.c b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
new file mode 100644
index 0000000000..329bd3779b
--- /dev/null
+++ b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
@@ -0,0 +1,404 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <blk.h>
+#include <dm.h>
+#include <efi_loader.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <part.h>
+#include <part_efi.h>
+
+#include <dm/device-internal.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <u-boot/crc.h>
+
+#define PRIMARY_PART		BIT(0)
+#define SECONDARY_PART		BIT(1)
+#define BOTH_PARTS		(PRIMARY_PART | SECONDARY_PART)
+
+#define MDATA_READ		BIT(0)
+#define MDATA_WRITE		BIT(1)
+
+static int gpt_get_mdata_partitions(struct blk_desc *desc,
+				    u16 *primary_mpart,
+				    u16 *secondary_mpart)
+{
+	int i, ret;
+	u32 mdata_parts;
+	efi_guid_t part_type_guid;
+	struct disk_partition info;
+	const efi_guid_t fwu_mdata_guid = FWU_MDATA_GUID;
+
+	mdata_parts = 0;
+	for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) {
+		if (part_get_info(desc, i, &info))
+			continue;
+		uuid_str_to_bin(info.type_guid, part_type_guid.b,
+				UUID_STR_FORMAT_GUID);
+
+		if (!guidcmp(&fwu_mdata_guid, &part_type_guid)) {
+			++mdata_parts;
+			if (!*primary_mpart)
+				*primary_mpart = i;
+			else
+				*secondary_mpart = i;
+		}
+	}
+
+	if (mdata_parts != 2) {
+		log_err("Expect two copies of the FWU metadata instead of %d\n",
+			mdata_parts);
+		ret = -EINVAL;
+	} else {
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int gpt_get_mdata_disk_part(struct blk_desc *desc,
+				   struct disk_partition *info,
+				   u32 part_num)
+{
+	int ret;
+	char *mdata_guid_str = "8a7a84a0-8387-40f6-ab41-a8b9a5a60d23";
+
+	ret = part_get_info(desc, part_num, info);
+	if (ret < 0) {
+		log_err("Unable to get the partition info for the FWU metadata part %d",
+			part_num);
+		return -1;
+	}
+
+	/* Check that it is indeed the FWU metadata partition */
+	if (!strncmp(info->type_guid, mdata_guid_str, UUID_STR_LEN)) {
+		/* Found the FWU metadata partition */
+		return 0;
+	}
+
+	return -1;
+}
+
+static int gpt_read_write_mdata(struct blk_desc *desc,
+				struct fwu_mdata *mdata,
+				u8 access, u32 part_num)
+{
+	int ret;
+	u32 len, blk_start, blkcnt;
+	struct disk_partition info;
+
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(struct fwu_mdata, mdata_aligned, 1,
+				     desc->blksz);
+
+	ret = gpt_get_mdata_disk_part(desc, &info, part_num);
+	if (ret < 0) {
+		printf("Unable to get the FWU metadata partition\n");
+		return -ENODEV;
+	}
+
+	len = sizeof(*mdata);
+	blkcnt = BLOCK_CNT(len, desc);
+	if (blkcnt > info.size) {
+		log_err("Block count exceeds FWU metadata partition size\n");
+		return -ERANGE;
+	}
+
+	blk_start = info.start;
+	if (access == MDATA_READ) {
+		if (blk_dread(desc, blk_start, blkcnt, mdata_aligned) != blkcnt) {
+			log_err("Error reading FWU metadata from the device\n");
+			return -EIO;
+		}
+		memcpy(mdata, mdata_aligned, sizeof(struct fwu_mdata));
+	} else {
+		if (blk_dwrite(desc, blk_start, blkcnt, mdata) != blkcnt) {
+			log_err("Error writing FWU metadata to the device\n");
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static int gpt_read_mdata(struct blk_desc *desc,
+			  struct fwu_mdata *mdata, u32 part_num)
+{
+	return gpt_read_write_mdata(desc, mdata, MDATA_READ, part_num);
+}
+
+static int gpt_write_mdata_partition(struct blk_desc *desc,
+					struct fwu_mdata *mdata,
+					u32 part_num)
+{
+	return gpt_read_write_mdata(desc, mdata, MDATA_WRITE, part_num);
+}
+
+static int fwu_gpt_update_mdata(struct udevice * dev, struct fwu_mdata *mdata)
+{
+	int ret;
+	struct blk_desc *desc;
+	u16 primary_mpart = 0, secondary_mpart = 0;
+
+	desc = dev_get_uclass_plat(dev_get_priv(dev));
+	if (!desc) {
+		log_err("Block device not found\n");
+		return -ENODEV;
+	}
+
+	ret = gpt_get_mdata_partitions(desc, &primary_mpart,
+				       &secondary_mpart);
+
+	if (ret < 0) {
+		log_err("Error getting the FWU metadata partitions\n");
+		return -ENODEV;
+	}
+
+	/* First write the primary partition*/
+	ret = gpt_write_mdata_partition(desc, mdata, primary_mpart);
+	if (ret < 0) {
+		log_err("Updating primary FWU metadata partition failed\n");
+		return ret;
+	}
+
+	/* And now the replica */
+	ret = gpt_write_mdata_partition(desc, mdata, secondary_mpart);
+	if (ret < 0) {
+		log_err("Updating secondary FWU metadata partition failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int gpt_get_mdata(struct blk_desc *desc, struct fwu_mdata **mdata)
+{
+	int ret;
+	u16 primary_mpart = 0, secondary_mpart = 0;
+
+	ret = gpt_get_mdata_partitions(desc, &primary_mpart,
+				       &secondary_mpart);
+
+	if (ret < 0) {
+		log_err("Error getting the FWU metadata partitions\n");
+		return -ENODEV;
+	}
+
+	*mdata = malloc(sizeof(struct fwu_mdata));
+	if (!*mdata) {
+		log_err("Unable to allocate memory for reading FWU metadata\n");
+		return -ENOMEM;
+	}
+
+	ret = gpt_read_mdata(desc, *mdata, primary_mpart);
+	if (ret < 0) {
+		log_err("Failed to read the FWU metadata from the device\n");
+		return -EIO;
+	}
+
+	ret = fwu_verify_mdata(*mdata, 1);
+	if (!ret)
+		return 0;
+
+	/*
+	 * Verification of the primary FWU metadata copy failed.
+	 * Try to read the replica.
+	 */
+	memset(*mdata, 0, sizeof(struct fwu_mdata));
+	ret = gpt_read_mdata(desc, *mdata, secondary_mpart);
+	if (ret < 0) {
+		log_err("Failed to read the FWU metadata from the device\n");
+		return -EIO;
+	}
+
+	ret = fwu_verify_mdata(*mdata, 0);
+	if (!ret)
+		return 0;
+
+	/* Both the FWU metadata copies are corrupted. */
+	return -1;
+}
+
+static int gpt_check_mdata_validity(struct udevice *dev)
+{
+	int ret;
+	struct blk_desc *desc;
+	struct fwu_mdata pri_mdata;
+	struct fwu_mdata secondary_mdata;
+	u16 primary_mpart = 0, secondary_mpart = 0;
+	u16 valid_partitions, invalid_partitions;
+
+	desc = dev_get_uclass_plat(dev_get_priv(dev));
+	if (!desc) {
+		log_err("Block device not found\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Two FWU metadata partitions are expected.
+	 * If we don't have two, user needs to create
+	 * them first
+	 */
+	valid_partitions = 0;
+	ret = gpt_get_mdata_partitions(desc, &primary_mpart,
+				       &secondary_mpart);
+
+	if (ret < 0) {
+		log_err("Error getting the FWU metadata partitions\n");
+		return -ENODEV;
+	}
+
+	ret = gpt_read_mdata(desc, &pri_mdata, primary_mpart);
+	if (ret < 0) {
+		log_err("Failed to read the FWU metadata from the device\n");
+		goto secondary_read;
+	}
+
+	ret = fwu_verify_mdata(&pri_mdata, 1);
+	if (!ret)
+		valid_partitions |= PRIMARY_PART;
+
+secondary_read:
+	/* Now check the secondary partition */
+	ret = gpt_read_mdata(desc, &secondary_mdata, secondary_mpart);
+	if (ret < 0) {
+		log_err("Failed to read the FWU metadata from the device\n");
+		goto mdata_restore;
+	}
+
+	ret = fwu_verify_mdata(&secondary_mdata, 0);
+	if (!ret)
+		valid_partitions |= SECONDARY_PART;
+
+mdata_restore:
+	if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) {
+		ret = -1;
+		/*
+		 * Before returning, check that both the
+		 * FWU metadata copies are the same. If not,
+		 * the FWU metadata copies need to be
+		 * re-populated.
+		 */
+		if (!memcmp(&pri_mdata, &secondary_mdata,
+			    sizeof(struct fwu_mdata))) {
+			ret = 0;
+		} else {
+			log_err("Both FWU metadata copies are valid but do not match. Please check!\n");
+		}
+		goto out;
+	}
+
+	ret = -1;
+	if (!(valid_partitions & BOTH_PARTS))
+		goto out;
+
+	invalid_partitions = valid_partitions ^ BOTH_PARTS;
+	ret = gpt_write_mdata_partition(desc,
+					(invalid_partitions == PRIMARY_PART) ?
+					&secondary_mdata : &pri_mdata,
+					(invalid_partitions == PRIMARY_PART) ?
+					primary_mpart : secondary_mpart);
+
+	if (ret < 0)
+		log_err("Restoring %s FWU metadata partition failed\n",
+			(invalid_partitions == PRIMARY_PART) ?
+			"primary" : "secondary");
+
+out:
+	return ret;
+}
+
+int fwu_gpt_mdata_check(struct udevice *dev)
+{
+	/*
+	 * Check if both the copies of the FWU metadata are
+	 * valid. If one has gone bad, restore it from the
+	 * other good copy.
+	 */
+	return gpt_check_mdata_validity(dev);
+}
+
+int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata **mdata)
+{
+	struct blk_desc *desc;
+
+	desc = dev_get_uclass_plat(dev_get_priv(dev));
+	if (!desc) {
+		log_err("Block device not found\n");
+		return -ENODEV;
+	}
+
+	return gpt_get_mdata(desc, mdata);
+}
+
+int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev)
+{
+	u32 phandle;
+	int ret, size;
+	struct udevice *parent, *child;
+	const fdt32_t *phandle_p = NULL;
+
+	phandle_p = ofnode_get_property(dev_ofnode(dev), "fwu-mdata-store",
+					&size);
+	if (!phandle_p) {
+		log_err("fwu-mdata-store property not found\n");
+		return -ENOENT;
+	}
+
+	phandle = fdt32_to_cpu(*phandle_p);
+
+	ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
+					  &parent);
+	if (ret)
+		return ret;
+
+	ret = -ENODEV;
+	for (device_find_first_child(parent, &child); child;
+	     device_find_next_child(&child)) {
+		if (device_get_uclass_id(child) == UCLASS_BLK) {
+			*mdata_dev = child;
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+static int fwu_mdata_gpt_blk_probe(struct udevice *dev)
+{
+	int ret;
+	struct udevice *mdata_dev = NULL;
+
+	ret = fwu_get_mdata_device(dev, &mdata_dev);
+	if (ret)
+		return ret;
+
+	dev_set_priv(dev, mdata_dev);
+
+	return 0;
+}
+
+static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
+	.mdata_check = fwu_gpt_mdata_check,
+	.get_mdata = fwu_gpt_get_mdata,
+	.update_mdata = fwu_gpt_update_mdata,
+};
+
+static const struct udevice_id fwu_mdata_ids[] = {
+	{ .compatible = "u-boot,fwu-mdata-gpt" },
+	{ }
+};
+
+U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
+	.name		= "fwu-mdata-gpt-blk",
+	.id		= UCLASS_FWU_MDATA,
+	.of_match	= fwu_mdata_ids,
+	.ops		= &fwu_gpt_blk_ops,
+	.probe		= fwu_mdata_gpt_blk_probe,
+};
diff --git a/include/fwu.h b/include/fwu.h
index f9e44e7b39..3b1ee4e83e 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -39,6 +39,8 @@ int fwu_get_active_index(u32 *active_idx);
 int fwu_update_active_index(u32 active_idx);
 int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
 			  int *alt_num);
+int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev);
+int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part);
 int fwu_mdata_check(void);
 int fwu_revert_boot_index(void);
 int fwu_accept_image(efi_guid_t *img_type_id, u32 bank);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 04/23] stm32mp1: dk2: Add a node for the FWU metadata device
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (2 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-21  9:36   ` Patrick DELAUNAY
  2022-06-09 12:29 ` [PATCH v5 05/23] stm32mp1: dk2: Add image information for capsule updates Sughosh Ganu
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

The FWU metadata structure is accessed through the driver model
interface. On the stm32mp157c-dk2 board, the FWU metadata is stored on
the uSD card. Add the fwu-mdata node on the u-boot specifc dtsi file
for accessing the metadata structure.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi
index 06ef3a4095..24f86209db 100644
--- a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi
+++ b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi
@@ -4,3 +4,10 @@
  */
 
 #include "stm32mp157a-dk1-u-boot.dtsi"
+
+/ {
+	fwu-mdata {
+		compatible = "u-boot,fwu-mdata-gpt";
+		fwu-mdata-store = <&sdmmc1>;
+	};
+};
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 05/23] stm32mp1: dk2: Add image information for capsule updates
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (3 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 04/23] stm32mp1: dk2: Add a node for the FWU metadata device Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-09 12:29 ` [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata Sughosh Ganu
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

Enabling capsule update functionality on the platform requires
populating information on the images that are to be updated using the
functionality. Do so for the DK2 board.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 board/st/stm32mp1/stm32mp1.c       | 19 +++++++++++++++++++
 include/configs/stm32mp15_common.h |  4 ++++
 2 files changed, 23 insertions(+)

diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index 07b1a63db7..62d98ad776 100644
--- a/board/st/stm32mp1/stm32mp1.c
+++ b/board/st/stm32mp1/stm32mp1.c
@@ -11,6 +11,7 @@
 #include <clk.h>
 #include <config.h>
 #include <dm.h>
+#include <efi_loader.h>
 #include <env.h>
 #include <env_internal.h>
 #include <fdt_simplefb.h>
@@ -92,6 +93,16 @@ DECLARE_GLOBAL_DATA_PTR;
 #define USB_START_LOW_THRESHOLD_UV	1230000
 #define USB_START_HIGH_THRESHOLD_UV	2150000
 
+#if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
+struct efi_fw_image fw_images[1];
+
+struct efi_capsule_update_info update_info = {
+	.images = fw_images,
+};
+
+u8 num_image_type_guids = ARRAY_SIZE(fw_images);
+#endif /* EFI_HAVE_CAPSULE_SUPPORT */
+
 int board_early_init_f(void)
 {
 	/* nothing to do, only used in SPL */
@@ -675,6 +686,14 @@ int board_init(void)
 
 	setup_led(LEDST_ON);
 
+#if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT) 
+	if (board_is_dk2()) {
+		efi_guid_t image_type_guid = STM32MP1_DK2_FIP_IMAGE_GUID;
+		guidcpy(&fw_images[0].image_type_id, &image_type_guid);
+		fw_images[0].fw_name = u"STM32MP1-DK2-FIP";
+		fw_images[0].image_index = 5;
+	}
+#endif
 	return 0;
 }
 
diff --git a/include/configs/stm32mp15_common.h b/include/configs/stm32mp15_common.h
index 6b40cdb017..6a1ae9788d 100644
--- a/include/configs/stm32mp15_common.h
+++ b/include/configs/stm32mp15_common.h
@@ -54,6 +54,10 @@
 #define CONFIG_SYS_AUTOLOAD		"no"
 #endif
 
+#define STM32MP1_DK2_FIP_IMAGE_GUID \
+	EFI_GUID(0x19d5df83, 0x11b0, 0x457b, 0xbe, 0x2c, \
+		 0x75, 0x59, 0xc1, 0x31, 0x42, 0xa5)
+
 /*****************************************************************************/
 #ifdef CONFIG_DISTRO_DEFAULTS
 /*****************************************************************************/
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (4 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 05/23] stm32mp1: dk2: Add image information for capsule updates Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-10 11:53   ` Ilias Apalodimas
  2022-06-21  9:49   ` Patrick DELAUNAY
  2022-06-09 12:29 ` [PATCH v5 07/23] FWU: STM32MP1: Add support to read boot index from backup register Sughosh Ganu
                   ` (17 subsequent siblings)
  23 siblings, 2 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

Add helper functions needed for accessing the FWU metadata which
contains information on the updatable images. These functions have
been added for the STM32MP157C-DK2 board which has the updatable
images on the uSD card, formatted as GPT partitions.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 board/st/stm32mp1/stm32mp1.c | 115 +++++++++++++++++++++++++++++++++++
 include/fwu.h                |   2 +
 2 files changed, 117 insertions(+)

diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index 62d98ad776..e68bf09955 100644
--- a/board/st/stm32mp1/stm32mp1.c
+++ b/board/st/stm32mp1/stm32mp1.c
@@ -7,9 +7,11 @@
 
 #include <common.h>
 #include <adc.h>
+#include <blk.h>
 #include <bootm.h>
 #include <clk.h>
 #include <config.h>
+#include <dfu.h>
 #include <dm.h>
 #include <efi_loader.h>
 #include <env.h>
@@ -25,9 +27,11 @@
 #include <log.h>
 #include <malloc.h>
 #include <misc.h>
+#include <mmc.h>
 #include <mtd_node.h>
 #include <net.h>
 #include <netdev.h>
+#include <part.h>
 #include <phy.h>
 #include <remoteproc.h>
 #include <reset.h>
@@ -967,3 +971,114 @@ static void board_copro_image_process(ulong fw_image, size_t fw_size)
 }
 
 U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_COPRO, board_copro_image_process);
+
+#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
+#include <fwu.h>
+#include <fwu_mdata.h>
+
+static int get_gpt_dfu_identifier(struct blk_desc *desc, efi_guid_t *image_guid)
+{
+	int i;
+	struct disk_partition info;
+	efi_guid_t unique_part_guid;
+
+	for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) {
+		if (part_get_info(desc, i, &info))
+			continue;
+		uuid_str_to_bin(info.uuid, unique_part_guid.b,
+				UUID_STR_FORMAT_GUID);
+
+		if (!guidcmp(&unique_part_guid, image_guid))
+			return i;
+	}
+
+	log_err("No partition found with image_guid %pUs\n", image_guid);
+	return -ENOENT;
+}
+
+static int gpt_plat_get_alt_num(struct blk_desc *desc, efi_guid_t *image_guid,
+				int *alt_num)
+{
+	int ret = -1;
+	int i, part, dev_num;
+	int nalt;
+	struct dfu_entity *dfu;
+
+	dev_num = desc->devnum;
+	part = get_gpt_dfu_identifier(desc, image_guid);
+	if (part < 0)
+		return -ENOENT;
+
+	dfu_init_env_entities(NULL, NULL);
+
+	nalt = 0;
+	list_for_each_entry(dfu, &dfu_list, list) {
+		nalt++;
+	}
+
+	if (!nalt) {
+		log_warning("No entities in dfu_alt_info\n");
+		dfu_free_entities();
+		return -ENOENT;
+	}
+
+
+	for (i = 0; i < nalt; i++) {
+		dfu = dfu_get_entity(i);
+
+		if (!dfu)
+			continue;
+
+		/*
+		 * Currently, Multi Bank update
+		 * feature is being supported
+		 * only on GPT partitioned
+		 * MMC/SD devices.
+		 */
+		if (dfu->dev_type != DFU_DEV_MMC)
+			continue;
+
+		if (dfu->layout == DFU_RAW_ADDR &&
+		    dfu->data.mmc.dev_num == dev_num &&
+		    dfu->data.mmc.part == part) {
+			*alt_num = dfu->alt;
+			ret = 0;
+			break;
+		}
+	}
+
+	dfu_free_entities();
+
+	return ret;
+}
+
+int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
+			 int *alt_num)
+{
+	struct blk_desc *desc;
+
+	desc = dev_get_uclass_plat(dev);
+	if (!desc) {
+		log_err("Block device not found\n");
+		return -ENODEV;
+	}
+
+	return gpt_plat_get_alt_num(desc, image_guid, alt_num);
+}
+
+int fwu_plat_get_update_index(u32 *update_idx)
+{
+	int ret;
+	u32 active_idx;
+
+	ret = fwu_get_active_index(&active_idx);
+
+	if (ret < 0)
+		return -1;
+
+	*update_idx = active_idx ^= 0x1;
+
+	return ret;
+}
+
+#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
diff --git a/include/fwu.h b/include/fwu.h
index 3b1ee4e83e..36e58afa29 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -46,6 +46,8 @@ int fwu_revert_boot_index(void);
 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_alt_num(struct udevice *dev, efi_guid_t *image_guid,
 			 int *alt_num);
+int fwu_plat_get_update_index(u32 *update_idx);
 #endif /* _FWU_H_ */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 07/23] FWU: STM32MP1: Add support to read boot index from backup register
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (5 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-10 12:02   ` Ilias Apalodimas
  2022-06-21 11:27   ` Patrick DELAUNAY
  2022-06-09 12:29 ` [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
                   ` (16 subsequent siblings)
  23 siblings, 2 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

The FWU Multi Bank Update feature allows the platform to boot the
firmware images from one of the partitions(banks). The first stage
bootloader(fsbl) passes the value of the boot index, i.e. the bank
from which the firmware images were booted from to U-Boot. On the
STM32MP157C-DK2 board, this value is passed through one of the SoC's
backup register. Add a function to read the boot index value from the
backup register.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 arch/arm/mach-stm32mp/include/mach/stm32.h | 4 ++++
 board/st/stm32mp1/stm32mp1.c               | 7 +++++++
 include/fwu.h                              | 2 +-
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h
index 47e88fc3dc..40995ee142 100644
--- a/arch/arm/mach-stm32mp/include/mach/stm32.h
+++ b/arch/arm/mach-stm32mp/include/mach/stm32.h
@@ -100,6 +100,7 @@ enum boot_device {
 #define TAMP_BACKUP_REGISTER(x)		(STM32_TAMP_BASE + 0x100 + 4 * x)
 #define TAMP_BACKUP_MAGIC_NUMBER	TAMP_BACKUP_REGISTER(4)
 #define TAMP_BACKUP_BRANCH_ADDRESS	TAMP_BACKUP_REGISTER(5)
+#define TAMP_FWU_BOOT_INFO_REG		TAMP_BACKUP_REGISTER(10)
 #define TAMP_COPRO_RSC_TBL_ADDRESS	TAMP_BACKUP_REGISTER(17)
 #define TAMP_COPRO_STATE		TAMP_BACKUP_REGISTER(18)
 #define TAMP_BOOT_CONTEXT		TAMP_BACKUP_REGISTER(20)
@@ -118,6 +119,9 @@ enum boot_device {
 #define TAMP_BOOT_INSTANCE_MASK		GENMASK(3, 0)
 #define TAMP_BOOT_FORCED_MASK		GENMASK(7, 0)
 #define TAMP_BOOT_DEBUG_ON		BIT(16)
+#define TAMP_FWU_BOOT_IDX_MASK		GENMASK(3, 0)
+
+#define TAMP_FWU_BOOT_IDX_OFFSET	0
 
 enum forced_boot_mode {
 	BOOT_NORMAL = 0x00,
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index e68bf09955..dff41ed6f6 100644
--- a/board/st/stm32mp1/stm32mp1.c
+++ b/board/st/stm32mp1/stm32mp1.c
@@ -1081,4 +1081,11 @@ int fwu_plat_get_update_index(u32 *update_idx)
 	return ret;
 }
 
+void fwu_plat_get_bootidx(void *boot_idx)
+{
+	u32 *bootidx = boot_idx;
+
+	*bootidx = (readl(TAMP_FWU_BOOT_INFO_REG) >>
+		    TAMP_FWU_BOOT_IDX_OFFSET) & TAMP_FWU_BOOT_IDX_MASK;
+}
 #endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
diff --git a/include/fwu.h b/include/fwu.h
index 36e58afa29..41774ff9e2 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -46,7 +46,7 @@ int fwu_revert_boot_index(void);
 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);
 
-
+void fwu_plat_get_bootidx(void *boot_idx);
 int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
 			 int *alt_num);
 int fwu_plat_get_update_index(u32 *update_idx);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (6 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 07/23] FWU: STM32MP1: Add support to read boot index from backup register Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-15  6:34   ` Heinrich Schuchardt
                     ` (2 more replies)
  2022-06-09 12:29 ` [PATCH v5 09/23] FWU: Add support for the FWU Multi Bank Update feature Sughosh Ganu
                   ` (15 subsequent siblings)
  23 siblings, 3 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

The FWU Multi Bank Update specification requires the Update Agent to
carry out certain checks at the time of platform boot. The Update
Agent is the component which is responsible for updating the firmware
components and maintaining and keeping the metadata in sync.

The spec requires that the Update Agent perform the following checks
at the time of boot
* Sanity check of both the metadata copies maintained by the platform.
* Get the boot index passed to U-Boot by the prior stage bootloader
  and use this value for metadata bookkeeping.
* Check if the system is booting in Trial State. If the system boots
  in the Trial State for more than a specified number of boot counts,
  change the Active Bank to be booting the platform from.

Add these checks in the board initialisation sequence, invoked after
relocation.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 common/board_r.c      |   5 ++
 include/fwu.h         |   3 +
 lib/fwu_updates/fwu.c | 170 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 178 insertions(+)
 create mode 100644 lib/fwu_updates/fwu.c

diff --git a/common/board_r.c b/common/board_r.c
index 6f4aca2077..33a600715d 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -15,6 +15,7 @@
 #include <cpu_func.h>
 #include <exports.h>
 #include <flash.h>
+#include <fwu.h>
 #include <hang.h>
 #include <image.h>
 #include <irq_func.h>
@@ -797,6 +798,10 @@ static init_fnc_t init_sequence_r[] = {
 #if defined(CONFIG_PRAM)
 	initr_mem,
 #endif
+
+#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
+	fwu_boottime_checks,
+#endif
 	run_main_loop,
 };
 
diff --git a/include/fwu.h b/include/fwu.h
index 41774ff9e2..8fbd91b463 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -33,6 +33,9 @@ struct fwu_mdata_ops {
 	EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
 		 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
 
+int fwu_boottime_checks(void);
+u8 fwu_update_checks_pass(void);
+
 int fwu_get_mdata(struct fwu_mdata **mdata);
 int fwu_update_mdata(struct fwu_mdata *mdata);
 int fwu_get_active_index(u32 *active_idx);
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
new file mode 100644
index 0000000000..af884439fb
--- /dev/null
+++ b/lib/fwu_updates/fwu.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <dm.h>
+#include <efi.h>
+#include <efi_loader.h>
+#include <efi_variable.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <malloc.h>
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+static u8 trial_state;
+static u8 boottime_check;
+
+static int fwu_trial_state_check(void)
+{
+	int ret, i;
+	efi_status_t status;
+	efi_uintn_t var_size;
+	u16 trial_state_ctr;
+	u32 nimages, active_bank, var_attributes, active_idx;
+	struct fwu_mdata *mdata = NULL;
+	struct fwu_image_entry *img_entry;
+	struct fwu_image_bank_info *img_bank_info;
+
+	ret = fwu_get_mdata(&mdata);
+	if (ret)
+		return ret;
+
+	ret = 0;
+	nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
+	active_bank = mdata->active_index;
+	img_entry = &mdata->img_entry[0];
+	for (i = 0; i < nimages; i++) {
+		img_bank_info = &img_entry[i].img_bank_info[active_bank];
+		if (!img_bank_info->accepted) {
+			trial_state = 1;
+			break;
+		}
+	}
+
+	if (trial_state) {
+		var_size = (efi_uintn_t)sizeof(trial_state_ctr);
+		log_info("System booting in Trial State\n");
+		var_attributes = EFI_VARIABLE_NON_VOLATILE |
+			EFI_VARIABLE_BOOTSERVICE_ACCESS;
+		status = efi_get_variable_int(L"TrialStateCtr",
+					      &efi_global_variable_guid,
+					      &var_attributes,
+					      &var_size, &trial_state_ctr,
+					      NULL);
+		if (status != EFI_SUCCESS) {
+			log_err("Unable to read TrialStateCtr variable\n");
+			ret = -1;
+			goto out;
+		}
+
+		++trial_state_ctr;
+		if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
+			log_info("Trial State count exceeded. Revert back to previous_active_index\n");
+			active_idx = mdata->active_index;
+			ret = fwu_revert_boot_index();
+			if (ret) {
+				log_err("Unable to revert active_index\n");
+				goto out;
+			}
+
+			trial_state_ctr = 0;
+			status = efi_set_variable_int(L"TrialStateCtr",
+						      &efi_global_variable_guid,
+						      var_attributes,
+						      0,
+						      &trial_state_ctr, false);
+			if (status != EFI_SUCCESS) {
+				log_err("Unable to clear TrialStateCtr variable\n");
+				ret = -1;
+				goto out;
+			}
+		} else {
+			status = efi_set_variable_int(L"TrialStateCtr",
+						      &efi_global_variable_guid,
+						      var_attributes,
+						      var_size,
+						      &trial_state_ctr, false);
+			if (status != EFI_SUCCESS) {
+				log_err("Unable to increment TrialStateCtr variable\n");
+				ret = -1;
+				goto out;
+			}
+		}
+	} else {
+		trial_state_ctr = 0;
+		status = efi_set_variable_int(L"TrialStateCtr",
+					      &efi_global_variable_guid,
+					      0,
+					      0, &trial_state_ctr,
+					      NULL);
+	}
+
+out:
+	free(mdata);
+	return ret;
+}
+
+u8 fwu_update_checks_pass(void)
+{
+	return !trial_state && boottime_check;
+}
+
+int fwu_boottime_checks(void)
+{
+	int ret;
+	struct udevice *dev;
+	u32 boot_idx, active_idx;
+
+	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
+		log_err("FWU Metadata device not found\n");
+		return 0;
+	}
+
+	ret = fwu_mdata_check();
+	if (ret) {
+		return 0;
+	}
+
+	/*
+	 * Get the Boot Index, i.e. the bank from
+	 * which the platform has booted. This value
+	 * gets passed from the ealier stage bootloader
+	 * which booted u-boot, e.g. tf-a. If the
+	 * boot index is not the same as the
+	 * active_index read from the FWU metadata,
+	 * update the active_index.
+	 */
+	fwu_plat_get_bootidx(&boot_idx);
+	if (boot_idx >= CONFIG_FWU_NUM_BANKS) {
+		log_err("Received incorrect value of boot_index\n");
+		return 0;
+	}
+
+	ret = fwu_get_active_index(&active_idx);
+	if (ret) {
+		log_err("Unable to read active_index\n");
+		return 0;
+	}
+
+	if (boot_idx != active_idx) {
+		log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
+			 boot_idx, active_idx);
+		ret = fwu_update_active_index(boot_idx);
+		if (!ret)
+			boottime_check = 1;
+
+		return 0;
+	}
+
+	if (efi_init_obj_list() != EFI_SUCCESS)
+		return 0;
+
+	ret = fwu_trial_state_check();
+	if (!ret)
+		boottime_check = 1;
+
+	return 0;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 09/23] FWU: Add support for the FWU Multi Bank Update feature
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (7 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-21 10:56   ` Etienne Carriere
  2022-06-21 11:55   ` Patrick DELAUNAY
  2022-06-09 12:29 ` [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata Sughosh Ganu
                   ` (14 subsequent siblings)
  23 siblings, 2 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

The FWU Multi Bank Update feature supports updation of firmware images
to one of multiple sets(also called banks) of images. The firmware
images are clubbed together in banks, with the system booting images
from the active bank. Information on the images such as which bank
they belong to is stored as part of the metadata structure, which is
stored on the same storage media as the firmware images on a dedicated
partition.

At the time of update, the metadata is read to identify the bank to
which the images need to be flashed(update bank). On a successful
update, the metadata is modified to set the updated bank as active
bank to subsequently boot from.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 include/fwu.h                |  12 +-
 lib/Kconfig                  |   6 +
 lib/Makefile                 |   1 +
 lib/efi_loader/efi_capsule.c | 231 ++++++++++++++++++++++++++++++++++-
 lib/efi_loader/efi_setup.c   |   3 +-
 lib/fwu_updates/Kconfig      |  31 +++++
 lib/fwu_updates/Makefile     |   6 +
 lib/fwu_updates/fwu.c        |  26 ++++
 8 files changed, 309 insertions(+), 7 deletions(-)
 create mode 100644 lib/fwu_updates/Kconfig
 create mode 100644 lib/fwu_updates/Makefile

diff --git a/include/fwu.h b/include/fwu.h
index 8fbd91b463..9c8012407b 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -28,13 +28,23 @@ struct fwu_mdata_ops {
 };
 
 #define FWU_MDATA_VERSION	0x1
+#define FWU_IMAGE_ACCEPTED	0x1
 
 #define FWU_MDATA_GUID \
 	EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
 		 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
 
-int fwu_boottime_checks(void);
+#define FWU_OS_REQUEST_FW_REVERT_GUID \
+	EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
+		 0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
+
+#define FWU_OS_REQUEST_FW_ACCEPT_GUID \
+	EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
+		 0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
+
 u8 fwu_update_checks_pass(void);
+int fwu_boottime_checks(void);
+int fwu_trial_state_ctr_start(void);
 
 int fwu_get_mdata(struct fwu_mdata **mdata);
 int fwu_update_mdata(struct fwu_mdata *mdata);
diff --git a/lib/Kconfig b/lib/Kconfig
index acc0ac081a..4ca6ea226b 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -966,3 +966,9 @@ config PHANDLE_CHECK_SEQ
 	  phandles in fdtdec_get_alias_seq() function.
 
 endmenu
+
+menu "FWU Multi Bank Updates"
+
+source lib/fwu_updates/Kconfig
+
+endmenu
diff --git a/lib/Makefile b/lib/Makefile
index d9b1811f75..0cf8527c2d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_EFI) += efi/
 obj-$(CONFIG_EFI_LOADER) += efi_driver/
 obj-$(CONFIG_EFI_LOADER) += efi_loader/
 obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/
+obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_updates/
 obj-$(CONFIG_LZMA) += lzma/
 obj-$(CONFIG_BZIP2) += bzip2/
 obj-$(CONFIG_TIZEN) += tizen/
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index c76a5f3570..8ca041e6a2 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -14,6 +14,7 @@
 #include <env.h>
 #include <fdtdec.h>
 #include <fs.h>
+#include <fwu.h>
 #include <hang.h>
 #include <malloc.h>
 #include <mapmem.h>
@@ -32,6 +33,17 @@ static const efi_guid_t efi_guid_firmware_management_capsule_id =
 		EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
 const efi_guid_t efi_guid_firmware_management_protocol =
 		EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
+const efi_guid_t fwu_guid_os_request_fw_revert =
+		FWU_OS_REQUEST_FW_REVERT_GUID;
+const efi_guid_t fwu_guid_os_request_fw_accept =
+		FWU_OS_REQUEST_FW_ACCEPT_GUID;
+
+#define FW_ACCEPT_OS	(u32)0x8000
+
+__maybe_unused static u32 update_index;
+__maybe_unused static bool capsule_update;
+__maybe_unused static bool fw_accept_os;
+static bool image_index_check = true;
 
 #ifdef CONFIG_EFI_CAPSULE_ON_DISK
 /* for file system access */
@@ -205,7 +217,8 @@ efi_fmp_find(efi_guid_t *image_type, u8 image_index, u64 instance,
 			log_debug("+++ desc[%d] index: %d, name: %ls\n",
 				  j, desc->image_index, desc->image_id_name);
 			if (!guidcmp(&desc->image_type_id, image_type) &&
-			    (desc->image_index == image_index) &&
+			    (!image_index_check ||
+			     desc->image_index == image_index) &&
 			    (!instance ||
 			     !desc->hardware_instance ||
 			      desc->hardware_instance == instance))
@@ -388,6 +401,87 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s
 }
 #endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
 
+static bool fwu_empty_capsule(struct efi_capsule_header *capsule)
+{
+	return !guidcmp(&capsule->capsule_guid,
+			&fwu_guid_os_request_fw_revert) ||
+		!guidcmp(&capsule->capsule_guid,
+			 &fwu_guid_os_request_fw_accept);
+}
+
+static efi_status_t fwu_empty_capsule_process(
+	struct efi_capsule_header *capsule)
+{
+	int status;
+	u32 active_idx;
+	efi_status_t ret;
+	efi_guid_t *image_guid;
+
+	if (!guidcmp(&capsule->capsule_guid,
+		     &fwu_guid_os_request_fw_revert)) {
+		/*
+		 * One of the previously updated image has
+		 * failed the OS acceptance test. OS has
+		 * requested to revert back to the earlier
+		 * boot index
+		 */
+		status = fwu_revert_boot_index();
+		if (status < 0) {
+			log_err("Failed to revert the FWU boot index\n");
+			if (status == -ENODEV ||
+			    status == -ERANGE ||
+			    status == -EIO)
+				ret = EFI_DEVICE_ERROR;
+			else if (status == -EINVAL)
+				ret = EFI_INVALID_PARAMETER;
+			else
+				ret = EFI_OUT_OF_RESOURCES;
+		} else {
+			ret = EFI_SUCCESS;
+			log_err("Reverted the FWU active_index. Recommend rebooting the system\n");
+		}
+	} else {
+		/*
+		 * Image accepted by the OS. Set the acceptance
+		 * status for the image.
+		 */
+		image_guid = (void *)(char *)capsule +
+			capsule->header_size;
+
+		status = fwu_get_active_index(&active_idx);
+		if (status < 0) {
+			log_err("Unable to get the active_index from the FWU metadata\n");
+			if (status == -ENODEV ||
+			    status == -ERANGE ||
+			    status == -EIO)
+				ret = EFI_DEVICE_ERROR;
+			else if (status == -EINVAL)
+				ret = EFI_INVALID_PARAMETER;
+			else
+				ret = EFI_OUT_OF_RESOURCES;
+
+			return ret;
+		}
+
+		status = fwu_accept_image(image_guid, active_idx);
+		if (status < 0) {
+			log_err("Unable to set the Accept bit for the image %pUs\n",
+				image_guid);
+			if (status == -ENODEV ||
+			    status == -ERANGE ||
+			    status == -EIO)
+				ret = EFI_DEVICE_ERROR;
+			else if (status == -EINVAL)
+				ret = EFI_INVALID_PARAMETER;
+			else
+				ret = EFI_OUT_OF_RESOURCES;
+		} else {
+			ret = EFI_SUCCESS;
+		}
+	}
+
+	return ret;
+}
 
 /**
  * efi_capsule_update_firmware - update firmware from capsule
@@ -407,10 +501,42 @@ static efi_status_t efi_capsule_update_firmware(
 	void *image_binary, *vendor_code;
 	efi_handle_t *handles;
 	efi_uintn_t no_handles;
-	int item;
+	int item, alt_no;
 	struct efi_firmware_management_protocol *fmp;
 	u16 *abort_reason;
+	efi_guid_t image_type_id;
 	efi_status_t ret = EFI_SUCCESS;
+	int status;
+	u8 image_index;
+
+	if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+		if (!fwu_empty_capsule(capsule_data) &&
+		    !fwu_update_checks_pass()) {
+			log_err("FWU checks failed. Cannot start update\n");
+			return EFI_INVALID_PARAMETER;
+		}
+
+		if (fwu_empty_capsule(capsule_data)) {
+			capsule_update = false;
+			return fwu_empty_capsule_process(capsule_data);
+		} else {
+			capsule_update = true;
+		}
+
+		/* Obtain the update_index from the platform */
+		status = fwu_plat_get_update_index(&update_index);
+		if (status < 0) {
+			log_err("Failed to get the FWU update_index value\n");
+			return EFI_DEVICE_ERROR;
+		}
+
+		fw_accept_os = capsule_data->flags & FW_ACCEPT_OS ? 0x1 : 0x0;
+		/*
+		 * For Multi Bank updates, the image index is determined at
+		 * runtime based on the value of the update bank.
+		 */
+		image_index_check = false;
+	}
 
 	/* sanity check */
 	if (capsule_data->header_size < sizeof(*capsule) ||
@@ -485,8 +611,36 @@ static efi_status_t efi_capsule_update_firmware(
 				goto out;
 		}
 
+		if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+			/*
+			 * Based on the value of update_image_type_id,
+			 * derive the alt number value. This will be
+			 * passed as update_image_index to the
+			 * set_image function.
+			 */
+			image_type_id = image->update_image_type_id;
+			status = fwu_get_image_alt_num(&image_type_id,
+						       update_index,
+						       &alt_no);
+			if (status < 0) {
+				log_err("Unable to get the alt no for the image type %pUs\n",
+					&image_type_id);
+				if (status == -ENODEV || status == -EIO)
+					ret = EFI_DEVICE_ERROR;
+				else if (status == -ENOMEM)
+					ret = EFI_OUT_OF_RESOURCES;
+				else if (status == -ERANGE || status == -EINVAL)
+					ret = EFI_INVALID_PARAMETER;
+				goto out;
+			}
+			log_debug("alt_no %u for Image Type Id %pUs\n",
+				  alt_no, &image_type_id);
+			image_index = alt_no + 1;
+		} else {
+			image_index = image->update_image_index;
+		}
 		abort_reason = NULL;
-		ret = EFI_CALL(fmp->set_image(fmp, image->update_image_index,
+		ret = EFI_CALL(fmp->set_image(fmp, image_index,
 					      image_binary,
 					      image_binary_size,
 					      vendor_code, NULL,
@@ -497,6 +651,38 @@ static efi_status_t efi_capsule_update_firmware(
 			efi_free_pool(abort_reason);
 			goto out;
 		}
+
+		if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+			if (!fw_accept_os) {
+				/*
+				 * The OS will not be accepting the firmware
+				 * images. Set the accept bit of all the
+				 * images contained in this capsule.
+				 */
+				status = fwu_accept_image(&image_type_id,
+							  update_index);
+			} else {
+				status = fwu_clear_accept_image(&image_type_id,
+								update_index);
+			}
+
+			if (status < 0) {
+				log_err("Unable to %s the accept bit for the image %pUs\n",
+					fw_accept_os ? "clear" : "set",
+					&image_type_id);
+				if (status == -ENODEV || status == -EIO)
+					ret = EFI_DEVICE_ERROR;
+				else if (status == -ENOMEM)
+					ret = EFI_OUT_OF_RESOURCES;
+				else if (status == -ERANGE || status == -EINVAL)
+					ret = EFI_INVALID_PARAMETER;
+				goto out;
+			}
+			log_debug("%s the accepted bit for Image %pUs\n",
+				  fw_accept_os ? "Cleared" : "Set",
+				  &image_type_id);
+		}
+
 	}
 
 out:
@@ -1101,8 +1287,10 @@ efi_status_t efi_launch_capsules(void)
 {
 	struct efi_capsule_header *capsule = NULL;
 	u16 **files;
+	int status;
 	unsigned int nfiles, index, i;
 	efi_status_t ret;
+	bool update_status = true;
 
 	if (check_run_capsules() != EFI_SUCCESS)
 		return EFI_SUCCESS;
@@ -1130,12 +1318,14 @@ efi_status_t efi_launch_capsules(void)
 		ret = efi_capsule_read_file(files[i], &capsule);
 		if (ret == EFI_SUCCESS) {
 			ret = efi_capsule_update_firmware(capsule);
-			if (ret != EFI_SUCCESS)
+			if (ret != EFI_SUCCESS) {
 				log_err("Applying capsule %ls failed.\n",
 					files[i]);
-			else
+				update_status = false;
+			} else {
 				log_info("Applying capsule %ls succeeded.\n",
 					 files[i]);
+			}
 
 			/* create CapsuleXXXX */
 			set_capsule_result(index, capsule, ret);
@@ -1143,6 +1333,7 @@ efi_status_t efi_launch_capsules(void)
 			free(capsule);
 		} else {
 			log_err("Reading capsule %ls failed\n", files[i]);
+			update_status = false;
 		}
 		/* delete a capsule either in case of success or failure */
 		ret = efi_capsule_delete_file(files[i]);
@@ -1150,7 +1341,37 @@ efi_status_t efi_launch_capsules(void)
 			log_err("Deleting capsule %ls failed\n",
 				files[i]);
 	}
+
 	efi_capsule_scan_done();
+	if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+		if (update_status == true && capsule_update == true) {
+			/*
+			 * All the capsules have been updated successfully,
+			 * update the FWU metadata.
+			 */
+			log_debug("Update Complete. Now updating active_index to %u\n",
+				  update_index);
+			status = fwu_update_active_index(update_index);
+			if (status < 0) {
+				log_err("Failed to update FWU metadata index values\n");
+				if (status == -EINVAL || status == -ERANGE)
+					ret = EFI_INVALID_PARAMETER;
+				else if (status == -ENODEV || status == -EIO)
+					ret = EFI_DEVICE_ERROR;
+				else if (status == -ENOMEM)
+					ret = EFI_OUT_OF_RESOURCES;
+			} else {
+				log_debug("Successfully updated the active_index\n");
+				status = fwu_trial_state_ctr_start();
+				if (status < 0)
+					ret = EFI_DEVICE_ERROR;
+				else
+					ret = EFI_SUCCESS;
+			}
+		} else if (capsule_update == true && update_status == false) {
+			log_err("All capsules were not updated. Not updating FWU metadata\n");
+		}
+	}
 
 	for (i = 0; i < nfiles; i++)
 		free(files[i]);
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index 250eeb2fcd..8658ebf56a 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -346,7 +346,8 @@ efi_status_t efi_init_obj_list(void)
 		goto out;
 
 	/* Execute capsules after reboot */
-	if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) &&
+	if (!IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE) &&
+	    IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) &&
 	    !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
 		ret = efi_launch_capsules();
 out:
diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
new file mode 100644
index 0000000000..6de28e0c9c
--- /dev/null
+++ b/lib/fwu_updates/Kconfig
@@ -0,0 +1,31 @@
+config FWU_MULTI_BANK_UPDATE
+	bool "Enable FWU Multi Bank Update Feature"
+	depends on EFI_HAVE_CAPSULE_SUPPORT
+	select PARTITION_TYPE_GUID
+	select EFI_SETUP_EARLY
+	help
+	  Feature for updating firmware images on platforms having
+	  multiple banks(copies) of the firmware images. One of the
+	  bank is selected for updating all the firmware components
+
+config FWU_NUM_BANKS
+	int "Number of Banks defined by the platform"
+	depends on FWU_MULTI_BANK_UPDATE
+	help
+	  Define the number of banks of firmware images on a platform
+
+config FWU_NUM_IMAGES_PER_BANK
+	int "Number of firmware images per bank"
+	depends on FWU_MULTI_BANK_UPDATE
+	help
+	  Define the number of firmware images per bank. This value
+	  should be the same for all the banks.
+
+config FWU_TRIAL_STATE_CNT
+	int "Number of times system boots in Trial State"
+	depends on FWU_MULTI_BANK_UPDATE
+	default 3
+	help
+	  With FWU Multi Bank Update feature enabled, number of times
+	  the platform is allowed to boot in Trial State after an
+	  update.
diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile
new file mode 100644
index 0000000000..74e37014e2
--- /dev/null
+++ b/lib/fwu_updates/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2022, Linaro Limited
+#
+
+obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index af884439fb..422ef58661 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -112,6 +112,32 @@ u8 fwu_update_checks_pass(void)
 	return !trial_state && boottime_check;
 }
 
+int fwu_trial_state_ctr_start(void)
+{
+	int ret;
+	u32 var_attributes;
+	efi_status_t status;
+	efi_uintn_t var_size;
+	u16 trial_state_ctr;
+
+	var_size = (efi_uintn_t)sizeof(trial_state_ctr);
+	var_attributes = EFI_VARIABLE_NON_VOLATILE |
+		EFI_VARIABLE_BOOTSERVICE_ACCESS;
+
+	trial_state_ctr = ret = 0;
+	status = efi_set_variable_int(L"TrialStateCtr",
+				      &efi_global_variable_guid,
+				      var_attributes,
+				      var_size,
+				      &trial_state_ctr, false);
+	if (status != EFI_SUCCESS) {
+		log_err("Unable to increment TrialStateCtr variable\n");
+		ret = -1;
+	}
+
+	return ret;
+}
+
 int fwu_boottime_checks(void)
 {
 	int ret;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (8 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 09/23] FWU: Add support for the FWU Multi Bank Update feature Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-10 12:07   ` Ilias Apalodimas
                     ` (2 more replies)
  2022-06-09 12:29 ` [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules Sughosh Ganu
                   ` (13 subsequent siblings)
  23 siblings, 3 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

Add a command to read the metadata as specified in the FWU
specification and print the fields of the metadata.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 cmd/Kconfig     |  7 +++++
 cmd/Makefile    |  1 +
 cmd/fwu_mdata.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)
 create mode 100644 cmd/fwu_mdata.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 09193b61b9..275becd837 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -144,6 +144,13 @@ config CMD_CPU
 	  internal name) and clock frequency. Other information may be
 	  available depending on the CPU driver.
 
+config CMD_FWU_METADATA
+	bool "fwu metadata read"
+	depends on FWU_MULTI_BANK_UPDATE
+	default y if FWU_MULTI_BANK_UPDATE
+	help
+	  Command to read the metadata and dump it's contents
+
 config CMD_LICENSE
 	bool "license"
 	select BUILD_BIN2C
diff --git a/cmd/Makefile b/cmd/Makefile
index 5e43a1e022..259a93bc65 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_CMD_FPGA) += fpga.o
 obj-$(CONFIG_CMD_FPGAD) += fpgad.o
 obj-$(CONFIG_CMD_FS_GENERIC) += fs.o
 obj-$(CONFIG_CMD_FUSE) += fuse.o
+obj-$(CONFIG_CMD_FWU_METADATA) += fwu_mdata.o
 obj-$(CONFIG_CMD_GETTIME) += gettime.o
 obj-$(CONFIG_CMD_GPIO) += gpio.o
 obj-$(CONFIG_CMD_HVC) += smccc.o
diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c
new file mode 100644
index 0000000000..bc20ca26a3
--- /dev/null
+++ b/cmd/fwu_mdata.c
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <command.h>
+#include <dm.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <linux/types.h>
+
+static void print_mdata(struct fwu_mdata *mdata)
+{
+	int i, j;
+	struct fwu_image_entry *img_entry;
+	struct fwu_image_bank_info *img_info;
+	u32 nimages, nbanks;
+
+	printf("\tFWU Metadata\n");
+	printf("crc32: %#x\n", mdata->crc32);
+	printf("version: %#x\n", mdata->version);
+	printf("active_index: %#x\n", mdata->active_index);
+	printf("previous_active_index: %#x\n", mdata->previous_active_index);
+
+	nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
+	nbanks = CONFIG_FWU_NUM_BANKS;
+	printf("\tImage Info\n");
+	for (i = 0; i < nimages; i++) {
+		img_entry = &mdata->img_entry[i];
+		printf("\nImage Type Guid: %pUL\n", &img_entry->image_type_uuid);
+		printf("Location Guid: %pUL\n", &img_entry->location_uuid);
+		for (j = 0; j < nbanks; j++) {
+			img_info = &img_entry->img_bank_info[j];
+			printf("Image Guid:  %pUL\n", &img_info->image_uuid);
+			printf("Image Acceptance: %#x\n", img_info->accepted);
+		}
+	}
+}
+
+int do_fwu_mdata_read(struct cmd_tbl *cmdtp, int flag,
+		     int argc, char * const argv[])
+{
+	struct udevice *dev;
+	int ret = CMD_RET_SUCCESS;
+	struct fwu_mdata *mdata = NULL;
+
+	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
+		log_err("Unable to get FWU metadata device\n");
+		return CMD_RET_FAILURE;
+	}
+
+	ret = fwu_get_mdata(&mdata);
+	if (ret < 0) {
+		log_err("Unable to get valid FWU metadata\n");
+		ret = CMD_RET_FAILURE;
+		goto out;
+	}
+
+	print_mdata(mdata);
+
+out:
+	free(mdata);
+	return ret;
+}
+
+U_BOOT_CMD(
+	fwu_mdata_read,	1,	1,	do_fwu_mdata_read,
+	"Read and print FWU metadata",
+	""
+);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (9 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-09 16:27   ` Heinrich Schuchardt
                     ` (2 more replies)
  2022-06-09 12:29 ` [PATCH v5 12/23] FWU: doc: Add documentation for the FWU feature Sughosh Ganu
                   ` (12 subsequent siblings)
  23 siblings, 3 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

The Dependable Boot specification[1] describes the structure of the
firmware accept and revert capsules. These are empty capsules which
are used for signalling the acceptance or rejection of the updated
firmware by the OS. Add support for generating these empty capsules.

[1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 doc/mkeficapsule.1   |  29 ++++++---
 tools/eficapsule.h   |   8 +++
 tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
 3 files changed, 151 insertions(+), 25 deletions(-)

diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
index 09bdc24295..77ca061efd 100644
--- a/doc/mkeficapsule.1
+++ b/doc/mkeficapsule.1
@@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
 
 .SH SYNOPSIS
 .B mkeficapsule
-.RI [ options "] " image-blob " " capsule-file
+.RI [ options ] " " [ image-blob ] " " capsule-file
 
 .SH "DESCRIPTION"
 .B mkeficapsule
@@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
 In this case, the update will be authenticated by verifying the signature
 before applying.
 
+Additionally, an empty capsule file can be generated for acceptance or
+rejection of firmware images by a governing component like an Operating
+System. The empty capsules do not require an image-blob input file.
+
+
 .B mkeficapsule
-takes any type of image files, including:
+takes any type of image files when generating non empty capsules, including:
 .TP
 .I raw image
 format is a single binary blob of any type of firmware.
@@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
 This type of image file can be generated by
 .BR mkimage .
 
-.PP
-If you want to use other types than above two, you should explicitly
-specify a guid for the FMP driver.
-
 .SH "OPTIONS"
+
 .TP
 .BI "-g\fR,\fB --guid " guid-string
 Specify guid for image blob type. The format is:
     xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
 
 The first three elements are in little endian, while the rest
-is in big endian.
+is in big endian. The option must be specified for all non empty and
+image acceptance capsules
 
 .TP
 .BI "-i\fR,\fB --index " index
@@ -57,6 +60,18 @@ Specify an image index
 .BI "-I\fR,\fB --instance " instance
 Specify a hardware instance
 
+.PP
+For generation of firmware accept empty capsule
+.BR --guid
+is mandatory
+.TP
+.BI "-A\fR,\fB --fw-accept "
+Generate a firmware acceptance empty capsule
+
+.TP
+.BI "-R\fR,\fB --fw-revert "
+Generate a firmware revert empty capsule
+
 .TP
 .BR -h ", " --help
 Print a help message
diff --git a/tools/eficapsule.h b/tools/eficapsule.h
index d63b831443..072a4b5598 100644
--- a/tools/eficapsule.h
+++ b/tools/eficapsule.h
@@ -41,6 +41,14 @@ typedef struct {
 	EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
 		 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
 
+#define FW_ACCEPT_OS_GUID \
+	EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
+		 0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
+
+#define FW_REVERT_OS_GUID \
+	EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
+		 0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
+
 /* flags */
 #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
 
diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
index 5f74d23b9e..e8eb6b070d 100644
--- a/tools/mkeficapsule.c
+++ b/tools/mkeficapsule.c
@@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
 efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
 efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
 
-static const char *opts_short = "g:i:I:v:p:c:m:dh";
+static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
+
+static bool empty_capsule;
+static unsigned char capsule;
+
+enum {
+	CAPSULE_NORMAL_BLOB = 0,
+	CAPSULE_ACCEPT,
+	CAPSULE_REVERT,
+} capsule_type;
 
 static struct option options[] = {
 	{"guid", required_argument, NULL, 'g'},
@@ -39,24 +48,47 @@ static struct option options[] = {
 	{"certificate", required_argument, NULL, 'c'},
 	{"monotonic-count", required_argument, NULL, 'm'},
 	{"dump-sig", no_argument, NULL, 'd'},
+	{"fw-accept", no_argument, NULL, 'A'},
+	{"fw-revert", no_argument, NULL, 'R'},
 	{"help", no_argument, NULL, 'h'},
 	{NULL, 0, NULL, 0},
 };
 
 static void print_usage(void)
 {
-	fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
-		"Options:\n"
-
-		"\t-g, --guid <guid string>    guid for image blob type\n"
-		"\t-i, --index <index>         update image index\n"
-		"\t-I, --instance <instance>   update hardware instance\n"
-		"\t-p, --private-key <privkey file>  private key file\n"
-		"\t-c, --certificate <cert file>     signer's certificate file\n"
-		"\t-m, --monotonic-count <count>     monotonic count\n"
-		"\t-d, --dump_sig              dump signature (*.p7)\n"
-		"\t-h, --help                  print a help message\n",
-		tool_name);
+	if (empty_capsule) {
+		if (capsule == CAPSULE_ACCEPT) {
+			fprintf(stderr, "Usage: %s [options] <output file>\n",
+				tool_name);
+			fprintf(stderr, "Options:\n"
+				"\t-A, --fw-accept             firmware accept capsule\n"
+				"\t-g, --guid <guid string>    guid for image blob type\n"
+				"\t-h, --help                  print a help message\n"
+				);
+		} else {
+			fprintf(stderr, "Usage: %s [options] <output file>\n",
+				tool_name);
+			fprintf(stderr, "Options:\n"
+				"\t-R, --fw-revert             firmware revert capsule\n"
+				"\t-h, --help                  print a help message\n"
+				);
+		}
+	} else {
+		fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
+			"Options:\n"
+
+			"\t-g, --guid <guid string>    guid for image blob type\n"
+			"\t-i, --index <index>         update image index\n"
+			"\t-I, --instance <instance>   update hardware instance\n"
+			"\t-p, --private-key <privkey file>  private key file\n"
+			"\t-c, --certificate <cert file>     signer's certificate file\n"
+			"\t-m, --monotonic-count <count>     monotonic count\n"
+			"\t-d, --dump_sig              dump signature (*.p7)\n"
+			"\t-A, --fw-accept             firmware accept capsule\n"
+			"\t-R, --fw-revert             firmware revert capsule\n"
+			"\t-h, --help                  print a help message\n",
+			tool_name);
+	}
 }
 
 /**
@@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
 	buf[7] = c;
 }
 
+static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
+{
+	struct efi_capsule_header header;
+	FILE *f = NULL;
+	int ret = -1;
+	efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
+	efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
+	efi_guid_t payload, capsule_guid;
+
+	f = fopen(path, "w");
+	if (!f) {
+		fprintf(stderr, "cannot open %s\n", path);
+		goto err;
+	}
+
+	capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
+
+	memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
+	header.header_size = sizeof(header);
+	header.flags = 0;
+
+	header.capsule_image_size = fw_accept ?
+		sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
+
+	if (write_capsule_file(f, &header, sizeof(header),
+			       "Capsule header"))
+		goto err;
+
+	if (fw_accept) {
+		memcpy(&payload, guid, sizeof(efi_guid_t));
+		if (write_capsule_file(f, &payload, sizeof(payload),
+				       "FW Accept Capsule Payload"))
+			goto err;
+	}
+
+	ret = 0;
+
+err:
+	if (f)
+		fclose(f);
+
+	return ret;
+}
+
 /**
  * main - main entry function of mkeficapsule
  * @argc:	Number of arguments
@@ -639,22 +715,49 @@ int main(int argc, char **argv)
 		case 'd':
 			dump_sig = 1;
 			break;
+		case 'A':
+			capsule |= CAPSULE_ACCEPT;
+			break;
+		case 'R':
+			capsule |= CAPSULE_REVERT;
+			break;
 		case 'h':
 			print_usage();
 			exit(EXIT_SUCCESS);
 		}
 	}
 
+	if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
+		fprintf(stderr,
+			"Select either of Accept or Revert capsule generation\n");
+		exit(EXIT_FAILURE);
+	}
+
+	empty_capsule = (capsule == CAPSULE_ACCEPT ||
+			 capsule == CAPSULE_REVERT);
+
 	/* check necessary parameters */
-	if ((argc != optind + 2) || !guid ||
-	    ((privkey_file && !cert_file) ||
-	     (!privkey_file && cert_file))) {
+	if ((!empty_capsule &&
+	    ((argc != optind + 2) || !guid ||
+	     ((privkey_file && !cert_file) ||
+	      (!privkey_file && cert_file)))) ||
+	    (empty_capsule &&
+	    ((argc != optind + 1) ||
+	     ((capsule == CAPSULE_ACCEPT) && !guid) ||
+	     ((capsule == CAPSULE_REVERT) && guid)))) {
 		print_usage();
 		exit(EXIT_FAILURE);
 	}
 
-	if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
-			 mcount, privkey_file, cert_file) < 0) {
+	if (empty_capsule) {
+		if (create_empty_capsule(argv[argc - 1], guid,
+					 capsule == CAPSULE_ACCEPT) < 0) {
+			fprintf(stderr, "Creating empty capsule failed\n");
+			exit(EXIT_FAILURE);
+		}
+	} else 	if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
+				 index, instance, mcount, privkey_file,
+				 cert_file) < 0) {
 		fprintf(stderr, "Creating firmware capsule failed\n");
 		exit(EXIT_FAILURE);
 	}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 12/23] FWU: doc: Add documentation for the FWU feature
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (10 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules Sughosh Ganu
@ 2022-06-09 12:29 ` Sughosh Ganu
  2022-06-21 12:12   ` Patrick DELAUNAY
  2022-06-09 12:30 ` [PATCH v5 13/23] FWU: Add FWU metadata access driver for non-GPT MTD devices Sughosh Ganu
                   ` (11 subsequent siblings)
  23 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:29 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

Add documentattion for the FWU Multi Bank Update feature. The document
describes the steps needed for setting up the platform for the
feature, as well as steps for enabling the feature on the platform.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 doc/develop/uefi/fwu_updates.rst | 142 +++++++++++++++++++++++++++++++
 doc/develop/uefi/index.rst       |   1 +
 doc/develop/uefi/uefi.rst        |   2 +
 3 files changed, 145 insertions(+)
 create mode 100644 doc/develop/uefi/fwu_updates.rst

diff --git a/doc/develop/uefi/fwu_updates.rst b/doc/develop/uefi/fwu_updates.rst
new file mode 100644
index 0000000000..1c34beb7d5
--- /dev/null
+++ b/doc/develop/uefi/fwu_updates.rst
@@ -0,0 +1,142 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (c) 2022 Linaro Limited
+
+FWU Multi Bank Updates in U-Boot
+================================
+
+The FWU Multi Bank Update feature implements the firmware update
+mechanism described in the PSA Firmware Update for A-profile Arm
+Architecture specification[1]. Certain aspects of the Dependable
+Boot specification[2] are also implemented. The feature provides a
+mechanism to have multiple banks of updatable firmware images and for
+updating the firmware images on the non-booted bank. On a successful
+update, the platform boots from the updated bank on subsequent
+boot. The UEFI capsule-on-disk update feature is used for performing
+the actual updates of the updatable firmware images.
+
+The bookkeeping of the updatable images is done through a structure
+called metadata. Currently, the FWU metadata supports identification
+of images based on image GUIDs stored on a GPT partitioned storage
+media. There are plans to extend the metadata structure for non GPT
+partitioned devices as well.
+
+Accessing the FWU metadata is done through generic API's which are
+defined in a driver which complies with the u-boot's driver model. A
+new uclass UCLASS_FWU_MDATA has been added for accessing the FWU
+metadata. Individual drivers can be added based on the type of storage
+media, and it's partitioning method. Details of the storage device
+containing the FWU metadata partitions are specified through a U-Boot
+specific device tree property `fwu-mdata-store`. Please refer to
+U-Boot `doc <doc/device-tree-bindings/firmware/fwu-mdata.txt>`__ for
+the device tree bindings.
+
+Enabling the FWU Multi Bank Update feature
+------------------------------------------
+
+The feature can be enabled by specifying the following configs::
+
+    CONFIG_EFI_CAPSULE_ON_DISK=y
+    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y
+    CONFIG_EFI_CAPSULE_FIRMWARE=y
+    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
+
+    CONFIG_FWU_MULTI_BANK_UPDATE=y
+    CONFIG_CMD_FWU_METADATA=y
+    CONFIG_DM_FWU_MDATA=y
+    CONFIG_FWU_MDATA_GPT_BLK=y
+    CONFIG_FWU_NUM_BANKS=<val>
+    CONFIG_FWU_NUM_IMAGES_PER_BANK=<val>
+
+in the .config file
+
+The first group of configs enable the UEFI capsule-on-disk update
+functionality. The second group of configs enable the FWU Multi Bank
+Update functionality. Please refer to the section
+:ref:`uefi_capsule_update_ref` for more details on generation of the
+UEFI capsule.
+
+Setting up the device for GPT partitioned storage
+-------------------------------------------------
+
+Before enabling the functionality in U-Boot, certain changes are
+required to be done on the storage device. Assuming a GPT partitioned
+storage device, the storage media needs to be partitioned with the
+correct number of partitions, given the number of banks and number of
+images per bank that the platform is going to support. Each updatable
+firmware image will be stored on an separate partition. In addition,
+the two copies of the FWU metadata will be stored on two separate
+partitions.
+
+As an example, a platform supporting two banks with each bank
+containing three images would need to have 2 * 3 = 6 parititions plus
+the two metadata partitions, or 8 partitions. In addition the storage
+media can have additional partitions of non-updatable images, like the
+EFI System Partition(ESP), a partition for the root file system etc.
+
+When generating the partitions, a few aspects need to be taken care
+of. Each GPT partition entry in the GPT header has two GUIDs::
+
+    *PartitionTypeGUID*
+    *UniquePartitionGUID*
+
+The PartitionTypeGUID value should correspond to the *image_type_uuid*
+field of the FWU metadata. This field is used to identify a given type
+of updatable firmware image, e.g. u-boot, op-tee, FIP etc. This GUID
+should also be used for specifying the `--guid` parameter when
+generating the capsule.
+
+The UniquePartitionGUID value should correspond to the *image_uuid*
+field in the FWU metadata. This GUID is used to identify images of a
+given image type in different banks.
+
+Similarly, the FWU specifications defines the GUID value to be used
+for the metadata partitions. This would be the PartitionTypeGUID for
+the metadata partitions.
+
+When generating the metadata, the *image_type_uuid* and the
+*image_uuid* values should match the *PartitionTypeGUID* and the
+*UniquePartitionGUID* values respectively.
+
+Performing the Update
+---------------------
+
+Once the storage media has been partitioned and populated with the
+metadata partitions, the UEFI capsule-on-disk update functionality can
+be used for performing the update. Refer to the section
+:ref:`uefi_capsule_update_ref` for details on how the update can be
+invoked.
+
+On a successful update, the FWU metadata gets updated to reflect the
+bank from which the platform would be booting on subsequent boot.
+
+Based on the value of bit15 of the Flags member of the capsule header,
+the updated images would either be accepted by the u-boot's UEFI
+implementation, or by the Operating System. If the Operating System is
+accepting the firmware images, it does so by generating an empty
+*accept* capsule. The Operating System can also reject the updated
+firmware by generating a *revert* capsule. The empty capsule can be
+applied by using the exact same procedure used for performing the
+capsule-on-disk update.
+
+Generating an empty capsule
+---------------------------
+
+The empty capsule can be generated using the mkeficapsule utility. To
+build the tool, enable::
+
+    CONFIG_TOOLS_MKEFICAPSULE=y
+
+Run the following commands to generate the accept/revert capsules::
+
+.. code-block:: bash
+
+    $ ./tools/mkeficapsule \
+      [--fw-accept --guid <image guid>] | \
+      [--fw-revert] \
+      <capsule_file_name>
+
+Links
+-----
+
+* [1] https://developer.arm.com/documentation/den0118/a/ - FWU Specification
+* [2] https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf - Dependable Boot Specification
diff --git a/doc/develop/uefi/index.rst b/doc/develop/uefi/index.rst
index 7e65dbc5d5..e26b1fbe05 100644
--- a/doc/develop/uefi/index.rst
+++ b/doc/develop/uefi/index.rst
@@ -13,3 +13,4 @@ can be run an UEFI payload.
    uefi.rst
    u-boot_on_efi.rst
    iscsi.rst
+   fwu_updates.rst
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst
index 941e427093..536b278dd9 100644
--- a/doc/develop/uefi/uefi.rst
+++ b/doc/develop/uefi/uefi.rst
@@ -277,6 +277,8 @@ Enable ``CONFIG_OPTEE``, ``CONFIG_CMD_OPTEE_RPMB`` and ``CONFIG_EFI_MM_COMM_TEE`
 
 [1] https://optee.readthedocs.io/en/latest/building/efi_vars/stmm.html
 
+.. _uefi_capsule_update_ref:
+
 Enabling UEFI Capsule Update feature
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 13/23] FWU: Add FWU metadata access driver for non-GPT MTD devices
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (11 preceding siblings ...)
  2022-06-09 12:29 ` [PATCH v5 12/23] FWU: doc: Add documentation for the FWU feature Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-21 10:56   ` Etienne Carriere
  2022-06-21 12:39   ` Patrick DELAUNAY
  2022-06-09 12:30 ` [PATCH v5 14/23] dt/bindings: firmware: Add FWU metadata on MTD devices binding Sughosh Ganu
                   ` (10 subsequent siblings)
  23 siblings, 2 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Masami Hiramatsu, Sughosh Ganu

From: Masami Hiramatsu <masami.hiramatsu@linaro.org>

For the platform which doesn't have GPT partitions for the firmware
but on MTD devices, the FWU metadata is stored on MTD device as raw
image at specific offset. This driver gives the access methods
for the FWU metadata information on such MTD devices.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 drivers/fwu-mdata/Kconfig         |   8 +
 drivers/fwu-mdata/Makefile        |   1 +
 drivers/fwu-mdata/fwu_mdata_mtd.c | 308 ++++++++++++++++++++++++++++++
 3 files changed, 317 insertions(+)
 create mode 100644 drivers/fwu-mdata/fwu_mdata_mtd.c

diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
index d5edef19d6..a8fa9ad783 100644
--- a/drivers/fwu-mdata/Kconfig
+++ b/drivers/fwu-mdata/Kconfig
@@ -14,3 +14,11 @@ config FWU_MDATA_GPT_BLK
 	help
 	  Enable support for accessing FWU Metadata on GPT partitioned
 	  block devices.
+
+config FWU_MDATA_MTD
+	bool "FWU Metadata access for non-GPT MTD devices"
+	depends on DM_FWU_MDATA && MTD
+	help
+	  Enable support for accessing FWU Metadata on non-partitioned
+	  (or non-GPT partitioned, e.g. partition nodes in devicetree)
+	  MTD devices.
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
index 12a5b4fe04..c574c59be2 100644
--- a/drivers/fwu-mdata/Makefile
+++ b/drivers/fwu-mdata/Makefile
@@ -5,3 +5,4 @@
 
 obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
 obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o
+obj-$(CONFIG_FWU_MDATA_MTD) += fwu_mdata_mtd.o
diff --git a/drivers/fwu-mdata/fwu_mdata_mtd.c b/drivers/fwu-mdata/fwu_mdata_mtd.c
new file mode 100644
index 0000000000..9eb471e73e
--- /dev/null
+++ b/drivers/fwu-mdata/fwu_mdata_mtd.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022, 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>
+
+struct fwu_mdata_mtd_priv {
+	struct mtd_info *mtd;
+	u32 pri_offset;
+	u32 sec_offset;
+};
+
+enum fwu_mtd_op {
+	FWU_MTD_READ,
+	FWU_MTD_WRITE,
+};
+
+static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
+{
+	return !do_div(size, mtd->erasesize);
+}
+
+static int mtd_io_data(struct mtd_info *mtd, u32 offs, u32 size, void *data,
+		       enum fwu_mtd_op op)
+{
+	struct mtd_oob_ops io_op ={};
+	u64 lock_offs, lock_len;
+	size_t len;
+	void *buf;
+	int ret;
+
+	if (!mtd_is_aligned_with_block_size(mtd, offs))
+		return -EINVAL;
+	lock_offs = offs;
+	lock_len = round_up(size, mtd->erasesize);
+
+	ret = mtd_unlock(mtd, lock_offs, lock_len);
+	if (ret && ret != -EOPNOTSUPP)
+		return ret;
+
+	if (op == FWU_MTD_WRITE) {
+		struct erase_info erase_op = {};
+
+		/* This will expand erase size to align with the block size */
+		erase_op.mtd = mtd;
+		erase_op.addr = lock_offs;
+		erase_op.len = lock_len;
+		erase_op.scrub = 0;
+
+		ret = mtd_erase(mtd, &erase_op);
+		if (ret)
+			goto lock_out;
+	}
+
+	/* Also, expand the write size to align with the write size */
+	len = round_up(size, mtd->writesize);
+
+	buf = memalign(ARCH_DMA_MINALIGN, len);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto lock_out;
+	}
+	io_op.mode = MTD_OPS_AUTO_OOB;
+	io_op.len = len;
+	io_op.ooblen = 0;
+	io_op.datbuf = buf;
+	io_op.oobbuf = NULL;
+
+	if (op == FWU_MTD_WRITE) {
+		memcpy(buf, data, size);
+		ret = mtd_write_oob(mtd, offs, &io_op);
+	} else {
+		ret = mtd_read_oob(mtd, offs, &io_op);
+		if (!ret)
+			memcpy(data, buf, size);
+	}
+	free(buf);
+
+lock_out:
+	mtd_lock(mtd, lock_offs, lock_len);
+
+	return ret;
+}
+
+static int fwu_mtd_load_mdata(struct mtd_info *mtd, struct fwu_mdata **mdata,
+			      u32 offs, bool primary)
+{
+	size_t size = sizeof(struct fwu_mdata);
+	int ret;
+
+	*mdata = malloc(size);
+	if (!*mdata)
+		return -ENOMEM;
+
+	ret = mtd_io_data(mtd, offs, size, (void *)*mdata, FWU_MTD_READ);
+	if (ret >= 0) {
+		ret = fwu_verify_mdata(*mdata, primary);
+		if (ret < 0) {
+			free(*mdata);
+			*mdata = NULL;
+		}
+	}
+
+	return ret;
+}
+
+static int fwu_mtd_load_primary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
+				     struct fwu_mdata **mdata)
+{
+	return fwu_mtd_load_mdata(mtd_priv->mtd, mdata, mtd_priv->pri_offset, true);
+}
+
+static int fwu_mtd_load_secondary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
+				       struct fwu_mdata **mdata)
+{
+	return fwu_mtd_load_mdata(mtd_priv->mtd, mdata, mtd_priv->sec_offset, false);
+}
+
+static int fwu_mtd_save_primary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
+				     struct fwu_mdata *mdata)
+{
+	return mtd_io_data(mtd_priv->mtd, mtd_priv->pri_offset,
+			   sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE);
+}
+
+static int fwu_mtd_save_secondary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
+				       struct fwu_mdata *mdata)
+{
+	return mtd_io_data(mtd_priv->mtd, mtd_priv->sec_offset,
+			   sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE);
+}
+
+static int fwu_mtd_get_valid_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
+				  struct fwu_mdata **mdata)
+{
+	if (fwu_mtd_load_primary_mdata(mtd_priv, mdata) == 0)
+		return 0;
+
+	log_err("Failed to load/verify primary mdata. Try secondary.\n");
+
+	if (fwu_mtd_load_secondary_mdata(mtd_priv, mdata) == 0)
+		return 0;
+
+	log_err("Failed to load/verify secondary mdata.\n");
+
+	return -1;
+}
+
+static int fwu_mtd_update_mdata(struct udevice *dev, struct fwu_mdata *mdata)
+{
+	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
+	int ret;
+
+	/* Update mdata crc32 field */
+	mdata->crc32 = crc32(0, (void *)&mdata->version,
+			     sizeof(*mdata) - sizeof(u32));
+
+	/* First write the primary mdata */
+	ret = fwu_mtd_save_primary_mdata(mtd_priv, mdata);
+	if (ret < 0) {
+		log_err("Failed to update the primary mdata.\n");
+		return ret;
+	}
+
+	/* And now the replica */
+	ret = fwu_mtd_save_secondary_mdata(mtd_priv, mdata);
+	if (ret < 0) {
+		log_err("Failed to update the secondary mdata.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fwu_mtd_mdata_check(struct udevice *dev)
+{
+	struct fwu_mdata *primary = NULL, *secondary = NULL;
+	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
+	int ret;
+
+	ret = fwu_mtd_load_primary_mdata(mtd_priv, &primary);
+	if (ret < 0)
+		log_err("Failed to read the primary mdata: %d\n", ret);
+
+	ret = fwu_mtd_load_secondary_mdata(mtd_priv, &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_mtd_save_secondary_mdata(mtd_priv, primary);
+		if (ret < 0)
+			log_err("Restoring secondary mdata partition failed\n");
+	} else if (secondary) {
+		ret = fwu_mtd_save_primary_mdata(mtd_priv, secondary);
+		if (ret < 0)
+			log_err("Restoring primary mdata partition failed\n");
+	}
+
+	free(primary);
+	free(secondary);
+	return ret;
+}
+
+static int fwu_mtd_get_mdata(struct udevice *dev, struct fwu_mdata **mdata)
+{
+	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
+
+	return fwu_mtd_get_valid_mdata(mtd_priv, mdata);
+}
+
+/**
+ * fwu_mdata_mtd_of_to_plat() - Translate from DT to fwu mdata device
+ */
+static int fwu_mdata_mtd_of_to_plat(struct udevice *dev)
+{
+	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
+	const fdt32_t *phandle_p = NULL;
+	struct udevice *mtd_dev;
+	struct mtd_info *mtd;
+	int ret, size;
+	u32 phandle;
+
+	/* Find the FWU mdata storage device */
+	phandle_p = ofnode_get_property(dev_ofnode(dev),
+					"fwu-mdata-store", &size);
+	if (!phandle_p) {
+		log_err("fwu-mdata-store property not found\n");
+		return -ENOENT;
+	}
+
+	phandle = fdt32_to_cpu(*phandle_p);
+
+	ret = device_get_global_by_ofnode(
+		ofnode_get_by_phandle(phandle),
+		&mtd_dev);
+	if (ret)
+		return ret;
+
+	mtd_probe_devices();
+
+	mtd_for_each_device(mtd) {
+		if (mtd->dev == mtd_dev) {
+			mtd_priv->mtd = mtd;
+			log_debug("Found the FWU mdata mtd device %s\n", mtd->name);
+			break;
+		}
+	}
+	if (!mtd_priv->mtd) {
+		log_err("Failed to find mtd device by fwu-mdata-store\n");
+		return -ENOENT;
+	}
+
+	/* Get the offset of primary and seconday mdata */
+	ret = ofnode_read_u32_index(dev_ofnode(dev), "mdata-offsets", 0,
+				    &mtd_priv->pri_offset);
+	if (ret)
+		return ret;
+	ret = ofnode_read_u32_index(dev_ofnode(dev), "mdata-offsets", 1,
+				    &mtd_priv->sec_offset);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int fwu_mdata_mtd_probe(struct udevice *dev)
+{
+	/* Ensure the metadata can be read. */
+	return fwu_mtd_mdata_check(dev);
+}
+
+static struct fwu_mdata_ops fwu_mtd_ops = {
+	.mdata_check = fwu_mtd_mdata_check,
+	.get_mdata = fwu_mtd_get_mdata,
+	.update_mdata = fwu_mtd_update_mdata,
+};
+
+static const struct udevice_id fwu_mdata_ids[] = {
+	{ .compatible = "u-boot,fwu-mdata-mtd" },
+	{ }
+};
+
+U_BOOT_DRIVER(fwu_mdata_mtd) = {
+	.name		= "fwu-mdata-mtd",
+	.id		= UCLASS_FWU_MDATA,
+	.of_match	= fwu_mdata_ids,
+	.ops		= &fwu_mtd_ops,
+	.probe		= fwu_mdata_mtd_probe,
+	.of_to_plat	= fwu_mdata_mtd_of_to_plat,
+	.priv_auto	= sizeof(struct fwu_mdata_mtd_priv),
+};
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 14/23] dt/bindings: firmware: Add FWU metadata on MTD devices binding
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (12 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 13/23] FWU: Add FWU metadata access driver for non-GPT MTD devices Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-21 10:56   ` Etienne Carriere
  2022-06-21 12:26   ` Patrick DELAUNAY
  2022-06-09 12:30 ` [PATCH v5 15/23] tools: Add mkfwumdata tool for FWU metadata image Sughosh Ganu
                   ` (9 subsequent siblings)
  23 siblings, 2 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Masami Hiramatsu, Sughosh Ganu

From: Masami Hiramatsu <masami.hiramatsu@linaro.org>

Add a devicetree-binding YAML file for the FWU metadata on MTD
devices without GPT.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 .../firmware/uboot,fwu-mdata-mtd.yaml         | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml

diff --git a/doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml b/doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
new file mode 100644
index 0000000000..4f5404f999
--- /dev/null
+++ b/doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/firmware/u-boot,fwu-mdata-sf.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: FWU metadata on MTD device without GPT
+
+maintainers:
+ - Masami Hiramatsu <masami.hiramatsu@linaro.org>
+
+properties:
+  compatible:
+    items:
+      - const: u-boot,fwu-mdata-mtd
+
+  fwu-mdata-store:
+    maxItems: 1
+    description: Phandle of the MTD device which contains the FWU medatata.
+
+  mdata-offsets:
+    minItems: 2
+    description: Offsets of the primary and secondary FWU metadata in the NOR flash.
+
+required:
+  - compatible
+  - fwu-mdata-store
+  - mdata-offsets
+
+additionalProperties: false
+
+examples:
+  - |
+    fwu-mdata {
+        compatible = "u-boot,fwu-mdata-mtd";
+        fwu-mdata-store = <&spi-flash>;
+        mdata-offsets = <0x500000 0x530000>;
+    };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 15/23] tools: Add mkfwumdata tool for FWU metadata image
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (13 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 14/23] dt/bindings: firmware: Add FWU metadata on MTD devices binding Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-21 10:57   ` Etienne Carriere
  2022-06-21 12:55   ` Patrick DELAUNAY
  2022-06-09 12:30 ` [PATCH v5 16/23] FWU: doc: Update documentation for the FWU non-GPT MTD Sughosh Ganu
                   ` (8 subsequent siblings)
  23 siblings, 2 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Masami Hiramatsu, Sughosh Ganu

From: Masami Hiramatsu <masami.hiramatsu@linaro.org>

Add 'mkfwumdata' tool which can generate an image of the FWU metadata
which is required for initializing the platform.

Usage:
  mkfwumdata -i NR_IMAGES -b NR_BANKS [--guid] \
    LOCATION_UUID0,IMAGE_TYPE_UUID0,BANK0_IMAGE_UUID[,BANK1_IMAGE_UUID[,...]] \
    LOCATION_UUID1,... \
    IMAGE_FILE

'-i' takes the number of images and '-b' takes the number of
banks. This takes lists of uuids for the images on arguments,
and the last argument must be the output image file name.

'--guid' (or '-g' in short) allows user to specify the location UUID
and image IDs in GUID instead of UUID. This option is useful if the
platform uses GPT partiotion. In this case, the UUID list
(for an image) becomes;

    DiskGUID,ParitionTypeGUID,UniquePartitionGUID,...

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 tools/Kconfig      |   9 ++
 tools/Makefile     |   4 +
 tools/mkfwumdata.c | 298 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 311 insertions(+)
 create mode 100644 tools/mkfwumdata.c

diff --git a/tools/Kconfig b/tools/Kconfig
index 117c921da3..3484be99d0 100644
--- a/tools/Kconfig
+++ b/tools/Kconfig
@@ -98,4 +98,13 @@ config TOOLS_MKEFICAPSULE
 	  optionally sign that file. If you want to enable UEFI capsule
 	  update feature on your target, you certainly need this.
 
+config TOOLS_MKFWUMDATA
+	bool "Build mkfwumdata command"
+	default y if FWU_MULTI_BANK_UPDATE
+	help
+	  This command allows users to create a raw image of the FWU
+	  metadata for initial installation of the FWU multi bank
+	  update on the board. The installation method depends on
+	  the platform.
+
 endmenu
diff --git a/tools/Makefile b/tools/Makefile
index 9f2339666a..cd39e5ff6f 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -245,6 +245,10 @@ HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
 HOSTLDLIBS_mkeficapsule += -lgnutls -luuid
 hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
 
+mkfwumdata-objs := mkfwumdata.o lib/crc32.o
+HOSTLDLIBS_mkfwumdata += -luuid
+hostprogs-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata
+
 # We build some files with extra pedantic flags to try to minimize things
 # that won't build on some weird host compiler -- though there are lots of
 # exceptions for files that aren't complaint.
diff --git a/tools/mkfwumdata.c b/tools/mkfwumdata.c
new file mode 100644
index 0000000000..4eb304cae3
--- /dev/null
+++ b/tools/mkfwumdata.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <u-boot/crc.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+
+/* This will dynamically allocate the fwu_mdata */
+#define CONFIG_FWU_NUM_BANKS		0
+#define CONFIG_FWU_NUM_IMAGES_PER_BANK	0
+
+/* Since we can not include fwu.h, redefine version here. */
+#define FWU_MDATA_VERSION		1
+
+typedef uint8_t u8;
+typedef int16_t s16;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+#include <fwu_mdata.h>
+
+/* TODO: Endianess conversion may be required for some arch. */
+
+static const char *opts_short = "b:i:a:gh";
+
+static struct option options[] = {
+	{"banks", required_argument, NULL, 'b'},
+	{"images", required_argument, NULL, 'i'},
+	{"guid", required_argument, NULL, 'g'},
+	{"active-bank", required_argument, NULL, 'a'},
+	{"help", no_argument, NULL, 'h'},
+	{NULL, 0, NULL, 0},
+};
+
+static void print_usage(void)
+{
+	fprintf(stderr, "Usage: mkfwumdata [options] <UUIDs list> [<UUIDs list>...] <output file>\n");
+	fprintf(stderr, "Options:\n"
+		"\t-i, --images <num>          Number of images\n"
+		"\t-b, --banks  <num>          Number of banks\n"
+		"\t-a, --active-bank  <num>    Active bank\n"
+		"\t-g, --guid                  Use GUID instead of UUID\n"
+		"\t-h, --help                  print a help message\n"
+		);
+	fprintf(stderr, "UUIDs list syntax:\n"
+		"\t<location uuid>,<image type uuid>,<image uuid>[,<image uuid>]\n"
+		"\n\tYou must specify # of banks of image-uuid and # of images of the lists.\n"
+		"\tIf the location uuid and image uuid are '0', those are filled with null uuid.\n"
+	       );
+}
+
+static bool __use_guid;
+static u32 active_bank;
+
+struct fwu_mdata_object {
+	size_t images;
+	size_t banks;
+	size_t size;
+	struct fwu_mdata *mdata;
+};
+
+struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks)
+{
+	struct fwu_mdata_object *mobj;
+
+	mobj = malloc(sizeof(*mobj));
+	if (!mobj)
+		return NULL;
+	mobj->size = sizeof(struct fwu_mdata) +
+		(sizeof(struct fwu_image_entry) +
+		 sizeof(struct fwu_image_bank_info) * banks) * images;
+	mobj->images = images;
+	mobj->banks = banks;
+	mobj->mdata = malloc(mobj->size);
+	if (!mobj->mdata) {
+		free(mobj);
+		return NULL;
+	}
+	memset(mobj->mdata, 0, mobj->size);
+
+	return mobj;
+}
+
+struct fwu_image_entry *fwu_get_image(struct fwu_mdata_object *mobj, size_t idx)
+{
+	size_t offset;
+
+	offset = sizeof(struct fwu_mdata) +
+		(sizeof(struct fwu_image_entry) +
+		 sizeof(struct fwu_image_bank_info) * mobj->banks) * idx;
+
+	return (struct fwu_image_entry *)((char *)mobj->mdata + offset);
+}
+
+struct fwu_image_bank_info *fwu_get_bank(struct fwu_mdata_object *mobj,
+					 size_t img_idx, size_t bnk_idx)
+{
+	size_t offset;
+
+	offset = sizeof(struct fwu_mdata) +
+		(sizeof(struct fwu_image_entry) +
+		 sizeof(struct fwu_image_bank_info) * mobj->banks) * img_idx +
+		sizeof(struct fwu_image_entry) +
+		sizeof(struct fwu_image_bank_info) * bnk_idx;
+
+	return (struct fwu_image_bank_info *)((char *)mobj->mdata + offset);
+}
+
+/**
+ * convert_uuid_to_guid() - convert UUID to GUID
+ * @buf:	UUID binary
+ *
+ * UUID and GUID have the same data structure, but their binary
+ * formats are different due to the endianness. See lib/uuid.c.
+ * Since uuid_parse() can handle only UUID, this function must
+ * be called to get correct data for GUID when parsing a string.
+ *
+ * The correct data will be returned in @buf.
+ */
+void convert_uuid_to_guid(unsigned char *buf)
+{
+	unsigned char c;
+
+	c = buf[0];
+	buf[0] = buf[3];
+	buf[3] = c;
+	c = buf[1];
+	buf[1] = buf[2];
+	buf[2] = c;
+
+	c = buf[4];
+	buf[4] = buf[5];
+	buf[5] = c;
+
+	c = buf[6];
+	buf[6] = buf[7];
+	buf[7] = c;
+}
+
+int uuid_guid_parse(char *uuidstr, unsigned char *uuid)
+{
+	int ret;
+
+	ret = uuid_parse(uuidstr, uuid);
+	if (ret < 0)
+		return ret;
+
+	if (__use_guid)
+		convert_uuid_to_guid(uuid);
+
+	return ret;
+}
+
+int fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj,
+			      size_t idx, char *uuids)
+{
+	struct fwu_image_entry *image = fwu_get_image(mobj, idx);
+	struct fwu_image_bank_info *bank;
+	char *p = uuids, *uuid;
+	int i;
+
+	if (!image)
+		return -ENOENT;
+
+	/* Image location UUID */
+	uuid = strsep(&p, ",");
+	if (!uuid)
+		return -EINVAL;
+
+	if (strcmp(uuid, "0") &&
+	    uuid_guid_parse(uuid, (unsigned char *)&image->location_uuid) < 0)
+		return -EINVAL;
+
+	/* Image type UUID */
+	uuid = strsep(&p, ",");
+	if (!uuid)
+		return -EINVAL;
+
+	if (uuid_guid_parse(uuid, (unsigned char *)&image->image_type_uuid) < 0)
+		return -EINVAL;
+
+	/* Fill bank image-UUID */
+	for (i = 0; i < mobj->banks; i++) {
+		bank = fwu_get_bank(mobj, idx, i);
+		if (!bank)
+			return -ENOENT;
+		bank->accepted = 1;
+		uuid = strsep(&p, ",");
+		if (!uuid)
+			return -EINVAL;
+
+		if (strcmp(uuid, "0") &&
+		    uuid_guid_parse(uuid, (unsigned char *)&bank->image_uuid) < 0)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* Caller must ensure that @uuids[] has @mobj->images entries. */
+int fwu_parse_fill_uuids(struct fwu_mdata_object *mobj, char *uuids[])
+{
+	struct fwu_mdata *mdata = mobj->mdata;
+	int i, ret;
+
+	mdata->version = FWU_MDATA_VERSION;
+	mdata->active_index = active_bank;
+	mdata->previous_active_index = active_bank ? 0 :
+		(uint32_t)(mobj->banks - 1);
+
+	for (i = 0; i < mobj->images; i++) {
+		ret = fwu_parse_fill_image_uuid(mobj, i, uuids[i]);
+		if (ret < 0)
+			return ret;
+	}
+
+	mdata->crc32 = crc32(0, (const unsigned char *)&mdata->version,
+                             mobj->size - sizeof(uint32_t));
+
+	return 0;
+}
+
+int fwu_make_mdata(size_t images, size_t banks, char *uuids[], char *output)
+{
+	struct fwu_mdata_object *mobj;
+	FILE *file;
+	int ret;
+
+	mobj = fwu_alloc_mdata(images, banks);
+	if (!mobj)
+		return -ENOMEM;
+
+	ret = fwu_parse_fill_uuids(mobj, uuids);
+	if (ret < 0)
+		return ret;
+
+	file = fopen(output, "w");
+	if (!file)
+		return -errno;
+
+	ret = fwrite(mobj->mdata, mobj->size, 1, file);
+	if (ret != mobj->size)
+		ret = -errno;
+	else
+		ret = 0;
+
+	fclose(file);
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	unsigned long banks = 0, images = 0;
+	int c, ret;
+
+	do {
+		c = getopt_long(argc, argv, opts_short, options, NULL);
+		switch (c) {
+		case 'h':
+			print_usage();
+			return 0;
+		case 'b':
+			banks = strtoul(optarg, NULL, 0);
+			break;
+		case 'i':
+			images = strtoul(optarg, NULL, 0);
+			break;
+		case 'g':
+			__use_guid = true;
+			break;
+		case 'a':
+			active_bank = strtoul(optarg, NULL, 0);
+			break;
+		}
+	} while (c != -1);
+
+	if (!banks || !images) {
+		fprintf(stderr, "Error: The number of banks and images must not be 0.\n");
+		return -EINVAL;
+	}
+
+	/* This command takes UUIDs * images and output file. */
+	if (optind + images + 1 != argc) {
+		fprintf(stderr, "Error: UUID list or output file is not specified or too much.\n");
+		print_usage();
+		return -ERANGE;
+	}
+	ret = fwu_make_mdata(images, banks, argv + optind, argv[argc - 1]);
+	if (ret < 0)
+		fprintf(stderr, "Error: Failed to parse and write image: %s\n",
+			strerror(-ret));
+	return ret;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 16/23] FWU: doc: Update documentation for the FWU non-GPT MTD
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (14 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 15/23] tools: Add mkfwumdata tool for FWU metadata image Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-09 12:30 ` [PATCH v5 17/23] synquacer: Update for TBBR (BL2) based new FIP layout Sughosh Ganu
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Masami Hiramatsu, Sughosh Ganu

From: Masami Hiramatsu <masami.hiramatsu@linaro.org>

Update documentation for the FWU non-GPT MTD device and
mkfwumdata command.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 doc/develop/uefi/fwu_updates.rst | 82 +++++++++++++++++++++++++++-----
 1 file changed, 70 insertions(+), 12 deletions(-)

diff --git a/doc/develop/uefi/fwu_updates.rst b/doc/develop/uefi/fwu_updates.rst
index 1c34beb7d5..1ea54328d1 100644
--- a/doc/develop/uefi/fwu_updates.rst
+++ b/doc/develop/uefi/fwu_updates.rst
@@ -15,10 +15,11 @@ boot. The UEFI capsule-on-disk update feature is used for performing
 the actual updates of the updatable firmware images.
 
 The bookkeeping of the updatable images is done through a structure
-called metadata. Currently, the FWU metadata supports identification
+called FWU metadata. Currently, the FWU metadata supports identification
 of images based on image GUIDs stored on a GPT partitioned storage
-media. There are plans to extend the metadata structure for non GPT
-partitioned devices as well.
+media. If the firmware images are stored on the flash device which
+has no GPT, the platform driver can provide the image identification
+feature.
 
 Accessing the FWU metadata is done through generic API's which are
 defined in a driver which complies with the u-boot's driver model. A
@@ -43,21 +44,31 @@ The feature can be enabled by specifying the following configs::
     CONFIG_FWU_MULTI_BANK_UPDATE=y
     CONFIG_CMD_FWU_METADATA=y
     CONFIG_DM_FWU_MDATA=y
-    CONFIG_FWU_MDATA_GPT_BLK=y
     CONFIG_FWU_NUM_BANKS=<val>
     CONFIG_FWU_NUM_IMAGES_PER_BANK=<val>
+    CONFIG_TOOLS_MKFWUMDATA=y
+
+    CONFIG_FWU_MDATA_GPT_BLK=y
+    CONFIG_FWU_MDATA_SF=y
 
-in the .config file
+in the .config file.
 
 The first group of configs enable the UEFI capsule-on-disk update
 functionality. The second group of configs enable the FWU Multi Bank
-Update functionality. Please refer to the section
-:ref:`uefi_capsule_update_ref` for more details on generation of the
-UEFI capsule.
+Update functionality. And the third group of configs are FWU Metadata
+drivers. You can enable either one of ``CONFIG_FWU_MDATA_GPT_BLK`` and
+``CONFIG_FWU_MDATA_SF`` or both of them, according to the platform
+support. Anyway, a correct driver will be probed by devicetree node.
+
+Please refer to the section :ref:`uefi_capsule_update_ref` for
+more details on generation of the UEFI capsule.
 
 Setting up the device for GPT partitioned storage
 -------------------------------------------------
 
+If your platform stores the firmware on GPT partitioned storage
+device (e.g. eMMC/SD), please follow this section.
+
 Before enabling the functionality in U-Boot, certain changes are
 required to be done on the storage device. Assuming a GPT partitioned
 storage device, the storage media needs to be partitioned with the
@@ -74,7 +85,14 @@ media can have additional partitions of non-updatable images, like the
 EFI System Partition(ESP), a partition for the root file system etc.
 
 When generating the partitions, a few aspects need to be taken care
-of. Each GPT partition entry in the GPT header has two GUIDs::
+of. The GPT itself has one GUID::
+
+    *DiskGUID*
+
+This DiskGUID value should correspond to the *location_uuid* field
+of the FWU metadata.
+
+And each GPT partition entry in the GPT header has two GUIDs::
 
     *PartitionTypeGUID*
     *UniquePartitionGUID*
@@ -93,9 +111,49 @@ Similarly, the FWU specifications defines the GUID value to be used
 for the metadata partitions. This would be the PartitionTypeGUID for
 the metadata partitions.
 
-When generating the metadata, the *image_type_uuid* and the
-*image_uuid* values should match the *PartitionTypeGUID* and the
-*UniquePartitionGUID* values respectively.
+Setting up the device for non-GPT partitioned MTD device
+--------------------------------------------------------
+
+If your platform stores the firmware on non-GPT partitioned MTD
+device, please follow this section.
+
+Before enabling the functionality in U-Boot, please confirm that
+your platform correctly define (or generate) `dfu_alt_info`, which
+has to have all *banks* as the dfu entries. Also, the devicetree's
+`fwu_mdata` node must be "u-boot,fwu-mdata-mtd" compatible node
+and has FWU metadata offsets on `mdata-offsets` property.
+Please refer to U-Boot
+`doc <doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml>`__ for
+the device tree bindings.
+
+Similar to the GPT, you can also define the DiskGUID, and the
+UniquePartitionGUID in the devicetree as additional properties of
+the "fixed-partitions" compatible partition nodes, and the platform
+code can generate the `dfu_alt_info` from that. In this case,
+*image_type_uuid* field of the FWU mdata is used instead of the
+PartitionTypeGUID.
+
+Generate the FWU metadata image
+-------------------------------
+
+To generate the FWU metadata raw image, you can use `tools/mkfwumdata`
+command.
+
+ tools/mkfwumdata -i <#images> -b <#banks> \
+   <location_uuid0,image_type_uuid0,image_uuid0_0,image_uuid0_1,...> \
+   [location_uuid1,image_type_uuid1,image_uuid1_0,image_uuid1_1,...] \
+   <output-file>
+
+Or, if you know GUID instead of UUID, you can use --guid option.
+
+ tools/mkfwumdata -i <#images> -b <#banks> --guid \
+   <DiskGUID0,PartitionTypeGUID0,UniquePartitionGUID0_0,UniquePartitionGUID0_1,...> \
+   [DiskGUID1,PartitionTypeGUID1,UniquePartitionGUID1_0,UniquePartitionGUID1_1,...] \
+   <output-file>
+
+When generating the metadata, the *location_uuid*, the *image_type_uuid*
+and the *image_uuid* values should match the *DiskGUID*, the
+*PartitionTypeGUID* and the *UniquePartitionGUID* values respectively.
 
 Performing the Update
 ---------------------
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 17/23] synquacer: Update for TBBR (BL2) based new FIP layout
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (15 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 16/23] FWU: doc: Update documentation for the FWU non-GPT MTD Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-09 12:30 ` [PATCH v5 18/23] developerbox: synquacer: Use FIP as the updatable image Sughosh Ganu
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Masami Hiramatsu, Sughosh Ganu

From: Masami Hiramatsu <masami.hiramatsu@linaro.org>

This changes SPI NOR flash partition layout for TBBR and
also make the U-Boot as position independent executable
again because BL33 is loaded on the memory.

With enabling TBBR, TF-A BL2 loads all BL3x images from
FIP image, and the U-Boot image is added to the FIP image
as BL33, and loaded to memory when boot instead of XIP
on SPI NOR flash. To avoid mixing up with the legacy images,
this new FIP image is stored on unused area (0x600000-) and
the U-Boot env vars are also stored at 0x580000 so that
it will not break existing EDK2 area.

NOTE: This introduces an incombatible change to the
synquacer_developerbox_defconfig. If you want to build
U-Boot for booting from legacy FIP image, you need to
specify previous configuration.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 .../synquacer-sc2a11-developerbox-u-boot.dtsi | 26 +++++++++++++------
 configs/synquacer_developerbox_defconfig      |  5 ++--
 include/configs/synquacer.h                   |  4 +--
 3 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
index 7a56116d6f..095727e03c 100644
--- a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
+++ b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
@@ -56,7 +56,7 @@
 				};
 
 				partition@180000 {
-					label = "FIP-TFA";
+					label = "LegacyFIP";
 					reg = <0x180000 0x78000>;
 				};
 
@@ -66,18 +66,28 @@
 				};
 
 				partition@200000 {
-					label = "U-Boot";
-					reg = <0x200000 0x100000>;
+					label = "EDK2";
+					reg = <0x200000 0x200000>;
 				};
 
-				partition@300000 {
-					label = "UBoot-Env";
-					reg = <0x300000 0x100000>;
+				partition@400000 {
+					label = "EDK2-Env";
+					reg = <0x400000 0x100000>;
 				};
 
 				partition@500000 {
-					label = "Ex-OPTEE";
-					reg = <0x500000 0x200000>;
+					label = "Metadata";
+					reg = <0x500000 0x80000>;
+				};
+
+				partition@580000 {
+					label = "UBoot-Env";
+					reg = <0x580000 0x80000>;
+				};
+
+				partition@600000 {
+					label = "FIP";
+					reg = <0x600000 0x400000>;
 				};
 			};
 		};
diff --git a/configs/synquacer_developerbox_defconfig b/configs/synquacer_developerbox_defconfig
index add6041e27..29b1e11401 100644
--- a/configs/synquacer_developerbox_defconfig
+++ b/configs/synquacer_developerbox_defconfig
@@ -1,10 +1,11 @@
 CONFIG_ARM=y
 CONFIG_ARCH_SYNQUACER=y
-CONFIG_SYS_TEXT_BASE=0x08200000
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_SYS_TEXT_BASE=0
 CONFIG_SYS_MALLOC_LEN=0x1000000
 CONFIG_SYS_MALLOC_F_LEN=0x400
 CONFIG_ENV_SIZE=0x30000
-CONFIG_ENV_OFFSET=0x300000
+CONFIG_ENV_OFFSET=0x580000
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_DM_GPIO=y
 CONFIG_DEFAULT_DEVICE_TREE="synquacer-sc2a11-developerbox"
diff --git a/include/configs/synquacer.h b/include/configs/synquacer.h
index 5686a5b910..572f0a42ac 100644
--- a/include/configs/synquacer.h
+++ b/include/configs/synquacer.h
@@ -47,9 +47,7 @@
 /* Since U-Boot 64bit PCIe support is limited, disable 64bit MMIO support */
 
 #define DEFAULT_DFU_ALT_INFO "dfu_alt_info="				\
-			"mtd nor1=u-boot.bin raw 200000 100000;"	\
-			"fip.bin raw 180000 78000;"			\
-			"optee.bin raw 500000 100000\0"
+			"mtd nor1=fip.bin raw 600000 400000\0"
 
 /* GUIDs for capsule updatable firmware images */
 #define DEVELOPERBOX_UBOOT_IMAGE_GUID \
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 18/23] developerbox: synquacer: Use FIP as the updatable image
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (16 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 17/23] synquacer: Update for TBBR (BL2) based new FIP layout Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-09 12:30 ` [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox Sughosh Ganu
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

From: Jassi Brar <jaswinder.singh@linaro.org>

The Synquacer board is migrating to using the FIP as the only
updatable image on the platform with the u-boot and op-tee images
packaged as part of the FIP image. Make changes to the structures used
for capsule updates to reflect this change.

Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 board/socionext/developerbox/developerbox.c | 17 +++--------------
 include/configs/synquacer.h                 | 13 ++-----------
 2 files changed, 5 insertions(+), 25 deletions(-)

diff --git a/board/socionext/developerbox/developerbox.c b/board/socionext/developerbox/developerbox.c
index f5a5fe0121..b946428ddb 100644
--- a/board/socionext/developerbox/developerbox.c
+++ b/board/socionext/developerbox/developerbox.c
@@ -20,27 +20,16 @@
 
 #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
 struct efi_fw_image fw_images[] = {
-	{
-		.image_type_id = DEVELOPERBOX_UBOOT_IMAGE_GUID,
-		.fw_name = u"DEVELOPERBOX-UBOOT",
-		.image_index = 1,
-	},
 	{
 		.image_type_id = DEVELOPERBOX_FIP_IMAGE_GUID,
 		.fw_name = u"DEVELOPERBOX-FIP",
-		.image_index = 2,
-	},
-	{
-		.image_type_id = DEVELOPERBOX_OPTEE_IMAGE_GUID,
-		.fw_name = u"DEVELOPERBOX-OPTEE",
-		.image_index = 3,
+		.image_index = 1,
 	},
 };
 
 struct efi_capsule_update_info update_info = {
-	.dfu_string = "mtd nor1=u-boot.bin raw 200000 100000;"
-			"fip.bin raw 180000 78000;"
-			"optee.bin raw 500000 100000",
+	.dfu_string = "mtd nor1=bank0 raw 600000 400000;"
+			"bank1 raw a00000 400000;",
 	.images = fw_images,
 };
 
diff --git a/include/configs/synquacer.h b/include/configs/synquacer.h
index 572f0a42ac..eafcc69e12 100644
--- a/include/configs/synquacer.h
+++ b/include/configs/synquacer.h
@@ -50,18 +50,9 @@
 			"mtd nor1=fip.bin raw 600000 400000\0"
 
 /* GUIDs for capsule updatable firmware images */
-#define DEVELOPERBOX_UBOOT_IMAGE_GUID \
-	EFI_GUID(0x53a92e83, 0x4ef4, 0x473a, 0x8b, 0x0d, \
-		 0xb5, 0xd8, 0xc7, 0xb2, 0xd6, 0x00)
-
 #define DEVELOPERBOX_FIP_IMAGE_GUID \
-	EFI_GUID(0x880866e9, 0x84ba, 0x4793, 0xa9, 0x08, \
-		 0x33, 0xe0, 0xb9, 0x16, 0xf3, 0x98)
-
-#define DEVELOPERBOX_OPTEE_IMAGE_GUID \
-	EFI_GUID(0xc1b629f1, 0xce0e, 0x4894, 0x82, 0xbf, \
-		 0xf0, 0xa3, 0x83, 0x87, 0xe6, 0x30)
-
+	EFI_GUID(0x7d6dc310, 0x52ca, 0x43b8, 0xb7, 0xb9, \
+		 0xf9, 0xd6, 0xc5, 0x01, 0xd1, 0x08)
 /* Distro boot settings */
 #ifndef CONFIG_SPL_BUILD
 #ifdef CONFIG_CMD_USB
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (17 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 18/23] developerbox: synquacer: Use FIP as the updatable image Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-17 14:00   ` Michal Simek
  2022-06-20  8:23   ` Michal Simek
  2022-06-09 12:30 ` [PATCH v5 20/23] FWU: synquacer: Generate dfu_alt_info from devicetree partition Sughosh Ganu
                   ` (4 subsequent siblings)
  23 siblings, 2 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Masami Hiramatsu, Sughosh Ganu

From: Masami Hiramatsu <masami.hiramatsu@linaro.org>

The DeveloperBox platform can support the FWU Multi bank
update. SCP firmware will switch the boot mode by DSW3-4
and load the Multi bank update supported TF-A BL2 from
0x600000 offset on the SPI flash. Thus it can co-exist
with the legacy boot mode (legacy U-Boot or EDK2).

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
---
 Changes in v3:
  - Change devicetree to add partitions.
  - Update fwu_plat_get_alt_num() to find the alt number from the bank index.
  - Use only 2 partitions for AB update.
  - Clear platform-mdata's boot_count to finish platform trial boot.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 .../synquacer-sc2a11-developerbox-u-boot.dtsi |  15 +-
 board/socionext/developerbox/Kconfig          |  13 ++
 board/socionext/developerbox/Makefile         |   1 +
 board/socionext/developerbox/fwu_plat.c       | 207 ++++++++++++++++++
 include/configs/synquacer.h                   |   8 +
 5 files changed, 241 insertions(+), 3 deletions(-)
 create mode 100644 board/socionext/developerbox/fwu_plat.c

diff --git a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
index 095727e03c..ab4e3d1c2b 100644
--- a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
+++ b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
@@ -23,7 +23,7 @@
 		active_clk_edges;
 		chipselect_num = <1>;
 
-		spi-flash@0 {
+		spi_flash: spi-flash@0 {
 			#address-cells = <1>;
 			#size-cells = <1>;
 			compatible = "jedec,spi-nor";
@@ -84,11 +84,15 @@
 					label = "UBoot-Env";
 					reg = <0x580000 0x80000>;
 				};
-
+				/* FWU Multi bank update partitions */
 				partition@600000 {
-					label = "FIP";
+					label = "FIP-Bank0";
 					reg = <0x600000 0x400000>;
 				};
+				partition@a00000 {
+					label = "FIP-Bank1";
+					reg = <0xa00000 0x400000>;
+				};
 			};
 		};
 	};
@@ -114,6 +118,11 @@
 		optee {
 			status = "okay";
 		};
+		fwu-mdata {
+			compatible = "u-boot,fwu-mdata-mtd";
+			fwu-mdata-store = <&spi_flash>;
+			mdata-offsets = <0x500000 0x530000>;
+		};
 	};
 };
 
diff --git a/board/socionext/developerbox/Kconfig b/board/socionext/developerbox/Kconfig
index c181d26a44..7df6750baf 100644
--- a/board/socionext/developerbox/Kconfig
+++ b/board/socionext/developerbox/Kconfig
@@ -32,4 +32,17 @@ config SYS_CONFIG_NAME
 	default "synquacer"
 
 endif
+
+config FWU_MULTI_BANK_UPDATE
+	select FWU_MDATA_MTD
+	select DM_SPI_FLASH
+	select DM_FWU_MDATA
+	select BOARD_LATE_INIT
+
+config FWU_NUM_BANKS
+	default 2
+
+config FWU_NUM_IMAGES_PER_BANK
+	default 1
+
 endif
diff --git a/board/socionext/developerbox/Makefile b/board/socionext/developerbox/Makefile
index 4a46de995a..9b80ee38e7 100644
--- a/board/socionext/developerbox/Makefile
+++ b/board/socionext/developerbox/Makefile
@@ -7,3 +7,4 @@
 #
 
 obj-y	:= developerbox.o
+obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_plat.o
diff --git a/board/socionext/developerbox/fwu_plat.c b/board/socionext/developerbox/fwu_plat.c
new file mode 100644
index 0000000000..fd6d0e3659
--- /dev/null
+++ b/board/socionext/developerbox/fwu_plat.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021, Linaro Limited
+ */
+
+#include <dfu.h>
+#include <efi_loader.h>
+#include <flash.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <u-boot/crc.h>
+
+/* SPI Flash accessors */
+static struct spi_flash *plat_spi_flash;
+
+static int __plat_sf_get_flash(void)
+{
+	/* TODO: define platform spi-flash somewhere. */
+	plat_spi_flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
+					 CONFIG_SF_DEFAULT_CS,
+					 CONFIG_SF_DEFAULT_SPEED,
+					 CONFIG_SF_DEFAULT_MODE);
+
+	return 0;
+}
+
+static int plat_sf_get_flash(struct spi_flash **flash)
+{
+	int ret = 0;
+
+	if (!plat_spi_flash)
+		ret = __plat_sf_get_flash();
+
+	*flash = plat_spi_flash;
+
+	return ret;
+}
+
+static int sf_load_data(u32 offs, u32 size, void **data)
+{
+	struct spi_flash *flash;
+	int ret;
+
+	ret = plat_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 = plat_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;
+}
+
+#define PLAT_METADATA_OFFSET	0x510000
+#define PLAT_METADATA_SIZE	(sizeof(struct devbox_metadata))
+
+struct __packed devbox_metadata {
+	u32 boot_index;
+	u32 boot_count;
+} *devbox_plat_metadata;
+
+int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
+			 efi_guid_t *image_id, int *alt_num)
+{
+	struct fwu_image_bank_info *bank;
+	struct fwu_mdata *mdata;
+	int i, ret;
+
+	ret = fwu_get_mdata(&mdata);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * DeveloperBox FWU expects Bank:Image = 1:1, and the dfu_alt_info
+	 * only has the entries for banks. Thus the alt_no should be equal
+	 * to the bank index number.
+	 */
+	ret = -ENOENT;
+	for (i = 0; i < CONFIG_FWU_NUM_BANKS; i++) {
+		bank = &mdata->img_entry[0].img_bank_info[i];
+		if (guidcmp(image_id, &bank->image_uuid) == 0) {
+			*alt_num = i;
+			ret = 0;
+			break;
+		}
+	}
+
+	free(mdata);
+
+	return ret;
+}
+
+/* This assumes that user doesn't change system default dfu_alt_info */
+efi_status_t fill_image_type_guid_array(const efi_guid_t __always_unused
+					*default_guid,
+					efi_guid_t **part_guid_arr)
+{
+	int i;
+
+	*part_guid_arr = malloc(sizeof(efi_guid_t) * DEFAULT_DFU_ALT_NUM);
+	if (!*part_guid_arr)
+		return EFI_OUT_OF_RESOURCES;
+
+	for (i = 0; i < DEFAULT_DFU_ALT_NUM; i++)
+		guidcpy((*part_guid_arr + i), &devbox_fip_image_type_guid);
+
+	return EFI_SUCCESS;
+}
+
+int fwu_plat_get_update_index(u32 *update_idx)
+{
+	int ret;
+	u32 active_idx;
+
+	ret = fwu_get_active_index(&active_idx);
+
+	if (ret < 0)
+		return ret;
+
+	*update_idx = (active_idx + 1) % CONFIG_FWU_NUM_BANKS;
+
+	return ret;
+}
+
+static int devbox_load_plat_metadata(void)
+{
+	if (devbox_plat_metadata)
+		return 0;
+
+	return sf_load_data(PLAT_METADATA_OFFSET, PLAT_METADATA_SIZE,
+			 (void **)&devbox_plat_metadata);
+}
+
+void fwu_plat_get_bootidx(void *boot_idx)
+{
+	u32 *bootidx = boot_idx;
+
+	if (devbox_load_plat_metadata() < 0)
+		*bootidx = 0;
+	else
+		*bootidx = devbox_plat_metadata->boot_index;
+}
+
+int board_late_init(void)
+{
+	int ret;
+
+	ret = devbox_load_plat_metadata();
+	if (ret < 0)
+		return ret;
+
+	if (devbox_plat_metadata->boot_count) {
+		/* We are in the platform trial boot. Finish it. */
+		devbox_plat_metadata->boot_count = 0;
+		ret = sf_save_data(PLAT_METADATA_OFFSET, PLAT_METADATA_SIZE,
+				   (void *)devbox_plat_metadata);
+		if (ret < 0)
+			return ret;
+
+		pr_debug("FWU: Finish platform trial boot safely.\n");
+	}
+
+	return 0;
+}
diff --git a/include/configs/synquacer.h b/include/configs/synquacer.h
index eafcc69e12..14eeb3f57e 100644
--- a/include/configs/synquacer.h
+++ b/include/configs/synquacer.h
@@ -46,8 +46,16 @@
 
 /* Since U-Boot 64bit PCIe support is limited, disable 64bit MMIO support */
 
+#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
+#define DEFAULT_DFU_ALT_NUM  2
+#define DEFAULT_DFU_ALT_INFO "dfu_alt_info="				\
+				"mtd nor1=bank0 raw  600000 400000;"	\
+					 "bank1 raw  a00000 400000\0"
+#else
+#define DEFAULT_DFU_ALT_NUM  1
 #define DEFAULT_DFU_ALT_INFO "dfu_alt_info="				\
 			"mtd nor1=fip.bin raw 600000 400000\0"
+#endif
 
 /* GUIDs for capsule updatable firmware images */
 #define DEVELOPERBOX_FIP_IMAGE_GUID \
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 20/23] FWU: synquacer: Generate dfu_alt_info from devicetree partition
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (18 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-17 14:02   ` Michal Simek
  2022-06-09 12:30 ` [PATCH v5 21/23] doc: synquacer: Add how to enable FWU Multi Bank Update Sughosh Ganu
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Masami Hiramatsu, Sughosh Ganu

From: Masami Hiramatsu <masami.hiramatsu@linaro.org>

Generate dfu_alt_info from the partition uuid information in the
devicetree, and record the mapping of partition uuid and the
index of dfu_alt_num.

This could be a reference implementation of the automatic DFU
generation for FWU multi-bank update for non GPT firmware
platforms.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 .../synquacer-sc2a11-developerbox-u-boot.dtsi |   3 +
 board/socionext/developerbox/Kconfig          |   1 +
 board/socionext/developerbox/fwu_plat.c       |  79 ++++----
 include/configs/synquacer.h                   |   6 +-
 include/fwu.h                                 |   6 +
 lib/fwu_updates/Makefile                      |   1 +
 lib/fwu_updates/fwu_mtd.c                     | 173 ++++++++++++++++++
 7 files changed, 221 insertions(+), 48 deletions(-)
 create mode 100644 lib/fwu_updates/fwu_mtd.c

diff --git a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
index ab4e3d1c2b..c7ec8a0321 100644
--- a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
+++ b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
@@ -36,6 +36,7 @@
 				compatible = "fixed-partitions";
 				#address-cells = <1>;
 				#size-cells = <1>;
+				uuid = "17e86d77-41f9-4fd7-87ec-a55df9842de5";
 
 				partition@0 {
 					label = "BootStrap-BL1";
@@ -88,10 +89,12 @@
 				partition@600000 {
 					label = "FIP-Bank0";
 					reg = <0x600000 0x400000>;
+					uuid = "5a66a702-99fd-4fef-a392-c26e261a2828";
 				};
 				partition@a00000 {
 					label = "FIP-Bank1";
 					reg = <0xa00000 0x400000>;
+					uuid = "a8f868a1-6e5c-4757-878d-ce63375ef2c0";
 				};
 			};
 		};
diff --git a/board/socionext/developerbox/Kconfig b/board/socionext/developerbox/Kconfig
index 7df6750baf..ad2a284f13 100644
--- a/board/socionext/developerbox/Kconfig
+++ b/board/socionext/developerbox/Kconfig
@@ -38,6 +38,7 @@ config FWU_MULTI_BANK_UPDATE
 	select DM_SPI_FLASH
 	select DM_FWU_MDATA
 	select BOARD_LATE_INIT
+	select SET_DFU_ALT_INFO
 
 config FWU_NUM_BANKS
 	default 2
diff --git a/board/socionext/developerbox/fwu_plat.c b/board/socionext/developerbox/fwu_plat.c
index fd6d0e3659..ff06eade7d 100644
--- a/board/socionext/developerbox/fwu_plat.c
+++ b/board/socionext/developerbox/fwu_plat.c
@@ -10,8 +10,10 @@
 #include <fwu_mdata.h>
 #include <malloc.h>
 #include <memalign.h>
+#include <mtd.h>
 #include <spi.h>
 #include <spi_flash.h>
+#include <uuid.h>
 
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -94,6 +96,36 @@ static int sf_save_data(u32 offs, u32 size, void *data)
 	return ret;
 }
 
+#define DFU_ALT_BUF_LEN 256
+#define DFU_ALT_NUM_MAX (CONFIG_FWU_NUM_IMAGES_PER_BANK * CONFIG_FWU_NUM_BANKS)
+
+/* Generate dfu_alt_info from partitions */
+void set_dfu_alt_info(char *interface, char *devstr)
+{
+	int ret;
+	struct mtd_info *mtd;
+	static char *buf = NULL;
+
+	if (!buf) {
+		buf = malloc_cache_aligned(DFU_ALT_BUF_LEN);
+		memset(buf, 0, DFU_ALT_BUF_LEN);
+
+		mtd_probe_devices();
+
+		mtd = get_mtd_device_nm("nor1");
+		if (IS_ERR_OR_NULL(mtd))
+			return;
+
+		ret = fwu_gen_alt_info_from_mtd(buf, DFU_ALT_BUF_LEN, mtd);
+		if (ret < 0) {
+			log_err("Error: Failed to generate dfu_alt_info. (%d)\n", ret);
+			return;
+		}
+		log_debug("Make dfu_alt_info: '%s'\n", buf);
+	}
+	env_set("dfu_alt_info", buf);
+}
+
 #define PLAT_METADATA_OFFSET	0x510000
 #define PLAT_METADATA_SIZE	(sizeof(struct devbox_metadata))
 
@@ -105,49 +137,7 @@ struct __packed devbox_metadata {
 int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
 			 efi_guid_t *image_id, int *alt_num)
 {
-	struct fwu_image_bank_info *bank;
-	struct fwu_mdata *mdata;
-	int i, ret;
-
-	ret = fwu_get_mdata(&mdata);
-	if (ret < 0)
-		return ret;
-
-	/*
-	 * DeveloperBox FWU expects Bank:Image = 1:1, and the dfu_alt_info
-	 * only has the entries for banks. Thus the alt_no should be equal
-	 * to the bank index number.
-	 */
-	ret = -ENOENT;
-	for (i = 0; i < CONFIG_FWU_NUM_BANKS; i++) {
-		bank = &mdata->img_entry[0].img_bank_info[i];
-		if (guidcmp(image_id, &bank->image_uuid) == 0) {
-			*alt_num = i;
-			ret = 0;
-			break;
-		}
-	}
-
-	free(mdata);
-
-	return ret;
-}
-
-/* This assumes that user doesn't change system default dfu_alt_info */
-efi_status_t fill_image_type_guid_array(const efi_guid_t __always_unused
-					*default_guid,
-					efi_guid_t **part_guid_arr)
-{
-	int i;
-
-	*part_guid_arr = malloc(sizeof(efi_guid_t) * DEFAULT_DFU_ALT_NUM);
-	if (!*part_guid_arr)
-		return EFI_OUT_OF_RESOURCES;
-
-	for (i = 0; i < DEFAULT_DFU_ALT_NUM; i++)
-		guidcpy((*part_guid_arr + i), &devbox_fip_image_type_guid);
-
-	return EFI_SUCCESS;
+	return fwu_get_mtd_alt_num(image_id, alt_num, "nor1", 0);
 }
 
 int fwu_plat_get_update_index(u32 *update_idx)
@@ -188,6 +178,9 @@ int board_late_init(void)
 {
 	int ret;
 
+	/* Make mmc available for EFI */
+	run_command("mmc dev 0", 0);
+
 	ret = devbox_load_plat_metadata();
 	if (ret < 0)
 		return ret;
diff --git a/include/configs/synquacer.h b/include/configs/synquacer.h
index 14eeb3f57e..103277661b 100644
--- a/include/configs/synquacer.h
+++ b/include/configs/synquacer.h
@@ -47,12 +47,8 @@
 /* Since U-Boot 64bit PCIe support is limited, disable 64bit MMIO support */
 
 #ifdef CONFIG_FWU_MULTI_BANK_UPDATE
-#define DEFAULT_DFU_ALT_NUM  2
-#define DEFAULT_DFU_ALT_INFO "dfu_alt_info="				\
-				"mtd nor1=bank0 raw  600000 400000;"	\
-					 "bank1 raw  a00000 400000\0"
+#define DEFAULT_DFU_ALT_INFO
 #else
-#define DEFAULT_DFU_ALT_NUM  1
 #define DEFAULT_DFU_ALT_INFO "dfu_alt_info="				\
 			"mtd nor1=fip.bin raw 600000 400000\0"
 #endif
diff --git a/include/fwu.h b/include/fwu.h
index 9c8012407b..fadbfedd07 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -63,4 +63,10 @@ void fwu_plat_get_bootidx(void *boot_idx);
 int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
 			 int *alt_num);
 int fwu_plat_get_update_index(u32 *update_idx);
+
+int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
+			const char *mtd_dev, bool guid);
+int gen_image_alt_info(char *buf, size_t len, int sidx,
+		       struct fwu_image_entry *img, struct mtd_info *mtd);
+int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd);
 #endif /* _FWU_H_ */
diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile
index 74e37014e2..a135fd3f4a 100644
--- a/lib/fwu_updates/Makefile
+++ b/lib/fwu_updates/Makefile
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o
+obj-$(CONFIG_FWU_MDATA_MTD) += fwu_mtd.o
diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
new file mode 100644
index 0000000000..3137f8635c
--- /dev/null
+++ b/lib/fwu_updates/fwu_mtd.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <dfu.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+#include <malloc.h>
+#include <mtd.h>
+#include <uuid.h>
+#include <vsprintf.h>
+
+#include <dm/ofnode.h>
+
+int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
+			const char *mtd_dev, bool guid)
+{
+	int i, nalt;
+	int ret = -1;
+	struct mtd_info *mtd;
+	struct dfu_entity *dfu;
+	ofnode node, parts_node;
+	fdt_addr_t offset, size;
+	char uuidbuf[UUID_STR_LEN + 1];
+
+	mtd_probe_devices();
+	mtd = get_mtd_device_nm(mtd_dev);
+
+	/* Find partition node under given MTD device. */
+	parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
+					  "fixed-partitions");
+
+	uuid_bin_to_str(image_id->b, uuidbuf,
+			guid ? UUID_STR_FORMAT_GUID : UUID_STR_FORMAT_STD);
+	node = ofnode_by_prop_value(parts_node, "uuid", uuidbuf,
+				    sizeof(uuidbuf));
+	if (!ofnode_valid(node)) {
+		log_warning("Warning: Failed to find partition by image UUID\n");
+		return -ENOENT;
+	}
+
+	offset = ofnode_get_addr_size_index_notrans(node, 0, &size);
+	if (offset == FDT_ADDR_T_NONE || !size)
+		return -ENOENT;
+
+	dfu_init_env_entities(NULL, NULL);
+
+	nalt = 0;
+	list_for_each_entry(dfu, &dfu_list, list) {
+		nalt++;
+	}
+
+	if (!nalt) {
+		log_warning("No entities in dfu_alt_info\n");
+		dfu_free_entities();
+		return -ENOENT;
+	}
+
+	for (i = 0; i < nalt; i++) {
+		dfu = dfu_get_entity(i);
+
+		if (!dfu)
+			continue;
+
+		if (dfu->dev_type != DFU_DEV_MTD)
+			continue;
+
+		if (dfu->layout == DFU_RAW_ADDR &&
+		    dfu->data.mtd.start == offset &&
+		    dfu->data.mtd.size == size) {
+			*alt_num = dfu->alt;
+			ret = 0;
+			break;
+		}
+	}
+
+	dfu_free_entities();
+
+	return ret;
+}
+
+int gen_image_alt_info(char *buf, size_t len, int sidx,
+		       struct fwu_image_entry *img, struct mtd_info *mtd)
+{
+	char *p = buf, *end = buf + len;
+	char uuidbuf[UUID_STR_LEN + 1];
+	ofnode node, parts_node;
+	const char *suuid;
+	int i;
+
+	/* Find partition node under given MTD device. */
+	parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
+					  "fixed-partitions");
+	if (!ofnode_valid(parts_node))
+		return -ENOENT;
+
+	/* Check the media UUID if exist. */
+	suuid = ofnode_read_string(parts_node, "uuid");
+	if (suuid) {
+		log_debug("Get location uuid %s\n", suuid);
+		uuid_bin_to_str(img->location_uuid.b, uuidbuf,
+				UUID_STR_FORMAT_STD);
+		if (strcasecmp(suuid, uuidbuf))
+			log_warning("Warning: Location UUID does not match!\n");
+	}
+
+	p += snprintf(p, end - p, "mtd %s", mtd->name);
+	if (end < p)
+		return -E2BIG;
+
+	/*
+	 * List up the image banks in the FWU mdata and search the corresponding
+	 * partition based on partition's uuid.
+	 */
+	for (i = 0; i < CONFIG_FWU_NUM_BANKS; i++) {
+		struct fwu_image_bank_info *bank;
+		fdt_addr_t offset, size;
+
+		/* Query a partition by image UUID */
+		bank = &img->img_bank_info[i];
+		uuid_bin_to_str(bank->image_uuid.b, uuidbuf,
+				UUID_STR_FORMAT_STD);
+		node = ofnode_by_prop_value(parts_node, "uuid", uuidbuf,
+					    sizeof(uuidbuf));
+		if (!ofnode_valid(node)) {
+			log_warning("Warning: Failed to find partition by image UUID\n");
+			break;
+		}
+
+		offset = ofnode_get_addr_size_index_notrans(node, 0, &size);
+		if (offset == FDT_ADDR_T_NONE || !size)
+			break;
+
+		p += snprintf(p, end - p, "%sbank%d raw %lx %lx",
+			      i == 0 ? "=" : ";", i, (unsigned long)offset,
+			      (unsigned long)size);
+		if (end < p)
+			return -E2BIG;
+	}
+
+	return i != CONFIG_FWU_NUM_BANKS ? -ENOENT : 0;
+}
+
+int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
+{
+	struct fwu_mdata *mdata;
+	int i, l, ret;
+
+	ret = fwu_get_mdata(&mdata);
+	if (ret < 0) {
+		log_debug("Failed to get the FWU mdata.\n");
+		return ret;
+	}
+
+	for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
+		ret = gen_image_alt_info(buf, len, i * CONFIG_FWU_NUM_BANKS,
+					 &mdata->img_entry[i], mtd);
+		if (ret)
+			break;
+		l = strlen(buf);
+		/* Replace the last ';' with '&' if there is another image. */
+		if (i != CONFIG_FWU_NUM_IMAGES_PER_BANK - 1 && l)
+			buf[l - 1] = '&';
+		len -= l;
+		buf += l;
+	}
+
+	free(mdata);
+
+	return ret;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 21/23] doc: synquacer: Add how to enable FWU Multi Bank Update
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (19 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 20/23] FWU: synquacer: Generate dfu_alt_info from devicetree partition Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-17 13:59   ` Michal Simek
  2022-06-09 12:30 ` [PATCH v5 22/23] [TEMP]configs: synquacer: Add FWU support for DeveloperBox Sughosh Ganu
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Masami Hiramatsu, Sughosh Ganu

From: Masami Hiramatsu <masami.hiramatsu@linaro.org>

Add a section for the instruction of building the FWU Multi Bank
Update supported U-Boot and installation.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 doc/board/socionext/developerbox.rst | 110 +++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/doc/board/socionext/developerbox.rst b/doc/board/socionext/developerbox.rst
index 2d943c23be..d9f38a3897 100644
--- a/doc/board/socionext/developerbox.rst
+++ b/doc/board/socionext/developerbox.rst
@@ -85,3 +85,113 @@ Once the flasher tool is running we are ready flash the UEFI image::
 
 After transferring the SPI_NOR_UBOOT.fd, turn off the DSW2-7 and reset the board.
 
+
+Enable FWU Multi Bank Update
+============================
+
+DeveloperBox supports the FWU Multi Bank Update. You *MUST* update both *SCP firmware* and *TF-A* for this feature. This will change the layout and the boot process but you can switch back to the normal one by changing the DSW 1-4 off.
+
+Configure U-Boot
+----------------
+
+To enable the FWU Multi Bank Update on the DeveloperBox, you need to add following configurations to configs/synquacer_developerbox_defconfig ::
+
+ CONFIG_FWU_MULTI_BANK_UPDATE=y
+ CONFIG_FWU_MDATA_MTD=y
+ CONFIG_CMD_FWU_METADATA=y
+ CONFIG_TOOLS_MKFWUMDATA=y
+
+And build it::
+
+  cd u-boot/
+  export ARCH=arm64
+  export CROSS_COMPILE=aarch64-linux-gnu-
+  make synqucer_developerbox_defconfig
+  make -j `noproc`
+  cd ../
+
+By default, the CONFIG_FWU_NUM_BANKS and COFNIG_FWU_NUM_IMAGES_PER_BANKS are set to 2 and 1 respectively. This uses FIP (Firmware Image Package) type image which contains TF-A, U-Boot and OP-TEE (the OP-TEE is optional.)
+You can use fiptool to compose the FIP image from those firmware images.
+
+Rebuild SCP firmware
+--------------------
+
+Rebuild SCP firmware which supports FWU Multi Bank Update as below::
+
+  cd SCP-firmware/
+  OUT=./build/product/synquacer
+  ROMFW_FILE=$OUT/scp_romfw/$SCP_BUILD_MODE/bin/scp_romfw.bin
+  RAMFW_FILE=$OUT/scp_ramfw/$SCP_BUILD_MODE/bin/scp_ramfw.bin
+  ROMRAMFW_FILE=scp_romramfw_release.bin
+
+  make CC=$ARM_EMB_GCC PRODUCT=synquacer MODE=release
+  tr "\000" "\377" < /dev/zero | dd of=${ROMRAMFW_FILE} bs=1 count=196608
+  dd if=${ROMFW_FILE} of=${ROMRAMFW_FILE} bs=1 conv=notrunc seek=0
+  dd if=${RAMFW_FILE} of=${ROMRAMFW_FILE} bs=1 seek=65536
+  cd ../
+
+And you can get the `scp_romramfw_release.bin` file
+
+Rebuild TF-A and FIP
+--------------------
+
+Rebuild TF-A which supports FWU Multi Bank Update as below::
+
+  cd arm-trusted-firmware/
+  make CROSS_COMPILE=aarch64-linux-gnu- -j`nproc` PLAT=synquacer \
+     SPD=opteed SQ_RESET_TO_BL2=1 GENERATE_COT=1 MBEDTLS_DIR=../mbedtls \
+     BL33=../u-boot/u-boot.bin all fip fiptool
+
+And make a FIP image.::
+
+  cp build/synquacer/release/fip.bin SPI_NOR_NEWFIP.fd
+  tools/fiptool/fiptool update --tb-fw build/synquacer/release/bl2.bin SPI_NOR_NEWFIP.fd
+
+
+UUIDs for the FWU Multi Bank Update
+-----------------------------------
+
+FWU multi-bank update requires some UUIDs. The DeveloperBox platform uses following UUIDs.
+
+ - Location UUID for the FIP image: 17e86d77-41f9-4fd7-87ec-a55df9842de5
+ - Image type UUID for the FIP image: 10c36d7d-ca52-b843-b7b9-f9d6c501d108
+ - Image UUID for Bank0 : 5a66a702-99fd-4fef-a392-c26e261a2828
+ - Image UUID for Bank1 : a8f868a1-6e5c-4757-878d-ce63375ef2c0
+
+These UUIDs are used for making a FWU metadata image.
+
+Generate FWU metadata image
+---------------------------
+
+Before installation, you need to generate a FWU metadata image file by mkfwumdata command as below::
+
+ tools/mkfwumdata -i 1 -b 2 "17e86d77-41f9-4fd7-87ec-a55df9842de5,10c36d7d-ca52-b843-b7b9-f9d6c501d108,5a66a702-99fd-4fef-a392-c26e261a2828,a8f868a1-6e5c-4757-878d-ce63375ef2c0" fwu-mdata.img
+
+Then, you can get the `fwu-mdata.img` image file.
+
+Install via flash writer
+------------------------
+
+As explained in above section, the new FIP image and the FWU metadata image can be installed via NOR flash writer. Note that the installation offsets for the FWU multi bank update supported firmware.
+
+Once the flasher tool is running we are ready flash the images. At first, please install FWU metadata at 0x500000 (primary) and 0x530000 (secondary).::
+
+  flash rawwrite 500000 60
+  >> Send fwu-mdata.img via XMODEM (Control-A S in minicom) <<
+
+  flash rawwrite 530000 60
+  >> Send fwu-mdata.img via XMODEM (Control-A S in minicom) <<
+
+And write the FIP image to the 0x600000 offset.::
+
+  flash rawwrite 600000 180000
+  >> Send SPI_NOR_NEWFIP.fd via XMODEM (Control-A S in minicom) <<
+
+And write the new SCP firmware.::
+
+  flash write cm3
+  >> Send scp_romramfw_release.bin via XMODEM (Control-A S in minicom) <<
+
+At last, turn on the DSW 3-4 on the board, and reboot.
+Note that if DSW 3-4 is turned off, the DeveloperBox will boot from
+the original EDK2 firmware (or non-FWU U-Boot if you already installed.)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 22/23] [TEMP]configs: synquacer: Add FWU support for DeveloperBox
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (20 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 21/23] doc: synquacer: Add how to enable FWU Multi Bank Update Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-09 12:30 ` [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox Sughosh Ganu
  2022-06-20 18:12 ` [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Patrick DELAUNAY
  23 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Masami Hiramatsu, Sughosh Ganu

From: Masami Hiramatsu <masami.hiramatsu@linaro.org>

Enable FWU Multi-Bank support for DeveloperBox SynQuacer platform.
This also enables fwu_metadata_read command and "reboot soon after
update" option.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
---
 Changes in v3:
  - Use CONFIG_FWU_MDATA_MTD.
  - Remove unused CONFIG_FWU_INIT_BROKEN_METADATA and add
    CONFIG_TOOLS_MKFWUMDATA.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 configs/synquacer_developerbox_defconfig | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/configs/synquacer_developerbox_defconfig b/configs/synquacer_developerbox_defconfig
index 29b1e11401..f2c8c3cc4e 100644
--- a/configs/synquacer_developerbox_defconfig
+++ b/configs/synquacer_developerbox_defconfig
@@ -94,3 +94,8 @@ CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
 CONFIG_EFI_CAPSULE_ON_DISK=y
 CONFIG_EFI_IGNORE_OSINDICATIONS=y
 CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
+CONFIG_EFI_SECURE_BOOT=y
+CONFIG_FWU_MULTI_BANK_UPDATE=y
+CONFIG_FWU_MDATA_MTD=y
+CONFIG_CMD_FWU_METADATA=y
+CONFIG_TOOLS_MKFWUMDATA=y
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (21 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 22/23] [TEMP]configs: synquacer: Add FWU support for DeveloperBox Sughosh Ganu
@ 2022-06-09 12:30 ` Sughosh Ganu
  2022-06-15  5:37   ` Takahiro Akashi
  2022-06-15  6:30   ` Takahiro Akashi
  2022-06-20 18:12 ` [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Patrick DELAUNAY
  23 siblings, 2 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-09 12:30 UTC (permalink / raw)
  To: u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar,
	Sughosh Ganu

Add a python test script for testing the FWU Multi Bank Update
functionality on the sandbox platform. The script has test cases for
updation of the u-boot binary and the u-boot environment image to the
non active bank.

The FWU metadata is being stored on the SPI NOR flash, along with the
updatable images, and the FWU metadata driver for MTD devices is being
used for accessing the metadata. Certain FWU boottime checks are
bypassed due to the unavailability of the EFI variable access very
early in the boot on the sandbox platform -- the variable access is
only available once the block disk image has been bound through the
host interface.

The FWU Multi Bank feature being enabled on the sandbox64 platform is
enabling the RAW Firmware Management Protocol(FMP) instance, therefore
the FIT FMP instance is being removed -- the FIT FMP is already being
tested on the sandbox flattree variant.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
 arch/sandbox/Kconfig                          |   6 +
 arch/sandbox/dts/test.dts                     |  45 ++-
 board/sandbox/sandbox.c                       |  49 +++
 configs/sandbox64_defconfig                   |  12 +-
 include/fwu.h                                 |   2 +
 lib/fwu_updates/Kconfig                       |   2 +-
 lib/fwu_updates/fwu.c                         |  18 +-
 lib/fwu_updates/fwu_mtd.c                     |  10 +-
 .../test_capsule_firmware_fit.py              |   1 -
 .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
 test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
 .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
 12 files changed, 587 insertions(+), 13 deletions(-)
 create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
 create mode 100644 test/py/tests/test_fwu_updates/conftest.py
 create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py

diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 5f55c7f28e..2985572083 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -84,3 +84,9 @@ config SYS_FDT_LOAD_ADDR
 	  See `doc/arch/sandbox.rst` for more information.
 
 endmenu
+
+config FWU_NUM_BANKS
+       default 2
+
+config FWU_NUM_IMAGES_PER_BANK
+	default 2
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 8f93775ff4..f11fa8733f 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1145,11 +1145,48 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinmux_spi0_pins>;
 
-		spi.bin@0 {
+		spi0: spi.bin@0 {
 			reg = <0>;
 			compatible = "spansion,m25p16", "jedec,spi-nor";
 			spi-max-frequency = <40000000>;
 			sandbox,filename = "spi.bin";
+
+			partitions {
+				compatible = "fixed-partitions";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				uuid = "af9e8c96-bec5-48be-9dab-3491c04b1366";
+
+				partition@0 {
+					label = "Metadata";
+					reg = <0x0 0x20000>;
+				};
+
+				/* FWU Multi bank update partitions */
+				partition@100000 {
+					label = "U-Boot-Bank0";
+					reg = <0x100000 0x10000>;
+					uuid = "a8f61787-5d68-4c9d-9e4a-37bb0df99da7";
+				};
+
+				partition@120000 {
+					label = "U-Boot-ENV-Bank0";
+					reg = <0x120000 0x10000>;
+					uuid = "ea9d59af-e0e8-4ef5-9b16-4c80ff67524c";
+				};
+
+				partition@140000 {
+					label = "U-Boot-Bank1";
+					reg = <0x140000 0x10000>;
+					uuid = "52377abf-c4e4-4d0b-aafd-ba081a500847";
+				};
+
+				partition@160000 {
+					label = "U-Boot-ENV-Bank1";
+					reg = <0x160000 0x10000>;
+					uuid = "4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3";
+				};
+			};
 		};
 		spi.bin@1 {
 			reg = <1>;
@@ -1633,6 +1670,12 @@
 			compatible = "sandbox,regmap_test";
 		};
 	};
+
+	fwu-mdata {
+		compatible = "u-boot,fwu-mdata-mtd";
+		fwu-mdata-store = <&spi0>;
+		mdata-offsets = <0x0 0x10000>;
+	};
 };
 
 #include "sandbox_pmic.dtsi"
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
index e054f300c4..222c36d301 100644
--- a/board/sandbox/sandbox.c
+++ b/board/sandbox/sandbox.c
@@ -6,13 +6,18 @@
 #include <common.h>
 #include <cpu_func.h>
 #include <cros_ec.h>
+#include <dfu.h>
 #include <dm.h>
 #include <efi.h>
 #include <efi_loader.h>
 #include <env_internal.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
 #include <init.h>
 #include <led.h>
+#include <mtd.h>
 #include <os.h>
+#include <uuid.h>
 #include <asm/global_data.h>
 #include <asm/test.h>
 #include <asm/u-boot-sandbox.h>
@@ -51,8 +56,15 @@ struct efi_fw_image fw_images[] = {
 };
 
 struct efi_capsule_update_info update_info = {
+#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
+	.dfu_string = "mtd nor0=u-boot-bin-a raw 0x100000 0x10000;"
+		"u-boot-env-a raw 0x120000 0x10000;"
+		"u-boot-bin-b raw 0x140000 0x10000;"
+		"u-boot-env-b raw 0x160000 0x10000",
+#else
 	.dfu_string = "sf 0:0=u-boot-bin raw 0x100000 0x50000;"
 		"u-boot-env raw 0x150000 0x200000",
+#endif
 	.images = fw_images,
 };
 
@@ -155,3 +167,40 @@ int board_late_init(void)
 	return 0;
 }
 #endif
+
+#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
+int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
+			 efi_guid_t *image_id, int *alt_num)
+{
+	return fwu_get_mtd_alt_num(image_id, alt_num, "nor0", 1);
+}
+
+int fwu_plat_get_update_index(u32 *update_idx)
+{
+	int ret;
+	u32 active_idx;
+
+	ret = fwu_get_active_index(&active_idx);
+
+	if (ret < 0)
+		return -1;
+
+	*update_idx = active_idx ^= 0x1;
+
+	return ret;
+}
+
+void fwu_plat_get_bootidx(void *boot_idx)
+{
+	int ret;
+	u32 active_idx;
+	u32 *bootidx = boot_idx;
+
+	ret = fwu_get_active_index(&active_idx);
+
+	if (ret < 0)
+		*bootidx = -1;
+
+	*bootidx = active_idx;
+}
+#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index d7f22b39ae..7a813b46a5 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -244,9 +244,19 @@ CONFIG_LZ4=y
 CONFIG_ERRNO_STR=y
 CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
 CONFIG_EFI_CAPSULE_ON_DISK=y
-CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
 CONFIG_EFI_SECURE_BOOT=y
 CONFIG_TEST_FDTDEC=y
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
+CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
+CONFIG_DM_FWU_MDATA=y
+CONFIG_FWU_MULTI_BANK_UPDATE=y
+CONFIG_FWU_MDATA_MTD=y
+CONFIG_CMD_FWU_METADATA=y
+CONFIG_TOOLS_MKFWUMDATA=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_CMD_MTD=y
+CONFIG_DFU_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_SPI_FLASH_MTD=y
diff --git a/include/fwu.h b/include/fwu.h
index fadbfedd07..9e550182eb 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -8,6 +8,8 @@
 
 #include <blk.h>
 #include <efi.h>
+#include <fwu_mdata.h>
+#include <mtd.h>
 
 #include <linux/types.h>
 
diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
index 6de28e0c9c..43bed7729c 100644
--- a/lib/fwu_updates/Kconfig
+++ b/lib/fwu_updates/Kconfig
@@ -2,7 +2,7 @@ config FWU_MULTI_BANK_UPDATE
 	bool "Enable FWU Multi Bank Update Feature"
 	depends on EFI_HAVE_CAPSULE_SUPPORT
 	select PARTITION_TYPE_GUID
-	select EFI_SETUP_EARLY
+	select EFI_SETUP_EARLY if !SANDBOX
 	help
 	  Feature for updating firmware images on platforms having
 	  multiple banks(copies) of the firmware images. One of the
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index 422ef58661..f2c10d836b 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -185,12 +185,22 @@ int fwu_boottime_checks(void)
 		return 0;
 	}
 
-	if (efi_init_obj_list() != EFI_SUCCESS)
-		return 0;
+	/*
+	 * On the sandbox platform, the EFI variable
+	 * access is available only after binding the
+	 * disk image with the host interface. Skip
+	 * the Trial State check on sandbox.
+	 */
+	if (!IS_ENABLED(CONFIG_SANDBOX)) {
+		if (efi_init_obj_list() != EFI_SUCCESS)
+			return 0;
 
-	ret = fwu_trial_state_check();
-	if (!ret)
+		ret = fwu_trial_state_check();
+		if (!ret)
+			boottime_check = 1;
+	} else {
 		boottime_check = 1;
+	}
 
 	return 0;
 }
diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
index 3137f8635c..3a9ad70203 100644
--- a/lib/fwu_updates/fwu_mtd.c
+++ b/lib/fwu_updates/fwu_mtd.c
@@ -84,11 +84,11 @@ int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
 int gen_image_alt_info(char *buf, size_t len, int sidx,
 		       struct fwu_image_entry *img, struct mtd_info *mtd)
 {
-	char *p = buf, *end = buf + len;
-	char uuidbuf[UUID_STR_LEN + 1];
-	ofnode node, parts_node;
-	const char *suuid;
 	int i;
+	const char *suuid;
+	ofnode node, parts_node;
+	char uuidbuf[UUID_STR_LEN + 1];
+	char *p = buf, *end = buf + len;
 
 	/* Find partition node under given MTD device. */
 	parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
@@ -145,7 +145,7 @@ int gen_image_alt_info(char *buf, size_t len, int sidx,
 
 int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
 {
-	struct fwu_mdata *mdata;
+	struct fwu_mdata *mdata = NULL;
 	int i, l, ret;
 
 	ret = fwu_get_mdata(&mdata);
diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
index 5bef84958b..93bc5ed44b 100644
--- a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
+++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
@@ -13,7 +13,6 @@ import pytest
 from capsule_defs import *
 
 
-@pytest.mark.boardspec('sandbox64')
 @pytest.mark.boardspec('sandbox_flattree')
 @pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
 @pytest.mark.buildconfigspec('efi_capsule_on_disk')
diff --git a/test/py/tests/test_fwu_updates/capsule_defs.py b/test/py/tests/test_fwu_updates/capsule_defs.py
new file mode 100644
index 0000000000..59b40f11bd
--- /dev/null
+++ b/test/py/tests/test_fwu_updates/capsule_defs.py
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier:      GPL-2.0+
+
+# Directories
+CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'
+CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
+
+# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and
+# you need build a newer version on your own.
+# The path must terminate with '/' if it is not null.
+EFITOOLS_PATH = ''
diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
new file mode 100644
index 0000000000..cdf824c3be
--- /dev/null
+++ b/test/py/tests/test_fwu_updates/conftest.py
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2020, Linaro Limited
+# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+
+import os
+import os.path
+import re
+from subprocess import call, check_call, check_output, CalledProcessError
+import pytest
+from capsule_defs import *
+
+#
+# Fixture for UEFI capsule test
+#
+
+@pytest.fixture(scope='session')
+def efi_capsule_data(request, u_boot_config):
+    """Set up a file system to be used in UEFI capsule and
+       authentication test.
+
+    Args:
+        request: Pytest request object.
+        u_boot_config: U-boot configuration.
+
+    Return:
+        A path to disk image to be used for testing
+    """
+    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
+
+    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
+    data_dir = mnt_point + CAPSULE_DATA_DIR
+    install_dir = mnt_point + CAPSULE_INSTALL_DIR
+    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
+
+    try:
+        # Create a target device
+        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
+
+        check_call('rm -rf %s' % mnt_point, shell=True)
+        check_call('mkdir -p %s' % data_dir, shell=True)
+        check_call('mkdir -p %s' % install_dir, shell=True)
+
+        # Create capsule files
+        # two regions: one for u-boot.bin and the other for u-boot.env
+        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
+                   shell=True)
+        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
+        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
+
+        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
+                   (data_dir, u_boot_config.build_dir),
+                   shell=True)
+        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
+                   (data_dir, u_boot_config.build_dir),
+                   shell=True)
+
+        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
+                   (data_dir, u_boot_config.build_dir),
+                   shell=True)
+        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
+                   (data_dir, u_boot_config.build_dir),
+                   shell=True)
+
+        # Create a disk image with EFI system partition
+        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
+                   (mnt_point, image_path), shell=True)
+        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
+                   image_path, shell=True)
+
+    except CalledProcessError as exception:
+        pytest.skip('Setup failed: %s' % exception.cmd)
+        return
+    else:
+        yield image_path
+    finally:
+        call('rm -rf %s' % mnt_point, shell=True)
+        call('rm -f %s' % image_path, shell=True)
+        call('rm -f ./spi.bin', shell=True)
diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
new file mode 100644
index 0000000000..d9dff3afaf
--- /dev/null
+++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
@@ -0,0 +1,367 @@
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2022, Linaro Limited
+#
+# FWU Multi Bank Firmware Update Test
+
+"""
+This test verifies FWU Multi Bank firmware update for raw images
+"""
+
+from subprocess import check_call, check_output, CalledProcessError
+import pytest
+from capsule_defs import *
+
+
+@pytest.mark.boardspec('sandbox64')
+@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
+@pytest.mark.buildconfigspec('efi_capsule_on_disk')
+@pytest.mark.buildconfigspec('dfu')
+@pytest.mark.buildconfigspec('dfu_sf')
+@pytest.mark.buildconfigspec('cmd_efidebug')
+@pytest.mark.buildconfigspec('cmd_fat')
+@pytest.mark.buildconfigspec('cmd_memory')
+@pytest.mark.buildconfigspec('cmd_nvedit_efi')
+@pytest.mark.buildconfigspec('cmd_sf')
+@pytest.mark.buildconfigspec('fwu_multi_bank_update')
+@pytest.mark.buildconfigspec('dm_fwu_mdata')
+@pytest.mark.buildconfigspec('fwu_mdata_mtd')
+@pytest.mark.slow
+class TestEfiCapsuleFirmwareRaw(object):
+    def test_fwu_updates_fw1(
+            self, u_boot_config, u_boot_console, efi_capsule_data):
+        """
+        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
+                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
+                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
+        """
+
+        # other tests might have run and the
+        # system might not be in a clean state.
+        # Restart before starting the tests.
+        u_boot_console.restart_uboot()
+
+        disk_img = efi_capsule_data
+        with u_boot_console.log.section('Test Case 1-a, before reboot'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
+                'efidebug boot order 1',
+                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
+                'env save'])
+
+            # initialize contents
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 100000 10',
+                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 140000 10'])
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 100000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5100000 140000 10',
+                'md.b 5100000 10'
+                ])
+            assert 'u-boot-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
+                'sf write 4000000 0 $filesize',
+                'sf write 4000000 10000 $filesize'])
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x0' in ''.join(output)
+            assert 'previous_active_index: 0x1' in ''.join(output)
+
+            # place a capsule file
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test01' in ''.join(output)
+
+        # reboot
+        u_boot_console.restart_uboot()
+
+        with u_boot_console.log.section('Test Case 1-b, after reboot'):
+            # make sure that dfu_alt_info exists even persistent variables
+            # are not available.
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test01' in ''.join(output)
+
+            # need to run uefi command to initiate capsule handling
+            output = u_boot_console.run_command(
+                'efidebug capsule disk-update', wait_for_reboot = True)
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x1' in ''.join(output)
+            assert 'previous_active_index: 0x0' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 100000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 140000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-b:New' in ''.join(output)
+
+    def test_fwu_updates_fw2(
+            self, u_boot_config, u_boot_console, efi_capsule_data):
+        """
+        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
+                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
+                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
+                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
+                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
+        """
+
+        # other tests might have run and the
+        # system might not be in a clean state.
+        # Restart before starting the tests.
+        u_boot_console.restart_uboot()
+
+        disk_img = efi_capsule_data
+        with u_boot_console.log.section('Test Case 2-a, before reboot'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
+                'efidebug boot order 1',
+                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
+                'env save'])
+
+            # initialize contents
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 100000 10',
+                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 120000 10',
+                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 140000 10',
+                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 160000 10'])
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 100000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 120000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-env-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5100000 140000 10',
+                'md.b 5100000 10'
+                ])
+            assert 'u-boot-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 160000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-env-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
+                'sf write 4000000 0 100',
+                'sf write 4000000 10000 100'])
+
+            output = u_boot_console.run_command(
+               'fwu_mdata_read')
+            assert 'active_index: 0x0' in ''.join(output)
+            assert 'previous_active_index: 0x1' in ''.join(output)
+
+            # place a capsule file
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test01' in ''.join(output)
+            assert 'Test02' in ''.join(output)
+
+        # reboot
+        u_boot_console.restart_uboot()
+
+        with u_boot_console.log.section('Test Case 2-b, after reboot'):
+            # make sure that dfu_alt_info exists even persistent variables
+            # are not available.
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test01' in ''.join(output)
+            assert 'Test02' in ''.join(output)
+
+            # need to run uefi command to initiate capsule handling
+            output = u_boot_console.run_command(
+                'efidebug capsule disk-update', wait_for_reboot = True)
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x1' in ''.join(output)
+            assert 'previous_active_index: 0x0' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 100000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 120000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 140000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-b:New' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 160000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env-b:New' in ''.join(output)
+
+    def test_fwu_updates_fw3(
+            self, u_boot_config, u_boot_console, efi_capsule_data):
+        """
+        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
+                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
+                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
+                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
+                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
+        """
+
+        # other tests might have run and the
+        # system might not be in a clean state.
+        # Restart before starting the tests.
+        u_boot_console.restart_uboot()
+
+        disk_img = efi_capsule_data
+        with u_boot_console.log.section('Test Case 3-a, before reboot'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
+                'efidebug boot order 1',
+                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
+                'env save'])
+
+            # initialize contents
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 100000 10',
+                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 120000 10',
+                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 140000 10',
+                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
+                'sf write 4000000 160000 10'])
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 100000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 120000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-env-a:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5100000 140000 10',
+                'md.b 5100000 10'
+                ])
+            assert 'u-boot-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 5000000 160000 10',
+                'md.b 5000000 10'
+                ])
+            assert 'u-boot-env-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
+                'sf write 4000000 0 100',
+                'sf write 4000000 10000 100'])
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x1' in ''.join(output)
+            assert 'previous_active_index: 0x0' in ''.join(output)
+
+            # place a capsule file
+            output = u_boot_console.run_command_list([
+                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
+                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test03' in ''.join(output)
+            assert 'Test04' in ''.join(output)
+
+        # reboot
+        u_boot_console.restart_uboot()
+
+        with u_boot_console.log.section('Test Case 3-b, after reboot'):
+            # make sure that dfu_alt_info exists even persistent variables
+            # are not available.
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % disk_img,
+                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
+            assert 'Test03' in ''.join(output)
+            assert 'Test04' in ''.join(output)
+
+            # need to run uefi command to initiate capsule handling
+            output = u_boot_console.run_command(
+                'efidebug capsule disk-update', wait_for_reboot = True)
+
+            output = u_boot_console.run_command(
+                'fwu_mdata_read')
+            assert 'active_index: 0x0' in ''.join(output)
+            assert 'previous_active_index: 0x1' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 100000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-a:New' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf probe 0:0',
+                'sf read 4000000 120000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env-a:New' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 140000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-b:Old' in ''.join(output)
+
+            output = u_boot_console.run_command_list([
+                'sf read 4000000 160000 10',
+                'md.b 4000000 10'])
+            assert 'u-boot-env-b:Old' in ''.join(output)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-09 12:29 ` [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules Sughosh Ganu
@ 2022-06-09 16:27   ` Heinrich Schuchardt
  2022-06-13 12:33     ` Sughosh Ganu
  2022-06-15  5:11   ` Takahiro Akashi
  2022-06-21 10:58   ` Etienne Carriere
  2 siblings, 1 reply; 104+ messages in thread
From: Heinrich Schuchardt @ 2022-06-09 16:27 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: Ilias Apalodimas, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar, u-boot

On 6/9/22 14:29, Sughosh Ganu wrote:
> The Dependable Boot specification[1] describes the structure of the
> firmware accept and revert capsules. These are empty capsules which
> are used for signalling the acceptance or rejection of the updated
> firmware by the OS. Add support for generating these empty capsules.
>
> [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   doc/mkeficapsule.1   |  29 ++++++---
>   tools/eficapsule.h   |   8 +++
>   tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
>   3 files changed, 151 insertions(+), 25 deletions(-)
>
> diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
> index 09bdc24295..77ca061efd 100644
> --- a/doc/mkeficapsule.1
> +++ b/doc/mkeficapsule.1
> @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
>
>   .SH SYNOPSIS
>   .B mkeficapsule
> -.RI [ options "] " image-blob " " capsule-file
> +.RI [ options ] " " [ image-blob ] " " capsule-file
>
>   .SH "DESCRIPTION"
>   .B mkeficapsule
> @@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
>   In this case, the update will be authenticated by verifying the signature
>   before applying.
>
> +Additionally, an empty capsule file can be generated for acceptance or
> +rejection of firmware images by a governing component like an Operating
> +System. The empty capsules do not require an image-blob input file.
> +
> +
>   .B mkeficapsule
> -takes any type of image files, including:
> +takes any type of image files when generating non empty capsules, including:
>   .TP
>   .I raw image
>   format is a single binary blob of any type of firmware.
> @@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
>   This type of image file can be generated by
>   .BR mkimage .
>
> -.PP
> -If you want to use other types than above two, you should explicitly
> -specify a guid for the FMP driver.
> -
>   .SH "OPTIONS"
> +
>   .TP
>   .BI "-g\fR,\fB --guid " guid-string
>   Specify guid for image blob type. The format is:
>       xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
>
>   The first three elements are in little endian, while the rest
> -is in big endian.
> +is in big endian. The option must be specified for all non empty and
> +image acceptance capsules
>
>   .TP
>   .BI "-i\fR,\fB --index " index
> @@ -57,6 +60,18 @@ Specify an image index
>   .BI "-I\fR,\fB --instance " instance
>   Specify a hardware instance
>
> +.PP
> +For generation of firmware accept empty capsule
> +.BR --guid
> +is mandatory
> +.TP
> +.BI "-A\fR,\fB --fw-accept "
> +Generate a firmware acceptance empty capsule
> +
> +.TP
> +.BI "-R\fR,\fB --fw-revert "
> +Generate a firmware revert empty capsule
> +
>   .TP
>   .BR -h ", " --help
>   Print a help message
> diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> index d63b831443..072a4b5598 100644
> --- a/tools/eficapsule.h
> +++ b/tools/eficapsule.h
> @@ -41,6 +41,14 @@ typedef struct {
>   	EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
>   		 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
>
> +#define FW_ACCEPT_OS_GUID \
> +	EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
> +		 0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
> +
> +#define FW_REVERT_OS_GUID \
> +	EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
> +		 0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
> +
>   /* flags */
>   #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
>
> diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> index 5f74d23b9e..e8eb6b070d 100644
> --- a/tools/mkeficapsule.c
> +++ b/tools/mkeficapsule.c
> @@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
>   efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
>   efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
>
> -static const char *opts_short = "g:i:I:v:p:c:m:dh";
> +static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
> +
> +static bool empty_capsule;
> +static unsigned char capsule;
> +
> +enum {
> +	CAPSULE_NORMAL_BLOB = 0,
> +	CAPSULE_ACCEPT,
> +	CAPSULE_REVERT,
> +} capsule_type;
>
>   static struct option options[] = {
>   	{"guid", required_argument, NULL, 'g'},
> @@ -39,24 +48,47 @@ static struct option options[] = {
>   	{"certificate", required_argument, NULL, 'c'},
>   	{"monotonic-count", required_argument, NULL, 'm'},
>   	{"dump-sig", no_argument, NULL, 'd'},
> +	{"fw-accept", no_argument, NULL, 'A'},
> +	{"fw-revert", no_argument, NULL, 'R'},
>   	{"help", no_argument, NULL, 'h'},
>   	{NULL, 0, NULL, 0},
>   };
>
>   static void print_usage(void)
>   {
> -	fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> -		"Options:\n"
> -
> -		"\t-g, --guid <guid string>    guid for image blob type\n"
> -		"\t-i, --index <index>         update image index\n"
> -		"\t-I, --instance <instance>   update hardware instance\n"
> -		"\t-p, --private-key <privkey file>  private key file\n"
> -		"\t-c, --certificate <cert file>     signer's certificate file\n"
> -		"\t-m, --monotonic-count <count>     monotonic count\n"
> -		"\t-d, --dump_sig              dump signature (*.p7)\n"
> -		"\t-h, --help                  print a help message\n",
> -		tool_name);
> +	if (empty_capsule) {
> +		if (capsule == CAPSULE_ACCEPT) {
> +			fprintf(stderr, "Usage: %s [options] <output file>\n",

My expectation is that this function always provides the same output.

If different scenarios allow only specific combinations of arguments you
may describe it here.


> +				tool_name);
> +			fprintf(stderr, "Options:\n"
> +				"\t-A, --fw-accept             firmware accept capsule\n"
> +				"\t-g, --guid <guid string>    guid for image blob type\n"
> +				"\t-h, --help                  print a help message\n"
> +				);
> +		} else {
> +			fprintf(stderr, "Usage: %s [options] <output file>\n",
> +				tool_name);
> +			fprintf(stderr, "Options:\n"
> +				"\t-R, --fw-revert             firmware revert capsule\n"
> +				"\t-h, --help                  print a help message\n"
> +				);
> +		}
> +	} else {
> +		fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> +			"Options:\n"
> +
> +			"\t-g, --guid <guid string>    guid for image blob type\n"
> +			"\t-i, --index <index>         update image index\n"
> +			"\t-I, --instance <instance>   update hardware instance\n"
> +			"\t-p, --private-key <privkey file>  private key file\n"
> +			"\t-c, --certificate <cert file>     signer's certificate file\n"
> +			"\t-m, --monotonic-count <count>     monotonic count\n"
> +			"\t-d, --dump_sig              dump signature (*.p7)\n"
> +			"\t-A, --fw-accept             firmware accept capsule\n"

"\t-A, --fw-accept             firmware accept capsule, requires GUID\n"

> +			"\t-R, --fw-revert             firmware revert capsule\n"

"\t-R, --fw-revert             firmware revert capsule, takes no GUID\n"

> +			"\t-h, --help                  print a help message\n",
> +			tool_name);
> +	}
>   }
>
>   /**
> @@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
>   	buf[7] = c;
>   }
>
> +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> +{
> +	struct efi_capsule_header header;
> +	FILE *f = NULL;
> +	int ret = -1;
> +	efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
> +	efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
> +	efi_guid_t payload, capsule_guid;
> +
> +	f = fopen(path, "w");
> +	if (!f) {
> +		fprintf(stderr, "cannot open %s\n", path);
> +		goto err;
> +	}
> +
> +	capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
> +
> +	memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
> +	header.header_size = sizeof(header);
> +	header.flags = 0;
> +
> +	header.capsule_image_size = fw_accept ?
> +		sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
> +
> +	if (write_capsule_file(f, &header, sizeof(header),
> +			       "Capsule header"))
> +		goto err;
> +
> +	if (fw_accept) {
> +		memcpy(&payload, guid, sizeof(efi_guid_t));
> +		if (write_capsule_file(f, &payload, sizeof(payload),
> +				       "FW Accept Capsule Payload"))
> +			goto err;
> +	}
> +
> +	ret = 0;
> +
> +err:
> +	if (f)
> +		fclose(f);
> +
> +	return ret;
> +}
> +
>   /**
>    * main - main entry function of mkeficapsule
>    * @argc:	Number of arguments
> @@ -639,22 +715,49 @@ int main(int argc, char **argv)

>   		case 'd':
>   			dump_sig = 1;
>   			break;
> +		case 'A':
> +			capsule |= CAPSULE_ACCEPT;
> +			break;
> +		case 'R':
> +			capsule |= CAPSULE_REVERT;
> +			break;
>   		case 'h':

You must handle '?' and ':' here too. Just use

default:


>   			print_usage();
>   			exit(EXIT_SUCCESS);
>   		}
>   	}
>
> +	if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
> +		fprintf(stderr,
> +			"Select either of Accept or Revert capsule generation\n");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	empty_capsule = (capsule == CAPSULE_ACCEPT ||
> +			 capsule == CAPSULE_REVERT);
> +
>   	/* check necessary parameters */
> -	if ((argc != optind + 2) || !guid ||
> -	    ((privkey_file && !cert_file) ||
> -	     (!privkey_file && cert_file))) {
> +	if ((!empty_capsule &&
> +	    ((argc != optind + 2) || !guid ||
> +	     ((privkey_file && !cert_file) ||
> +	      (!privkey_file && cert_file)))) ||
> +	    (empty_capsule &&
> +	    ((argc != optind + 1) ||
> +	     ((capsule == CAPSULE_ACCEPT) && !guid) ||
> +	     ((capsule == CAPSULE_REVERT) && guid)))) {

Please, write a message explaining to the user what was wrong, e.g.

"Option -A does not take a GUID" or
"Option -R requires a GUID"


>   		print_usage();
>   		exit(EXIT_FAILURE);
>   	}
>
> -	if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
> -			 mcount, privkey_file, cert_file) < 0) {
> +	if (empty_capsule) {
> +		if (create_empty_capsule(argv[argc - 1], guid,
> +					 capsule == CAPSULE_ACCEPT) < 0) {
> +			fprintf(stderr, "Creating empty capsule failed\n");

The called function should provide a message that describes what went wrong.

Best regards

Heinrich


> +			exit(EXIT_FAILURE);
> +		}
> +	} else 	if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
> +				 index, instance, mcount, privkey_file,
> +				 cert_file) < 0) {
>   		fprintf(stderr, "Creating firmware capsule failed\n");
>   		exit(EXIT_FAILURE);
>   	}


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata
  2022-06-09 12:29 ` [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata Sughosh Ganu
@ 2022-06-10 11:53   ` Ilias Apalodimas
  2022-06-13 12:37     ` Sughosh Ganu
  2022-06-21  9:49   ` Patrick DELAUNAY
  1 sibling, 1 reply; 104+ messages in thread
From: Ilias Apalodimas @ 2022-06-10 11:53 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi Sughosh, 

On Thu, Jun 09, 2022 at 05:59:53PM +0530, Sughosh Ganu wrote:
> Add helper functions needed for accessing the FWU metadata which
> contains information on the updatable images. These functions have
> been added for the STM32MP157C-DK2 board which has the updatable
> images on the uSD card, formatted as GPT partitions.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  board/st/stm32mp1/stm32mp1.c | 115 +++++++++++++++++++++++++++++++++++
>  include/fwu.h                |   2 +
>  2 files changed, 117 insertions(+)
> 
> diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> index 62d98ad776..e68bf09955 100644
> --- a/board/st/stm32mp1/stm32mp1.c
> +++ b/board/st/stm32mp1/stm32mp1.c
> @@ -7,9 +7,11 @@
>  
>  #include <common.h>
>  #include <adc.h>
> +#include <blk.h>
>  #include <bootm.h>
>  #include <clk.h>
>  #include <config.h>
> +#include <dfu.h>
>  #include <dm.h>
>  #include <efi_loader.h>
>  #include <env.h>
> @@ -25,9 +27,11 @@
>  #include <log.h>
>  #include <malloc.h>
>  #include <misc.h>
> +#include <mmc.h>
>  #include <mtd_node.h>
>  #include <net.h>
>  #include <netdev.h>
> +#include <part.h>
>  #include <phy.h>
>  #include <remoteproc.h>
>  #include <reset.h>
> @@ -967,3 +971,114 @@ static void board_copro_image_process(ulong fw_image, size_t fw_size)
>  }
>  
>  U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_COPRO, board_copro_image_process);
> +
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +
> +static int get_gpt_dfu_identifier(struct blk_desc *desc, efi_guid_t *image_guid)
> +{
> +	int i;
> +	struct disk_partition info;
> +	efi_guid_t unique_part_guid;
> +
> +	for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) {
> +		if (part_get_info(desc, i, &info))
> +			continue;
> +		uuid_str_to_bin(info.uuid, unique_part_guid.b,
> +				UUID_STR_FORMAT_GUID);
> +
> +		if (!guidcmp(&unique_part_guid, image_guid))
> +			return i;
> +	}
> +
> +	log_err("No partition found with image_guid %pUs\n", image_guid);
> +	return -ENOENT;
> +}
> +
> +static int gpt_plat_get_alt_num(struct blk_desc *desc, efi_guid_t *image_guid,
> +				int *alt_num)

Does this really need to be defined per platform?

Most of the stuff in here are generic apart from the info of were  the
metadata is stored.  So wouldn't it better to move this in the generic API 
and add an argument for the dfu device type?

The platform portion would then just call this function with an extra arg
e.g DFU_DEV_MMC

> +{
> +	int ret = -1;
> +	int i, part, dev_num;
> +	int nalt;
> +	struct dfu_entity *dfu;
> +
> +	dev_num = desc->devnum;
> +	part = get_gpt_dfu_identifier(desc, image_guid);
> +	if (part < 0)
> +		return -ENOENT;
> +
> +	dfu_init_env_entities(NULL, NULL);

[...]


Regards
/Ilias

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 07/23] FWU: STM32MP1: Add support to read boot index from backup register
  2022-06-09 12:29 ` [PATCH v5 07/23] FWU: STM32MP1: Add support to read boot index from backup register Sughosh Ganu
@ 2022-06-10 12:02   ` Ilias Apalodimas
  2022-06-21 11:27   ` Patrick DELAUNAY
  1 sibling, 0 replies; 104+ messages in thread
From: Ilias Apalodimas @ 2022-06-10 12:02 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

That's looks ok to me, but I'd rather ST people to have a look

On Thu, 9 Jun 2022 at 15:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> The FWU Multi Bank Update feature allows the platform to boot the
> firmware images from one of the partitions(banks). The first stage
> bootloader(fsbl) passes the value of the boot index, i.e. the bank
> from which the firmware images were booted from to U-Boot. On the
> STM32MP157C-DK2 board, this value is passed through one of the SoC's
> backup register. Add a function to read the boot index value from the
> backup register.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  arch/arm/mach-stm32mp/include/mach/stm32.h | 4 ++++
>  board/st/stm32mp1/stm32mp1.c               | 7 +++++++
>  include/fwu.h                              | 2 +-
>  3 files changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h
> index 47e88fc3dc..40995ee142 100644
> --- a/arch/arm/mach-stm32mp/include/mach/stm32.h
> +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h
> @@ -100,6 +100,7 @@ enum boot_device {
>  #define TAMP_BACKUP_REGISTER(x)                (STM32_TAMP_BASE + 0x100 + 4 * x)
>  #define TAMP_BACKUP_MAGIC_NUMBER       TAMP_BACKUP_REGISTER(4)
>  #define TAMP_BACKUP_BRANCH_ADDRESS     TAMP_BACKUP_REGISTER(5)
> +#define TAMP_FWU_BOOT_INFO_REG         TAMP_BACKUP_REGISTER(10)
>  #define TAMP_COPRO_RSC_TBL_ADDRESS     TAMP_BACKUP_REGISTER(17)
>  #define TAMP_COPRO_STATE               TAMP_BACKUP_REGISTER(18)
>  #define TAMP_BOOT_CONTEXT              TAMP_BACKUP_REGISTER(20)
> @@ -118,6 +119,9 @@ enum boot_device {
>  #define TAMP_BOOT_INSTANCE_MASK                GENMASK(3, 0)
>  #define TAMP_BOOT_FORCED_MASK          GENMASK(7, 0)
>  #define TAMP_BOOT_DEBUG_ON             BIT(16)
> +#define TAMP_FWU_BOOT_IDX_MASK         GENMASK(3, 0)
> +
> +#define TAMP_FWU_BOOT_IDX_OFFSET       0
>
>  enum forced_boot_mode {
>         BOOT_NORMAL = 0x00,
> diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> index e68bf09955..dff41ed6f6 100644
> --- a/board/st/stm32mp1/stm32mp1.c
> +++ b/board/st/stm32mp1/stm32mp1.c
> @@ -1081,4 +1081,11 @@ int fwu_plat_get_update_index(u32 *update_idx)
>         return ret;
>  }
>
> +void fwu_plat_get_bootidx(void *boot_idx)
> +{
> +       u32 *bootidx = boot_idx;
> +
> +       *bootidx = (readl(TAMP_FWU_BOOT_INFO_REG) >>
> +                   TAMP_FWU_BOOT_IDX_OFFSET) & TAMP_FWU_BOOT_IDX_MASK;
> +}
>  #endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> diff --git a/include/fwu.h b/include/fwu.h
> index 36e58afa29..41774ff9e2 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -46,7 +46,7 @@ int fwu_revert_boot_index(void);
>  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);
>
> -
> +void fwu_plat_get_bootidx(void *boot_idx);
>  int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
>                          int *alt_num);
>  int fwu_plat_get_update_index(u32 *update_idx);
> --
> 2.25.1
>
Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata
  2022-06-09 12:29 ` [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata Sughosh Ganu
@ 2022-06-10 12:07   ` Ilias Apalodimas
  2022-06-13 12:38     ` Sughosh Ganu
  2022-06-20 12:53   ` Michal Simek
  2022-06-21 12:07   ` Patrick DELAUNAY
  2 siblings, 1 reply; 104+ messages in thread
From: Ilias Apalodimas @ 2022-06-10 12:07 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

On Thu, Jun 09, 2022 at 05:59:57PM +0530, Sughosh Ganu wrote:
> Add a command to read the metadata as specified in the FWU
> specification and print the fields of the metadata.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  cmd/Kconfig     |  7 +++++
>  cmd/Makefile    |  1 +
>  cmd/fwu_mdata.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 82 insertions(+)
>  create mode 100644 cmd/fwu_mdata.c
> 
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 09193b61b9..275becd837 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -144,6 +144,13 @@ config CMD_CPU
>  	  internal name) and clock frequency. Other information may be
>  	  available depending on the CPU driver.
>  
> +config CMD_FWU_METADATA
> +	bool "fwu metadata read"
> +	depends on FWU_MULTI_BANK_UPDATE
> +	default y if FWU_MULTI_BANK_UPDATE
> +	help
> +	  Command to read the metadata and dump it's contents
> +
>  config CMD_LICENSE
>  	bool "license"
>  	select BUILD_BIN2C
> diff --git a/cmd/Makefile b/cmd/Makefile
> index 5e43a1e022..259a93bc65 100644
> --- a/cmd/Makefile
> +++ b/cmd/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_CMD_FPGA) += fpga.o
>  obj-$(CONFIG_CMD_FPGAD) += fpgad.o
>  obj-$(CONFIG_CMD_FS_GENERIC) += fs.o
>  obj-$(CONFIG_CMD_FUSE) += fuse.o
> +obj-$(CONFIG_CMD_FWU_METADATA) += fwu_mdata.o
>  obj-$(CONFIG_CMD_GETTIME) += gettime.o
>  obj-$(CONFIG_CMD_GPIO) += gpio.o
>  obj-$(CONFIG_CMD_HVC) += smccc.o
> diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c
> new file mode 100644
> index 0000000000..bc20ca26a3
> --- /dev/null
> +++ b/cmd/fwu_mdata.c
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <command.h>
> +#include <dm.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <log.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include <linux/types.h>
> +
> +static void print_mdata(struct fwu_mdata *mdata)
> +{
> +	int i, j;
> +	struct fwu_image_entry *img_entry;
> +	struct fwu_image_bank_info *img_info;
> +	u32 nimages, nbanks;

nit but we don't really need those two.  Just use the define.

> +
> +	printf("\tFWU Metadata\n");
> +	printf("crc32: %#x\n", mdata->crc32);
> +	printf("version: %#x\n", mdata->version);
> +	printf("active_index: %#x\n", mdata->active_index);
> +	printf("previous_active_index: %#x\n", mdata->previous_active_index);
> +
> +	nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> +	nbanks = CONFIG_FWU_NUM_BANKS;
> +	printf("\tImage Info\n");
> +	for (i = 0; i < nimages; i++) {
> +		img_entry = &mdata->img_entry[i];
> +		printf("\nImage Type Guid: %pUL\n", &img_entry->image_type_uuid);
> +		printf("Location Guid: %pUL\n", &img_entry->location_uuid);
> +		for (j = 0; j < nbanks; j++) {
> +			img_info = &img_entry->img_bank_info[j];
> +			printf("Image Guid:  %pUL\n", &img_info->image_uuid);
> +			printf("Image Acceptance: %#x\n", img_info->accepted);

Can we do 'yes/no' on the image acceptance please?

> +		}
> +	}
> +}
> +
> +int do_fwu_mdata_read(struct cmd_tbl *cmdtp, int flag,
> +		     int argc, char * const argv[])
> +{
> +	struct udevice *dev;
> +	int ret = CMD_RET_SUCCESS;
> +	struct fwu_mdata *mdata = NULL;
> +
> +	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> +		log_err("Unable to get FWU metadata device\n");
> +		return CMD_RET_FAILURE;
> +	}
> +
> +	ret = fwu_get_mdata(&mdata);
> +	if (ret < 0) {
> +		log_err("Unable to get valid FWU metadata\n");
> +		ret = CMD_RET_FAILURE;
> +		goto out;
> +	}
> +
> +	print_mdata(mdata);
> +
> +out:
> +	free(mdata);
> +	return ret;
> +}
> +
> +U_BOOT_CMD(
> +	fwu_mdata_read,	1,	1,	do_fwu_mdata_read,
> +	"Read and print FWU metadata",
> +	""
> +);
> -- 
> 2.25.1
> 

Regards
/Ilias

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-09 16:27   ` Heinrich Schuchardt
@ 2022-06-13 12:33     ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-13 12:33 UTC (permalink / raw)
  To: Heinrich Schuchardt
  Cc: Ilias Apalodimas, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar, u-boot

On Thu, 9 Jun 2022 at 21:58, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>
> On 6/9/22 14:29, Sughosh Ganu wrote:
> > The Dependable Boot specification[1] describes the structure of the
> > firmware accept and revert capsules. These are empty capsules which
> > are used for signalling the acceptance or rejection of the updated
> > firmware by the OS. Add support for generating these empty capsules.
> >
> > [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >   doc/mkeficapsule.1   |  29 ++++++---
> >   tools/eficapsule.h   |   8 +++
> >   tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
> >   3 files changed, 151 insertions(+), 25 deletions(-)

<snip>

> > diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> > index 5f74d23b9e..e8eb6b070d 100644
> > --- a/tools/mkeficapsule.c
> > +++ b/tools/mkeficapsule.c
> > @@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
> >   efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
> >   efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
> >
> > -static const char *opts_short = "g:i:I:v:p:c:m:dh";
> > +static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
> > +
> > +static bool empty_capsule;
> > +static unsigned char capsule;
> > +
> > +enum {
> > +     CAPSULE_NORMAL_BLOB = 0,
> > +     CAPSULE_ACCEPT,
> > +     CAPSULE_REVERT,
> > +} capsule_type;
> >
> >   static struct option options[] = {
> >       {"guid", required_argument, NULL, 'g'},
> > @@ -39,24 +48,47 @@ static struct option options[] = {
> >       {"certificate", required_argument, NULL, 'c'},
> >       {"monotonic-count", required_argument, NULL, 'm'},
> >       {"dump-sig", no_argument, NULL, 'd'},
> > +     {"fw-accept", no_argument, NULL, 'A'},
> > +     {"fw-revert", no_argument, NULL, 'R'},
> >       {"help", no_argument, NULL, 'h'},
> >       {NULL, 0, NULL, 0},
> >   };
> >
> >   static void print_usage(void)
> >   {
> > -     fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > -             "Options:\n"
> > -
> > -             "\t-g, --guid <guid string>    guid for image blob type\n"
> > -             "\t-i, --index <index>         update image index\n"
> > -             "\t-I, --instance <instance>   update hardware instance\n"
> > -             "\t-p, --private-key <privkey file>  private key file\n"
> > -             "\t-c, --certificate <cert file>     signer's certificate file\n"
> > -             "\t-m, --monotonic-count <count>     monotonic count\n"
> > -             "\t-d, --dump_sig              dump signature (*.p7)\n"
> > -             "\t-h, --help                  print a help message\n",
> > -             tool_name);
> > +     if (empty_capsule) {
> > +             if (capsule == CAPSULE_ACCEPT) {
> > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
>
> My expectation is that this function always provides the same output.
>
> If different scenarios allow only specific combinations of arguments you
> may describe it here.

Okay

>
>
> > +                             tool_name);
> > +                     fprintf(stderr, "Options:\n"
> > +                             "\t-A, --fw-accept             firmware accept capsule\n"
> > +                             "\t-g, --guid <guid string>    guid for image blob type\n"
> > +                             "\t-h, --help                  print a help message\n"
> > +                             );
> > +             } else {
> > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > +                             tool_name);
> > +                     fprintf(stderr, "Options:\n"
> > +                             "\t-R, --fw-revert             firmware revert capsule\n"
> > +                             "\t-h, --help                  print a help message\n"
> > +                             );
> > +             }
> > +     } else {
> > +             fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > +                     "Options:\n"
> > +
> > +                     "\t-g, --guid <guid string>    guid for image blob type\n"
> > +                     "\t-i, --index <index>         update image index\n"
> > +                     "\t-I, --instance <instance>   update hardware instance\n"
> > +                     "\t-p, --private-key <privkey file>  private key file\n"
> > +                     "\t-c, --certificate <cert file>     signer's certificate file\n"
> > +                     "\t-m, --monotonic-count <count>     monotonic count\n"
> > +                     "\t-d, --dump_sig              dump signature (*.p7)\n"
> > +                     "\t-A, --fw-accept             firmware accept capsule\n"
>
> "\t-A, --fw-accept             firmware accept capsule, requires GUID\n"
>
> > +                     "\t-R, --fw-revert             firmware revert capsule\n"
>
> "\t-R, --fw-revert             firmware revert capsule, takes no GUID\n"
>
> > +                     "\t-h, --help                  print a help message\n",
> > +                     tool_name);
> > +     }
> >   }
> >
> >   /**
> > @@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
> >       buf[7] = c;
> >   }
> >
> > +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> > +{
> > +     struct efi_capsule_header header;
> > +     FILE *f = NULL;
> > +     int ret = -1;
> > +     efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
> > +     efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
> > +     efi_guid_t payload, capsule_guid;
> > +
> > +     f = fopen(path, "w");
> > +     if (!f) {
> > +             fprintf(stderr, "cannot open %s\n", path);
> > +             goto err;
> > +     }
> > +
> > +     capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
> > +
> > +     memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
> > +     header.header_size = sizeof(header);
> > +     header.flags = 0;
> > +
> > +     header.capsule_image_size = fw_accept ?
> > +             sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
> > +
> > +     if (write_capsule_file(f, &header, sizeof(header),
> > +                            "Capsule header"))
> > +             goto err;
> > +
> > +     if (fw_accept) {
> > +             memcpy(&payload, guid, sizeof(efi_guid_t));
> > +             if (write_capsule_file(f, &payload, sizeof(payload),
> > +                                    "FW Accept Capsule Payload"))
> > +                     goto err;
> > +     }
> > +
> > +     ret = 0;
> > +
> > +err:
> > +     if (f)
> > +             fclose(f);
> > +
> > +     return ret;
> > +}
> > +
> >   /**
> >    * main - main entry function of mkeficapsule
> >    * @argc:   Number of arguments
> > @@ -639,22 +715,49 @@ int main(int argc, char **argv)
>
> >               case 'd':
> >                       dump_sig = 1;
> >                       break;
> > +             case 'A':
> > +                     capsule |= CAPSULE_ACCEPT;
> > +                     break;
> > +             case 'R':
> > +                     capsule |= CAPSULE_REVERT;
> > +                     break;
> >               case 'h':
>
> You must handle '?' and ':' here too. Just use
>
> default:

Okay

>
>
> >                       print_usage();
> >                       exit(EXIT_SUCCESS);
> >               }
> >       }
> >
> > +     if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
> > +             fprintf(stderr,
> > +                     "Select either of Accept or Revert capsule generation\n");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     empty_capsule = (capsule == CAPSULE_ACCEPT ||
> > +                      capsule == CAPSULE_REVERT);
> > +
> >       /* check necessary parameters */
> > -     if ((argc != optind + 2) || !guid ||
> > -         ((privkey_file && !cert_file) ||
> > -          (!privkey_file && cert_file))) {
> > +     if ((!empty_capsule &&
> > +         ((argc != optind + 2) || !guid ||
> > +          ((privkey_file && !cert_file) ||
> > +           (!privkey_file && cert_file)))) ||
> > +         (empty_capsule &&
> > +         ((argc != optind + 1) ||
> > +          ((capsule == CAPSULE_ACCEPT) && !guid) ||
> > +          ((capsule == CAPSULE_REVERT) && guid)))) {
>
> Please, write a message explaining to the user what was wrong, e.g.
>
> "Option -A does not take a GUID" or
> "Option -R requires a GUID"

We are calling the print_usage function where I am adding the
additional information that you suggested above. I think that would
suffice. Else we are basically repeating the same information twice.

>
>
> >               print_usage();
> >               exit(EXIT_FAILURE);
> >       }
> >
> > -     if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
> > -                      mcount, privkey_file, cert_file) < 0) {
> > +     if (empty_capsule) {
> > +             if (create_empty_capsule(argv[argc - 1], guid,
> > +                                      capsule == CAPSULE_ACCEPT) < 0) {
> > +                     fprintf(stderr, "Creating empty capsule failed\n");
>
> The called function should provide a message that describes what went wrong.

The create_empty_capsule function calls the write_capsule_file
function for creation of the capsule file, and passes the string that
is to be printed in case of an error condition.

-sughosh

>
> Best regards
>
> Heinrich
>
>
> > +                     exit(EXIT_FAILURE);
> > +             }
> > +     } else  if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
> > +                              index, instance, mcount, privkey_file,
> > +                              cert_file) < 0) {
> >               fprintf(stderr, "Creating firmware capsule failed\n");
> >               exit(EXIT_FAILURE);
> >       }
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata
  2022-06-10 11:53   ` Ilias Apalodimas
@ 2022-06-13 12:37     ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-13 12:37 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: u-boot, Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

hi Ilias,

On Fri, 10 Jun 2022 at 17:23, Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>
> Hi Sughosh,
>
> On Thu, Jun 09, 2022 at 05:59:53PM +0530, Sughosh Ganu wrote:
> > Add helper functions needed for accessing the FWU metadata which
> > contains information on the updatable images. These functions have
> > been added for the STM32MP157C-DK2 board which has the updatable
> > images on the uSD card, formatted as GPT partitions.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  board/st/stm32mp1/stm32mp1.c | 115 +++++++++++++++++++++++++++++++++++
> >  include/fwu.h                |   2 +
> >  2 files changed, 117 insertions(+)
> >
> > diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> > index 62d98ad776..e68bf09955 100644
> > --- a/board/st/stm32mp1/stm32mp1.c
> > +++ b/board/st/stm32mp1/stm32mp1.c
> > @@ -7,9 +7,11 @@
> >
> >  #include <common.h>
> >  #include <adc.h>
> > +#include <blk.h>
> >  #include <bootm.h>
> >  #include <clk.h>
> >  #include <config.h>
> > +#include <dfu.h>
> >  #include <dm.h>
> >  #include <efi_loader.h>
> >  #include <env.h>
> > @@ -25,9 +27,11 @@
> >  #include <log.h>
> >  #include <malloc.h>
> >  #include <misc.h>
> > +#include <mmc.h>
> >  #include <mtd_node.h>
> >  #include <net.h>
> >  #include <netdev.h>
> > +#include <part.h>
> >  #include <phy.h>
> >  #include <remoteproc.h>
> >  #include <reset.h>
> > @@ -967,3 +971,114 @@ static void board_copro_image_process(ulong fw_image, size_t fw_size)
> >  }
> >
> >  U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_COPRO, board_copro_image_process);
> > +
> > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +
> > +static int get_gpt_dfu_identifier(struct blk_desc *desc, efi_guid_t *image_guid)
> > +{
> > +     int i;
> > +     struct disk_partition info;
> > +     efi_guid_t unique_part_guid;
> > +
> > +     for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) {
> > +             if (part_get_info(desc, i, &info))
> > +                     continue;
> > +             uuid_str_to_bin(info.uuid, unique_part_guid.b,
> > +                             UUID_STR_FORMAT_GUID);
> > +
> > +             if (!guidcmp(&unique_part_guid, image_guid))
> > +                     return i;
> > +     }
> > +
> > +     log_err("No partition found with image_guid %pUs\n", image_guid);
> > +     return -ENOENT;
> > +}
> > +
> > +static int gpt_plat_get_alt_num(struct blk_desc *desc, efi_guid_t *image_guid,
> > +                             int *alt_num)
>
> Does this really need to be defined per platform?
>
> Most of the stuff in here are generic apart from the info of were  the
> metadata is stored.  So wouldn't it better to move this in the generic API
> and add an argument for the dfu device type?
>
> The platform portion would then just call this function with an extra arg
> e.g DFU_DEV_MMC

Yes, it makes sense. I will make the change that you suggest. Thanks.

-sughosh

>
> > +{
> > +     int ret = -1;
> > +     int i, part, dev_num;
> > +     int nalt;
> > +     struct dfu_entity *dfu;
> > +
> > +     dev_num = desc->devnum;
> > +     part = get_gpt_dfu_identifier(desc, image_guid);
> > +     if (part < 0)
> > +             return -ENOENT;
> > +
> > +     dfu_init_env_entities(NULL, NULL);
>
> [...]
>
>
> Regards
> /Ilias

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata
  2022-06-10 12:07   ` Ilias Apalodimas
@ 2022-06-13 12:38     ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-13 12:38 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: u-boot, Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

hi Ilias,

On Fri, 10 Jun 2022 at 17:37, Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>
> On Thu, Jun 09, 2022 at 05:59:57PM +0530, Sughosh Ganu wrote:
> > Add a command to read the metadata as specified in the FWU
> > specification and print the fields of the metadata.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  cmd/Kconfig     |  7 +++++
> >  cmd/Makefile    |  1 +
> >  cmd/fwu_mdata.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 82 insertions(+)
> >  create mode 100644 cmd/fwu_mdata.c
> >
> > diff --git a/cmd/Kconfig b/cmd/Kconfig
> > index 09193b61b9..275becd837 100644
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -144,6 +144,13 @@ config CMD_CPU
> >         internal name) and clock frequency. Other information may be
> >         available depending on the CPU driver.
> >
> > +config CMD_FWU_METADATA
> > +     bool "fwu metadata read"
> > +     depends on FWU_MULTI_BANK_UPDATE
> > +     default y if FWU_MULTI_BANK_UPDATE
> > +     help
> > +       Command to read the metadata and dump it's contents
> > +
> >  config CMD_LICENSE
> >       bool "license"
> >       select BUILD_BIN2C
> > diff --git a/cmd/Makefile b/cmd/Makefile
> > index 5e43a1e022..259a93bc65 100644
> > --- a/cmd/Makefile
> > +++ b/cmd/Makefile
> > @@ -76,6 +76,7 @@ obj-$(CONFIG_CMD_FPGA) += fpga.o
> >  obj-$(CONFIG_CMD_FPGAD) += fpgad.o
> >  obj-$(CONFIG_CMD_FS_GENERIC) += fs.o
> >  obj-$(CONFIG_CMD_FUSE) += fuse.o
> > +obj-$(CONFIG_CMD_FWU_METADATA) += fwu_mdata.o
> >  obj-$(CONFIG_CMD_GETTIME) += gettime.o
> >  obj-$(CONFIG_CMD_GPIO) += gpio.o
> >  obj-$(CONFIG_CMD_HVC) += smccc.o
> > diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c
> > new file mode 100644
> > index 0000000000..bc20ca26a3
> > --- /dev/null
> > +++ b/cmd/fwu_mdata.c
> > @@ -0,0 +1,74 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#include <command.h>
> > +#include <dm.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +#include <log.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +
> > +#include <linux/types.h>
> > +
> > +static void print_mdata(struct fwu_mdata *mdata)
> > +{
> > +     int i, j;
> > +     struct fwu_image_entry *img_entry;
> > +     struct fwu_image_bank_info *img_info;
> > +     u32 nimages, nbanks;
>
> nit but we don't really need those two.  Just use the define.

Okay. Will change.

>
> > +
> > +     printf("\tFWU Metadata\n");
> > +     printf("crc32: %#x\n", mdata->crc32);
> > +     printf("version: %#x\n", mdata->version);
> > +     printf("active_index: %#x\n", mdata->active_index);
> > +     printf("previous_active_index: %#x\n", mdata->previous_active_index);
> > +
> > +     nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> > +     nbanks = CONFIG_FWU_NUM_BANKS;
> > +     printf("\tImage Info\n");
> > +     for (i = 0; i < nimages; i++) {
> > +             img_entry = &mdata->img_entry[i];
> > +             printf("\nImage Type Guid: %pUL\n", &img_entry->image_type_uuid);
> > +             printf("Location Guid: %pUL\n", &img_entry->location_uuid);
> > +             for (j = 0; j < nbanks; j++) {
> > +                     img_info = &img_entry->img_bank_info[j];
> > +                     printf("Image Guid:  %pUL\n", &img_info->image_uuid);
> > +                     printf("Image Acceptance: %#x\n", img_info->accepted);
>
> Can we do 'yes/no' on the image acceptance please?

Okay. Will change.

-sughosh

>
> > +             }
> > +     }
> > +}
> > +
> > +int do_fwu_mdata_read(struct cmd_tbl *cmdtp, int flag,
> > +                  int argc, char * const argv[])
> > +{
> > +     struct udevice *dev;
> > +     int ret = CMD_RET_SUCCESS;
> > +     struct fwu_mdata *mdata = NULL;
> > +
> > +     if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> > +             log_err("Unable to get FWU metadata device\n");
> > +             return CMD_RET_FAILURE;
> > +     }
> > +
> > +     ret = fwu_get_mdata(&mdata);
> > +     if (ret < 0) {
> > +             log_err("Unable to get valid FWU metadata\n");
> > +             ret = CMD_RET_FAILURE;
> > +             goto out;
> > +     }
> > +
> > +     print_mdata(mdata);
> > +
> > +out:
> > +     free(mdata);
> > +     return ret;
> > +}
> > +
> > +U_BOOT_CMD(
> > +     fwu_mdata_read, 1,      1,      do_fwu_mdata_read,
> > +     "Read and print FWU metadata",
> > +     ""
> > +);
> > --
> > 2.25.1
> >
>
> Regards
> /Ilias

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-09 12:29 ` [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules Sughosh Ganu
  2022-06-09 16:27   ` Heinrich Schuchardt
@ 2022-06-15  5:11   ` Takahiro Akashi
  2022-06-15 10:49     ` Sughosh Ganu
  2022-06-21 10:58   ` Etienne Carriere
  2 siblings, 1 reply; 104+ messages in thread
From: Takahiro Akashi @ 2022-06-15  5:11 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

On Thu, Jun 09, 2022 at 05:59:58PM +0530, Sughosh Ganu wrote:
> The Dependable Boot specification[1] describes the structure of the
> firmware accept and revert capsules. These are empty capsules which
> are used for signalling the acceptance or rejection of the updated
> firmware by the OS. Add support for generating these empty capsules.
> 
> [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  doc/mkeficapsule.1   |  29 ++++++---
>  tools/eficapsule.h   |   8 +++
>  tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
>  3 files changed, 151 insertions(+), 25 deletions(-)
> 
> diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
> index 09bdc24295..77ca061efd 100644
> --- a/doc/mkeficapsule.1
> +++ b/doc/mkeficapsule.1
> @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
>  
>  .SH SYNOPSIS
>  .B mkeficapsule
> -.RI [ options "] " image-blob " " capsule-file
> +.RI [ options ] " " [ image-blob ] " " capsule-file
>  
>  .SH "DESCRIPTION"
>  .B mkeficapsule
> @@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
>  In this case, the update will be authenticated by verifying the signature
>  before applying.
>  
> +Additionally, an empty capsule file can be generated for acceptance or
> +rejection of firmware images by a governing component like an Operating
> +System. The empty capsules do not require an image-blob input file.
> +
> +
>  .B mkeficapsule
> -takes any type of image files, including:
> +takes any type of image files when generating non empty capsules, including:
>  .TP
>  .I raw image
>  format is a single binary blob of any type of firmware.
> @@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
>  This type of image file can be generated by
>  .BR mkimage .
>  
> -.PP
> -If you want to use other types than above two, you should explicitly
> -specify a guid for the FMP driver.
> -
>  .SH "OPTIONS"
> +
>  .TP
>  .BI "-g\fR,\fB --guid " guid-string
>  Specify guid for image blob type. The format is:
>      xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
>  
>  The first three elements are in little endian, while the rest
> -is in big endian.
> +is in big endian. The option must be specified for all non empty and
> +image acceptance capsules

"image acceptance" -> "firmware acceptance"

I don't still understand why we need a guid for acceptance
while revert doesn't require it.
I believe that firmware update is "all or nothing", isn't it?

If there is a good reason, please describe a possible/expected
scenario.

>  .TP
>  .BI "-i\fR,\fB --index " index
> @@ -57,6 +60,18 @@ Specify an image index
>  .BI "-I\fR,\fB --instance " instance
>  Specify a hardware instance
>  
> +.PP
> +For generation of firmware accept empty capsule
> +.BR --guid
> +is mandatory
> +.TP
> +.BI "-A\fR,\fB --fw-accept "
> +Generate a firmware acceptance empty capsule
> +
> +.TP
> +.BI "-R\fR,\fB --fw-revert "
> +Generate a firmware revert empty capsule
> +
>  .TP
>  .BR -h ", " --help
>  Print a help message
> diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> index d63b831443..072a4b5598 100644
> --- a/tools/eficapsule.h
> +++ b/tools/eficapsule.h
> @@ -41,6 +41,14 @@ typedef struct {
>  	EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
>  		 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
>  
> +#define FW_ACCEPT_OS_GUID \
> +	EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
> +		 0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
> +
> +#define FW_REVERT_OS_GUID \
> +	EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
> +		 0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
> +
>  /* flags */
>  #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
>  
> diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> index 5f74d23b9e..e8eb6b070d 100644
> --- a/tools/mkeficapsule.c
> +++ b/tools/mkeficapsule.c
> @@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
>  efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
>  efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
>  
> -static const char *opts_short = "g:i:I:v:p:c:m:dh";
> +static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
> +
> +static bool empty_capsule;
> +static unsigned char capsule;
> +
> +enum {
> +	CAPSULE_NORMAL_BLOB = 0,
> +	CAPSULE_ACCEPT,
> +	CAPSULE_REVERT,
> +} capsule_type;
>  
>  static struct option options[] = {
>  	{"guid", required_argument, NULL, 'g'},
> @@ -39,24 +48,47 @@ static struct option options[] = {
>  	{"certificate", required_argument, NULL, 'c'},
>  	{"monotonic-count", required_argument, NULL, 'm'},
>  	{"dump-sig", no_argument, NULL, 'd'},
> +	{"fw-accept", no_argument, NULL, 'A'},
> +	{"fw-revert", no_argument, NULL, 'R'},
>  	{"help", no_argument, NULL, 'h'},
>  	{NULL, 0, NULL, 0},
>  };
>  
>  static void print_usage(void)
>  {
> -	fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> -		"Options:\n"
> -
> -		"\t-g, --guid <guid string>    guid for image blob type\n"
> -		"\t-i, --index <index>         update image index\n"
> -		"\t-I, --instance <instance>   update hardware instance\n"
> -		"\t-p, --private-key <privkey file>  private key file\n"
> -		"\t-c, --certificate <cert file>     signer's certificate file\n"
> -		"\t-m, --monotonic-count <count>     monotonic count\n"
> -		"\t-d, --dump_sig              dump signature (*.p7)\n"
> -		"\t-h, --help                  print a help message\n",
> -		tool_name);
> +	if (empty_capsule) {
> +		if (capsule == CAPSULE_ACCEPT) {
> +			fprintf(stderr, "Usage: %s [options] <output file>\n",
> +				tool_name);
> +			fprintf(stderr, "Options:\n"
> +				"\t-A, --fw-accept             firmware accept capsule\n"
> +				"\t-g, --guid <guid string>    guid for image blob type\n"
> +				"\t-h, --help                  print a help message\n"
> +				);
> +		} else {
> +			fprintf(stderr, "Usage: %s [options] <output file>\n",
> +				tool_name);
> +			fprintf(stderr, "Options:\n"
> +				"\t-R, --fw-revert             firmware revert capsule\n"
> +				"\t-h, --help                  print a help message\n"
> +				);
> +		}
> +	} else {
> +		fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> +			"Options:\n"
> +
> +			"\t-g, --guid <guid string>    guid for image blob type\n"
> +			"\t-i, --index <index>         update image index\n"
> +			"\t-I, --instance <instance>   update hardware instance\n"
> +			"\t-p, --private-key <privkey file>  private key file\n"
> +			"\t-c, --certificate <cert file>     signer's certificate file\n"
> +			"\t-m, --monotonic-count <count>     monotonic count\n"
> +			"\t-d, --dump_sig              dump signature (*.p7)\n"
> +			"\t-A, --fw-accept             firmware accept capsule\n"
> +			"\t-R, --fw-revert             firmware revert capsule\n"
> +			"\t-h, --help                  print a help message\n",
> +			tool_name);
> +	}
>  }
>  
>  /**
> @@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
>  	buf[7] = c;
>  }
>  
> +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> +{
> +	struct efi_capsule_header header;
> +	FILE *f = NULL;
> +	int ret = -1;
> +	efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
> +	efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
> +	efi_guid_t payload, capsule_guid;
> +
> +	f = fopen(path, "w");
> +	if (!f) {
> +		fprintf(stderr, "cannot open %s\n", path);
> +		goto err;
> +	}
> +
> +	capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
> +
> +	memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));

  -> guidcpy()

> +	header.header_size = sizeof(header);
> +	header.flags = 0;
> +
> +	header.capsule_image_size = fw_accept ?
> +		sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
> +
> +	if (write_capsule_file(f, &header, sizeof(header),
> +			       "Capsule header"))
> +		goto err;
> +
> +	if (fw_accept) {
> +		memcpy(&payload, guid, sizeof(efi_guid_t));

ditto

> +		if (write_capsule_file(f, &payload, sizeof(payload),
> +				       "FW Accept Capsule Payload"))
> +			goto err;
> +	}
> +
> +	ret = 0;
> +
> +err:
> +	if (f)
> +		fclose(f);
> +
> +	return ret;
> +}
> +
>  /**
>   * main - main entry function of mkeficapsule
>   * @argc:	Number of arguments
> @@ -639,22 +715,49 @@ int main(int argc, char **argv)
>  		case 'd':
>  			dump_sig = 1;
>  			break;
> +		case 'A':
> +			capsule |= CAPSULE_ACCEPT;
> +			break;
> +		case 'R':
> +			capsule |= CAPSULE_REVERT;
> +			break;
>  		case 'h':
>  			print_usage();
>  			exit(EXIT_SUCCESS);
>  		}
>  	}
>  
> +	if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
> +		fprintf(stderr,
> +			"Select either of Accept or Revert capsule generation\n");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	empty_capsule = (capsule == CAPSULE_ACCEPT ||
> +			 capsule == CAPSULE_REVERT);
> +

So empty_capsule is redundant as empty_capsule is equivalent with
"capsule == CAPSULE_NORMAL_BLOB".
I think that a single variable, say capsule_type, is enough.

>  	/* check necessary parameters */
> -	if ((argc != optind + 2) || !guid ||
> -	    ((privkey_file && !cert_file) ||
> -	     (!privkey_file && cert_file))) {
> +	if ((!empty_capsule &&
> +	    ((argc != optind + 2) || !guid ||
> +	     ((privkey_file && !cert_file) ||
> +	      (!privkey_file && cert_file)))) ||
> +	    (empty_capsule &&
> +	    ((argc != optind + 1) ||
> +	     ((capsule == CAPSULE_ACCEPT) && !guid) ||
> +	     ((capsule == CAPSULE_REVERT) && guid)))) {
>  		print_usage();
>  		exit(EXIT_FAILURE);
>  	}
>  
> -	if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
> -			 mcount, privkey_file, cert_file) < 0) {
> +	if (empty_capsule) {
> +		if (create_empty_capsule(argv[argc - 1], guid,
> +					 capsule == CAPSULE_ACCEPT) < 0) {

        if (capsule_type != CAPSULE_NORMAL_BLOB)
                create_empty_capsule(..., capsule_type == CAPSULE_ACCEPT);

Simple is the best :)

-Takahiro Akashi
> +			fprintf(stderr, "Creating empty capsule failed\n");
> +			exit(EXIT_FAILURE);
> +		}
> +	} else 	if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
> +				 index, instance, mcount, privkey_file,
> +				 cert_file) < 0) {
>  		fprintf(stderr, "Creating firmware capsule failed\n");
>  		exit(EXIT_FAILURE);
>  	}
> -- 
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox
  2022-06-09 12:30 ` [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox Sughosh Ganu
@ 2022-06-15  5:37   ` Takahiro Akashi
  2022-06-15 12:10     ` Sughosh Ganu
  2022-06-15  6:30   ` Takahiro Akashi
  1 sibling, 1 reply; 104+ messages in thread
From: Takahiro Akashi @ 2022-06-15  5:37 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> Add a python test script for testing the FWU Multi Bank Update
> functionality on the sandbox platform. The script has test cases for
> updation of the u-boot binary and the u-boot environment image to the
> non active bank.
> 
> The FWU metadata is being stored on the SPI NOR flash, along with the
> updatable images, and the FWU metadata driver for MTD devices is being
> used for accessing the metadata. Certain FWU boottime checks are
> bypassed due to the unavailability of the EFI variable access very
> early in the boot on the sandbox platform -- the variable access is
> only available once the block disk image has been bound through the
> host interface.
> 
> The FWU Multi Bank feature being enabled on the sandbox64 platform is
> enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> the FIT FMP instance is being removed -- the FIT FMP is already being
> tested on the sandbox flattree variant.

IMO,
Thinking of the importance of this feature, FIT FMP should also be
tested *with FWU*.

> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  arch/sandbox/Kconfig                          |   6 +
>  arch/sandbox/dts/test.dts                     |  45 ++-
>  board/sandbox/sandbox.c                       |  49 +++
>  configs/sandbox64_defconfig                   |  12 +-
>  include/fwu.h                                 |   2 +
>  lib/fwu_updates/Kconfig                       |   2 +-
>  lib/fwu_updates/fwu.c                         |  18 +-
>  lib/fwu_updates/fwu_mtd.c                     |  10 +-
>  .../test_capsule_firmware_fit.py              |   1 -
>  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
>  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
>  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
>  12 files changed, 587 insertions(+), 13 deletions(-)
>  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
>  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
>  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> 
> diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
> index 5f55c7f28e..2985572083 100644
> --- a/arch/sandbox/Kconfig
> +++ b/arch/sandbox/Kconfig
> @@ -84,3 +84,9 @@ config SYS_FDT_LOAD_ADDR
>  	  See `doc/arch/sandbox.rst` for more information.
>  
>  endmenu
> +
> +config FWU_NUM_BANKS
> +       default 2
> +
> +config FWU_NUM_IMAGES_PER_BANK
> +	default 2
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index 8f93775ff4..f11fa8733f 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -1145,11 +1145,48 @@
>  		pinctrl-names = "default";
>  		pinctrl-0 = <&pinmux_spi0_pins>;
>  
> -		spi.bin@0 {
> +		spi0: spi.bin@0 {
>  			reg = <0>;
>  			compatible = "spansion,m25p16", "jedec,spi-nor";
>  			spi-max-frequency = <40000000>;
>  			sandbox,filename = "spi.bin";
> +
> +			partitions {
> +				compatible = "fixed-partitions";
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				uuid = "af9e8c96-bec5-48be-9dab-3491c04b1366";
> +
> +				partition@0 {
> +					label = "Metadata";
> +					reg = <0x0 0x20000>;
> +				};
> +
> +				/* FWU Multi bank update partitions */
> +				partition@100000 {
> +					label = "U-Boot-Bank0";
> +					reg = <0x100000 0x10000>;
> +					uuid = "a8f61787-5d68-4c9d-9e4a-37bb0df99da7";
> +				};
> +
> +				partition@120000 {
> +					label = "U-Boot-ENV-Bank0";
> +					reg = <0x120000 0x10000>;
> +					uuid = "ea9d59af-e0e8-4ef5-9b16-4c80ff67524c";
> +				};
> +
> +				partition@140000 {
> +					label = "U-Boot-Bank1";
> +					reg = <0x140000 0x10000>;
> +					uuid = "52377abf-c4e4-4d0b-aafd-ba081a500847";
> +				};
> +
> +				partition@160000 {
> +					label = "U-Boot-ENV-Bank1";
> +					reg = <0x160000 0x10000>;
> +					uuid = "4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3";
> +				};
> +			};
>  		};
>  		spi.bin@1 {
>  			reg = <1>;
> @@ -1633,6 +1670,12 @@
>  			compatible = "sandbox,regmap_test";
>  		};
>  	};
> +
> +	fwu-mdata {
> +		compatible = "u-boot,fwu-mdata-mtd";
> +		fwu-mdata-store = <&spi0>;
> +		mdata-offsets = <0x0 0x10000>;
> +	};
>  };
>  
>  #include "sandbox_pmic.dtsi"
> diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
> index e054f300c4..222c36d301 100644
> --- a/board/sandbox/sandbox.c
> +++ b/board/sandbox/sandbox.c
> @@ -6,13 +6,18 @@
>  #include <common.h>
>  #include <cpu_func.h>
>  #include <cros_ec.h>
> +#include <dfu.h>
>  #include <dm.h>
>  #include <efi.h>
>  #include <efi_loader.h>
>  #include <env_internal.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
>  #include <init.h>
>  #include <led.h>
> +#include <mtd.h>
>  #include <os.h>
> +#include <uuid.h>
>  #include <asm/global_data.h>
>  #include <asm/test.h>
>  #include <asm/u-boot-sandbox.h>
> @@ -51,8 +56,15 @@ struct efi_fw_image fw_images[] = {
>  };
>  
>  struct efi_capsule_update_info update_info = {
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +	.dfu_string = "mtd nor0=u-boot-bin-a raw 0x100000 0x10000;"
> +		"u-boot-env-a raw 0x120000 0x10000;"
> +		"u-boot-bin-b raw 0x140000 0x10000;"
> +		"u-boot-env-b raw 0x160000 0x10000",
> +#else
>  	.dfu_string = "sf 0:0=u-boot-bin raw 0x100000 0x50000;"
>  		"u-boot-env raw 0x150000 0x200000",
> +#endif
>  	.images = fw_images,
>  };
>  
> @@ -155,3 +167,40 @@ int board_late_init(void)
>  	return 0;
>  }
>  #endif
> +
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
> +			 efi_guid_t *image_id, int *alt_num)
> +{
> +	return fwu_get_mtd_alt_num(image_id, alt_num, "nor0", 1);
> +}
> +
> +int fwu_plat_get_update_index(u32 *update_idx)
> +{
> +	int ret;
> +	u32 active_idx;
> +
> +	ret = fwu_get_active_index(&active_idx);
> +
> +	if (ret < 0)
> +		return -1;
> +
> +	*update_idx = active_idx ^= 0x1;
> +
> +	return ret;
> +}
> +
> +void fwu_plat_get_bootidx(void *boot_idx)
> +{
> +	int ret;
> +	u32 active_idx;
> +	u32 *bootidx = boot_idx;
> +
> +	ret = fwu_get_active_index(&active_idx);
> +
> +	if (ret < 0)
> +		*bootidx = -1;
> +
> +	*bootidx = active_idx;
> +}
> +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
> index d7f22b39ae..7a813b46a5 100644
> --- a/configs/sandbox64_defconfig
> +++ b/configs/sandbox64_defconfig
> @@ -244,9 +244,19 @@ CONFIG_LZ4=y
>  CONFIG_ERRNO_STR=y
>  CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
>  CONFIG_EFI_CAPSULE_ON_DISK=y
> -CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
>  CONFIG_EFI_SECURE_BOOT=y
>  CONFIG_TEST_FDTDEC=y
>  CONFIG_UNIT_TEST=y
>  CONFIG_UT_TIME=y
>  CONFIG_UT_DM=y
> +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
> +CONFIG_DM_FWU_MDATA=y
> +CONFIG_FWU_MULTI_BANK_UPDATE=y
> +CONFIG_FWU_MDATA_MTD=y
> +CONFIG_CMD_FWU_METADATA=y
> +CONFIG_TOOLS_MKFWUMDATA=y
> +CONFIG_DM_SPI_FLASH=y
> +CONFIG_CMD_MTD=y
> +CONFIG_DFU_MTD=y
> +CONFIG_DM_MTD=y
> +CONFIG_SPI_FLASH_MTD=y
> diff --git a/include/fwu.h b/include/fwu.h
> index fadbfedd07..9e550182eb 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -8,6 +8,8 @@
>  
>  #include <blk.h>
>  #include <efi.h>
> +#include <fwu_mdata.h>
> +#include <mtd.h>
>  
>  #include <linux/types.h>
>  
> diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
> index 6de28e0c9c..43bed7729c 100644
> --- a/lib/fwu_updates/Kconfig
> +++ b/lib/fwu_updates/Kconfig
> @@ -2,7 +2,7 @@ config FWU_MULTI_BANK_UPDATE
>  	bool "Enable FWU Multi Bank Update Feature"
>  	depends on EFI_HAVE_CAPSULE_SUPPORT
>  	select PARTITION_TYPE_GUID
> -	select EFI_SETUP_EARLY
> +	select EFI_SETUP_EARLY if !SANDBOX
>  	help
>  	  Feature for updating firmware images on platforms having
>  	  multiple banks(copies) of the firmware images. One of the
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> index 422ef58661..f2c10d836b 100644
> --- a/lib/fwu_updates/fwu.c
> +++ b/lib/fwu_updates/fwu.c
> @@ -185,12 +185,22 @@ int fwu_boottime_checks(void)
>  		return 0;
>  	}
>  
> -	if (efi_init_obj_list() != EFI_SUCCESS)
> -		return 0;
> +	/*
> +	 * On the sandbox platform, the EFI variable
> +	 * access is available only after binding the
> +	 * disk image with the host interface. Skip
> +	 * the Trial State check on sandbox.
> +	 */
> +	if (!IS_ENABLED(CONFIG_SANDBOX)) {
> +		if (efi_init_obj_list() != EFI_SUCCESS)
> +			return 0;
>  
> -	ret = fwu_trial_state_check();
> -	if (!ret)
> +		ret = fwu_trial_state_check();
> +		if (!ret)
> +			boottime_check = 1;
> +	} else {
>  		boottime_check = 1;
> +	}
>  
>  	return 0;
>  }
> diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
> index 3137f8635c..3a9ad70203 100644
> --- a/lib/fwu_updates/fwu_mtd.c
> +++ b/lib/fwu_updates/fwu_mtd.c
> @@ -84,11 +84,11 @@ int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
>  int gen_image_alt_info(char *buf, size_t len, int sidx,
>  		       struct fwu_image_entry *img, struct mtd_info *mtd)
>  {
> -	char *p = buf, *end = buf + len;
> -	char uuidbuf[UUID_STR_LEN + 1];
> -	ofnode node, parts_node;
> -	const char *suuid;
>  	int i;
> +	const char *suuid;
> +	ofnode node, parts_node;
> +	char uuidbuf[UUID_STR_LEN + 1];
> +	char *p = buf, *end = buf + len;
>  
>  	/* Find partition node under given MTD device. */
>  	parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
> @@ -145,7 +145,7 @@ int gen_image_alt_info(char *buf, size_t len, int sidx,
>  
>  int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
>  {
> -	struct fwu_mdata *mdata;
> +	struct fwu_mdata *mdata = NULL;
>  	int i, l, ret;
>  
>  	ret = fwu_get_mdata(&mdata);
> diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> index 5bef84958b..93bc5ed44b 100644
> --- a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> @@ -13,7 +13,6 @@ import pytest
>  from capsule_defs import *
>  
>  
> -@pytest.mark.boardspec('sandbox64')
>  @pytest.mark.boardspec('sandbox_flattree')
>  @pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
>  @pytest.mark.buildconfigspec('efi_capsule_on_disk')
> diff --git a/test/py/tests/test_fwu_updates/capsule_defs.py b/test/py/tests/test_fwu_updates/capsule_defs.py
> new file mode 100644
> index 0000000000..59b40f11bd
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/capsule_defs.py
> @@ -0,0 +1,10 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +
> +# Directories
> +CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'
> +CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
> +
> +# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and
> +# you need build a newer version on your own.
> +# The path must terminate with '/' if it is not null.
> +EFITOOLS_PATH = ''
> diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> new file mode 100644
> index 0000000000..cdf824c3be
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/conftest.py
> @@ -0,0 +1,78 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +# Copyright (c) 2020, Linaro Limited
> +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>

If this file is exactly same as test_efi_capsule/conftest.py,
why not move all the tests (test_fwu_updates.py) to test_efi_capsule?

The basic scenario of updating firmware, u-boot.bin and u-boot.env,
is also the same, isn't it? The only difference is whether FWU_MULTI_BANK_UPDATE
is enabled or not.

-Takahiro Akashi

> +
> +import os
> +import os.path
> +import re
> +from subprocess import call, check_call, check_output, CalledProcessError
> +import pytest
> +from capsule_defs import *
> +
> +#
> +# Fixture for UEFI capsule test
> +#
> +
> +@pytest.fixture(scope='session')
> +def efi_capsule_data(request, u_boot_config):
> +    """Set up a file system to be used in UEFI capsule and
> +       authentication test.
> +
> +    Args:
> +        request: Pytest request object.
> +        u_boot_config: U-boot configuration.
> +
> +    Return:
> +        A path to disk image to be used for testing
> +    """
> +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> +
> +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> +    data_dir = mnt_point + CAPSULE_DATA_DIR
> +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> +
> +    try:
> +        # Create a target device
> +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> +
> +        check_call('rm -rf %s' % mnt_point, shell=True)
> +        check_call('mkdir -p %s' % data_dir, shell=True)
> +        check_call('mkdir -p %s' % install_dir, shell=True)
> +
> +        # Create capsule files
> +        # two regions: one for u-boot.bin and the other for u-boot.env
> +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> +
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +
> +        # Create a disk image with EFI system partition
> +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> +                   (mnt_point, image_path), shell=True)
> +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> +                   image_path, shell=True)
> +
> +    except CalledProcessError as exception:
> +        pytest.skip('Setup failed: %s' % exception.cmd)
> +        return
> +    else:
> +        yield image_path
> +    finally:
> +        call('rm -rf %s' % mnt_point, shell=True)
> +        call('rm -f %s' % image_path, shell=True)
> +        call('rm -f ./spi.bin', shell=True)
> diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> new file mode 100644
> index 0000000000..d9dff3afaf
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> @@ -0,0 +1,367 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +# Copyright (c) 2022, Linaro Limited
> +#
> +# FWU Multi Bank Firmware Update Test
> +
> +"""
> +This test verifies FWU Multi Bank firmware update for raw images
> +"""
> +
> +from subprocess import check_call, check_output, CalledProcessError
> +import pytest
> +from capsule_defs import *
> +
> +
> +@pytest.mark.boardspec('sandbox64')
> +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> +@pytest.mark.buildconfigspec('dfu')
> +@pytest.mark.buildconfigspec('dfu_sf')
> +@pytest.mark.buildconfigspec('cmd_efidebug')
> +@pytest.mark.buildconfigspec('cmd_fat')
> +@pytest.mark.buildconfigspec('cmd_memory')
> +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> +@pytest.mark.buildconfigspec('cmd_sf')
> +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> +@pytest.mark.slow
> +class TestEfiCapsuleFirmwareRaw(object):
> +    def test_fwu_updates_fw1(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 $filesize',
> +                'sf write 4000000 10000 $filesize'])
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:New' in ''.join(output)
> +
> +    def test_fwu_updates_fw2(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 120000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 160000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 120000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 160000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 100',
> +                'sf write 4000000 10000 100'])
> +
> +            output = u_boot_console.run_command(
> +               'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +            assert 'Test02' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +            assert 'Test02' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 120000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 160000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-b:New' in ''.join(output)
> +
> +    def test_fwu_updates_fw3(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 120000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 160000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 120000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 160000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 100',
> +                'sf write 4000000 10000 100'])
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test03' in ''.join(output)
> +            assert 'Test04' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test03' in ''.join(output)
> +            assert 'Test04' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 120000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-a:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 160000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> -- 
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox
  2022-06-09 12:30 ` [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox Sughosh Ganu
  2022-06-15  5:37   ` Takahiro Akashi
@ 2022-06-15  6:30   ` Takahiro Akashi
  2022-06-15 12:13     ` Sughosh Ganu
  1 sibling, 1 reply; 104+ messages in thread
From: Takahiro Akashi @ 2022-06-15  6:30 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> Add a python test script for testing the FWU Multi Bank Update
> functionality on the sandbox platform. The script has test cases for
> updation of the u-boot binary and the u-boot environment image to the
> non active bank.

IIUC, your test doesn't not exercise neither accept-capsule nor
revert capsule.
I think those tests are crucial for verifying the code.

-Takahiro Akashi

> The FWU metadata is being stored on the SPI NOR flash, along with the
> updatable images, and the FWU metadata driver for MTD devices is being
> used for accessing the metadata. Certain FWU boottime checks are
> bypassed due to the unavailability of the EFI variable access very
> early in the boot on the sandbox platform -- the variable access is
> only available once the block disk image has been bound through the
> host interface.
> 
> The FWU Multi Bank feature being enabled on the sandbox64 platform is
> enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> the FIT FMP instance is being removed -- the FIT FMP is already being
> tested on the sandbox flattree variant.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  arch/sandbox/Kconfig                          |   6 +
>  arch/sandbox/dts/test.dts                     |  45 ++-
>  board/sandbox/sandbox.c                       |  49 +++
>  configs/sandbox64_defconfig                   |  12 +-
>  include/fwu.h                                 |   2 +
>  lib/fwu_updates/Kconfig                       |   2 +-
>  lib/fwu_updates/fwu.c                         |  18 +-
>  lib/fwu_updates/fwu_mtd.c                     |  10 +-
>  .../test_capsule_firmware_fit.py              |   1 -
>  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
>  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
>  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
>  12 files changed, 587 insertions(+), 13 deletions(-)
>  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
>  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
>  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> 
> diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
> index 5f55c7f28e..2985572083 100644
> --- a/arch/sandbox/Kconfig
> +++ b/arch/sandbox/Kconfig
> @@ -84,3 +84,9 @@ config SYS_FDT_LOAD_ADDR
>  	  See `doc/arch/sandbox.rst` for more information.
>  
>  endmenu
> +
> +config FWU_NUM_BANKS
> +       default 2
> +
> +config FWU_NUM_IMAGES_PER_BANK
> +	default 2
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index 8f93775ff4..f11fa8733f 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -1145,11 +1145,48 @@
>  		pinctrl-names = "default";
>  		pinctrl-0 = <&pinmux_spi0_pins>;
>  
> -		spi.bin@0 {
> +		spi0: spi.bin@0 {
>  			reg = <0>;
>  			compatible = "spansion,m25p16", "jedec,spi-nor";
>  			spi-max-frequency = <40000000>;
>  			sandbox,filename = "spi.bin";
> +
> +			partitions {
> +				compatible = "fixed-partitions";
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				uuid = "af9e8c96-bec5-48be-9dab-3491c04b1366";
> +
> +				partition@0 {
> +					label = "Metadata";
> +					reg = <0x0 0x20000>;
> +				};
> +
> +				/* FWU Multi bank update partitions */
> +				partition@100000 {
> +					label = "U-Boot-Bank0";
> +					reg = <0x100000 0x10000>;
> +					uuid = "a8f61787-5d68-4c9d-9e4a-37bb0df99da7";
> +				};
> +
> +				partition@120000 {
> +					label = "U-Boot-ENV-Bank0";
> +					reg = <0x120000 0x10000>;
> +					uuid = "ea9d59af-e0e8-4ef5-9b16-4c80ff67524c";
> +				};
> +
> +				partition@140000 {
> +					label = "U-Boot-Bank1";
> +					reg = <0x140000 0x10000>;
> +					uuid = "52377abf-c4e4-4d0b-aafd-ba081a500847";
> +				};
> +
> +				partition@160000 {
> +					label = "U-Boot-ENV-Bank1";
> +					reg = <0x160000 0x10000>;
> +					uuid = "4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3";
> +				};
> +			};
>  		};
>  		spi.bin@1 {
>  			reg = <1>;
> @@ -1633,6 +1670,12 @@
>  			compatible = "sandbox,regmap_test";
>  		};
>  	};
> +
> +	fwu-mdata {
> +		compatible = "u-boot,fwu-mdata-mtd";
> +		fwu-mdata-store = <&spi0>;
> +		mdata-offsets = <0x0 0x10000>;
> +	};
>  };
>  
>  #include "sandbox_pmic.dtsi"
> diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
> index e054f300c4..222c36d301 100644
> --- a/board/sandbox/sandbox.c
> +++ b/board/sandbox/sandbox.c
> @@ -6,13 +6,18 @@
>  #include <common.h>
>  #include <cpu_func.h>
>  #include <cros_ec.h>
> +#include <dfu.h>
>  #include <dm.h>
>  #include <efi.h>
>  #include <efi_loader.h>
>  #include <env_internal.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
>  #include <init.h>
>  #include <led.h>
> +#include <mtd.h>
>  #include <os.h>
> +#include <uuid.h>
>  #include <asm/global_data.h>
>  #include <asm/test.h>
>  #include <asm/u-boot-sandbox.h>
> @@ -51,8 +56,15 @@ struct efi_fw_image fw_images[] = {
>  };
>  
>  struct efi_capsule_update_info update_info = {
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +	.dfu_string = "mtd nor0=u-boot-bin-a raw 0x100000 0x10000;"
> +		"u-boot-env-a raw 0x120000 0x10000;"
> +		"u-boot-bin-b raw 0x140000 0x10000;"
> +		"u-boot-env-b raw 0x160000 0x10000",
> +#else
>  	.dfu_string = "sf 0:0=u-boot-bin raw 0x100000 0x50000;"
>  		"u-boot-env raw 0x150000 0x200000",
> +#endif
>  	.images = fw_images,
>  };
>  
> @@ -155,3 +167,40 @@ int board_late_init(void)
>  	return 0;
>  }
>  #endif
> +
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
> +			 efi_guid_t *image_id, int *alt_num)
> +{
> +	return fwu_get_mtd_alt_num(image_id, alt_num, "nor0", 1);
> +}
> +
> +int fwu_plat_get_update_index(u32 *update_idx)
> +{
> +	int ret;
> +	u32 active_idx;
> +
> +	ret = fwu_get_active_index(&active_idx);
> +
> +	if (ret < 0)
> +		return -1;
> +
> +	*update_idx = active_idx ^= 0x1;
> +
> +	return ret;
> +}
> +
> +void fwu_plat_get_bootidx(void *boot_idx)
> +{
> +	int ret;
> +	u32 active_idx;
> +	u32 *bootidx = boot_idx;
> +
> +	ret = fwu_get_active_index(&active_idx);
> +
> +	if (ret < 0)
> +		*bootidx = -1;
> +
> +	*bootidx = active_idx;
> +}
> +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
> index d7f22b39ae..7a813b46a5 100644
> --- a/configs/sandbox64_defconfig
> +++ b/configs/sandbox64_defconfig
> @@ -244,9 +244,19 @@ CONFIG_LZ4=y
>  CONFIG_ERRNO_STR=y
>  CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
>  CONFIG_EFI_CAPSULE_ON_DISK=y
> -CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
>  CONFIG_EFI_SECURE_BOOT=y
>  CONFIG_TEST_FDTDEC=y
>  CONFIG_UNIT_TEST=y
>  CONFIG_UT_TIME=y
>  CONFIG_UT_DM=y
> +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
> +CONFIG_DM_FWU_MDATA=y
> +CONFIG_FWU_MULTI_BANK_UPDATE=y
> +CONFIG_FWU_MDATA_MTD=y
> +CONFIG_CMD_FWU_METADATA=y
> +CONFIG_TOOLS_MKFWUMDATA=y
> +CONFIG_DM_SPI_FLASH=y
> +CONFIG_CMD_MTD=y
> +CONFIG_DFU_MTD=y
> +CONFIG_DM_MTD=y
> +CONFIG_SPI_FLASH_MTD=y
> diff --git a/include/fwu.h b/include/fwu.h
> index fadbfedd07..9e550182eb 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -8,6 +8,8 @@
>  
>  #include <blk.h>
>  #include <efi.h>
> +#include <fwu_mdata.h>
> +#include <mtd.h>
>  
>  #include <linux/types.h>
>  
> diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
> index 6de28e0c9c..43bed7729c 100644
> --- a/lib/fwu_updates/Kconfig
> +++ b/lib/fwu_updates/Kconfig
> @@ -2,7 +2,7 @@ config FWU_MULTI_BANK_UPDATE
>  	bool "Enable FWU Multi Bank Update Feature"
>  	depends on EFI_HAVE_CAPSULE_SUPPORT
>  	select PARTITION_TYPE_GUID
> -	select EFI_SETUP_EARLY
> +	select EFI_SETUP_EARLY if !SANDBOX
>  	help
>  	  Feature for updating firmware images on platforms having
>  	  multiple banks(copies) of the firmware images. One of the
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> index 422ef58661..f2c10d836b 100644
> --- a/lib/fwu_updates/fwu.c
> +++ b/lib/fwu_updates/fwu.c
> @@ -185,12 +185,22 @@ int fwu_boottime_checks(void)
>  		return 0;
>  	}
>  
> -	if (efi_init_obj_list() != EFI_SUCCESS)
> -		return 0;
> +	/*
> +	 * On the sandbox platform, the EFI variable
> +	 * access is available only after binding the
> +	 * disk image with the host interface. Skip
> +	 * the Trial State check on sandbox.
> +	 */
> +	if (!IS_ENABLED(CONFIG_SANDBOX)) {
> +		if (efi_init_obj_list() != EFI_SUCCESS)
> +			return 0;
>  
> -	ret = fwu_trial_state_check();
> -	if (!ret)
> +		ret = fwu_trial_state_check();
> +		if (!ret)
> +			boottime_check = 1;
> +	} else {
>  		boottime_check = 1;
> +	}
>  
>  	return 0;
>  }
> diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
> index 3137f8635c..3a9ad70203 100644
> --- a/lib/fwu_updates/fwu_mtd.c
> +++ b/lib/fwu_updates/fwu_mtd.c
> @@ -84,11 +84,11 @@ int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
>  int gen_image_alt_info(char *buf, size_t len, int sidx,
>  		       struct fwu_image_entry *img, struct mtd_info *mtd)
>  {
> -	char *p = buf, *end = buf + len;
> -	char uuidbuf[UUID_STR_LEN + 1];
> -	ofnode node, parts_node;
> -	const char *suuid;
>  	int i;
> +	const char *suuid;
> +	ofnode node, parts_node;
> +	char uuidbuf[UUID_STR_LEN + 1];
> +	char *p = buf, *end = buf + len;
>  
>  	/* Find partition node under given MTD device. */
>  	parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
> @@ -145,7 +145,7 @@ int gen_image_alt_info(char *buf, size_t len, int sidx,
>  
>  int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
>  {
> -	struct fwu_mdata *mdata;
> +	struct fwu_mdata *mdata = NULL;
>  	int i, l, ret;
>  
>  	ret = fwu_get_mdata(&mdata);
> diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> index 5bef84958b..93bc5ed44b 100644
> --- a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> @@ -13,7 +13,6 @@ import pytest
>  from capsule_defs import *
>  
>  
> -@pytest.mark.boardspec('sandbox64')
>  @pytest.mark.boardspec('sandbox_flattree')
>  @pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
>  @pytest.mark.buildconfigspec('efi_capsule_on_disk')
> diff --git a/test/py/tests/test_fwu_updates/capsule_defs.py b/test/py/tests/test_fwu_updates/capsule_defs.py
> new file mode 100644
> index 0000000000..59b40f11bd
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/capsule_defs.py
> @@ -0,0 +1,10 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +
> +# Directories
> +CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'
> +CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
> +
> +# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and
> +# you need build a newer version on your own.
> +# The path must terminate with '/' if it is not null.
> +EFITOOLS_PATH = ''
> diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> new file mode 100644
> index 0000000000..cdf824c3be
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/conftest.py
> @@ -0,0 +1,78 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +# Copyright (c) 2020, Linaro Limited
> +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> +
> +import os
> +import os.path
> +import re
> +from subprocess import call, check_call, check_output, CalledProcessError
> +import pytest
> +from capsule_defs import *
> +
> +#
> +# Fixture for UEFI capsule test
> +#
> +
> +@pytest.fixture(scope='session')
> +def efi_capsule_data(request, u_boot_config):
> +    """Set up a file system to be used in UEFI capsule and
> +       authentication test.
> +
> +    Args:
> +        request: Pytest request object.
> +        u_boot_config: U-boot configuration.
> +
> +    Return:
> +        A path to disk image to be used for testing
> +    """
> +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> +
> +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> +    data_dir = mnt_point + CAPSULE_DATA_DIR
> +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> +
> +    try:
> +        # Create a target device
> +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> +
> +        check_call('rm -rf %s' % mnt_point, shell=True)
> +        check_call('mkdir -p %s' % data_dir, shell=True)
> +        check_call('mkdir -p %s' % install_dir, shell=True)
> +
> +        # Create capsule files
> +        # two regions: one for u-boot.bin and the other for u-boot.env
> +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> +
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> +                   (data_dir, u_boot_config.build_dir),
> +                   shell=True)
> +
> +        # Create a disk image with EFI system partition
> +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> +                   (mnt_point, image_path), shell=True)
> +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> +                   image_path, shell=True)
> +
> +    except CalledProcessError as exception:
> +        pytest.skip('Setup failed: %s' % exception.cmd)
> +        return
> +    else:
> +        yield image_path
> +    finally:
> +        call('rm -rf %s' % mnt_point, shell=True)
> +        call('rm -f %s' % image_path, shell=True)
> +        call('rm -f ./spi.bin', shell=True)
> diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> new file mode 100644
> index 0000000000..d9dff3afaf
> --- /dev/null
> +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> @@ -0,0 +1,367 @@
> +# SPDX-License-Identifier:      GPL-2.0+
> +# Copyright (c) 2022, Linaro Limited
> +#
> +# FWU Multi Bank Firmware Update Test
> +
> +"""
> +This test verifies FWU Multi Bank firmware update for raw images
> +"""
> +
> +from subprocess import check_call, check_output, CalledProcessError
> +import pytest
> +from capsule_defs import *
> +
> +
> +@pytest.mark.boardspec('sandbox64')
> +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> +@pytest.mark.buildconfigspec('dfu')
> +@pytest.mark.buildconfigspec('dfu_sf')
> +@pytest.mark.buildconfigspec('cmd_efidebug')
> +@pytest.mark.buildconfigspec('cmd_fat')
> +@pytest.mark.buildconfigspec('cmd_memory')
> +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> +@pytest.mark.buildconfigspec('cmd_sf')
> +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> +@pytest.mark.slow
> +class TestEfiCapsuleFirmwareRaw(object):
> +    def test_fwu_updates_fw1(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 $filesize',
> +                'sf write 4000000 10000 $filesize'])
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:New' in ''.join(output)
> +
> +    def test_fwu_updates_fw2(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 120000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 160000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 120000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 160000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 100',
> +                'sf write 4000000 10000 100'])
> +
> +            output = u_boot_console.run_command(
> +               'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +            assert 'Test02' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test01' in ''.join(output)
> +            assert 'Test02' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 120000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 160000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-b:New' in ''.join(output)
> +
> +    def test_fwu_updates_fw3(
> +            self, u_boot_config, u_boot_console, efi_capsule_data):
> +        """
> +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> +        """
> +
> +        # other tests might have run and the
> +        # system might not be in a clean state.
> +        # Restart before starting the tests.
> +        u_boot_console.restart_uboot()
> +
> +        disk_img = efi_capsule_data
> +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> +                'efidebug boot order 1',
> +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> +                'env save'])
> +
> +            # initialize contents
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 100000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 120000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 140000 10',
> +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 160000 10'])
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 100000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 120000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-a:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5100000 140000 10',
> +                'md.b 5100000 10'
> +                ])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 5000000 160000 10',
> +                'md.b 5000000 10'
> +                ])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> +                'sf write 4000000 0 100',
> +                'sf write 4000000 10000 100'])
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x1' in ''.join(output)
> +            assert 'previous_active_index: 0x0' in ''.join(output)
> +
> +            # place a capsule file
> +            output = u_boot_console.run_command_list([
> +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test03' in ''.join(output)
> +            assert 'Test04' in ''.join(output)
> +
> +        # reboot
> +        u_boot_console.restart_uboot()
> +
> +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> +            # make sure that dfu_alt_info exists even persistent variables
> +            # are not available.
> +            output = u_boot_console.run_command_list([
> +                'host bind 0 %s' % disk_img,
> +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> +            assert 'Test03' in ''.join(output)
> +            assert 'Test04' in ''.join(output)
> +
> +            # need to run uefi command to initiate capsule handling
> +            output = u_boot_console.run_command(
> +                'efidebug capsule disk-update', wait_for_reboot = True)
> +
> +            output = u_boot_console.run_command(
> +                'fwu_mdata_read')
> +            assert 'active_index: 0x0' in ''.join(output)
> +            assert 'previous_active_index: 0x1' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 100000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-a:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf probe 0:0',
> +                'sf read 4000000 120000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-a:New' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 140000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-b:Old' in ''.join(output)
> +
> +            output = u_boot_console.run_command_list([
> +                'sf read 4000000 160000 10',
> +                'md.b 4000000 10'])
> +            assert 'u-boot-env-b:Old' in ''.join(output)
> -- 
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification
  2022-06-09 12:29 ` [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
@ 2022-06-15  6:34   ` Heinrich Schuchardt
  2022-06-15  6:39     ` Takahiro Akashi
  2022-06-21 10:56   ` Etienne Carriere
  2022-06-21 11:46   ` Patrick DELAUNAY
  2 siblings, 1 reply; 104+ messages in thread
From: Heinrich Schuchardt @ 2022-06-15  6:34 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar, u-boot

On 6/9/22 14:29, Sughosh Ganu wrote:
> The FWU Multi Bank Update specification requires the Update Agent to
> carry out certain checks at the time of platform boot. The Update
> Agent is the component which is responsible for updating the firmware
> components and maintaining and keeping the metadata in sync.
>
> The spec requires that the Update Agent perform the following checks
> at the time of boot
> * Sanity check of both the metadata copies maintained by the platform.
> * Get the boot index passed to U-Boot by the prior stage bootloader
>    and use this value for metadata bookkeeping.
> * Check if the system is booting in Trial State. If the system boots
>    in the Trial State for more than a specified number of boot counts,
>    change the Active Bank to be booting the platform from.
>
> Add these checks in the board initialisation sequence, invoked after
> relocation.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   common/board_r.c      |   5 ++
>   include/fwu.h         |   3 +
>   lib/fwu_updates/fwu.c | 170 ++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 178 insertions(+)
>   create mode 100644 lib/fwu_updates/fwu.c
>
> diff --git a/common/board_r.c b/common/board_r.c
> index 6f4aca2077..33a600715d 100644
> --- a/common/board_r.c
> +++ b/common/board_r.c
> @@ -15,6 +15,7 @@
>   #include <cpu_func.h>
>   #include <exports.h>
>   #include <flash.h>
> +#include <fwu.h>
>   #include <hang.h>
>   #include <image.h>
>   #include <irq_func.h>
> @@ -797,6 +798,10 @@ static init_fnc_t init_sequence_r[] = {
>   #if defined(CONFIG_PRAM)
>   	initr_mem,
>   #endif
> +
> +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
> +	fwu_boottime_checks,
> +#endif
>   	run_main_loop,
>   };
>
> diff --git a/include/fwu.h b/include/fwu.h
> index 41774ff9e2..8fbd91b463 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -33,6 +33,9 @@ struct fwu_mdata_ops {
>   	EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
>   		 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
>
> +int fwu_boottime_checks(void);
> +u8 fwu_update_checks_pass(void);
> +
>   int fwu_get_mdata(struct fwu_mdata **mdata);
>   int fwu_update_mdata(struct fwu_mdata *mdata);
>   int fwu_get_active_index(u32 *active_idx);
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> new file mode 100644
> index 0000000000..af884439fb
> --- /dev/null
> +++ b/lib/fwu_updates/fwu.c
> @@ -0,0 +1,170 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <dm.h>
> +#include <efi.h>
> +#include <efi_loader.h>
> +#include <efi_variable.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <malloc.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
> +static u8 trial_state;
> +static u8 boottime_check;
> +
> +static int fwu_trial_state_check(void)
> +{
> +	int ret, i;
> +	efi_status_t status;
> +	efi_uintn_t var_size;
> +	u16 trial_state_ctr;
> +	u32 nimages, active_bank, var_attributes, active_idx;
> +	struct fwu_mdata *mdata = NULL;
> +	struct fwu_image_entry *img_entry;
> +	struct fwu_image_bank_info *img_bank_info;
> +
> +	ret = fwu_get_mdata(&mdata);
> +	if (ret)
> +		return ret;
> +
> +	ret = 0;
> +	nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> +	active_bank = mdata->active_index;
> +	img_entry = &mdata->img_entry[0];
> +	for (i = 0; i < nimages; i++) {
> +		img_bank_info = &img_entry[i].img_bank_info[active_bank];
> +		if (!img_bank_info->accepted) {
> +			trial_state = 1;
> +			break;
> +		}
> +	}
> +
> +	if (trial_state) {
> +		var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> +		log_info("System booting in Trial State\n");
> +		var_attributes = EFI_VARIABLE_NON_VOLATILE |
> +			EFI_VARIABLE_BOOTSERVICE_ACCESS;
> +		status = efi_get_variable_int(L"TrialStateCtr",
> +					      &efi_global_variable_guid,
> +					      &var_attributes,
> +					      &var_size, &trial_state_ctr,
> +					      NULL);
> +		if (status != EFI_SUCCESS) {
> +			log_err("Unable to read TrialStateCtr variable\n");
> +			ret = -1;
> +			goto out;
> +		}
> +
> +		++trial_state_ctr;
> +		if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
> +			log_info("Trial State count exceeded. Revert back to previous_active_index\n");
> +			active_idx = mdata->active_index;
> +			ret = fwu_revert_boot_index();
> +			if (ret) {
> +				log_err("Unable to revert active_index\n");
> +				goto out;
> +			}
> +
> +			trial_state_ctr = 0;
> +			status = efi_set_variable_int(L"TrialStateCtr",
> +						      &efi_global_variable_guid,
> +						      var_attributes,
> +						      0,
> +						      &trial_state_ctr, false);
> +			if (status != EFI_SUCCESS) {
> +				log_err("Unable to clear TrialStateCtr variable\n");
> +				ret = -1;
> +				goto out;
> +			}
> +		} else {
> +			status = efi_set_variable_int(L"TrialStateCtr",
> +						      &efi_global_variable_guid,
> +						      var_attributes,
> +						      var_size,
> +						      &trial_state_ctr, false);
> +			if (status != EFI_SUCCESS) {
> +				log_err("Unable to increment TrialStateCtr variable\n");
> +				ret = -1;
> +				goto out;
> +			}
> +		}
> +	} else {
> +		trial_state_ctr = 0;
> +		status = efi_set_variable_int(L"TrialStateCtr",
> +					      &efi_global_variable_guid,
> +					      0,
> +					      0, &trial_state_ctr,
> +					      NULL);
> +	}
> +
> +out:
> +	free(mdata);
> +	return ret;
> +}
> +
> +u8 fwu_update_checks_pass(void)
> +{
> +	return !trial_state && boottime_check;
> +}
> +
> +int fwu_boottime_checks(void)
> +{
> +	int ret;
> +	struct udevice *dev;
> +	u32 boot_idx, active_idx;
> +
> +	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> +		log_err("FWU Metadata device not found\n");
> +		return 0;
> +	}
> +
> +	ret = fwu_mdata_check();
> +	if (ret) {
> +		return 0;
> +	}
> +
> +	/*
> +	 * Get the Boot Index, i.e. the bank from
> +	 * which the platform has booted. This value
> +	 * gets passed from the ealier stage bootloader
> +	 * which booted u-boot, e.g. tf-a. If the
> +	 * boot index is not the same as the
> +	 * active_index read from the FWU metadata,
> +	 * update the active_index.
> +	 */
> +	fwu_plat_get_bootidx(&boot_idx);
> +	if (boot_idx >= CONFIG_FWU_NUM_BANKS) {
> +		log_err("Received incorrect value of boot_index\n");
> +		return 0;
> +	}
> +
> +	ret = fwu_get_active_index(&active_idx);
> +	if (ret) {
> +		log_err("Unable to read active_index\n");
> +		return 0;
> +	}
> +
> +	if (boot_idx != active_idx) {
> +		log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
> +			 boot_idx, active_idx);
> +		ret = fwu_update_active_index(boot_idx);
> +		if (!ret)
> +			boottime_check = 1;
> +
> +		return 0;
> +	}
> +
> +	if (efi_init_obj_list() != EFI_SUCCESS)

efi_init_obj_list() slows down the boot process. Why do want to invoke
it if no EFI binary is launched?

See also Takahiro's hint in
https://lore.kernel.org/all/20220615061616.GD58082@laputa/

Best regards

Heinrich

> +		return 0;
> +
> +	ret = fwu_trial_state_check();
> +	if (!ret)
> +		boottime_check = 1;
> +
> +	return 0;
> +}


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification
  2022-06-15  6:34   ` Heinrich Schuchardt
@ 2022-06-15  6:39     ` Takahiro Akashi
  0 siblings, 0 replies; 104+ messages in thread
From: Takahiro Akashi @ 2022-06-15  6:39 UTC (permalink / raw)
  To: Heinrich Schuchardt
  Cc: Sughosh Ganu, Ilias Apalodimas, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar, u-boot

On Wed, Jun 15, 2022 at 08:34:18AM +0200, Heinrich Schuchardt wrote:
> On 6/9/22 14:29, Sughosh Ganu wrote:
> > The FWU Multi Bank Update specification requires the Update Agent to
> > carry out certain checks at the time of platform boot. The Update
> > Agent is the component which is responsible for updating the firmware
> > components and maintaining and keeping the metadata in sync.
> > 
> > The spec requires that the Update Agent perform the following checks
> > at the time of boot
> > * Sanity check of both the metadata copies maintained by the platform.
> > * Get the boot index passed to U-Boot by the prior stage bootloader
> >    and use this value for metadata bookkeeping.
> > * Check if the system is booting in Trial State. If the system boots
> >    in the Trial State for more than a specified number of boot counts,
> >    change the Active Bank to be booting the platform from.
> > 
> > Add these checks in the board initialisation sequence, invoked after
> > relocation.
> > 
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >   common/board_r.c      |   5 ++
> >   include/fwu.h         |   3 +
> >   lib/fwu_updates/fwu.c | 170 ++++++++++++++++++++++++++++++++++++++++++
> >   3 files changed, 178 insertions(+)
> >   create mode 100644 lib/fwu_updates/fwu.c
> > 
> > diff --git a/common/board_r.c b/common/board_r.c
> > index 6f4aca2077..33a600715d 100644
> > --- a/common/board_r.c
> > +++ b/common/board_r.c
> > @@ -15,6 +15,7 @@
> >   #include <cpu_func.h>
> >   #include <exports.h>
> >   #include <flash.h>
> > +#include <fwu.h>
> >   #include <hang.h>
> >   #include <image.h>
> >   #include <irq_func.h>
> > @@ -797,6 +798,10 @@ static init_fnc_t init_sequence_r[] = {
> >   #if defined(CONFIG_PRAM)
> >   	initr_mem,
> >   #endif
> > +
> > +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
> > +	fwu_boottime_checks,
> > +#endif
> >   	run_main_loop,
> >   };
> > 
> > diff --git a/include/fwu.h b/include/fwu.h
> > index 41774ff9e2..8fbd91b463 100644
> > --- a/include/fwu.h
> > +++ b/include/fwu.h
> > @@ -33,6 +33,9 @@ struct fwu_mdata_ops {
> >   	EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
> >   		 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
> > 
> > +int fwu_boottime_checks(void);
> > +u8 fwu_update_checks_pass(void);
> > +
> >   int fwu_get_mdata(struct fwu_mdata **mdata);
> >   int fwu_update_mdata(struct fwu_mdata *mdata);
> >   int fwu_get_active_index(u32 *active_idx);
> > diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> > new file mode 100644
> > index 0000000000..af884439fb
> > --- /dev/null
> > +++ b/lib/fwu_updates/fwu.c
> > @@ -0,0 +1,170 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#include <dm.h>
> > +#include <efi.h>
> > +#include <efi_loader.h>
> > +#include <efi_variable.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +#include <malloc.h>
> > +
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +
> > +static u8 trial_state;
> > +static u8 boottime_check;
> > +
> > +static int fwu_trial_state_check(void)
> > +{
> > +	int ret, i;
> > +	efi_status_t status;
> > +	efi_uintn_t var_size;
> > +	u16 trial_state_ctr;
> > +	u32 nimages, active_bank, var_attributes, active_idx;
> > +	struct fwu_mdata *mdata = NULL;
> > +	struct fwu_image_entry *img_entry;
> > +	struct fwu_image_bank_info *img_bank_info;
> > +
> > +	ret = fwu_get_mdata(&mdata);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = 0;
> > +	nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> > +	active_bank = mdata->active_index;
> > +	img_entry = &mdata->img_entry[0];
> > +	for (i = 0; i < nimages; i++) {
> > +		img_bank_info = &img_entry[i].img_bank_info[active_bank];
> > +		if (!img_bank_info->accepted) {
> > +			trial_state = 1;
> > +			break;
> > +		}
> > +	}
> > +
> > +	if (trial_state) {
> > +		var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> > +		log_info("System booting in Trial State\n");
> > +		var_attributes = EFI_VARIABLE_NON_VOLATILE |
> > +			EFI_VARIABLE_BOOTSERVICE_ACCESS;
> > +		status = efi_get_variable_int(L"TrialStateCtr",
> > +					      &efi_global_variable_guid,
> > +					      &var_attributes,
> > +					      &var_size, &trial_state_ctr,
> > +					      NULL);
> > +		if (status != EFI_SUCCESS) {
> > +			log_err("Unable to read TrialStateCtr variable\n");
> > +			ret = -1;
> > +			goto out;
> > +		}
> > +
> > +		++trial_state_ctr;
> > +		if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
> > +			log_info("Trial State count exceeded. Revert back to previous_active_index\n");
> > +			active_idx = mdata->active_index;
> > +			ret = fwu_revert_boot_index();
> > +			if (ret) {
> > +				log_err("Unable to revert active_index\n");
> > +				goto out;
> > +			}
> > +
> > +			trial_state_ctr = 0;
> > +			status = efi_set_variable_int(L"TrialStateCtr",
> > +						      &efi_global_variable_guid,
> > +						      var_attributes,
> > +						      0,
> > +						      &trial_state_ctr, false);
> > +			if (status != EFI_SUCCESS) {
> > +				log_err("Unable to clear TrialStateCtr variable\n");
> > +				ret = -1;
> > +				goto out;
> > +			}
> > +		} else {
> > +			status = efi_set_variable_int(L"TrialStateCtr",
> > +						      &efi_global_variable_guid,
> > +						      var_attributes,
> > +						      var_size,
> > +						      &trial_state_ctr, false);
> > +			if (status != EFI_SUCCESS) {
> > +				log_err("Unable to increment TrialStateCtr variable\n");
> > +				ret = -1;
> > +				goto out;
> > +			}
> > +		}
> > +	} else {
> > +		trial_state_ctr = 0;
> > +		status = efi_set_variable_int(L"TrialStateCtr",
> > +					      &efi_global_variable_guid,
> > +					      0,
> > +					      0, &trial_state_ctr,
> > +					      NULL);
> > +	}
> > +
> > +out:
> > +	free(mdata);
> > +	return ret;
> > +}
> > +
> > +u8 fwu_update_checks_pass(void)
> > +{
> > +	return !trial_state && boottime_check;
> > +}
> > +
> > +int fwu_boottime_checks(void)
> > +{
> > +	int ret;
> > +	struct udevice *dev;
> > +	u32 boot_idx, active_idx;
> > +
> > +	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> > +		log_err("FWU Metadata device not found\n");
> > +		return 0;
> > +	}
> > +
> > +	ret = fwu_mdata_check();
> > +	if (ret) {
> > +		return 0;
> > +	}
> > +
> > +	/*
> > +	 * Get the Boot Index, i.e. the bank from
> > +	 * which the platform has booted. This value
> > +	 * gets passed from the ealier stage bootloader
> > +	 * which booted u-boot, e.g. tf-a. If the
> > +	 * boot index is not the same as the
> > +	 * active_index read from the FWU metadata,
> > +	 * update the active_index.
> > +	 */
> > +	fwu_plat_get_bootidx(&boot_idx);
> > +	if (boot_idx >= CONFIG_FWU_NUM_BANKS) {
> > +		log_err("Received incorrect value of boot_index\n");
> > +		return 0;
> > +	}
> > +
> > +	ret = fwu_get_active_index(&active_idx);
> > +	if (ret) {
> > +		log_err("Unable to read active_index\n");
> > +		return 0;
> > +	}
> > +
> > +	if (boot_idx != active_idx) {
> > +		log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
> > +			 boot_idx, active_idx);
> > +		ret = fwu_update_active_index(boot_idx);
> > +		if (!ret)
> > +			boottime_check = 1;
> > +
> > +		return 0;
> > +	}
> > +
> > +	if (efi_init_obj_list() != EFI_SUCCESS)
> 
> efi_init_obj_list() slows down the boot process. Why do want to invoke
> it if no EFI binary is launched?

Because fwu_boottime_checks() must access UEFI variables.

-Takahiro Akashi

> See also Takahiro's hint in
> https://lore.kernel.org/all/20220615061616.GD58082@laputa/
> 
> Best regards
> 
> Heinrich
> 
> > +		return 0;
> > +
> > +	ret = fwu_trial_state_check();
> > +	if (!ret)
> > +		boottime_check = 1;
> > +
> > +	return 0;
> > +}
> 

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-15  5:11   ` Takahiro Akashi
@ 2022-06-15 10:49     ` Sughosh Ganu
  2022-06-16  1:01       ` Takahiro Akashi
  0 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-15 10:49 UTC (permalink / raw)
  To: Takahiro Akashi, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Ilias Apalodimas, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Michal Simek, Jose Marinho
  Cc: Jassi Brar

On Wed, 15 Jun 2022 at 10:41, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> On Thu, Jun 09, 2022 at 05:59:58PM +0530, Sughosh Ganu wrote:
> > The Dependable Boot specification[1] describes the structure of the
> > firmware accept and revert capsules. These are empty capsules which
> > are used for signalling the acceptance or rejection of the updated
> > firmware by the OS. Add support for generating these empty capsules.
> >
> > [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  doc/mkeficapsule.1   |  29 ++++++---
> >  tools/eficapsule.h   |   8 +++
> >  tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
> >  3 files changed, 151 insertions(+), 25 deletions(-)
> >
> > diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
> > index 09bdc24295..77ca061efd 100644
> > --- a/doc/mkeficapsule.1
> > +++ b/doc/mkeficapsule.1
> > @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
> >
> >  .SH SYNOPSIS
> >  .B mkeficapsule
> > -.RI [ options "] " image-blob " " capsule-file
> > +.RI [ options ] " " [ image-blob ] " " capsule-file
> >
> >  .SH "DESCRIPTION"
> >  .B mkeficapsule
> > @@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
> >  In this case, the update will be authenticated by verifying the signature
> >  before applying.
> >
> > +Additionally, an empty capsule file can be generated for acceptance or
> > +rejection of firmware images by a governing component like an Operating
> > +System. The empty capsules do not require an image-blob input file.
> > +
> > +
> >  .B mkeficapsule
> > -takes any type of image files, including:
> > +takes any type of image files when generating non empty capsules, including:
> >  .TP
> >  .I raw image
> >  format is a single binary blob of any type of firmware.
> > @@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
> >  This type of image file can be generated by
> >  .BR mkimage .
> >
> > -.PP
> > -If you want to use other types than above two, you should explicitly
> > -specify a guid for the FMP driver.
> > -
> >  .SH "OPTIONS"
> > +
> >  .TP
> >  .BI "-g\fR,\fB --guid " guid-string
> >  Specify guid for image blob type. The format is:
> >      xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
> >
> >  The first three elements are in little endian, while the rest
> > -is in big endian.
> > +is in big endian. The option must be specified for all non empty and
> > +image acceptance capsules
>
> "image acceptance" -> "firmware acceptance"

Okay

>
> I don't still understand why we need a guid for acceptance
> while revert doesn't require it.
> I believe that firmware update is "all or nothing", isn't it?

I believe this gives more flexibility in that different components
might be required to accept the various firmware images. So, one
component might accept the optee_os, while another might be
responsible for accepting u-boot. In any case, we do check that all
the components have their accepted bit set, and only if so, does the
bank boot in the regular state. In case of a firmware revert, it would
not matter which firmware component is being reverted -- the platform
would simply need to boot from the other bank. Do you see any issue
with the current method that we have?

>
> If there is a good reason, please describe a possible/expected
> scenario.

Where do you want me to explain this, in the feature documentation? Or
do you think this can be elaborated in greater detail in the spec.

>
> >  .TP
> >  .BI "-i\fR,\fB --index " index
> > @@ -57,6 +60,18 @@ Specify an image index
> >  .BI "-I\fR,\fB --instance " instance
> >  Specify a hardware instance
> >
> > +.PP
> > +For generation of firmware accept empty capsule
> > +.BR --guid
> > +is mandatory
> > +.TP
> > +.BI "-A\fR,\fB --fw-accept "
> > +Generate a firmware acceptance empty capsule
> > +
> > +.TP
> > +.BI "-R\fR,\fB --fw-revert "
> > +Generate a firmware revert empty capsule
> > +
> >  .TP
> >  .BR -h ", " --help
> >  Print a help message
> > diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> > index d63b831443..072a4b5598 100644
> > --- a/tools/eficapsule.h
> > +++ b/tools/eficapsule.h
> > @@ -41,6 +41,14 @@ typedef struct {
> >       EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
> >                0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
> >
> > +#define FW_ACCEPT_OS_GUID \
> > +     EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
> > +              0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
> > +
> > +#define FW_REVERT_OS_GUID \
> > +     EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
> > +              0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
> > +
> >  /* flags */
> >  #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
> >
> > diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> > index 5f74d23b9e..e8eb6b070d 100644
> > --- a/tools/mkeficapsule.c
> > +++ b/tools/mkeficapsule.c
> > @@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
> >  efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
> >  efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
> >
> > -static const char *opts_short = "g:i:I:v:p:c:m:dh";
> > +static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
> > +
> > +static bool empty_capsule;
> > +static unsigned char capsule;
> > +
> > +enum {
> > +     CAPSULE_NORMAL_BLOB = 0,
> > +     CAPSULE_ACCEPT,
> > +     CAPSULE_REVERT,
> > +} capsule_type;
> >
> >  static struct option options[] = {
> >       {"guid", required_argument, NULL, 'g'},
> > @@ -39,24 +48,47 @@ static struct option options[] = {
> >       {"certificate", required_argument, NULL, 'c'},
> >       {"monotonic-count", required_argument, NULL, 'm'},
> >       {"dump-sig", no_argument, NULL, 'd'},
> > +     {"fw-accept", no_argument, NULL, 'A'},
> > +     {"fw-revert", no_argument, NULL, 'R'},
> >       {"help", no_argument, NULL, 'h'},
> >       {NULL, 0, NULL, 0},
> >  };
> >
> >  static void print_usage(void)
> >  {
> > -     fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > -             "Options:\n"
> > -
> > -             "\t-g, --guid <guid string>    guid for image blob type\n"
> > -             "\t-i, --index <index>         update image index\n"
> > -             "\t-I, --instance <instance>   update hardware instance\n"
> > -             "\t-p, --private-key <privkey file>  private key file\n"
> > -             "\t-c, --certificate <cert file>     signer's certificate file\n"
> > -             "\t-m, --monotonic-count <count>     monotonic count\n"
> > -             "\t-d, --dump_sig              dump signature (*.p7)\n"
> > -             "\t-h, --help                  print a help message\n",
> > -             tool_name);
> > +     if (empty_capsule) {
> > +             if (capsule == CAPSULE_ACCEPT) {
> > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > +                             tool_name);
> > +                     fprintf(stderr, "Options:\n"
> > +                             "\t-A, --fw-accept             firmware accept capsule\n"
> > +                             "\t-g, --guid <guid string>    guid for image blob type\n"
> > +                             "\t-h, --help                  print a help message\n"
> > +                             );
> > +             } else {
> > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > +                             tool_name);
> > +                     fprintf(stderr, "Options:\n"
> > +                             "\t-R, --fw-revert             firmware revert capsule\n"
> > +                             "\t-h, --help                  print a help message\n"
> > +                             );
> > +             }
> > +     } else {
> > +             fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > +                     "Options:\n"
> > +
> > +                     "\t-g, --guid <guid string>    guid for image blob type\n"
> > +                     "\t-i, --index <index>         update image index\n"
> > +                     "\t-I, --instance <instance>   update hardware instance\n"
> > +                     "\t-p, --private-key <privkey file>  private key file\n"
> > +                     "\t-c, --certificate <cert file>     signer's certificate file\n"
> > +                     "\t-m, --monotonic-count <count>     monotonic count\n"
> > +                     "\t-d, --dump_sig              dump signature (*.p7)\n"
> > +                     "\t-A, --fw-accept             firmware accept capsule\n"
> > +                     "\t-R, --fw-revert             firmware revert capsule\n"
> > +                     "\t-h, --help                  print a help message\n",
> > +                     tool_name);
> > +     }
> >  }
> >
> >  /**
> > @@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
> >       buf[7] = c;
> >  }
> >
> > +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> > +{
> > +     struct efi_capsule_header header;
> > +     FILE *f = NULL;
> > +     int ret = -1;
> > +     efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
> > +     efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
> > +     efi_guid_t payload, capsule_guid;
> > +
> > +     f = fopen(path, "w");
> > +     if (!f) {
> > +             fprintf(stderr, "cannot open %s\n", path);
> > +             goto err;
> > +     }
> > +
> > +     capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
> > +
> > +     memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
>
>   -> guidcpy()

This being a host tool, guidcpy cannot be used. You have used memcpy
in the create_fwbin() for the same reason I guess.

>
> > +     header.header_size = sizeof(header);
> > +     header.flags = 0;
> > +
> > +     header.capsule_image_size = fw_accept ?
> > +             sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
> > +
> > +     if (write_capsule_file(f, &header, sizeof(header),
> > +                            "Capsule header"))
> > +             goto err;
> > +
> > +     if (fw_accept) {
> > +             memcpy(&payload, guid, sizeof(efi_guid_t));
>
> ditto

Same as above.

>
> > +             if (write_capsule_file(f, &payload, sizeof(payload),
> > +                                    "FW Accept Capsule Payload"))
> > +                     goto err;
> > +     }
> > +
> > +     ret = 0;
> > +
> > +err:
> > +     if (f)
> > +             fclose(f);
> > +
> > +     return ret;
> > +}
> > +
> >  /**
> >   * main - main entry function of mkeficapsule
> >   * @argc:    Number of arguments
> > @@ -639,22 +715,49 @@ int main(int argc, char **argv)
> >               case 'd':
> >                       dump_sig = 1;
> >                       break;
> > +             case 'A':
> > +                     capsule |= CAPSULE_ACCEPT;
> > +                     break;
> > +             case 'R':
> > +                     capsule |= CAPSULE_REVERT;
> > +                     break;
> >               case 'h':
> >                       print_usage();
> >                       exit(EXIT_SUCCESS);
> >               }
> >       }
> >
> > +     if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
> > +             fprintf(stderr,
> > +                     "Select either of Accept or Revert capsule generation\n");
> > +             exit(EXIT_FAILURE);
> > +     }
> > +
> > +     empty_capsule = (capsule == CAPSULE_ACCEPT ||
> > +                      capsule == CAPSULE_REVERT);
> > +
>
> So empty_capsule is redundant as empty_capsule is equivalent with
> "capsule == CAPSULE_NORMAL_BLOB".
> I think that a single variable, say capsule_type, is enough.

I was using empty_capsule primarily to make the check done below look
more succinct and readable. But I can change that to capsule !=
CAPSULE_NORMAL_BLOB.

>
> >       /* check necessary parameters */
> > -     if ((argc != optind + 2) || !guid ||
> > -         ((privkey_file && !cert_file) ||
> > -          (!privkey_file && cert_file))) {
> > +     if ((!empty_capsule &&
> > +         ((argc != optind + 2) || !guid ||
> > +          ((privkey_file && !cert_file) ||
> > +           (!privkey_file && cert_file)))) ||
> > +         (empty_capsule &&
> > +         ((argc != optind + 1) ||
> > +          ((capsule == CAPSULE_ACCEPT) && !guid) ||
> > +          ((capsule == CAPSULE_REVERT) && guid)))) {
> >               print_usage();
> >               exit(EXIT_FAILURE);
> >       }
> >
> > -     if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
> > -                      mcount, privkey_file, cert_file) < 0) {
> > +     if (empty_capsule) {
> > +             if (create_empty_capsule(argv[argc - 1], guid,
> > +                                      capsule == CAPSULE_ACCEPT) < 0) {
>
>         if (capsule_type != CAPSULE_NORMAL_BLOB)
>                 create_empty_capsule(..., capsule_type == CAPSULE_ACCEPT);
>
> Simple is the best :)

Common, please don't tell me that the code above is complicated. Just
that we can do without the empty_capsule variable, yes.

-sughosh

>
> -Takahiro Akashi
> > +                     fprintf(stderr, "Creating empty capsule failed\n");
> > +                     exit(EXIT_FAILURE);
> > +             }
> > +     } else  if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
> > +                              index, instance, mcount, privkey_file,
> > +                              cert_file) < 0) {
> >               fprintf(stderr, "Creating firmware capsule failed\n");
> >               exit(EXIT_FAILURE);
> >       }
> > --
> > 2.25.1
> >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox
  2022-06-15  5:37   ` Takahiro Akashi
@ 2022-06-15 12:10     ` Sughosh Ganu
  2022-06-17  1:08       ` Takahiro Akashi
  0 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-15 12:10 UTC (permalink / raw)
  To: Takahiro Akashi, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Ilias Apalodimas, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar

On Wed, 15 Jun 2022 at 11:07, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> > Add a python test script for testing the FWU Multi Bank Update
> > functionality on the sandbox platform. The script has test cases for
> > updation of the u-boot binary and the u-boot environment image to the
> > non active bank.
> >
> > The FWU metadata is being stored on the SPI NOR flash, along with the
> > updatable images, and the FWU metadata driver for MTD devices is being
> > used for accessing the metadata. Certain FWU boottime checks are
> > bypassed due to the unavailability of the EFI variable access very
> > early in the boot on the sandbox platform -- the variable access is
> > only available once the block disk image has been bound through the
> > host interface.
> >
> > The FWU Multi Bank feature being enabled on the sandbox64 platform is
> > enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> > the FIT FMP instance is being removed -- the FIT FMP is already being
> > tested on the sandbox flattree variant.
>
> IMO,
> Thinking of the importance of this feature, FIT FMP should also be
> tested *with FWU*.

How will the FWU update feature work for FIT images? As I understand
FIT, it is a way of packaging different firmware images into a single
package. At the time of writing the images, the FIT image parser would
check the image configuration, and write the images to their
respective locations. As you are aware, for the FWU feature, the
information about the images, and the update bank is obtained from the
structure called metadata. How does the FIT update mechanism map with
the FWU metadata which is used to identify which bank needs to be
updated. The bank to which the image is to be written translates into
the DFU alt_num value for that image, and this gets computed at
runtime. In the case of the FIT image, as per my understanding, the
alt_num value is irrelevant. So my question is, how do we map the
information obtained from the FWU metadata to tell the FIT image
writing function(fit_update) which locations do the images need to be
written to. I think this needs some more thought.

>
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  arch/sandbox/Kconfig                          |   6 +
> >  arch/sandbox/dts/test.dts                     |  45 ++-
> >  board/sandbox/sandbox.c                       |  49 +++
> >  configs/sandbox64_defconfig                   |  12 +-
> >  include/fwu.h                                 |   2 +
> >  lib/fwu_updates/Kconfig                       |   2 +-
> >  lib/fwu_updates/fwu.c                         |  18 +-
> >  lib/fwu_updates/fwu_mtd.c                     |  10 +-
> >  .../test_capsule_firmware_fit.py              |   1 -
> >  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
> >  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
> >  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
> >  12 files changed, 587 insertions(+), 13 deletions(-)
> >  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
> >  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
> >  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> >

<snip>

> > diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> > new file mode 100644
> > index 0000000000..cdf824c3be
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/conftest.py
> > @@ -0,0 +1,78 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +# Copyright (c) 2020, Linaro Limited
> > +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
>
> If this file is exactly same as test_efi_capsule/conftest.py,
> why not move all the tests (test_fwu_updates.py) to test_efi_capsule?

The files are not exactly the same. There is use of the mkfwumdata
utility used for FWU tests, along with the capsule files that are
being generated. I had tried putting the code under the
test_efi_capsule directory, but the result was getting cluttered.
Which is why I decided to put the changes separately under the
test_fwu_updates directory.

>
> The basic scenario of updating firmware, u-boot.bin and u-boot.env,
> is also the same, isn't it? The only difference is whether FWU_MULTI_BANK_UPDATE
> is enabled or not.

There are two capsule files per image, one per bank. Also, the FWU
metadata is being written to the SPI NOR device, which is being
formatted as a MTD partitioned device. The underlying update mechanism
is the same, yes.

-sughosh

>
> -Takahiro Akashi
>
> > +
> > +import os
> > +import os.path
> > +import re
> > +from subprocess import call, check_call, check_output, CalledProcessError
> > +import pytest
> > +from capsule_defs import *
> > +
> > +#
> > +# Fixture for UEFI capsule test
> > +#
> > +
> > +@pytest.fixture(scope='session')
> > +def efi_capsule_data(request, u_boot_config):
> > +    """Set up a file system to be used in UEFI capsule and
> > +       authentication test.
> > +
> > +    Args:
> > +        request: Pytest request object.
> > +        u_boot_config: U-boot configuration.
> > +
> > +    Return:
> > +        A path to disk image to be used for testing
> > +    """
> > +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> > +
> > +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> > +    data_dir = mnt_point + CAPSULE_DATA_DIR
> > +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> > +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> > +
> > +    try:
> > +        # Create a target device
> > +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> > +
> > +        check_call('rm -rf %s' % mnt_point, shell=True)
> > +        check_call('mkdir -p %s' % data_dir, shell=True)
> > +        check_call('mkdir -p %s' % install_dir, shell=True)
> > +
> > +        # Create capsule files
> > +        # two regions: one for u-boot.bin and the other for u-boot.env
> > +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > +
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +
> > +        # Create a disk image with EFI system partition
> > +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> > +                   (mnt_point, image_path), shell=True)
> > +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> > +                   image_path, shell=True)
> > +
> > +    except CalledProcessError as exception:
> > +        pytest.skip('Setup failed: %s' % exception.cmd)
> > +        return
> > +    else:
> > +        yield image_path
> > +    finally:
> > +        call('rm -rf %s' % mnt_point, shell=True)
> > +        call('rm -f %s' % image_path, shell=True)
> > +        call('rm -f ./spi.bin', shell=True)
> > diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > new file mode 100644
> > index 0000000000..d9dff3afaf
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > @@ -0,0 +1,367 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +# Copyright (c) 2022, Linaro Limited
> > +#
> > +# FWU Multi Bank Firmware Update Test
> > +
> > +"""
> > +This test verifies FWU Multi Bank firmware update for raw images
> > +"""
> > +
> > +from subprocess import check_call, check_output, CalledProcessError
> > +import pytest
> > +from capsule_defs import *
> > +
> > +
> > +@pytest.mark.boardspec('sandbox64')
> > +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> > +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > +@pytest.mark.buildconfigspec('dfu')
> > +@pytest.mark.buildconfigspec('dfu_sf')
> > +@pytest.mark.buildconfigspec('cmd_efidebug')
> > +@pytest.mark.buildconfigspec('cmd_fat')
> > +@pytest.mark.buildconfigspec('cmd_memory')
> > +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> > +@pytest.mark.buildconfigspec('cmd_sf')
> > +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> > +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> > +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> > +@pytest.mark.slow
> > +class TestEfiCapsuleFirmwareRaw(object):
> > +    def test_fwu_updates_fw1(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> > +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> > +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 $filesize',
> > +                'sf write 4000000 10000 $filesize'])
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:New' in ''.join(output)
> > +
> > +    def test_fwu_updates_fw2(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 120000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 160000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 120000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 160000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 100',
> > +                'sf write 4000000 10000 100'])
> > +
> > +            output = u_boot_console.run_command(
> > +               'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +            assert 'Test02' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +            assert 'Test02' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 120000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 160000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-b:New' in ''.join(output)
> > +
> > +    def test_fwu_updates_fw3(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 120000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 160000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 120000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 160000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 100',
> > +                'sf write 4000000 10000 100'])
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test03' in ''.join(output)
> > +            assert 'Test04' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test03' in ''.join(output)
> > +            assert 'Test04' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 120000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-a:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 160000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > --
> > 2.25.1
> >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox
  2022-06-15  6:30   ` Takahiro Akashi
@ 2022-06-15 12:13     ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-15 12:13 UTC (permalink / raw)
  To: Takahiro Akashi, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Ilias Apalodimas, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Michal Simek, Jassi Brar

On Wed, 15 Jun 2022 at 12:00, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> > Add a python test script for testing the FWU Multi Bank Update
> > functionality on the sandbox platform. The script has test cases for
> > updation of the u-boot binary and the u-boot environment image to the
> > non active bank.
>
> IIUC, your test doesn't not exercise neither accept-capsule nor
> revert capsule.
> I think those tests are crucial for verifying the code.

Yes, this is on my todo list. By default, all the images get accepted
by the firmware itself, which is being done in u-boot. In case the
oemflag bit 15 is set to 1 in the capsule header, the image acceptance
is done through the accept capsule. I will need to add support for
passing the oemflag parameter to the mkeficapsule, and then I can test
this. Will keep this on my todo list, and try to put it in the
upcoming versions.

-sughosh

>
> -Takahiro Akashi
>
> > The FWU metadata is being stored on the SPI NOR flash, along with the
> > updatable images, and the FWU metadata driver for MTD devices is being
> > used for accessing the metadata. Certain FWU boottime checks are
> > bypassed due to the unavailability of the EFI variable access very
> > early in the boot on the sandbox platform -- the variable access is
> > only available once the block disk image has been bound through the
> > host interface.
> >
> > The FWU Multi Bank feature being enabled on the sandbox64 platform is
> > enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> > the FIT FMP instance is being removed -- the FIT FMP is already being
> > tested on the sandbox flattree variant.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  arch/sandbox/Kconfig                          |   6 +
> >  arch/sandbox/dts/test.dts                     |  45 ++-
> >  board/sandbox/sandbox.c                       |  49 +++
> >  configs/sandbox64_defconfig                   |  12 +-
> >  include/fwu.h                                 |   2 +
> >  lib/fwu_updates/Kconfig                       |   2 +-
> >  lib/fwu_updates/fwu.c                         |  18 +-
> >  lib/fwu_updates/fwu_mtd.c                     |  10 +-
> >  .../test_capsule_firmware_fit.py              |   1 -
> >  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
> >  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
> >  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
> >  12 files changed, 587 insertions(+), 13 deletions(-)
> >  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
> >  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
> >  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> >
> > diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
> > index 5f55c7f28e..2985572083 100644
> > --- a/arch/sandbox/Kconfig
> > +++ b/arch/sandbox/Kconfig
> > @@ -84,3 +84,9 @@ config SYS_FDT_LOAD_ADDR
> >         See `doc/arch/sandbox.rst` for more information.
> >
> >  endmenu
> > +
> > +config FWU_NUM_BANKS
> > +       default 2
> > +
> > +config FWU_NUM_IMAGES_PER_BANK
> > +     default 2
> > diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> > index 8f93775ff4..f11fa8733f 100644
> > --- a/arch/sandbox/dts/test.dts
> > +++ b/arch/sandbox/dts/test.dts
> > @@ -1145,11 +1145,48 @@
> >               pinctrl-names = "default";
> >               pinctrl-0 = <&pinmux_spi0_pins>;
> >
> > -             spi.bin@0 {
> > +             spi0: spi.bin@0 {
> >                       reg = <0>;
> >                       compatible = "spansion,m25p16", "jedec,spi-nor";
> >                       spi-max-frequency = <40000000>;
> >                       sandbox,filename = "spi.bin";
> > +
> > +                     partitions {
> > +                             compatible = "fixed-partitions";
> > +                             #address-cells = <1>;
> > +                             #size-cells = <1>;
> > +                             uuid = "af9e8c96-bec5-48be-9dab-3491c04b1366";
> > +
> > +                             partition@0 {
> > +                                     label = "Metadata";
> > +                                     reg = <0x0 0x20000>;
> > +                             };
> > +
> > +                             /* FWU Multi bank update partitions */
> > +                             partition@100000 {
> > +                                     label = "U-Boot-Bank0";
> > +                                     reg = <0x100000 0x10000>;
> > +                                     uuid = "a8f61787-5d68-4c9d-9e4a-37bb0df99da7";
> > +                             };
> > +
> > +                             partition@120000 {
> > +                                     label = "U-Boot-ENV-Bank0";
> > +                                     reg = <0x120000 0x10000>;
> > +                                     uuid = "ea9d59af-e0e8-4ef5-9b16-4c80ff67524c";
> > +                             };
> > +
> > +                             partition@140000 {
> > +                                     label = "U-Boot-Bank1";
> > +                                     reg = <0x140000 0x10000>;
> > +                                     uuid = "52377abf-c4e4-4d0b-aafd-ba081a500847";
> > +                             };
> > +
> > +                             partition@160000 {
> > +                                     label = "U-Boot-ENV-Bank1";
> > +                                     reg = <0x160000 0x10000>;
> > +                                     uuid = "4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3";
> > +                             };
> > +                     };
> >               };
> >               spi.bin@1 {
> >                       reg = <1>;
> > @@ -1633,6 +1670,12 @@
> >                       compatible = "sandbox,regmap_test";
> >               };
> >       };
> > +
> > +     fwu-mdata {
> > +             compatible = "u-boot,fwu-mdata-mtd";
> > +             fwu-mdata-store = <&spi0>;
> > +             mdata-offsets = <0x0 0x10000>;
> > +     };
> >  };
> >
> >  #include "sandbox_pmic.dtsi"
> > diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
> > index e054f300c4..222c36d301 100644
> > --- a/board/sandbox/sandbox.c
> > +++ b/board/sandbox/sandbox.c
> > @@ -6,13 +6,18 @@
> >  #include <common.h>
> >  #include <cpu_func.h>
> >  #include <cros_ec.h>
> > +#include <dfu.h>
> >  #include <dm.h>
> >  #include <efi.h>
> >  #include <efi_loader.h>
> >  #include <env_internal.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> >  #include <init.h>
> >  #include <led.h>
> > +#include <mtd.h>
> >  #include <os.h>
> > +#include <uuid.h>
> >  #include <asm/global_data.h>
> >  #include <asm/test.h>
> >  #include <asm/u-boot-sandbox.h>
> > @@ -51,8 +56,15 @@ struct efi_fw_image fw_images[] = {
> >  };
> >
> >  struct efi_capsule_update_info update_info = {
> > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > +     .dfu_string = "mtd nor0=u-boot-bin-a raw 0x100000 0x10000;"
> > +             "u-boot-env-a raw 0x120000 0x10000;"
> > +             "u-boot-bin-b raw 0x140000 0x10000;"
> > +             "u-boot-env-b raw 0x160000 0x10000",
> > +#else
> >       .dfu_string = "sf 0:0=u-boot-bin raw 0x100000 0x50000;"
> >               "u-boot-env raw 0x150000 0x200000",
> > +#endif
> >       .images = fw_images,
> >  };
> >
> > @@ -155,3 +167,40 @@ int board_late_init(void)
> >       return 0;
> >  }
> >  #endif
> > +
> > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > +int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
> > +                      efi_guid_t *image_id, int *alt_num)
> > +{
> > +     return fwu_get_mtd_alt_num(image_id, alt_num, "nor0", 1);
> > +}
> > +
> > +int fwu_plat_get_update_index(u32 *update_idx)
> > +{
> > +     int ret;
> > +     u32 active_idx;
> > +
> > +     ret = fwu_get_active_index(&active_idx);
> > +
> > +     if (ret < 0)
> > +             return -1;
> > +
> > +     *update_idx = active_idx ^= 0x1;
> > +
> > +     return ret;
> > +}
> > +
> > +void fwu_plat_get_bootidx(void *boot_idx)
> > +{
> > +     int ret;
> > +     u32 active_idx;
> > +     u32 *bootidx = boot_idx;
> > +
> > +     ret = fwu_get_active_index(&active_idx);
> > +
> > +     if (ret < 0)
> > +             *bootidx = -1;
> > +
> > +     *bootidx = active_idx;
> > +}
> > +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> > diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
> > index d7f22b39ae..7a813b46a5 100644
> > --- a/configs/sandbox64_defconfig
> > +++ b/configs/sandbox64_defconfig
> > @@ -244,9 +244,19 @@ CONFIG_LZ4=y
> >  CONFIG_ERRNO_STR=y
> >  CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
> >  CONFIG_EFI_CAPSULE_ON_DISK=y
> > -CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
> >  CONFIG_EFI_SECURE_BOOT=y
> >  CONFIG_TEST_FDTDEC=y
> >  CONFIG_UNIT_TEST=y
> >  CONFIG_UT_TIME=y
> >  CONFIG_UT_DM=y
> > +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
> > +CONFIG_DM_FWU_MDATA=y
> > +CONFIG_FWU_MULTI_BANK_UPDATE=y
> > +CONFIG_FWU_MDATA_MTD=y
> > +CONFIG_CMD_FWU_METADATA=y
> > +CONFIG_TOOLS_MKFWUMDATA=y
> > +CONFIG_DM_SPI_FLASH=y
> > +CONFIG_CMD_MTD=y
> > +CONFIG_DFU_MTD=y
> > +CONFIG_DM_MTD=y
> > +CONFIG_SPI_FLASH_MTD=y
> > diff --git a/include/fwu.h b/include/fwu.h
> > index fadbfedd07..9e550182eb 100644
> > --- a/include/fwu.h
> > +++ b/include/fwu.h
> > @@ -8,6 +8,8 @@
> >
> >  #include <blk.h>
> >  #include <efi.h>
> > +#include <fwu_mdata.h>
> > +#include <mtd.h>
> >
> >  #include <linux/types.h>
> >
> > diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
> > index 6de28e0c9c..43bed7729c 100644
> > --- a/lib/fwu_updates/Kconfig
> > +++ b/lib/fwu_updates/Kconfig
> > @@ -2,7 +2,7 @@ config FWU_MULTI_BANK_UPDATE
> >       bool "Enable FWU Multi Bank Update Feature"
> >       depends on EFI_HAVE_CAPSULE_SUPPORT
> >       select PARTITION_TYPE_GUID
> > -     select EFI_SETUP_EARLY
> > +     select EFI_SETUP_EARLY if !SANDBOX
> >       help
> >         Feature for updating firmware images on platforms having
> >         multiple banks(copies) of the firmware images. One of the
> > diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> > index 422ef58661..f2c10d836b 100644
> > --- a/lib/fwu_updates/fwu.c
> > +++ b/lib/fwu_updates/fwu.c
> > @@ -185,12 +185,22 @@ int fwu_boottime_checks(void)
> >               return 0;
> >       }
> >
> > -     if (efi_init_obj_list() != EFI_SUCCESS)
> > -             return 0;
> > +     /*
> > +      * On the sandbox platform, the EFI variable
> > +      * access is available only after binding the
> > +      * disk image with the host interface. Skip
> > +      * the Trial State check on sandbox.
> > +      */
> > +     if (!IS_ENABLED(CONFIG_SANDBOX)) {
> > +             if (efi_init_obj_list() != EFI_SUCCESS)
> > +                     return 0;
> >
> > -     ret = fwu_trial_state_check();
> > -     if (!ret)
> > +             ret = fwu_trial_state_check();
> > +             if (!ret)
> > +                     boottime_check = 1;
> > +     } else {
> >               boottime_check = 1;
> > +     }
> >
> >       return 0;
> >  }
> > diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
> > index 3137f8635c..3a9ad70203 100644
> > --- a/lib/fwu_updates/fwu_mtd.c
> > +++ b/lib/fwu_updates/fwu_mtd.c
> > @@ -84,11 +84,11 @@ int fwu_get_mtd_alt_num(efi_guid_t *image_id, int *alt_num,
> >  int gen_image_alt_info(char *buf, size_t len, int sidx,
> >                      struct fwu_image_entry *img, struct mtd_info *mtd)
> >  {
> > -     char *p = buf, *end = buf + len;
> > -     char uuidbuf[UUID_STR_LEN + 1];
> > -     ofnode node, parts_node;
> > -     const char *suuid;
> >       int i;
> > +     const char *suuid;
> > +     ofnode node, parts_node;
> > +     char uuidbuf[UUID_STR_LEN + 1];
> > +     char *p = buf, *end = buf + len;
> >
> >       /* Find partition node under given MTD device. */
> >       parts_node = ofnode_by_compatible(mtd_get_ofnode(mtd),
> > @@ -145,7 +145,7 @@ int gen_image_alt_info(char *buf, size_t len, int sidx,
> >
> >  int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
> >  {
> > -     struct fwu_mdata *mdata;
> > +     struct fwu_mdata *mdata = NULL;
> >       int i, l, ret;
> >
> >       ret = fwu_get_mdata(&mdata);
> > diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> > index 5bef84958b..93bc5ed44b 100644
> > --- a/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> > +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_fit.py
> > @@ -13,7 +13,6 @@ import pytest
> >  from capsule_defs import *
> >
> >
> > -@pytest.mark.boardspec('sandbox64')
> >  @pytest.mark.boardspec('sandbox_flattree')
> >  @pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
> >  @pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > diff --git a/test/py/tests/test_fwu_updates/capsule_defs.py b/test/py/tests/test_fwu_updates/capsule_defs.py
> > new file mode 100644
> > index 0000000000..59b40f11bd
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/capsule_defs.py
> > @@ -0,0 +1,10 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +
> > +# Directories
> > +CAPSULE_DATA_DIR = '/EFI/CapsuleTestData'
> > +CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
> > +
> > +# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and
> > +# you need build a newer version on your own.
> > +# The path must terminate with '/' if it is not null.
> > +EFITOOLS_PATH = ''
> > diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> > new file mode 100644
> > index 0000000000..cdf824c3be
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/conftest.py
> > @@ -0,0 +1,78 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +# Copyright (c) 2020, Linaro Limited
> > +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > +
> > +import os
> > +import os.path
> > +import re
> > +from subprocess import call, check_call, check_output, CalledProcessError
> > +import pytest
> > +from capsule_defs import *
> > +
> > +#
> > +# Fixture for UEFI capsule test
> > +#
> > +
> > +@pytest.fixture(scope='session')
> > +def efi_capsule_data(request, u_boot_config):
> > +    """Set up a file system to be used in UEFI capsule and
> > +       authentication test.
> > +
> > +    Args:
> > +        request: Pytest request object.
> > +        u_boot_config: U-boot configuration.
> > +
> > +    Return:
> > +        A path to disk image to be used for testing
> > +    """
> > +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> > +
> > +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> > +    data_dir = mnt_point + CAPSULE_DATA_DIR
> > +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> > +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> > +
> > +    try:
> > +        # Create a target device
> > +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> > +
> > +        check_call('rm -rf %s' % mnt_point, shell=True)
> > +        check_call('mkdir -p %s' % data_dir, shell=True)
> > +        check_call('mkdir -p %s' % install_dir, shell=True)
> > +
> > +        # Create capsule files
> > +        # two regions: one for u-boot.bin and the other for u-boot.env
> > +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > +
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> > +                   (data_dir, u_boot_config.build_dir),
> > +                   shell=True)
> > +
> > +        # Create a disk image with EFI system partition
> > +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> > +                   (mnt_point, image_path), shell=True)
> > +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> > +                   image_path, shell=True)
> > +
> > +    except CalledProcessError as exception:
> > +        pytest.skip('Setup failed: %s' % exception.cmd)
> > +        return
> > +    else:
> > +        yield image_path
> > +    finally:
> > +        call('rm -rf %s' % mnt_point, shell=True)
> > +        call('rm -f %s' % image_path, shell=True)
> > +        call('rm -f ./spi.bin', shell=True)
> > diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > new file mode 100644
> > index 0000000000..d9dff3afaf
> > --- /dev/null
> > +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > @@ -0,0 +1,367 @@
> > +# SPDX-License-Identifier:      GPL-2.0+
> > +# Copyright (c) 2022, Linaro Limited
> > +#
> > +# FWU Multi Bank Firmware Update Test
> > +
> > +"""
> > +This test verifies FWU Multi Bank firmware update for raw images
> > +"""
> > +
> > +from subprocess import check_call, check_output, CalledProcessError
> > +import pytest
> > +from capsule_defs import *
> > +
> > +
> > +@pytest.mark.boardspec('sandbox64')
> > +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> > +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > +@pytest.mark.buildconfigspec('dfu')
> > +@pytest.mark.buildconfigspec('dfu_sf')
> > +@pytest.mark.buildconfigspec('cmd_efidebug')
> > +@pytest.mark.buildconfigspec('cmd_fat')
> > +@pytest.mark.buildconfigspec('cmd_memory')
> > +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> > +@pytest.mark.buildconfigspec('cmd_sf')
> > +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> > +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> > +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> > +@pytest.mark.slow
> > +class TestEfiCapsuleFirmwareRaw(object):
> > +    def test_fwu_updates_fw1(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> > +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> > +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 $filesize',
> > +                'sf write 4000000 10000 $filesize'])
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:New' in ''.join(output)
> > +
> > +    def test_fwu_updates_fw2(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 120000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 160000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 120000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 160000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 100',
> > +                'sf write 4000000 10000 100'])
> > +
> > +            output = u_boot_console.run_command(
> > +               'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +            assert 'Test02' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test01' in ''.join(output)
> > +            assert 'Test02' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 120000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 160000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-b:New' in ''.join(output)
> > +
> > +    def test_fwu_updates_fw3(
> > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > +        """
> > +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > +        """
> > +
> > +        # other tests might have run and the
> > +        # system might not be in a clean state.
> > +        # Restart before starting the tests.
> > +        u_boot_console.restart_uboot()
> > +
> > +        disk_img = efi_capsule_data
> > +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > +                'efidebug boot order 1',
> > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > +                'env save'])
> > +
> > +            # initialize contents
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 100000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 120000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 140000 10',
> > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 160000 10'])
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 100000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 120000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5100000 140000 10',
> > +                'md.b 5100000 10'
> > +                ])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 5000000 160000 10',
> > +                'md.b 5000000 10'
> > +                ])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> > +                'sf write 4000000 0 100',
> > +                'sf write 4000000 10000 100'])
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x1' in ''.join(output)
> > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > +
> > +            # place a capsule file
> > +            output = u_boot_console.run_command_list([
> > +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> > +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test03' in ''.join(output)
> > +            assert 'Test04' in ''.join(output)
> > +
> > +        # reboot
> > +        u_boot_console.restart_uboot()
> > +
> > +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> > +            # make sure that dfu_alt_info exists even persistent variables
> > +            # are not available.
> > +            output = u_boot_console.run_command_list([
> > +                'host bind 0 %s' % disk_img,
> > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > +            assert 'Test03' in ''.join(output)
> > +            assert 'Test04' in ''.join(output)
> > +
> > +            # need to run uefi command to initiate capsule handling
> > +            output = u_boot_console.run_command(
> > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > +
> > +            output = u_boot_console.run_command(
> > +                'fwu_mdata_read')
> > +            assert 'active_index: 0x0' in ''.join(output)
> > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 100000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-a:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf probe 0:0',
> > +                'sf read 4000000 120000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-a:New' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 140000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-b:Old' in ''.join(output)
> > +
> > +            output = u_boot_console.run_command_list([
> > +                'sf read 4000000 160000 10',
> > +                'md.b 4000000 10'])
> > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > --
> > 2.25.1
> >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-15 10:49     ` Sughosh Ganu
@ 2022-06-16  1:01       ` Takahiro Akashi
  2022-06-16  7:12         ` Sughosh Ganu
  0 siblings, 1 reply; 104+ messages in thread
From: Takahiro Akashi @ 2022-06-16  1:01 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jose Marinho, Jassi Brar

Sughosh,

On Wed, Jun 15, 2022 at 04:19:56PM +0530, Sughosh Ganu wrote:
> On Wed, 15 Jun 2022 at 10:41, Takahiro Akashi
> <takahiro.akashi@linaro.org> wrote:
> >
> > On Thu, Jun 09, 2022 at 05:59:58PM +0530, Sughosh Ganu wrote:
> > > The Dependable Boot specification[1] describes the structure of the
> > > firmware accept and revert capsules. These are empty capsules which
> > > are used for signalling the acceptance or rejection of the updated
> > > firmware by the OS. Add support for generating these empty capsules.
> > >
> > > [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
> > >
> > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > ---
> > >  doc/mkeficapsule.1   |  29 ++++++---
> > >  tools/eficapsule.h   |   8 +++
> > >  tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
> > >  3 files changed, 151 insertions(+), 25 deletions(-)
> > >
> > > diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
> > > index 09bdc24295..77ca061efd 100644
> > > --- a/doc/mkeficapsule.1
> > > +++ b/doc/mkeficapsule.1
> > > @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
> > >
> > >  .SH SYNOPSIS
> > >  .B mkeficapsule
> > > -.RI [ options "] " image-blob " " capsule-file
> > > +.RI [ options ] " " [ image-blob ] " " capsule-file
> > >
> > >  .SH "DESCRIPTION"
> > >  .B mkeficapsule
> > > @@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
> > >  In this case, the update will be authenticated by verifying the signature
> > >  before applying.
> > >
> > > +Additionally, an empty capsule file can be generated for acceptance or
> > > +rejection of firmware images by a governing component like an Operating
> > > +System. The empty capsules do not require an image-blob input file.
> > > +
> > > +
> > >  .B mkeficapsule
> > > -takes any type of image files, including:
> > > +takes any type of image files when generating non empty capsules, including:
> > >  .TP
> > >  .I raw image
> > >  format is a single binary blob of any type of firmware.
> > > @@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
> > >  This type of image file can be generated by
> > >  .BR mkimage .
> > >
> > > -.PP
> > > -If you want to use other types than above two, you should explicitly
> > > -specify a guid for the FMP driver.
> > > -
> > >  .SH "OPTIONS"
> > > +
> > >  .TP
> > >  .BI "-g\fR,\fB --guid " guid-string
> > >  Specify guid for image blob type. The format is:
> > >      xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
> > >
> > >  The first three elements are in little endian, while the rest
> > > -is in big endian.
> > > +is in big endian. The option must be specified for all non empty and
> > > +image acceptance capsules
> >
> > "image acceptance" -> "firmware acceptance"
> 
> Okay
> 
> >
> > I don't still understand why we need a guid for acceptance
> > while revert doesn't require it.
> > I believe that firmware update is "all or nothing", isn't it?
> 
> I believe this gives more flexibility in that different components
> might be required to accept the various firmware images. So, one
> component might accept the optee_os, while another might be
> responsible for accepting u-boot. In any case, we do check that all
> the components have their accepted bit set, and only if so, does the
> bank boot in the regular state.

Probably I don't understand the behavior.
Let's assume that we have firmware A and firmware B and then
update both.
When the firmware A is accepted and B is not (not yet issuing
acceptance capsule) and I try to reboot the system, what happens?
From which bank does the system boot, old one or new one?

> In case of a firmware revert, it would
> not matter which firmware component is being reverted -- the platform
> would simply need to boot from the other bank. Do you see any issue
> with the current method that we have?
> 
> >
> > If there is a good reason, please describe a possible/expected
> > scenario.
> 
> Where do you want me to explain this, in the feature documentation? Or
> do you think this can be elaborated in greater detail in the spec.

I prefer some explanation in U-Boot doc.

> >
> > >  .TP
> > >  .BI "-i\fR,\fB --index " index
> > > @@ -57,6 +60,18 @@ Specify an image index
> > >  .BI "-I\fR,\fB --instance " instance
> > >  Specify a hardware instance
> > >
> > > +.PP
> > > +For generation of firmware accept empty capsule
> > > +.BR --guid
> > > +is mandatory
> > > +.TP
> > > +.BI "-A\fR,\fB --fw-accept "
> > > +Generate a firmware acceptance empty capsule
> > > +
> > > +.TP
> > > +.BI "-R\fR,\fB --fw-revert "
> > > +Generate a firmware revert empty capsule
> > > +
> > >  .TP
> > >  .BR -h ", " --help
> > >  Print a help message
> > > diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> > > index d63b831443..072a4b5598 100644
> > > --- a/tools/eficapsule.h
> > > +++ b/tools/eficapsule.h
> > > @@ -41,6 +41,14 @@ typedef struct {
> > >       EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
> > >                0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
> > >
> > > +#define FW_ACCEPT_OS_GUID \
> > > +     EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
> > > +              0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
> > > +
> > > +#define FW_REVERT_OS_GUID \
> > > +     EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
> > > +              0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
> > > +
> > >  /* flags */
> > >  #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
> > >
> > > diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> > > index 5f74d23b9e..e8eb6b070d 100644
> > > --- a/tools/mkeficapsule.c
> > > +++ b/tools/mkeficapsule.c
> > > @@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
> > >  efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
> > >  efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
> > >
> > > -static const char *opts_short = "g:i:I:v:p:c:m:dh";
> > > +static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
> > > +
> > > +static bool empty_capsule;
> > > +static unsigned char capsule;
> > > +
> > > +enum {
> > > +     CAPSULE_NORMAL_BLOB = 0,
> > > +     CAPSULE_ACCEPT,
> > > +     CAPSULE_REVERT,
> > > +} capsule_type;
> > >
> > >  static struct option options[] = {
> > >       {"guid", required_argument, NULL, 'g'},
> > > @@ -39,24 +48,47 @@ static struct option options[] = {
> > >       {"certificate", required_argument, NULL, 'c'},
> > >       {"monotonic-count", required_argument, NULL, 'm'},
> > >       {"dump-sig", no_argument, NULL, 'd'},
> > > +     {"fw-accept", no_argument, NULL, 'A'},
> > > +     {"fw-revert", no_argument, NULL, 'R'},
> > >       {"help", no_argument, NULL, 'h'},
> > >       {NULL, 0, NULL, 0},
> > >  };
> > >
> > >  static void print_usage(void)
> > >  {
> > > -     fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > > -             "Options:\n"
> > > -
> > > -             "\t-g, --guid <guid string>    guid for image blob type\n"
> > > -             "\t-i, --index <index>         update image index\n"
> > > -             "\t-I, --instance <instance>   update hardware instance\n"
> > > -             "\t-p, --private-key <privkey file>  private key file\n"
> > > -             "\t-c, --certificate <cert file>     signer's certificate file\n"
> > > -             "\t-m, --monotonic-count <count>     monotonic count\n"
> > > -             "\t-d, --dump_sig              dump signature (*.p7)\n"
> > > -             "\t-h, --help                  print a help message\n",
> > > -             tool_name);
> > > +     if (empty_capsule) {
> > > +             if (capsule == CAPSULE_ACCEPT) {
> > > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > > +                             tool_name);
> > > +                     fprintf(stderr, "Options:\n"
> > > +                             "\t-A, --fw-accept             firmware accept capsule\n"
> > > +                             "\t-g, --guid <guid string>    guid for image blob type\n"
> > > +                             "\t-h, --help                  print a help message\n"
> > > +                             );
> > > +             } else {
> > > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > > +                             tool_name);
> > > +                     fprintf(stderr, "Options:\n"
> > > +                             "\t-R, --fw-revert             firmware revert capsule\n"
> > > +                             "\t-h, --help                  print a help message\n"
> > > +                             );
> > > +             }
> > > +     } else {
> > > +             fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > > +                     "Options:\n"
> > > +
> > > +                     "\t-g, --guid <guid string>    guid for image blob type\n"
> > > +                     "\t-i, --index <index>         update image index\n"
> > > +                     "\t-I, --instance <instance>   update hardware instance\n"
> > > +                     "\t-p, --private-key <privkey file>  private key file\n"
> > > +                     "\t-c, --certificate <cert file>     signer's certificate file\n"
> > > +                     "\t-m, --monotonic-count <count>     monotonic count\n"
> > > +                     "\t-d, --dump_sig              dump signature (*.p7)\n"
> > > +                     "\t-A, --fw-accept             firmware accept capsule\n"
> > > +                     "\t-R, --fw-revert             firmware revert capsule\n"
> > > +                     "\t-h, --help                  print a help message\n",
> > > +                     tool_name);
> > > +     }
> > >  }
> > >
> > >  /**
> > > @@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
> > >       buf[7] = c;
> > >  }
> > >
> > > +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> > > +{
> > > +     struct efi_capsule_header header;
> > > +     FILE *f = NULL;
> > > +     int ret = -1;
> > > +     efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
> > > +     efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
> > > +     efi_guid_t payload, capsule_guid;
> > > +
> > > +     f = fopen(path, "w");
> > > +     if (!f) {
> > > +             fprintf(stderr, "cannot open %s\n", path);
> > > +             goto err;
> > > +     }
> > > +
> > > +     capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
> > > +
> > > +     memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
> >
> >   -> guidcpy()
> 
> This being a host tool, guidcpy cannot be used. You have used memcpy
> in the create_fwbin() for the same reason I guess.

Ah, right.

> >
> > > +     header.header_size = sizeof(header);
> > > +     header.flags = 0;
> > > +
> > > +     header.capsule_image_size = fw_accept ?
> > > +             sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
> > > +
> > > +     if (write_capsule_file(f, &header, sizeof(header),
> > > +                            "Capsule header"))
> > > +             goto err;
> > > +
> > > +     if (fw_accept) {
> > > +             memcpy(&payload, guid, sizeof(efi_guid_t));
> >
> > ditto
> 
> Same as above.
> 
> >
> > > +             if (write_capsule_file(f, &payload, sizeof(payload),
> > > +                                    "FW Accept Capsule Payload"))
> > > +                     goto err;
> > > +     }
> > > +
> > > +     ret = 0;
> > > +
> > > +err:
> > > +     if (f)
> > > +             fclose(f);
> > > +
> > > +     return ret;
> > > +}
> > > +
> > >  /**
> > >   * main - main entry function of mkeficapsule
> > >   * @argc:    Number of arguments
> > > @@ -639,22 +715,49 @@ int main(int argc, char **argv)
> > >               case 'd':
> > >                       dump_sig = 1;
> > >                       break;
> > > +             case 'A':
> > > +                     capsule |= CAPSULE_ACCEPT;
> > > +                     break;
> > > +             case 'R':
> > > +                     capsule |= CAPSULE_REVERT;
> > > +                     break;
> > >               case 'h':
> > >                       print_usage();
> > >                       exit(EXIT_SUCCESS);
> > >               }
> > >       }
> > >
> > > +     if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
> > > +             fprintf(stderr,
> > > +                     "Select either of Accept or Revert capsule generation\n");
> > > +             exit(EXIT_FAILURE);
> > > +     }
> > > +
> > > +     empty_capsule = (capsule == CAPSULE_ACCEPT ||
> > > +                      capsule == CAPSULE_REVERT);
> > > +
> >
> > So empty_capsule is redundant as empty_capsule is equivalent with
> > "capsule == CAPSULE_NORMAL_BLOB".
> > I think that a single variable, say capsule_type, is enough.
> 
> I was using empty_capsule primarily to make the check done below look
> more succinct and readable. But I can change that to capsule !=
> CAPSULE_NORMAL_BLOB.
> 
> >
> > >       /* check necessary parameters */
> > > -     if ((argc != optind + 2) || !guid ||
> > > -         ((privkey_file && !cert_file) ||
> > > -          (!privkey_file && cert_file))) {
> > > +     if ((!empty_capsule &&
> > > +         ((argc != optind + 2) || !guid ||
> > > +          ((privkey_file && !cert_file) ||
> > > +           (!privkey_file && cert_file)))) ||
> > > +         (empty_capsule &&
> > > +         ((argc != optind + 1) ||
> > > +          ((capsule == CAPSULE_ACCEPT) && !guid) ||
> > > +          ((capsule == CAPSULE_REVERT) && guid)))) {
> > >               print_usage();
> > >               exit(EXIT_FAILURE);
> > >       }
> > >
> > > -     if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
> > > -                      mcount, privkey_file, cert_file) < 0) {
> > > +     if (empty_capsule) {
> > > +             if (create_empty_capsule(argv[argc - 1], guid,
> > > +                                      capsule == CAPSULE_ACCEPT) < 0) {
> >
> >         if (capsule_type != CAPSULE_NORMAL_BLOB)
> >                 create_empty_capsule(..., capsule_type == CAPSULE_ACCEPT);
> >
> > Simple is the best :)
> 
> Common, please don't tell me that the code above is complicated. Just
> that we can do without the empty_capsule variable, yes.

Sorry, not complicated, but having two variables make little sense.

-Takahiro Akashi

> -sughosh
> 
> >
> > -Takahiro Akashi
> > > +                     fprintf(stderr, "Creating empty capsule failed\n");
> > > +                     exit(EXIT_FAILURE);
> > > +             }
> > > +     } else  if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
> > > +                              index, instance, mcount, privkey_file,
> > > +                              cert_file) < 0) {
> > >               fprintf(stderr, "Creating firmware capsule failed\n");
> > >               exit(EXIT_FAILURE);
> > >       }
> > > --
> > > 2.25.1
> > >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-16  1:01       ` Takahiro Akashi
@ 2022-06-16  7:12         ` Sughosh Ganu
  2022-06-17  0:46           ` Takahiro Akashi
  0 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-16  7:12 UTC (permalink / raw)
  To: Takahiro Akashi, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Ilias Apalodimas, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Michal Simek, Jose Marinho,
	Jassi Brar

hi Takahiro,

On Thu, 16 Jun 2022 at 06:31, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> Sughosh,
>
> On Wed, Jun 15, 2022 at 04:19:56PM +0530, Sughosh Ganu wrote:
> > On Wed, 15 Jun 2022 at 10:41, Takahiro Akashi
> > <takahiro.akashi@linaro.org> wrote:
> > >
> > > On Thu, Jun 09, 2022 at 05:59:58PM +0530, Sughosh Ganu wrote:
> > > > The Dependable Boot specification[1] describes the structure of the
> > > > firmware accept and revert capsules. These are empty capsules which
> > > > are used for signalling the acceptance or rejection of the updated
> > > > firmware by the OS. Add support for generating these empty capsules.
> > > >
> > > > [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
> > > >
> > > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > > ---
> > > >  doc/mkeficapsule.1   |  29 ++++++---
> > > >  tools/eficapsule.h   |   8 +++
> > > >  tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
> > > >  3 files changed, 151 insertions(+), 25 deletions(-)
> > > >
> > > > diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
> > > > index 09bdc24295..77ca061efd 100644
> > > > --- a/doc/mkeficapsule.1
> > > > +++ b/doc/mkeficapsule.1
> > > > @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
> > > >
> > > >  .SH SYNOPSIS
> > > >  .B mkeficapsule
> > > > -.RI [ options "] " image-blob " " capsule-file
> > > > +.RI [ options ] " " [ image-blob ] " " capsule-file
> > > >
> > > >  .SH "DESCRIPTION"
> > > >  .B mkeficapsule
> > > > @@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
> > > >  In this case, the update will be authenticated by verifying the signature
> > > >  before applying.
> > > >
> > > > +Additionally, an empty capsule file can be generated for acceptance or
> > > > +rejection of firmware images by a governing component like an Operating
> > > > +System. The empty capsules do not require an image-blob input file.
> > > > +
> > > > +
> > > >  .B mkeficapsule
> > > > -takes any type of image files, including:
> > > > +takes any type of image files when generating non empty capsules, including:
> > > >  .TP
> > > >  .I raw image
> > > >  format is a single binary blob of any type of firmware.
> > > > @@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
> > > >  This type of image file can be generated by
> > > >  .BR mkimage .
> > > >
> > > > -.PP
> > > > -If you want to use other types than above two, you should explicitly
> > > > -specify a guid for the FMP driver.
> > > > -
> > > >  .SH "OPTIONS"
> > > > +
> > > >  .TP
> > > >  .BI "-g\fR,\fB --guid " guid-string
> > > >  Specify guid for image blob type. The format is:
> > > >      xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
> > > >
> > > >  The first three elements are in little endian, while the rest
> > > > -is in big endian.
> > > > +is in big endian. The option must be specified for all non empty and
> > > > +image acceptance capsules
> > >
> > > "image acceptance" -> "firmware acceptance"
> >
> > Okay
> >
> > >
> > > I don't still understand why we need a guid for acceptance
> > > while revert doesn't require it.
> > > I believe that firmware update is "all or nothing", isn't it?
> >
> > I believe this gives more flexibility in that different components
> > might be required to accept the various firmware images. So, one
> > component might accept the optee_os, while another might be
> > responsible for accepting u-boot. In any case, we do check that all
> > the components have their accepted bit set, and only if so, does the
> > bank boot in the regular state.
>
> Probably I don't understand the behavior.
> Let's assume that we have firmware A and firmware B and then
> update both.
> When the firmware A is accepted and B is not (not yet issuing
> acceptance capsule) and I try to reboot the system, what happens?
> From which bank does the system boot, old one or new one?

Once any/all of the images have been updated, on subsequent reboot,
the platform would boot in Trial State from the updated bank. I have
introduced an EFI variable, TrialeStateCtr for counting the number of
times the system is booting in the trial state. The system remains in
trial state as long as all the images from the updated bank have not
been accepted. The platform boots in trial state for a particular
number of iterations(configurable), and once that count has exceeded,
the active bank value gets changed to the previous_active_index, and
the platform subsequently boots from the other bank. If all the images
do get accepted while the platform is in trial state, the platform
transitions to the regular state, and continues booting from that
bank.

-sughosh

>
> > In case of a firmware revert, it would
> > not matter which firmware component is being reverted -- the platform
> > would simply need to boot from the other bank. Do you see any issue
> > with the current method that we have?
> >
> > >
> > > If there is a good reason, please describe a possible/expected
> > > scenario.
> >
> > Where do you want me to explain this, in the feature documentation? Or
> > do you think this can be elaborated in greater detail in the spec.
>
> I prefer some explanation in U-Boot doc.
>
> > >
> > > >  .TP
> > > >  .BI "-i\fR,\fB --index " index
> > > > @@ -57,6 +60,18 @@ Specify an image index
> > > >  .BI "-I\fR,\fB --instance " instance
> > > >  Specify a hardware instance
> > > >
> > > > +.PP
> > > > +For generation of firmware accept empty capsule
> > > > +.BR --guid
> > > > +is mandatory
> > > > +.TP
> > > > +.BI "-A\fR,\fB --fw-accept "
> > > > +Generate a firmware acceptance empty capsule
> > > > +
> > > > +.TP
> > > > +.BI "-R\fR,\fB --fw-revert "
> > > > +Generate a firmware revert empty capsule
> > > > +
> > > >  .TP
> > > >  .BR -h ", " --help
> > > >  Print a help message
> > > > diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> > > > index d63b831443..072a4b5598 100644
> > > > --- a/tools/eficapsule.h
> > > > +++ b/tools/eficapsule.h
> > > > @@ -41,6 +41,14 @@ typedef struct {
> > > >       EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
> > > >                0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
> > > >
> > > > +#define FW_ACCEPT_OS_GUID \
> > > > +     EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
> > > > +              0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
> > > > +
> > > > +#define FW_REVERT_OS_GUID \
> > > > +     EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
> > > > +              0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
> > > > +
> > > >  /* flags */
> > > >  #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
> > > >
> > > > diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> > > > index 5f74d23b9e..e8eb6b070d 100644
> > > > --- a/tools/mkeficapsule.c
> > > > +++ b/tools/mkeficapsule.c
> > > > @@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
> > > >  efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
> > > >  efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
> > > >
> > > > -static const char *opts_short = "g:i:I:v:p:c:m:dh";
> > > > +static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
> > > > +
> > > > +static bool empty_capsule;
> > > > +static unsigned char capsule;
> > > > +
> > > > +enum {
> > > > +     CAPSULE_NORMAL_BLOB = 0,
> > > > +     CAPSULE_ACCEPT,
> > > > +     CAPSULE_REVERT,
> > > > +} capsule_type;
> > > >
> > > >  static struct option options[] = {
> > > >       {"guid", required_argument, NULL, 'g'},
> > > > @@ -39,24 +48,47 @@ static struct option options[] = {
> > > >       {"certificate", required_argument, NULL, 'c'},
> > > >       {"monotonic-count", required_argument, NULL, 'm'},
> > > >       {"dump-sig", no_argument, NULL, 'd'},
> > > > +     {"fw-accept", no_argument, NULL, 'A'},
> > > > +     {"fw-revert", no_argument, NULL, 'R'},
> > > >       {"help", no_argument, NULL, 'h'},
> > > >       {NULL, 0, NULL, 0},
> > > >  };
> > > >
> > > >  static void print_usage(void)
> > > >  {
> > > > -     fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > > > -             "Options:\n"
> > > > -
> > > > -             "\t-g, --guid <guid string>    guid for image blob type\n"
> > > > -             "\t-i, --index <index>         update image index\n"
> > > > -             "\t-I, --instance <instance>   update hardware instance\n"
> > > > -             "\t-p, --private-key <privkey file>  private key file\n"
> > > > -             "\t-c, --certificate <cert file>     signer's certificate file\n"
> > > > -             "\t-m, --monotonic-count <count>     monotonic count\n"
> > > > -             "\t-d, --dump_sig              dump signature (*.p7)\n"
> > > > -             "\t-h, --help                  print a help message\n",
> > > > -             tool_name);
> > > > +     if (empty_capsule) {
> > > > +             if (capsule == CAPSULE_ACCEPT) {
> > > > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > > > +                             tool_name);
> > > > +                     fprintf(stderr, "Options:\n"
> > > > +                             "\t-A, --fw-accept             firmware accept capsule\n"
> > > > +                             "\t-g, --guid <guid string>    guid for image blob type\n"
> > > > +                             "\t-h, --help                  print a help message\n"
> > > > +                             );
> > > > +             } else {
> > > > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > > > +                             tool_name);
> > > > +                     fprintf(stderr, "Options:\n"
> > > > +                             "\t-R, --fw-revert             firmware revert capsule\n"
> > > > +                             "\t-h, --help                  print a help message\n"
> > > > +                             );
> > > > +             }
> > > > +     } else {
> > > > +             fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > > > +                     "Options:\n"
> > > > +
> > > > +                     "\t-g, --guid <guid string>    guid for image blob type\n"
> > > > +                     "\t-i, --index <index>         update image index\n"
> > > > +                     "\t-I, --instance <instance>   update hardware instance\n"
> > > > +                     "\t-p, --private-key <privkey file>  private key file\n"
> > > > +                     "\t-c, --certificate <cert file>     signer's certificate file\n"
> > > > +                     "\t-m, --monotonic-count <count>     monotonic count\n"
> > > > +                     "\t-d, --dump_sig              dump signature (*.p7)\n"
> > > > +                     "\t-A, --fw-accept             firmware accept capsule\n"
> > > > +                     "\t-R, --fw-revert             firmware revert capsule\n"
> > > > +                     "\t-h, --help                  print a help message\n",
> > > > +                     tool_name);
> > > > +     }
> > > >  }
> > > >
> > > >  /**
> > > > @@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
> > > >       buf[7] = c;
> > > >  }
> > > >
> > > > +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> > > > +{
> > > > +     struct efi_capsule_header header;
> > > > +     FILE *f = NULL;
> > > > +     int ret = -1;
> > > > +     efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
> > > > +     efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
> > > > +     efi_guid_t payload, capsule_guid;
> > > > +
> > > > +     f = fopen(path, "w");
> > > > +     if (!f) {
> > > > +             fprintf(stderr, "cannot open %s\n", path);
> > > > +             goto err;
> > > > +     }
> > > > +
> > > > +     capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
> > > > +
> > > > +     memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
> > >
> > >   -> guidcpy()
> >
> > This being a host tool, guidcpy cannot be used. You have used memcpy
> > in the create_fwbin() for the same reason I guess.
>
> Ah, right.
>
> > >
> > > > +     header.header_size = sizeof(header);
> > > > +     header.flags = 0;
> > > > +
> > > > +     header.capsule_image_size = fw_accept ?
> > > > +             sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
> > > > +
> > > > +     if (write_capsule_file(f, &header, sizeof(header),
> > > > +                            "Capsule header"))
> > > > +             goto err;
> > > > +
> > > > +     if (fw_accept) {
> > > > +             memcpy(&payload, guid, sizeof(efi_guid_t));
> > >
> > > ditto
> >
> > Same as above.
> >
> > >
> > > > +             if (write_capsule_file(f, &payload, sizeof(payload),
> > > > +                                    "FW Accept Capsule Payload"))
> > > > +                     goto err;
> > > > +     }
> > > > +
> > > > +     ret = 0;
> > > > +
> > > > +err:
> > > > +     if (f)
> > > > +             fclose(f);
> > > > +
> > > > +     return ret;
> > > > +}
> > > > +
> > > >  /**
> > > >   * main - main entry function of mkeficapsule
> > > >   * @argc:    Number of arguments
> > > > @@ -639,22 +715,49 @@ int main(int argc, char **argv)
> > > >               case 'd':
> > > >                       dump_sig = 1;
> > > >                       break;
> > > > +             case 'A':
> > > > +                     capsule |= CAPSULE_ACCEPT;
> > > > +                     break;
> > > > +             case 'R':
> > > > +                     capsule |= CAPSULE_REVERT;
> > > > +                     break;
> > > >               case 'h':
> > > >                       print_usage();
> > > >                       exit(EXIT_SUCCESS);
> > > >               }
> > > >       }
> > > >
> > > > +     if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
> > > > +             fprintf(stderr,
> > > > +                     "Select either of Accept or Revert capsule generation\n");
> > > > +             exit(EXIT_FAILURE);
> > > > +     }
> > > > +
> > > > +     empty_capsule = (capsule == CAPSULE_ACCEPT ||
> > > > +                      capsule == CAPSULE_REVERT);
> > > > +
> > >
> > > So empty_capsule is redundant as empty_capsule is equivalent with
> > > "capsule == CAPSULE_NORMAL_BLOB".
> > > I think that a single variable, say capsule_type, is enough.
> >
> > I was using empty_capsule primarily to make the check done below look
> > more succinct and readable. But I can change that to capsule !=
> > CAPSULE_NORMAL_BLOB.
> >
> > >
> > > >       /* check necessary parameters */
> > > > -     if ((argc != optind + 2) || !guid ||
> > > > -         ((privkey_file && !cert_file) ||
> > > > -          (!privkey_file && cert_file))) {
> > > > +     if ((!empty_capsule &&
> > > > +         ((argc != optind + 2) || !guid ||
> > > > +          ((privkey_file && !cert_file) ||
> > > > +           (!privkey_file && cert_file)))) ||
> > > > +         (empty_capsule &&
> > > > +         ((argc != optind + 1) ||
> > > > +          ((capsule == CAPSULE_ACCEPT) && !guid) ||
> > > > +          ((capsule == CAPSULE_REVERT) && guid)))) {
> > > >               print_usage();
> > > >               exit(EXIT_FAILURE);
> > > >       }
> > > >
> > > > -     if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
> > > > -                      mcount, privkey_file, cert_file) < 0) {
> > > > +     if (empty_capsule) {
> > > > +             if (create_empty_capsule(argv[argc - 1], guid,
> > > > +                                      capsule == CAPSULE_ACCEPT) < 0) {
> > >
> > >         if (capsule_type != CAPSULE_NORMAL_BLOB)
> > >                 create_empty_capsule(..., capsule_type == CAPSULE_ACCEPT);
> > >
> > > Simple is the best :)
> >
> > Common, please don't tell me that the code above is complicated. Just
> > that we can do without the empty_capsule variable, yes.
>
> Sorry, not complicated, but having two variables make little sense.
>
> -Takahiro Akashi
>
> > -sughosh
> >
> > >
> > > -Takahiro Akashi
> > > > +                     fprintf(stderr, "Creating empty capsule failed\n");
> > > > +                     exit(EXIT_FAILURE);
> > > > +             }
> > > > +     } else  if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
> > > > +                              index, instance, mcount, privkey_file,
> > > > +                              cert_file) < 0) {
> > > >               fprintf(stderr, "Creating firmware capsule failed\n");
> > > >               exit(EXIT_FAILURE);
> > > >       }
> > > > --
> > > > 2.25.1
> > > >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 01/23] dt/bindings: Add bindings for FWU Metadata storage device
  2022-06-09 12:29 ` [PATCH v5 01/23] dt/bindings: Add bindings for FWU Metadata storage device Sughosh Ganu
@ 2022-06-16 13:34   ` Michal Simek
  2022-06-17  6:21     ` Sughosh Ganu
  0 siblings, 1 reply; 104+ messages in thread
From: Michal Simek @ 2022-06-16 13:34 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: U-Boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Jassi Brar

čt 9. 6. 2022 v 14:30 odesílatel Sughosh Ganu <sughosh.ganu@linaro.org> napsal:
>
> Add bindings needed for accessing the FWU metadata partitions. These
> include the compatible string which point to the access method and the
> actual device which stores the FWU metadata.
>
> The current patch adds basic bindings needed for accessing the
> metadata structure on GPT partitioned block devices.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  .../firmware/fwu-mdata.txt                     | 18 ++++++++++++++++++

Why is this in txt file when mtd one is in yaml.
doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml

Thanks,
Michal

-- 
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-16  7:12         ` Sughosh Ganu
@ 2022-06-17  0:46           ` Takahiro Akashi
  2022-06-17  8:01             ` Sughosh Ganu
  0 siblings, 1 reply; 104+ messages in thread
From: Takahiro Akashi @ 2022-06-17  0:46 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jose Marinho, Jassi Brar

Sughosh,

On Thu, Jun 16, 2022 at 12:42:08PM +0530, Sughosh Ganu wrote:
> hi Takahiro,
> 
> On Thu, 16 Jun 2022 at 06:31, Takahiro Akashi
> <takahiro.akashi@linaro.org> wrote:
> >
> > Sughosh,
> >
> > On Wed, Jun 15, 2022 at 04:19:56PM +0530, Sughosh Ganu wrote:
> > > On Wed, 15 Jun 2022 at 10:41, Takahiro Akashi
> > > <takahiro.akashi@linaro.org> wrote:
> > > >
> > > > On Thu, Jun 09, 2022 at 05:59:58PM +0530, Sughosh Ganu wrote:
> > > > > The Dependable Boot specification[1] describes the structure of the
> > > > > firmware accept and revert capsules. These are empty capsules which
> > > > > are used for signalling the acceptance or rejection of the updated
> > > > > firmware by the OS. Add support for generating these empty capsules.
> > > > >
> > > > > [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
> > > > >
> > > > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > > > ---
> > > > >  doc/mkeficapsule.1   |  29 ++++++---
> > > > >  tools/eficapsule.h   |   8 +++
> > > > >  tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
> > > > >  3 files changed, 151 insertions(+), 25 deletions(-)
> > > > >
> > > > > diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
> > > > > index 09bdc24295..77ca061efd 100644
> > > > > --- a/doc/mkeficapsule.1
> > > > > +++ b/doc/mkeficapsule.1
> > > > > @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
> > > > >
> > > > >  .SH SYNOPSIS
> > > > >  .B mkeficapsule
> > > > > -.RI [ options "] " image-blob " " capsule-file
> > > > > +.RI [ options ] " " [ image-blob ] " " capsule-file
> > > > >
> > > > >  .SH "DESCRIPTION"
> > > > >  .B mkeficapsule
> > > > > @@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
> > > > >  In this case, the update will be authenticated by verifying the signature
> > > > >  before applying.
> > > > >
> > > > > +Additionally, an empty capsule file can be generated for acceptance or
> > > > > +rejection of firmware images by a governing component like an Operating
> > > > > +System. The empty capsules do not require an image-blob input file.
> > > > > +
> > > > > +
> > > > >  .B mkeficapsule
> > > > > -takes any type of image files, including:
> > > > > +takes any type of image files when generating non empty capsules, including:
> > > > >  .TP
> > > > >  .I raw image
> > > > >  format is a single binary blob of any type of firmware.
> > > > > @@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
> > > > >  This type of image file can be generated by
> > > > >  .BR mkimage .
> > > > >
> > > > > -.PP
> > > > > -If you want to use other types than above two, you should explicitly
> > > > > -specify a guid for the FMP driver.
> > > > > -
> > > > >  .SH "OPTIONS"
> > > > > +
> > > > >  .TP
> > > > >  .BI "-g\fR,\fB --guid " guid-string
> > > > >  Specify guid for image blob type. The format is:
> > > > >      xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
> > > > >
> > > > >  The first three elements are in little endian, while the rest
> > > > > -is in big endian.
> > > > > +is in big endian. The option must be specified for all non empty and
> > > > > +image acceptance capsules
> > > >
> > > > "image acceptance" -> "firmware acceptance"
> > >
> > > Okay
> > >
> > > >
> > > > I don't still understand why we need a guid for acceptance
> > > > while revert doesn't require it.
> > > > I believe that firmware update is "all or nothing", isn't it?
> > >
> > > I believe this gives more flexibility in that different components
> > > might be required to accept the various firmware images. So, one
> > > component might accept the optee_os, while another might be
> > > responsible for accepting u-boot. In any case, we do check that all
> > > the components have their accepted bit set, and only if so, does the
> > > bank boot in the regular state.
> >
> > Probably I don't understand the behavior.
> > Let's assume that we have firmware A and firmware B and then
> > update both.
> > When the firmware A is accepted and B is not (not yet issuing
> > acceptance capsule) and I try to reboot the system, what happens?
> > From which bank does the system boot, old one or new one?
> 
> Once any/all of the images have been updated, on subsequent reboot,
> the platform would boot in Trial State from the updated bank. I have
> introduced an EFI variable, TrialeStateCtr for counting the number of
> times the system is booting in the trial state. The system remains in
> trial state as long as all the images from the updated bank have not
> been accepted. The platform boots in trial state for a particular
> number of iterations(configurable), and once that count has exceeded,
> the active bank value gets changed to the previous_active_index, and
> the platform subsequently boots from the other bank. If all the images
> do get accepted while the platform is in trial state, the platform
> transitions to the regular state, and continues booting from that
> bank.

Thank you for the details.
But if I understand correctly, why do we need a partially-accepted status?
When some are accepted but others not, the system boots from an update
bank in any way. Right?
So at the end, all that we should do is to accept the boot "from a new bank"
permanently (and transit to, what you say, regular state), or to let the system
boot from an old bank (again, in a regular state).

I don't see any good reason for having a partial acceptance.

We should continue this discussion, but anyhow, you should think of
adding such a description above in U-Boot doc.

-Takahiro Akashi


> -sughosh
> 
> >
> > > In case of a firmware revert, it would
> > > not matter which firmware component is being reverted -- the platform
> > > would simply need to boot from the other bank. Do you see any issue
> > > with the current method that we have?
> > >
> > > >
> > > > If there is a good reason, please describe a possible/expected
> > > > scenario.
> > >
> > > Where do you want me to explain this, in the feature documentation? Or
> > > do you think this can be elaborated in greater detail in the spec.
> >
> > I prefer some explanation in U-Boot doc.
> >
> > > >
> > > > >  .TP
> > > > >  .BI "-i\fR,\fB --index " index
> > > > > @@ -57,6 +60,18 @@ Specify an image index
> > > > >  .BI "-I\fR,\fB --instance " instance
> > > > >  Specify a hardware instance
> > > > >
> > > > > +.PP
> > > > > +For generation of firmware accept empty capsule
> > > > > +.BR --guid
> > > > > +is mandatory
> > > > > +.TP
> > > > > +.BI "-A\fR,\fB --fw-accept "
> > > > > +Generate a firmware acceptance empty capsule
> > > > > +
> > > > > +.TP
> > > > > +.BI "-R\fR,\fB --fw-revert "
> > > > > +Generate a firmware revert empty capsule
> > > > > +
> > > > >  .TP
> > > > >  .BR -h ", " --help
> > > > >  Print a help message
> > > > > diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> > > > > index d63b831443..072a4b5598 100644
> > > > > --- a/tools/eficapsule.h
> > > > > +++ b/tools/eficapsule.h
> > > > > @@ -41,6 +41,14 @@ typedef struct {
> > > > >       EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
> > > > >                0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
> > > > >
> > > > > +#define FW_ACCEPT_OS_GUID \
> > > > > +     EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
> > > > > +              0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
> > > > > +
> > > > > +#define FW_REVERT_OS_GUID \
> > > > > +     EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
> > > > > +              0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
> > > > > +
> > > > >  /* flags */
> > > > >  #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
> > > > >
> > > > > diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> > > > > index 5f74d23b9e..e8eb6b070d 100644
> > > > > --- a/tools/mkeficapsule.c
> > > > > +++ b/tools/mkeficapsule.c
> > > > > @@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
> > > > >  efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
> > > > >  efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
> > > > >
> > > > > -static const char *opts_short = "g:i:I:v:p:c:m:dh";
> > > > > +static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
> > > > > +
> > > > > +static bool empty_capsule;
> > > > > +static unsigned char capsule;
> > > > > +
> > > > > +enum {
> > > > > +     CAPSULE_NORMAL_BLOB = 0,
> > > > > +     CAPSULE_ACCEPT,
> > > > > +     CAPSULE_REVERT,
> > > > > +} capsule_type;
> > > > >
> > > > >  static struct option options[] = {
> > > > >       {"guid", required_argument, NULL, 'g'},
> > > > > @@ -39,24 +48,47 @@ static struct option options[] = {
> > > > >       {"certificate", required_argument, NULL, 'c'},
> > > > >       {"monotonic-count", required_argument, NULL, 'm'},
> > > > >       {"dump-sig", no_argument, NULL, 'd'},
> > > > > +     {"fw-accept", no_argument, NULL, 'A'},
> > > > > +     {"fw-revert", no_argument, NULL, 'R'},
> > > > >       {"help", no_argument, NULL, 'h'},
> > > > >       {NULL, 0, NULL, 0},
> > > > >  };
> > > > >
> > > > >  static void print_usage(void)
> > > > >  {
> > > > > -     fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > > > > -             "Options:\n"
> > > > > -
> > > > > -             "\t-g, --guid <guid string>    guid for image blob type\n"
> > > > > -             "\t-i, --index <index>         update image index\n"
> > > > > -             "\t-I, --instance <instance>   update hardware instance\n"
> > > > > -             "\t-p, --private-key <privkey file>  private key file\n"
> > > > > -             "\t-c, --certificate <cert file>     signer's certificate file\n"
> > > > > -             "\t-m, --monotonic-count <count>     monotonic count\n"
> > > > > -             "\t-d, --dump_sig              dump signature (*.p7)\n"
> > > > > -             "\t-h, --help                  print a help message\n",
> > > > > -             tool_name);
> > > > > +     if (empty_capsule) {
> > > > > +             if (capsule == CAPSULE_ACCEPT) {
> > > > > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > > > > +                             tool_name);
> > > > > +                     fprintf(stderr, "Options:\n"
> > > > > +                             "\t-A, --fw-accept             firmware accept capsule\n"
> > > > > +                             "\t-g, --guid <guid string>    guid for image blob type\n"
> > > > > +                             "\t-h, --help                  print a help message\n"
> > > > > +                             );
> > > > > +             } else {
> > > > > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > > > > +                             tool_name);
> > > > > +                     fprintf(stderr, "Options:\n"
> > > > > +                             "\t-R, --fw-revert             firmware revert capsule\n"
> > > > > +                             "\t-h, --help                  print a help message\n"
> > > > > +                             );
> > > > > +             }
> > > > > +     } else {
> > > > > +             fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > > > > +                     "Options:\n"
> > > > > +
> > > > > +                     "\t-g, --guid <guid string>    guid for image blob type\n"
> > > > > +                     "\t-i, --index <index>         update image index\n"
> > > > > +                     "\t-I, --instance <instance>   update hardware instance\n"
> > > > > +                     "\t-p, --private-key <privkey file>  private key file\n"
> > > > > +                     "\t-c, --certificate <cert file>     signer's certificate file\n"
> > > > > +                     "\t-m, --monotonic-count <count>     monotonic count\n"
> > > > > +                     "\t-d, --dump_sig              dump signature (*.p7)\n"
> > > > > +                     "\t-A, --fw-accept             firmware accept capsule\n"
> > > > > +                     "\t-R, --fw-revert             firmware revert capsule\n"
> > > > > +                     "\t-h, --help                  print a help message\n",
> > > > > +                     tool_name);
> > > > > +     }
> > > > >  }
> > > > >
> > > > >  /**
> > > > > @@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
> > > > >       buf[7] = c;
> > > > >  }
> > > > >
> > > > > +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> > > > > +{
> > > > > +     struct efi_capsule_header header;
> > > > > +     FILE *f = NULL;
> > > > > +     int ret = -1;
> > > > > +     efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
> > > > > +     efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
> > > > > +     efi_guid_t payload, capsule_guid;
> > > > > +
> > > > > +     f = fopen(path, "w");
> > > > > +     if (!f) {
> > > > > +             fprintf(stderr, "cannot open %s\n", path);
> > > > > +             goto err;
> > > > > +     }
> > > > > +
> > > > > +     capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
> > > > > +
> > > > > +     memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
> > > >
> > > >   -> guidcpy()
> > >
> > > This being a host tool, guidcpy cannot be used. You have used memcpy
> > > in the create_fwbin() for the same reason I guess.
> >
> > Ah, right.
> >
> > > >
> > > > > +     header.header_size = sizeof(header);
> > > > > +     header.flags = 0;
> > > > > +
> > > > > +     header.capsule_image_size = fw_accept ?
> > > > > +             sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
> > > > > +
> > > > > +     if (write_capsule_file(f, &header, sizeof(header),
> > > > > +                            "Capsule header"))
> > > > > +             goto err;
> > > > > +
> > > > > +     if (fw_accept) {
> > > > > +             memcpy(&payload, guid, sizeof(efi_guid_t));
> > > >
> > > > ditto
> > >
> > > Same as above.
> > >
> > > >
> > > > > +             if (write_capsule_file(f, &payload, sizeof(payload),
> > > > > +                                    "FW Accept Capsule Payload"))
> > > > > +                     goto err;
> > > > > +     }
> > > > > +
> > > > > +     ret = 0;
> > > > > +
> > > > > +err:
> > > > > +     if (f)
> > > > > +             fclose(f);
> > > > > +
> > > > > +     return ret;
> > > > > +}
> > > > > +
> > > > >  /**
> > > > >   * main - main entry function of mkeficapsule
> > > > >   * @argc:    Number of arguments
> > > > > @@ -639,22 +715,49 @@ int main(int argc, char **argv)
> > > > >               case 'd':
> > > > >                       dump_sig = 1;
> > > > >                       break;
> > > > > +             case 'A':
> > > > > +                     capsule |= CAPSULE_ACCEPT;
> > > > > +                     break;
> > > > > +             case 'R':
> > > > > +                     capsule |= CAPSULE_REVERT;
> > > > > +                     break;
> > > > >               case 'h':
> > > > >                       print_usage();
> > > > >                       exit(EXIT_SUCCESS);
> > > > >               }
> > > > >       }
> > > > >
> > > > > +     if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
> > > > > +             fprintf(stderr,
> > > > > +                     "Select either of Accept or Revert capsule generation\n");
> > > > > +             exit(EXIT_FAILURE);
> > > > > +     }
> > > > > +
> > > > > +     empty_capsule = (capsule == CAPSULE_ACCEPT ||
> > > > > +                      capsule == CAPSULE_REVERT);
> > > > > +
> > > >
> > > > So empty_capsule is redundant as empty_capsule is equivalent with
> > > > "capsule == CAPSULE_NORMAL_BLOB".
> > > > I think that a single variable, say capsule_type, is enough.
> > >
> > > I was using empty_capsule primarily to make the check done below look
> > > more succinct and readable. But I can change that to capsule !=
> > > CAPSULE_NORMAL_BLOB.
> > >
> > > >
> > > > >       /* check necessary parameters */
> > > > > -     if ((argc != optind + 2) || !guid ||
> > > > > -         ((privkey_file && !cert_file) ||
> > > > > -          (!privkey_file && cert_file))) {
> > > > > +     if ((!empty_capsule &&
> > > > > +         ((argc != optind + 2) || !guid ||
> > > > > +          ((privkey_file && !cert_file) ||
> > > > > +           (!privkey_file && cert_file)))) ||
> > > > > +         (empty_capsule &&
> > > > > +         ((argc != optind + 1) ||
> > > > > +          ((capsule == CAPSULE_ACCEPT) && !guid) ||
> > > > > +          ((capsule == CAPSULE_REVERT) && guid)))) {
> > > > >               print_usage();
> > > > >               exit(EXIT_FAILURE);
> > > > >       }
> > > > >
> > > > > -     if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
> > > > > -                      mcount, privkey_file, cert_file) < 0) {
> > > > > +     if (empty_capsule) {
> > > > > +             if (create_empty_capsule(argv[argc - 1], guid,
> > > > > +                                      capsule == CAPSULE_ACCEPT) < 0) {
> > > >
> > > >         if (capsule_type != CAPSULE_NORMAL_BLOB)
> > > >                 create_empty_capsule(..., capsule_type == CAPSULE_ACCEPT);
> > > >
> > > > Simple is the best :)
> > >
> > > Common, please don't tell me that the code above is complicated. Just
> > > that we can do without the empty_capsule variable, yes.
> >
> > Sorry, not complicated, but having two variables make little sense.
> >
> > -Takahiro Akashi
> >
> > > -sughosh
> > >
> > > >
> > > > -Takahiro Akashi
> > > > > +                     fprintf(stderr, "Creating empty capsule failed\n");
> > > > > +                     exit(EXIT_FAILURE);
> > > > > +             }
> > > > > +     } else  if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
> > > > > +                              index, instance, mcount, privkey_file,
> > > > > +                              cert_file) < 0) {
> > > > >               fprintf(stderr, "Creating firmware capsule failed\n");
> > > > >               exit(EXIT_FAILURE);
> > > > >       }
> > > > > --
> > > > > 2.25.1
> > > > >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox
  2022-06-15 12:10     ` Sughosh Ganu
@ 2022-06-17  1:08       ` Takahiro Akashi
  2022-06-17  7:57         ` Sughosh Ganu
  0 siblings, 1 reply; 104+ messages in thread
From: Takahiro Akashi @ 2022-06-17  1:08 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Sughosh,

On Wed, Jun 15, 2022 at 05:40:12PM +0530, Sughosh Ganu wrote:
> On Wed, 15 Jun 2022 at 11:07, Takahiro Akashi
> <takahiro.akashi@linaro.org> wrote:
> >
> > On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> > > Add a python test script for testing the FWU Multi Bank Update
> > > functionality on the sandbox platform. The script has test cases for
> > > updation of the u-boot binary and the u-boot environment image to the
> > > non active bank.
> > >
> > > The FWU metadata is being stored on the SPI NOR flash, along with the
> > > updatable images, and the FWU metadata driver for MTD devices is being
> > > used for accessing the metadata. Certain FWU boottime checks are
> > > bypassed due to the unavailability of the EFI variable access very
> > > early in the boot on the sandbox platform -- the variable access is
> > > only available once the block disk image has been bound through the
> > > host interface.
> > >
> > > The FWU Multi Bank feature being enabled on the sandbox64 platform is
> > > enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> > > the FIT FMP instance is being removed -- the FIT FMP is already being
> > > tested on the sandbox flattree variant.
> >
> > IMO,
> > Thinking of the importance of this feature, FIT FMP should also be
> > tested *with FWU*.
> 
> How will the FWU update feature work for FIT images? As I understand

So are you deliberately designing and proposing a solution that is
incompatible with (or not applicable to) an existing interface (FIT FMP)?

> FIT, it is a way of packaging different firmware images into a single
> package. At the time of writing the images, the FIT image parser would
> check the image configuration, and write the images to their
> respective locations. As you are aware, for the FWU feature, the
> information about the images, and the update bank is obtained from the
> structure called metadata. How does the FIT update mechanism map with
> the FWU metadata which is used to identify which bank needs to be
> updated. The bank to which the image is to be written translates into
> the DFU alt_num value for that image, and this gets computed at
> runtime. In the case of the FIT image, as per my understanding, the
> alt_num value is irrelevant. So my question is, how do we map the
> information obtained from the FWU metadata to tell the FIT image
> writing function(fit_update) which locations do the images need to be
> written to. I think this needs some more thought.
> 
> >
> > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > ---
> > >  arch/sandbox/Kconfig                          |   6 +
> > >  arch/sandbox/dts/test.dts                     |  45 ++-
> > >  board/sandbox/sandbox.c                       |  49 +++
> > >  configs/sandbox64_defconfig                   |  12 +-
> > >  include/fwu.h                                 |   2 +
> > >  lib/fwu_updates/Kconfig                       |   2 +-
> > >  lib/fwu_updates/fwu.c                         |  18 +-
> > >  lib/fwu_updates/fwu_mtd.c                     |  10 +-
> > >  .../test_capsule_firmware_fit.py              |   1 -
> > >  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
> > >  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
> > >  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
> > >  12 files changed, 587 insertions(+), 13 deletions(-)
> > >  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
> > >  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
> > >  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> > >
> 
> <snip>
> 
> > > diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> > > new file mode 100644
> > > index 0000000000..cdf824c3be
> > > --- /dev/null
> > > +++ b/test/py/tests/test_fwu_updates/conftest.py
> > > @@ -0,0 +1,78 @@
> > > +# SPDX-License-Identifier:      GPL-2.0+
> > > +# Copyright (c) 2020, Linaro Limited
> > > +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >
> > If this file is exactly same as test_efi_capsule/conftest.py,
> > why not move all the tests (test_fwu_updates.py) to test_efi_capsule?
> 
> The files are not exactly the same. There is use of the mkfwumdata
> utility used for FWU tests, along with the capsule files that are
> being generated. I had tried putting the code under the
> test_efi_capsule directory, but the result was getting cluttered.

Okay, but from my curiosity, how cluttered was it?
It seems to me that you are simply adding extra setup steps.

My simple concern is that, if there is a fair amount of common code
between two tests, it should be unified for maintainability.

-Takahiro Akashi

> Which is why I decided to put the changes separately under the
> test_fwu_updates directory.
> 
> >
> > The basic scenario of updating firmware, u-boot.bin and u-boot.env,
> > is also the same, isn't it? The only difference is whether FWU_MULTI_BANK_UPDATE
> > is enabled or not.
> 
> There are two capsule files per image, one per bank. Also, the FWU
> metadata is being written to the SPI NOR device, which is being
> formatted as a MTD partitioned device. The underlying update mechanism
> is the same, yes.
> 
> -sughosh
> 
> >
> > -Takahiro Akashi
> >
> > > +
> > > +import os
> > > +import os.path
> > > +import re
> > > +from subprocess import call, check_call, check_output, CalledProcessError
> > > +import pytest
> > > +from capsule_defs import *
> > > +
> > > +#
> > > +# Fixture for UEFI capsule test
> > > +#
> > > +
> > > +@pytest.fixture(scope='session')
> > > +def efi_capsule_data(request, u_boot_config):
> > > +    """Set up a file system to be used in UEFI capsule and
> > > +       authentication test.
> > > +
> > > +    Args:
> > > +        request: Pytest request object.
> > > +        u_boot_config: U-boot configuration.
> > > +
> > > +    Return:
> > > +        A path to disk image to be used for testing
> > > +    """
> > > +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> > > +
> > > +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> > > +    data_dir = mnt_point + CAPSULE_DATA_DIR
> > > +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> > > +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> > > +
> > > +    try:
> > > +        # Create a target device
> > > +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> > > +
> > > +        check_call('rm -rf %s' % mnt_point, shell=True)
> > > +        check_call('mkdir -p %s' % data_dir, shell=True)
> > > +        check_call('mkdir -p %s' % install_dir, shell=True)
> > > +
> > > +        # Create capsule files
> > > +        # two regions: one for u-boot.bin and the other for u-boot.env
> > > +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> > > +                   shell=True)
> > > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > > +
> > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> > > +                   (data_dir, u_boot_config.build_dir),
> > > +                   shell=True)
> > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> > > +                   (data_dir, u_boot_config.build_dir),
> > > +                   shell=True)
> > > +
> > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> > > +                   (data_dir, u_boot_config.build_dir),
> > > +                   shell=True)
> > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> > > +                   (data_dir, u_boot_config.build_dir),
> > > +                   shell=True)
> > > +
> > > +        # Create a disk image with EFI system partition
> > > +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> > > +                   (mnt_point, image_path), shell=True)
> > > +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> > > +                   image_path, shell=True)
> > > +
> > > +    except CalledProcessError as exception:
> > > +        pytest.skip('Setup failed: %s' % exception.cmd)
> > > +        return
> > > +    else:
> > > +        yield image_path
> > > +    finally:
> > > +        call('rm -rf %s' % mnt_point, shell=True)
> > > +        call('rm -f %s' % image_path, shell=True)
> > > +        call('rm -f ./spi.bin', shell=True)
> > > diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > new file mode 100644
> > > index 0000000000..d9dff3afaf
> > > --- /dev/null
> > > +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > @@ -0,0 +1,367 @@
> > > +# SPDX-License-Identifier:      GPL-2.0+
> > > +# Copyright (c) 2022, Linaro Limited
> > > +#
> > > +# FWU Multi Bank Firmware Update Test
> > > +
> > > +"""
> > > +This test verifies FWU Multi Bank firmware update for raw images
> > > +"""
> > > +
> > > +from subprocess import check_call, check_output, CalledProcessError
> > > +import pytest
> > > +from capsule_defs import *
> > > +
> > > +
> > > +@pytest.mark.boardspec('sandbox64')
> > > +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> > > +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > > +@pytest.mark.buildconfigspec('dfu')
> > > +@pytest.mark.buildconfigspec('dfu_sf')
> > > +@pytest.mark.buildconfigspec('cmd_efidebug')
> > > +@pytest.mark.buildconfigspec('cmd_fat')
> > > +@pytest.mark.buildconfigspec('cmd_memory')
> > > +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> > > +@pytest.mark.buildconfigspec('cmd_sf')
> > > +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> > > +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> > > +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> > > +@pytest.mark.slow
> > > +class TestEfiCapsuleFirmwareRaw(object):
> > > +    def test_fwu_updates_fw1(
> > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > +        """
> > > +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> > > +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> > > +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> > > +        """
> > > +
> > > +        # other tests might have run and the
> > > +        # system might not be in a clean state.
> > > +        # Restart before starting the tests.
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        disk_img = efi_capsule_data
> > > +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > +                'efidebug boot order 1',
> > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > +                'env save'])
> > > +
> > > +            # initialize contents
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 100000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 140000 10'])
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 100000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5100000 140000 10',
> > > +                'md.b 5100000 10'
> > > +                ])
> > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 0 $filesize',
> > > +                'sf write 4000000 10000 $filesize'])
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x0' in ''.join(output)
> > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > +
> > > +            # place a capsule file
> > > +            output = u_boot_console.run_command_list([
> > > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test01' in ''.join(output)
> > > +
> > > +        # reboot
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> > > +            # make sure that dfu_alt_info exists even persistent variables
> > > +            # are not available.
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test01' in ''.join(output)
> > > +
> > > +            # need to run uefi command to initiate capsule handling
> > > +            output = u_boot_console.run_command(
> > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x1' in ''.join(output)
> > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 100000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 140000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-b:New' in ''.join(output)
> > > +
> > > +    def test_fwu_updates_fw2(
> > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > +        """
> > > +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> > > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > > +        """
> > > +
> > > +        # other tests might have run and the
> > > +        # system might not be in a clean state.
> > > +        # Restart before starting the tests.
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        disk_img = efi_capsule_data
> > > +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > +                'efidebug boot order 1',
> > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > +                'env save'])
> > > +
> > > +            # initialize contents
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 100000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 120000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 140000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 160000 10'])
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 100000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 120000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5100000 140000 10',
> > > +                'md.b 5100000 10'
> > > +                ])
> > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 160000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 0 100',
> > > +                'sf write 4000000 10000 100'])
> > > +
> > > +            output = u_boot_console.run_command(
> > > +               'fwu_mdata_read')
> > > +            assert 'active_index: 0x0' in ''.join(output)
> > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > +
> > > +            # place a capsule file
> > > +            output = u_boot_console.run_command_list([
> > > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test01' in ''.join(output)
> > > +            assert 'Test02' in ''.join(output)
> > > +
> > > +        # reboot
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> > > +            # make sure that dfu_alt_info exists even persistent variables
> > > +            # are not available.
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test01' in ''.join(output)
> > > +            assert 'Test02' in ''.join(output)
> > > +
> > > +            # need to run uefi command to initiate capsule handling
> > > +            output = u_boot_console.run_command(
> > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x1' in ''.join(output)
> > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 100000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 120000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 140000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-b:New' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 160000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-env-b:New' in ''.join(output)
> > > +
> > > +    def test_fwu_updates_fw3(
> > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > +        """
> > > +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> > > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > > +        """
> > > +
> > > +        # other tests might have run and the
> > > +        # system might not be in a clean state.
> > > +        # Restart before starting the tests.
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        disk_img = efi_capsule_data
> > > +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > +                'efidebug boot order 1',
> > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > +                'env save'])
> > > +
> > > +            # initialize contents
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 100000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 120000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 140000 10',
> > > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 160000 10'])
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 100000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 120000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5100000 140000 10',
> > > +                'md.b 5100000 10'
> > > +                ])
> > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 5000000 160000 10',
> > > +                'md.b 5000000 10'
> > > +                ])
> > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> > > +                'sf write 4000000 0 100',
> > > +                'sf write 4000000 10000 100'])
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x1' in ''.join(output)
> > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > +
> > > +            # place a capsule file
> > > +            output = u_boot_console.run_command_list([
> > > +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> > > +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test03' in ''.join(output)
> > > +            assert 'Test04' in ''.join(output)
> > > +
> > > +        # reboot
> > > +        u_boot_console.restart_uboot()
> > > +
> > > +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> > > +            # make sure that dfu_alt_info exists even persistent variables
> > > +            # are not available.
> > > +            output = u_boot_console.run_command_list([
> > > +                'host bind 0 %s' % disk_img,
> > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > +            assert 'Test03' in ''.join(output)
> > > +            assert 'Test04' in ''.join(output)
> > > +
> > > +            # need to run uefi command to initiate capsule handling
> > > +            output = u_boot_console.run_command(
> > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > +
> > > +            output = u_boot_console.run_command(
> > > +                'fwu_mdata_read')
> > > +            assert 'active_index: 0x0' in ''.join(output)
> > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 100000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-a:New' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf probe 0:0',
> > > +                'sf read 4000000 120000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-env-a:New' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 140000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > +
> > > +            output = u_boot_console.run_command_list([
> > > +                'sf read 4000000 160000 10',
> > > +                'md.b 4000000 10'])
> > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > --
> > > 2.25.1
> > >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 01/23] dt/bindings: Add bindings for FWU Metadata storage device
  2022-06-16 13:34   ` Michal Simek
@ 2022-06-17  6:21     ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-17  6:21 UTC (permalink / raw)
  To: Michal Simek
  Cc: U-Boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Jassi Brar

On Thu, 16 Jun 2022 at 19:04, Michal Simek <monstr@monstr.eu> wrote:
>
> čt 9. 6. 2022 v 14:30 odesílatel Sughosh Ganu <sughosh.ganu@linaro.org> napsal:
> >
> > Add bindings needed for accessing the FWU metadata partitions. These
> > include the compatible string which point to the access method and the
> > actual device which stores the FWU metadata.
> >
> > The current patch adds basic bindings needed for accessing the
> > metadata structure on GPT partitioned block devices.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  .../firmware/fwu-mdata.txt                     | 18 ++++++++++++++++++
>
> Why is this in txt file when mtd one is in yaml.
> doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml

The above binding was written by me in txt, while the mtd one is
authored by Masami Hiramatsu. I will change this to yaml in the next
version.

-sughosh

>
> Thanks,
> Michal
>
> --
> Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
> w: www.monstr.eu p: +42-0-721842854
> Maintainer of Linux kernel - Xilinx Microblaze
> Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
> U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox
  2022-06-17  1:08       ` Takahiro Akashi
@ 2022-06-17  7:57         ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-17  7:57 UTC (permalink / raw)
  To: Takahiro Akashi, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Ilias Apalodimas, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Michal Simek
  Cc: Jassi Brar

On Fri, 17 Jun 2022 at 06:38, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> Sughosh,
>
> On Wed, Jun 15, 2022 at 05:40:12PM +0530, Sughosh Ganu wrote:
> > On Wed, 15 Jun 2022 at 11:07, Takahiro Akashi
> > <takahiro.akashi@linaro.org> wrote:
> > >
> > > On Thu, Jun 09, 2022 at 06:00:10PM +0530, Sughosh Ganu wrote:
> > > > Add a python test script for testing the FWU Multi Bank Update
> > > > functionality on the sandbox platform. The script has test cases for
> > > > updation of the u-boot binary and the u-boot environment image to the
> > > > non active bank.
> > > >
> > > > The FWU metadata is being stored on the SPI NOR flash, along with the
> > > > updatable images, and the FWU metadata driver for MTD devices is being
> > > > used for accessing the metadata. Certain FWU boottime checks are
> > > > bypassed due to the unavailability of the EFI variable access very
> > > > early in the boot on the sandbox platform -- the variable access is
> > > > only available once the block disk image has been bound through the
> > > > host interface.
> > > >
> > > > The FWU Multi Bank feature being enabled on the sandbox64 platform is
> > > > enabling the RAW Firmware Management Protocol(FMP) instance, therefore
> > > > the FIT FMP instance is being removed -- the FIT FMP is already being
> > > > tested on the sandbox flattree variant.
> > >
> > > IMO,
> > > Thinking of the importance of this feature, FIT FMP should also be
> > > tested *with FWU*.
> >
> > How will the FWU update feature work for FIT images? As I understand
>
> So are you deliberately designing and proposing a solution that is
> incompatible with (or not applicable to) an existing interface (FIT FMP)?

Heh, why would anyone do that? The very fact that we are introducing
support on two platforms, one with a GPT layout, and another with MTD
is because the idea is to encourage adoption on multiple platforms.
Secondly, this is a specification from Arm which was driven by Jose
Marinho, and I believe he has incorporated feedback from various
engineers for drafting the specification -- this specification is not
limited only to platforms booting with u-boot. The main issue, as I
see it, is that the FWU metadata is doing the bookkeeping for images
that are present on the platform's storage device, and this just does
not map with FIT which is a packaging mechanism. However, this being
software, you can make changes to the fit_update function and
incorporate the information from the metadata to write to the relevant
locations. However, this needs to be thought through.

>
> > FIT, it is a way of packaging different firmware images into a single
> > package. At the time of writing the images, the FIT image parser would
> > check the image configuration, and write the images to their
> > respective locations. As you are aware, for the FWU feature, the
> > information about the images, and the update bank is obtained from the
> > structure called metadata. How does the FIT update mechanism map with
> > the FWU metadata which is used to identify which bank needs to be
> > updated. The bank to which the image is to be written translates into
> > the DFU alt_num value for that image, and this gets computed at
> > runtime. In the case of the FIT image, as per my understanding, the
> > alt_num value is irrelevant. So my question is, how do we map the
> > information obtained from the FWU metadata to tell the FIT image
> > writing function(fit_update) which locations do the images need to be
> > written to. I think this needs some more thought.
> >
> > >
> > > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > > ---
> > > >  arch/sandbox/Kconfig                          |   6 +
> > > >  arch/sandbox/dts/test.dts                     |  45 ++-
> > > >  board/sandbox/sandbox.c                       |  49 +++
> > > >  configs/sandbox64_defconfig                   |  12 +-
> > > >  include/fwu.h                                 |   2 +
> > > >  lib/fwu_updates/Kconfig                       |   2 +-
> > > >  lib/fwu_updates/fwu.c                         |  18 +-
> > > >  lib/fwu_updates/fwu_mtd.c                     |  10 +-
> > > >  .../test_capsule_firmware_fit.py              |   1 -
> > > >  .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
> > > >  test/py/tests/test_fwu_updates/conftest.py    |  78 ++++
> > > >  .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++++++
> > > >  12 files changed, 587 insertions(+), 13 deletions(-)
> > > >  create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
> > > >  create mode 100644 test/py/tests/test_fwu_updates/conftest.py
> > > >  create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > >
> >
> > <snip>
> >
> > > > diff --git a/test/py/tests/test_fwu_updates/conftest.py b/test/py/tests/test_fwu_updates/conftest.py
> > > > new file mode 100644
> > > > index 0000000000..cdf824c3be
> > > > --- /dev/null
> > > > +++ b/test/py/tests/test_fwu_updates/conftest.py
> > > > @@ -0,0 +1,78 @@
> > > > +# SPDX-License-Identifier:      GPL-2.0+
> > > > +# Copyright (c) 2020, Linaro Limited
> > > > +# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > >
> > > If this file is exactly same as test_efi_capsule/conftest.py,
> > > why not move all the tests (test_fwu_updates.py) to test_efi_capsule?
> >
> > The files are not exactly the same. There is use of the mkfwumdata
> > utility used for FWU tests, along with the capsule files that are
> > being generated. I had tried putting the code under the
> > test_efi_capsule directory, but the result was getting cluttered.
>
> Okay, but from my curiosity, how cluttered was it?
> It seems to me that you are simply adding extra setup steps.

Yes, I am adding extra commands to be called, but I found the multiple
commands for creation of the u-boot, u-boot-env and the same images
per bank subsequently to be adding some confusion. Same for the
capsule file creation as well.

>
> My simple concern is that, if there is a fair amount of common code
> between two tests, it should be unified for maintainability.

Yes, I understand, which is why I had even started with putting these
commands under the capsule test's conftest.py file.

-sughosh

>
> -Takahiro Akashi
>
> > Which is why I decided to put the changes separately under the
> > test_fwu_updates directory.
> >
> > >
> > > The basic scenario of updating firmware, u-boot.bin and u-boot.env,
> > > is also the same, isn't it? The only difference is whether FWU_MULTI_BANK_UPDATE
> > > is enabled or not.
> >
> > There are two capsule files per image, one per bank. Also, the FWU
> > metadata is being written to the SPI NOR device, which is being
> > formatted as a MTD partitioned device. The underlying update mechanism
> > is the same, yes.
> >
> > -sughosh
> >
> > >
> > > -Takahiro Akashi
> > >
> > > > +
> > > > +import os
> > > > +import os.path
> > > > +import re
> > > > +from subprocess import call, check_call, check_output, CalledProcessError
> > > > +import pytest
> > > > +from capsule_defs import *
> > > > +
> > > > +#
> > > > +# Fixture for UEFI capsule test
> > > > +#
> > > > +
> > > > +@pytest.fixture(scope='session')
> > > > +def efi_capsule_data(request, u_boot_config):
> > > > +    """Set up a file system to be used in UEFI capsule and
> > > > +       authentication test.
> > > > +
> > > > +    Args:
> > > > +        request: Pytest request object.
> > > > +        u_boot_config: U-boot configuration.
> > > > +
> > > > +    Return:
> > > > +        A path to disk image to be used for testing
> > > > +    """
> > > > +    global CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
> > > > +
> > > > +    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule'
> > > > +    data_dir = mnt_point + CAPSULE_DATA_DIR
> > > > +    install_dir = mnt_point + CAPSULE_INSTALL_DIR
> > > > +    image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
> > > > +
> > > > +    try:
> > > > +        # Create a target device
> > > > +        check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
> > > > +
> > > > +        check_call('rm -rf %s' % mnt_point, shell=True)
> > > > +        check_call('mkdir -p %s' % data_dir, shell=True)
> > > > +        check_call('mkdir -p %s' % install_dir, shell=True)
> > > > +
> > > > +        # Create capsule files
> > > > +        # two regions: one for u-boot.bin and the other for u-boot.env
> > > > +        check_call('cd %s; echo -n u-boot-a:Old > u-boot-a.bin.old; echo -n u-boot-env-a:Old > u-boot-env-a.old; echo -n u-boot-a:New > u-boot-a.bin.new; echo -n u-boot-env-a:New > u-boot-env-a.new; echo -n u-boot-b:Old > u-boot-b.bin.old; echo -n u-boot-env-b:Old > u-boot-env-b.old; echo -n u-boot-b:New > u-boot-b.bin.new; echo -n u-boot-env-b:New > u-boot-env-b.new;' % data_dir,
> > > > +                   shell=True)
> > > > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 0 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank0.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > > > +        check_call('cd %s; %s/tools/mkfwumdata -i 2 -b 2 -a 1 -g af9e8c96-bec5-48be-9dab-3491c04b1366,09D7CF52-0720-4710-91D1-08469B7FE9C8,a8f61787-5d68-4c9d-9e4a-37bb0df99da7,52377abf-c4e4-4d0b-aafd-ba081a500847 af9e8c96-bec5-48be-9dab-3491c04b1366,5A7021F5-FEF2-48B4-AABA-832E777418C0,ea9d59af-e0e8-4ef5-9b16-4c80ff67524c,4e01d1fa-eebb-437e-9cfe-e7dfbcd04bb3 metadata_bank1.bin' %(data_dir, u_boot_config.build_dir), shell=True)
> > > > +
> > > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-b.bin.new Test01' %
> > > > +                   (data_dir, u_boot_config.build_dir),
> > > > +                   shell=True)
> > > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-b.new Test02' %
> > > > +                   (data_dir, u_boot_config.build_dir),
> > > > +                   shell=True)
> > > > +
> > > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot-a.bin.new Test03' %
> > > > +                   (data_dir, u_boot_config.build_dir),
> > > > +                   shell=True)
> > > > +        check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot-env-a.new Test04' %
> > > > +                   (data_dir, u_boot_config.build_dir),
> > > > +                   shell=True)
> > > > +
> > > > +        # Create a disk image with EFI system partition
> > > > +        check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
> > > > +                   (mnt_point, image_path), shell=True)
> > > > +        check_call('sgdisk %s -A 1:set:0 -t 1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B' %
> > > > +                   image_path, shell=True)
> > > > +
> > > > +    except CalledProcessError as exception:
> > > > +        pytest.skip('Setup failed: %s' % exception.cmd)
> > > > +        return
> > > > +    else:
> > > > +        yield image_path
> > > > +    finally:
> > > > +        call('rm -rf %s' % mnt_point, shell=True)
> > > > +        call('rm -f %s' % image_path, shell=True)
> > > > +        call('rm -f ./spi.bin', shell=True)
> > > > diff --git a/test/py/tests/test_fwu_updates/test_fwu_updates.py b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > > new file mode 100644
> > > > index 0000000000..d9dff3afaf
> > > > --- /dev/null
> > > > +++ b/test/py/tests/test_fwu_updates/test_fwu_updates.py
> > > > @@ -0,0 +1,367 @@
> > > > +# SPDX-License-Identifier:      GPL-2.0+
> > > > +# Copyright (c) 2022, Linaro Limited
> > > > +#
> > > > +# FWU Multi Bank Firmware Update Test
> > > > +
> > > > +"""
> > > > +This test verifies FWU Multi Bank firmware update for raw images
> > > > +"""
> > > > +
> > > > +from subprocess import check_call, check_output, CalledProcessError
> > > > +import pytest
> > > > +from capsule_defs import *
> > > > +
> > > > +
> > > > +@pytest.mark.boardspec('sandbox64')
> > > > +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
> > > > +@pytest.mark.buildconfigspec('efi_capsule_on_disk')
> > > > +@pytest.mark.buildconfigspec('dfu')
> > > > +@pytest.mark.buildconfigspec('dfu_sf')
> > > > +@pytest.mark.buildconfigspec('cmd_efidebug')
> > > > +@pytest.mark.buildconfigspec('cmd_fat')
> > > > +@pytest.mark.buildconfigspec('cmd_memory')
> > > > +@pytest.mark.buildconfigspec('cmd_nvedit_efi')
> > > > +@pytest.mark.buildconfigspec('cmd_sf')
> > > > +@pytest.mark.buildconfigspec('fwu_multi_bank_update')
> > > > +@pytest.mark.buildconfigspec('dm_fwu_mdata')
> > > > +@pytest.mark.buildconfigspec('fwu_mdata_mtd')
> > > > +@pytest.mark.slow
> > > > +class TestEfiCapsuleFirmwareRaw(object):
> > > > +    def test_fwu_updates_fw1(
> > > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > > +        """
> > > > +        Test Case 1 - Update U-Boot Bank 1 binary on SPI Flash
> > > > +                      0x100000-0x150000: U-Boot binary Bank 0 (but dummy)
> > > > +                      0x150000-0x200000: U-Boot binary Bank 1 (but dummy)
> > > > +        """
> > > > +
> > > > +        # other tests might have run and the
> > > > +        # system might not be in a clean state.
> > > > +        # Restart before starting the tests.
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        disk_img = efi_capsule_data
> > > > +        with u_boot_console.log.section('Test Case 1-a, before reboot'):
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > > +                'efidebug boot order 1',
> > > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > > +                'env save'])
> > > > +
> > > > +            # initialize contents
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 100000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 140000 10'])
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 100000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5100000 140000 10',
> > > > +                'md.b 5100000 10'
> > > > +                ])
> > > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 0 $filesize',
> > > > +                'sf write 4000000 10000 $filesize'])
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x0' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > > +
> > > > +            # place a capsule file
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test01' in ''.join(output)
> > > > +
> > > > +        # reboot
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        with u_boot_console.log.section('Test Case 1-b, after reboot'):
> > > > +            # make sure that dfu_alt_info exists even persistent variables
> > > > +            # are not available.
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test01' in ''.join(output)
> > > > +
> > > > +            # need to run uefi command to initiate capsule handling
> > > > +            output = u_boot_console.run_command(
> > > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x1' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 100000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 140000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-b:New' in ''.join(output)
> > > > +
> > > > +    def test_fwu_updates_fw2(
> > > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > > +        """
> > > > +        Test Case 2 - Update U-Boot and U-Boot Env Bank 1 binary on SPI Flash
> > > > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > > > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > > > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > > > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > > > +        """
> > > > +
> > > > +        # other tests might have run and the
> > > > +        # system might not be in a clean state.
> > > > +        # Restart before starting the tests.
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        disk_img = efi_capsule_data
> > > > +        with u_boot_console.log.section('Test Case 2-a, before reboot'):
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > > +                'efidebug boot order 1',
> > > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > > +                'env save'])
> > > > +
> > > > +            # initialize contents
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 100000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 120000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 140000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 160000 10'])
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 100000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 120000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5100000 140000 10',
> > > > +                'md.b 5100000 10'
> > > > +                ])
> > > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 160000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/metadata_bank0.bin' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 0 100',
> > > > +                'sf write 4000000 10000 100'])
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +               'fwu_mdata_read')
> > > > +            assert 'active_index: 0x0' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > > +
> > > > +            # place a capsule file
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'fatload host 0:1 4000000 %s/Test01' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test01 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test01' in ''.join(output)
> > > > +            assert 'Test02' in ''.join(output)
> > > > +
> > > > +        # reboot
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        with u_boot_console.log.section('Test Case 2-b, after reboot'):
> > > > +            # make sure that dfu_alt_info exists even persistent variables
> > > > +            # are not available.
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test01' in ''.join(output)
> > > > +            assert 'Test02' in ''.join(output)
> > > > +
> > > > +            # need to run uefi command to initiate capsule handling
> > > > +            output = u_boot_console.run_command(
> > > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x1' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 100000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 120000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 140000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-b:New' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 160000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-env-b:New' in ''.join(output)
> > > > +
> > > > +    def test_fwu_updates_fw3(
> > > > +            self, u_boot_config, u_boot_console, efi_capsule_data):
> > > > +        """
> > > > +        Test Case 3 - Update U-Boot and U-Boot Env Bank 0 binary on SPI Flash
> > > > +                      0x100000-0x110000: U-Boot binary Bank 0 (but dummy)
> > > > +                      0x120000-0x130000: U-Boot Env binary Bank 0 (but dummy)
> > > > +                      0x140000-0x150000: U-Boot binary Bank 1 (but dummy)
> > > > +                      0x160000-0x170000: U-Boot Env binary Bank 1 (but dummy)
> > > > +        """
> > > > +
> > > > +        # other tests might have run and the
> > > > +        # system might not be in a clean state.
> > > > +        # Restart before starting the tests.
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        disk_img = efi_capsule_data
> > > > +        with u_boot_console.log.section('Test Case 3-a, before reboot'):
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""',
> > > > +                'efidebug boot order 1',
> > > > +                'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
> > > > +                'env save'])
> > > > +
> > > > +            # initialize contents
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-a.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 100000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-env-a.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 120000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-b.bin.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 140000 10',
> > > > +                'fatload host 0:1 4000000 %s/u-boot-env-b.old' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 160000 10'])
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 100000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 120000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-env-a:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5100000 140000 10',
> > > > +                'md.b 5100000 10'
> > > > +                ])
> > > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 5000000 160000 10',
> > > > +                'md.b 5000000 10'
> > > > +                ])
> > > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'fatload host 0:1 4000000 %s/metadata_bank1.bin' % CAPSULE_DATA_DIR,
> > > > +                'sf write 4000000 0 100',
> > > > +                'sf write 4000000 10000 100'])
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x1' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x0' in ''.join(output)
> > > > +
> > > > +            # place a capsule file
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
> > > > +                'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test03' in ''.join(output)
> > > > +            assert 'Test04' in ''.join(output)
> > > > +
> > > > +        # reboot
> > > > +        u_boot_console.restart_uboot()
> > > > +
> > > > +        with u_boot_console.log.section('Test Case 3-b, after reboot'):
> > > > +            # make sure that dfu_alt_info exists even persistent variables
> > > > +            # are not available.
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'host bind 0 %s' % disk_img,
> > > > +                'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
> > > > +            assert 'Test03' in ''.join(output)
> > > > +            assert 'Test04' in ''.join(output)
> > > > +
> > > > +            # need to run uefi command to initiate capsule handling
> > > > +            output = u_boot_console.run_command(
> > > > +                'efidebug capsule disk-update', wait_for_reboot = True)
> > > > +
> > > > +            output = u_boot_console.run_command(
> > > > +                'fwu_mdata_read')
> > > > +            assert 'active_index: 0x0' in ''.join(output)
> > > > +            assert 'previous_active_index: 0x1' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 100000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-a:New' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf probe 0:0',
> > > > +                'sf read 4000000 120000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-env-a:New' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 140000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-b:Old' in ''.join(output)
> > > > +
> > > > +            output = u_boot_console.run_command_list([
> > > > +                'sf read 4000000 160000 10',
> > > > +                'md.b 4000000 10'])
> > > > +            assert 'u-boot-env-b:Old' in ''.join(output)
> > > > --
> > > > 2.25.1
> > > >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-17  0:46           ` Takahiro Akashi
@ 2022-06-17  8:01             ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-17  8:01 UTC (permalink / raw)
  To: Takahiro Akashi, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Ilias Apalodimas, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Michal Simek, Jose Marinho,
	Jassi Brar

Takahiro,

On Fri, 17 Jun 2022 at 06:16, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> Sughosh,
>
> On Thu, Jun 16, 2022 at 12:42:08PM +0530, Sughosh Ganu wrote:
> > hi Takahiro,
> >
> > On Thu, 16 Jun 2022 at 06:31, Takahiro Akashi
> > <takahiro.akashi@linaro.org> wrote:
> > >
> > > Sughosh,
> > >
> > > On Wed, Jun 15, 2022 at 04:19:56PM +0530, Sughosh Ganu wrote:
> > > > On Wed, 15 Jun 2022 at 10:41, Takahiro Akashi
> > > > <takahiro.akashi@linaro.org> wrote:
> > > > >
> > > > > On Thu, Jun 09, 2022 at 05:59:58PM +0530, Sughosh Ganu wrote:
> > > > > > The Dependable Boot specification[1] describes the structure of the
> > > > > > firmware accept and revert capsules. These are empty capsules which
> > > > > > are used for signalling the acceptance or rejection of the updated
> > > > > > firmware by the OS. Add support for generating these empty capsules.
> > > > > >
> > > > > > [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
> > > > > >
> > > > > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > > > > ---
> > > > > >  doc/mkeficapsule.1   |  29 ++++++---
> > > > > >  tools/eficapsule.h   |   8 +++
> > > > > >  tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
> > > > > >  3 files changed, 151 insertions(+), 25 deletions(-)
> > > > > >
> > > > > > diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
> > > > > > index 09bdc24295..77ca061efd 100644
> > > > > > --- a/doc/mkeficapsule.1
> > > > > > +++ b/doc/mkeficapsule.1
> > > > > > @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
> > > > > >
> > > > > >  .SH SYNOPSIS
> > > > > >  .B mkeficapsule
> > > > > > -.RI [ options "] " image-blob " " capsule-file
> > > > > > +.RI [ options ] " " [ image-blob ] " " capsule-file
> > > > > >
> > > > > >  .SH "DESCRIPTION"
> > > > > >  .B mkeficapsule
> > > > > > @@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
> > > > > >  In this case, the update will be authenticated by verifying the signature
> > > > > >  before applying.
> > > > > >
> > > > > > +Additionally, an empty capsule file can be generated for acceptance or
> > > > > > +rejection of firmware images by a governing component like an Operating
> > > > > > +System. The empty capsules do not require an image-blob input file.
> > > > > > +
> > > > > > +
> > > > > >  .B mkeficapsule
> > > > > > -takes any type of image files, including:
> > > > > > +takes any type of image files when generating non empty capsules, including:
> > > > > >  .TP
> > > > > >  .I raw image
> > > > > >  format is a single binary blob of any type of firmware.
> > > > > > @@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
> > > > > >  This type of image file can be generated by
> > > > > >  .BR mkimage .
> > > > > >
> > > > > > -.PP
> > > > > > -If you want to use other types than above two, you should explicitly
> > > > > > -specify a guid for the FMP driver.
> > > > > > -
> > > > > >  .SH "OPTIONS"
> > > > > > +
> > > > > >  .TP
> > > > > >  .BI "-g\fR,\fB --guid " guid-string
> > > > > >  Specify guid for image blob type. The format is:
> > > > > >      xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
> > > > > >
> > > > > >  The first three elements are in little endian, while the rest
> > > > > > -is in big endian.
> > > > > > +is in big endian. The option must be specified for all non empty and
> > > > > > +image acceptance capsules
> > > > >
> > > > > "image acceptance" -> "firmware acceptance"
> > > >
> > > > Okay
> > > >
> > > > >
> > > > > I don't still understand why we need a guid for acceptance
> > > > > while revert doesn't require it.
> > > > > I believe that firmware update is "all or nothing", isn't it?
> > > >
> > > > I believe this gives more flexibility in that different components
> > > > might be required to accept the various firmware images. So, one
> > > > component might accept the optee_os, while another might be
> > > > responsible for accepting u-boot. In any case, we do check that all
> > > > the components have their accepted bit set, and only if so, does the
> > > > bank boot in the regular state.
> > >
> > > Probably I don't understand the behavior.
> > > Let's assume that we have firmware A and firmware B and then
> > > update both.
> > > When the firmware A is accepted and B is not (not yet issuing
> > > acceptance capsule) and I try to reboot the system, what happens?
> > > From which bank does the system boot, old one or new one?
> >
> > Once any/all of the images have been updated, on subsequent reboot,
> > the platform would boot in Trial State from the updated bank. I have
> > introduced an EFI variable, TrialeStateCtr for counting the number of
> > times the system is booting in the trial state. The system remains in
> > trial state as long as all the images from the updated bank have not
> > been accepted. The platform boots in trial state for a particular
> > number of iterations(configurable), and once that count has exceeded,
> > the active bank value gets changed to the previous_active_index, and
> > the platform subsequently boots from the other bank. If all the images
> > do get accepted while the platform is in trial state, the platform
> > transitions to the regular state, and continues booting from that
> > bank.
>
> Thank you for the details.
> But if I understand correctly, why do we need a partially-accepted status?

It's not so much about needing a partial update, but allowing for a
scenario where multiple components might be tasked with accepting
different firmware images. I see this as a kind of flexibility given.
I do appreciate your point of view to have a common format for accept
and reject capsules, but this format does not hurt IMO as long as it
is documented and explained.

> When some are accepted but others not, the system boots from an update
> bank in any way. Right?
> So at the end, all that we should do is to accept the boot "from a new bank"
> permanently (and transit to, what you say, regular state), or to let the system
> boot from an old bank (again, in a regular state).
>
> I don't see any good reason for having a partial acceptance.
>
> We should continue this discussion, but anyhow, you should think of
> adding such a description above in U-Boot doc.

Okay. Will do.

-sughosh
>
> -Takahiro Akashi
>
>
> > -sughosh
> >
> > >
> > > > In case of a firmware revert, it would
> > > > not matter which firmware component is being reverted -- the platform
> > > > would simply need to boot from the other bank. Do you see any issue
> > > > with the current method that we have?
> > > >
> > > > >
> > > > > If there is a good reason, please describe a possible/expected
> > > > > scenario.
> > > >
> > > > Where do you want me to explain this, in the feature documentation? Or
> > > > do you think this can be elaborated in greater detail in the spec.
> > >
> > > I prefer some explanation in U-Boot doc.
> > >
> > > > >
> > > > > >  .TP
> > > > > >  .BI "-i\fR,\fB --index " index
> > > > > > @@ -57,6 +60,18 @@ Specify an image index
> > > > > >  .BI "-I\fR,\fB --instance " instance
> > > > > >  Specify a hardware instance
> > > > > >
> > > > > > +.PP
> > > > > > +For generation of firmware accept empty capsule
> > > > > > +.BR --guid
> > > > > > +is mandatory
> > > > > > +.TP
> > > > > > +.BI "-A\fR,\fB --fw-accept "
> > > > > > +Generate a firmware acceptance empty capsule
> > > > > > +
> > > > > > +.TP
> > > > > > +.BI "-R\fR,\fB --fw-revert "
> > > > > > +Generate a firmware revert empty capsule
> > > > > > +
> > > > > >  .TP
> > > > > >  .BR -h ", " --help
> > > > > >  Print a help message
> > > > > > diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> > > > > > index d63b831443..072a4b5598 100644
> > > > > > --- a/tools/eficapsule.h
> > > > > > +++ b/tools/eficapsule.h
> > > > > > @@ -41,6 +41,14 @@ typedef struct {
> > > > > >       EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
> > > > > >                0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
> > > > > >
> > > > > > +#define FW_ACCEPT_OS_GUID \
> > > > > > +     EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
> > > > > > +              0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
> > > > > > +
> > > > > > +#define FW_REVERT_OS_GUID \
> > > > > > +     EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
> > > > > > +              0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
> > > > > > +
> > > > > >  /* flags */
> > > > > >  #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
> > > > > >
> > > > > > diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> > > > > > index 5f74d23b9e..e8eb6b070d 100644
> > > > > > --- a/tools/mkeficapsule.c
> > > > > > +++ b/tools/mkeficapsule.c
> > > > > > @@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
> > > > > >  efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
> > > > > >  efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
> > > > > >
> > > > > > -static const char *opts_short = "g:i:I:v:p:c:m:dh";
> > > > > > +static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
> > > > > > +
> > > > > > +static bool empty_capsule;
> > > > > > +static unsigned char capsule;
> > > > > > +
> > > > > > +enum {
> > > > > > +     CAPSULE_NORMAL_BLOB = 0,
> > > > > > +     CAPSULE_ACCEPT,
> > > > > > +     CAPSULE_REVERT,
> > > > > > +} capsule_type;
> > > > > >
> > > > > >  static struct option options[] = {
> > > > > >       {"guid", required_argument, NULL, 'g'},
> > > > > > @@ -39,24 +48,47 @@ static struct option options[] = {
> > > > > >       {"certificate", required_argument, NULL, 'c'},
> > > > > >       {"monotonic-count", required_argument, NULL, 'm'},
> > > > > >       {"dump-sig", no_argument, NULL, 'd'},
> > > > > > +     {"fw-accept", no_argument, NULL, 'A'},
> > > > > > +     {"fw-revert", no_argument, NULL, 'R'},
> > > > > >       {"help", no_argument, NULL, 'h'},
> > > > > >       {NULL, 0, NULL, 0},
> > > > > >  };
> > > > > >
> > > > > >  static void print_usage(void)
> > > > > >  {
> > > > > > -     fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > > > > > -             "Options:\n"
> > > > > > -
> > > > > > -             "\t-g, --guid <guid string>    guid for image blob type\n"
> > > > > > -             "\t-i, --index <index>         update image index\n"
> > > > > > -             "\t-I, --instance <instance>   update hardware instance\n"
> > > > > > -             "\t-p, --private-key <privkey file>  private key file\n"
> > > > > > -             "\t-c, --certificate <cert file>     signer's certificate file\n"
> > > > > > -             "\t-m, --monotonic-count <count>     monotonic count\n"
> > > > > > -             "\t-d, --dump_sig              dump signature (*.p7)\n"
> > > > > > -             "\t-h, --help                  print a help message\n",
> > > > > > -             tool_name);
> > > > > > +     if (empty_capsule) {
> > > > > > +             if (capsule == CAPSULE_ACCEPT) {
> > > > > > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > > > > > +                             tool_name);
> > > > > > +                     fprintf(stderr, "Options:\n"
> > > > > > +                             "\t-A, --fw-accept             firmware accept capsule\n"
> > > > > > +                             "\t-g, --guid <guid string>    guid for image blob type\n"
> > > > > > +                             "\t-h, --help                  print a help message\n"
> > > > > > +                             );
> > > > > > +             } else {
> > > > > > +                     fprintf(stderr, "Usage: %s [options] <output file>\n",
> > > > > > +                             tool_name);
> > > > > > +                     fprintf(stderr, "Options:\n"
> > > > > > +                             "\t-R, --fw-revert             firmware revert capsule\n"
> > > > > > +                             "\t-h, --help                  print a help message\n"
> > > > > > +                             );
> > > > > > +             }
> > > > > > +     } else {
> > > > > > +             fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> > > > > > +                     "Options:\n"
> > > > > > +
> > > > > > +                     "\t-g, --guid <guid string>    guid for image blob type\n"
> > > > > > +                     "\t-i, --index <index>         update image index\n"
> > > > > > +                     "\t-I, --instance <instance>   update hardware instance\n"
> > > > > > +                     "\t-p, --private-key <privkey file>  private key file\n"
> > > > > > +                     "\t-c, --certificate <cert file>     signer's certificate file\n"
> > > > > > +                     "\t-m, --monotonic-count <count>     monotonic count\n"
> > > > > > +                     "\t-d, --dump_sig              dump signature (*.p7)\n"
> > > > > > +                     "\t-A, --fw-accept             firmware accept capsule\n"
> > > > > > +                     "\t-R, --fw-revert             firmware revert capsule\n"
> > > > > > +                     "\t-h, --help                  print a help message\n",
> > > > > > +                     tool_name);
> > > > > > +     }
> > > > > >  }
> > > > > >
> > > > > >  /**
> > > > > > @@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
> > > > > >       buf[7] = c;
> > > > > >  }
> > > > > >
> > > > > > +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> > > > > > +{
> > > > > > +     struct efi_capsule_header header;
> > > > > > +     FILE *f = NULL;
> > > > > > +     int ret = -1;
> > > > > > +     efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
> > > > > > +     efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
> > > > > > +     efi_guid_t payload, capsule_guid;
> > > > > > +
> > > > > > +     f = fopen(path, "w");
> > > > > > +     if (!f) {
> > > > > > +             fprintf(stderr, "cannot open %s\n", path);
> > > > > > +             goto err;
> > > > > > +     }
> > > > > > +
> > > > > > +     capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
> > > > > > +
> > > > > > +     memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
> > > > >
> > > > >   -> guidcpy()
> > > >
> > > > This being a host tool, guidcpy cannot be used. You have used memcpy
> > > > in the create_fwbin() for the same reason I guess.
> > >
> > > Ah, right.
> > >
> > > > >
> > > > > > +     header.header_size = sizeof(header);
> > > > > > +     header.flags = 0;
> > > > > > +
> > > > > > +     header.capsule_image_size = fw_accept ?
> > > > > > +             sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
> > > > > > +
> > > > > > +     if (write_capsule_file(f, &header, sizeof(header),
> > > > > > +                            "Capsule header"))
> > > > > > +             goto err;
> > > > > > +
> > > > > > +     if (fw_accept) {
> > > > > > +             memcpy(&payload, guid, sizeof(efi_guid_t));
> > > > >
> > > > > ditto
> > > >
> > > > Same as above.
> > > >
> > > > >
> > > > > > +             if (write_capsule_file(f, &payload, sizeof(payload),
> > > > > > +                                    "FW Accept Capsule Payload"))
> > > > > > +                     goto err;
> > > > > > +     }
> > > > > > +
> > > > > > +     ret = 0;
> > > > > > +
> > > > > > +err:
> > > > > > +     if (f)
> > > > > > +             fclose(f);
> > > > > > +
> > > > > > +     return ret;
> > > > > > +}
> > > > > > +
> > > > > >  /**
> > > > > >   * main - main entry function of mkeficapsule
> > > > > >   * @argc:    Number of arguments
> > > > > > @@ -639,22 +715,49 @@ int main(int argc, char **argv)
> > > > > >               case 'd':
> > > > > >                       dump_sig = 1;
> > > > > >                       break;
> > > > > > +             case 'A':
> > > > > > +                     capsule |= CAPSULE_ACCEPT;
> > > > > > +                     break;
> > > > > > +             case 'R':
> > > > > > +                     capsule |= CAPSULE_REVERT;
> > > > > > +                     break;
> > > > > >               case 'h':
> > > > > >                       print_usage();
> > > > > >                       exit(EXIT_SUCCESS);
> > > > > >               }
> > > > > >       }
> > > > > >
> > > > > > +     if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
> > > > > > +             fprintf(stderr,
> > > > > > +                     "Select either of Accept or Revert capsule generation\n");
> > > > > > +             exit(EXIT_FAILURE);
> > > > > > +     }
> > > > > > +
> > > > > > +     empty_capsule = (capsule == CAPSULE_ACCEPT ||
> > > > > > +                      capsule == CAPSULE_REVERT);
> > > > > > +
> > > > >
> > > > > So empty_capsule is redundant as empty_capsule is equivalent with
> > > > > "capsule == CAPSULE_NORMAL_BLOB".
> > > > > I think that a single variable, say capsule_type, is enough.
> > > >
> > > > I was using empty_capsule primarily to make the check done below look
> > > > more succinct and readable. But I can change that to capsule !=
> > > > CAPSULE_NORMAL_BLOB.
> > > >
> > > > >
> > > > > >       /* check necessary parameters */
> > > > > > -     if ((argc != optind + 2) || !guid ||
> > > > > > -         ((privkey_file && !cert_file) ||
> > > > > > -          (!privkey_file && cert_file))) {
> > > > > > +     if ((!empty_capsule &&
> > > > > > +         ((argc != optind + 2) || !guid ||
> > > > > > +          ((privkey_file && !cert_file) ||
> > > > > > +           (!privkey_file && cert_file)))) ||
> > > > > > +         (empty_capsule &&
> > > > > > +         ((argc != optind + 1) ||
> > > > > > +          ((capsule == CAPSULE_ACCEPT) && !guid) ||
> > > > > > +          ((capsule == CAPSULE_REVERT) && guid)))) {
> > > > > >               print_usage();
> > > > > >               exit(EXIT_FAILURE);
> > > > > >       }
> > > > > >
> > > > > > -     if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
> > > > > > -                      mcount, privkey_file, cert_file) < 0) {
> > > > > > +     if (empty_capsule) {
> > > > > > +             if (create_empty_capsule(argv[argc - 1], guid,
> > > > > > +                                      capsule == CAPSULE_ACCEPT) < 0) {
> > > > >
> > > > >         if (capsule_type != CAPSULE_NORMAL_BLOB)
> > > > >                 create_empty_capsule(..., capsule_type == CAPSULE_ACCEPT);
> > > > >
> > > > > Simple is the best :)
> > > >
> > > > Common, please don't tell me that the code above is complicated. Just
> > > > that we can do without the empty_capsule variable, yes.
> > >
> > > Sorry, not complicated, but having two variables make little sense.
> > >
> > > -Takahiro Akashi
> > >
> > > > -sughosh
> > > >
> > > > >
> > > > > -Takahiro Akashi
> > > > > > +                     fprintf(stderr, "Creating empty capsule failed\n");
> > > > > > +                     exit(EXIT_FAILURE);
> > > > > > +             }
> > > > > > +     } else  if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
> > > > > > +                              index, instance, mcount, privkey_file,
> > > > > > +                              cert_file) < 0) {
> > > > > >               fprintf(stderr, "Creating firmware capsule failed\n");
> > > > > >               exit(EXIT_FAILURE);
> > > > > >       }
> > > > > > --
> > > > > > 2.25.1
> > > > > >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 21/23] doc: synquacer: Add how to enable FWU Multi Bank Update
  2022-06-09 12:30 ` [PATCH v5 21/23] doc: synquacer: Add how to enable FWU Multi Bank Update Sughosh Ganu
@ 2022-06-17 13:59   ` Michal Simek
  0 siblings, 0 replies; 104+ messages in thread
From: Michal Simek @ 2022-06-17 13:59 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Jassi Brar, Masami Hiramatsu



On 6/9/22 14:30, Sughosh Ganu wrote:
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> 
> Add a section for the instruction of building the FWU Multi Bank
> Update supported U-Boot and installation.
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   doc/board/socionext/developerbox.rst | 110 +++++++++++++++++++++++++++
>   1 file changed, 110 insertions(+)
> 
> diff --git a/doc/board/socionext/developerbox.rst b/doc/board/socionext/developerbox.rst
> index 2d943c23be..d9f38a3897 100644
> --- a/doc/board/socionext/developerbox.rst
> +++ b/doc/board/socionext/developerbox.rst
> @@ -85,3 +85,113 @@ Once the flasher tool is running we are ready flash the UEFI image::
>   
>   After transferring the SPI_NOR_UBOOT.fd, turn off the DSW2-7 and reset the board.
>   
> +
> +Enable FWU Multi Bank Update
> +============================
> +
> +DeveloperBox supports the FWU Multi Bank Update. You *MUST* update both *SCP firmware* and *TF-A* for this feature. This will change the layout and the boot process but you can switch back to the normal one by changing the DSW 1-4 off.
> +
> +Configure U-Boot
> +----------------
> +
> +To enable the FWU Multi Bank Update on the DeveloperBox, you need to add following configurations to configs/synquacer_developerbox_defconfig ::
> +
> + CONFIG_FWU_MULTI_BANK_UPDATE=y
> + CONFIG_FWU_MDATA_MTD=y
> + CONFIG_CMD_FWU_METADATA=y
> + CONFIG_TOOLS_MKFWUMDATA=y
> +
> +And build it::
> +
> +  cd u-boot/
> +  export ARCH=arm64
> +  export CROSS_COMPILE=aarch64-linux-gnu-
> +  make synqucer_developerbox_defconfig
> +  make -j `noproc`
> +  cd ../
> +
> +By default, the CONFIG_FWU_NUM_BANKS and COFNIG_FWU_NUM_IMAGES_PER_BANKS are set to 2 and 1 respectively. This uses FIP (Firmware 

typo CONFIG_

Thanks,
Michal
-- 
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-06-09 12:30 ` [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox Sughosh Ganu
@ 2022-06-17 14:00   ` Michal Simek
  2022-06-20  8:23   ` Michal Simek
  1 sibling, 0 replies; 104+ messages in thread
From: Michal Simek @ 2022-06-17 14:00 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Jassi Brar, Masami Hiramatsu



On 6/9/22 14:30, Sughosh Ganu wrote:
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> 
> The DeveloperBox platform can support the FWU Multi bank
> update. SCP firmware will switch the boot mode by DSW3-4
> and load the Multi bank update supported TF-A BL2 from
> 0x600000 offset on the SPI flash. Thus it can co-exist
> with the legacy boot mode (legacy U-Boot or EDK2).
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> ---
>   Changes in v3:
>    - Change devicetree to add partitions.
>    - Update fwu_plat_get_alt_num() to find the alt number from the bank index.
>    - Use only 2 partitions for AB update.
>    - Clear platform-mdata's boot_count to finish platform trial boot.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   .../synquacer-sc2a11-developerbox-u-boot.dtsi |  15 +-
>   board/socionext/developerbox/Kconfig          |  13 ++
>   board/socionext/developerbox/Makefile         |   1 +
>   board/socionext/developerbox/fwu_plat.c       | 207 ++++++++++++++++++
>   include/configs/synquacer.h                   |   8 +
>   5 files changed, 241 insertions(+), 3 deletions(-)
>   create mode 100644 board/socionext/developerbox/fwu_plat.c
> 
> diff --git a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> index 095727e03c..ab4e3d1c2b 100644
> --- a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> +++ b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> @@ -23,7 +23,7 @@
>   		active_clk_edges;
>   		chipselect_num = <1>;
>   
> -		spi-flash@0 {
> +		spi_flash: spi-flash@0 {
>   			#address-cells = <1>;
>   			#size-cells = <1>;
>   			compatible = "jedec,spi-nor";
> @@ -84,11 +84,15 @@
>   					label = "UBoot-Env";
>   					reg = <0x580000 0x80000>;
>   				};
> -
> +				/* FWU Multi bank update partitions */
>   				partition@600000 {
> -					label = "FIP";
> +					label = "FIP-Bank0";
>   					reg = <0x600000 0x400000>;
>   				};
> +				partition@a00000 {
> +					label = "FIP-Bank1";
> +					reg = <0xa00000 0x400000>;
> +				};
>   			};
>   		};
>   	};
> @@ -114,6 +118,11 @@
>   		optee {
>   			status = "okay";
>   		};
> +		fwu-mdata {
> +			compatible = "u-boot,fwu-mdata-mtd";
> +			fwu-mdata-store = <&spi_flash>;
> +			mdata-offsets = <0x500000 0x530000>;
> +		};
>   	};
>   };
>   
> diff --git a/board/socionext/developerbox/Kconfig b/board/socionext/developerbox/Kconfig
> index c181d26a44..7df6750baf 100644
> --- a/board/socionext/developerbox/Kconfig
> +++ b/board/socionext/developerbox/Kconfig
> @@ -32,4 +32,17 @@ config SYS_CONFIG_NAME
>   	default "synquacer"
>   
>   endif
> +
> +config FWU_MULTI_BANK_UPDATE
> +	select FWU_MDATA_MTD
> +	select DM_SPI_FLASH
> +	select DM_FWU_MDATA
> +	select BOARD_LATE_INIT
> +
> +config FWU_NUM_BANKS
> +	default 2
> +
> +config FWU_NUM_IMAGES_PER_BANK
> +	default 1
> +
>   endif
> diff --git a/board/socionext/developerbox/Makefile b/board/socionext/developerbox/Makefile
> index 4a46de995a..9b80ee38e7 100644
> --- a/board/socionext/developerbox/Makefile
> +++ b/board/socionext/developerbox/Makefile
> @@ -7,3 +7,4 @@
>   #
>   
>   obj-y	:= developerbox.o
> +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_plat.o
> diff --git a/board/socionext/developerbox/fwu_plat.c b/board/socionext/developerbox/fwu_plat.c
> new file mode 100644
> index 0000000000..fd6d0e3659
> --- /dev/null
> +++ b/board/socionext/developerbox/fwu_plat.c
> @@ -0,0 +1,207 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2021, Linaro Limited
> + */
> +
> +#include <dfu.h>
> +#include <efi_loader.h>
> +#include <flash.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <malloc.h>
> +#include <memalign.h>
> +#include <spi.h>
> +#include <spi_flash.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <u-boot/crc.h>
> +
> +/* SPI Flash accessors */
> +static struct spi_flash *plat_spi_flash;
> +
> +static int __plat_sf_get_flash(void)
> +{
> +	/* TODO: define platform spi-flash somewhere. */
> +	plat_spi_flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
> +					 CONFIG_SF_DEFAULT_CS,
> +					 CONFIG_SF_DEFAULT_SPEED,
> +					 CONFIG_SF_DEFAULT_MODE);
> +
> +	return 0;
> +}
> +
> +static int plat_sf_get_flash(struct spi_flash **flash)
> +{
> +	int ret = 0;
> +
> +	if (!plat_spi_flash)
> +		ret = __plat_sf_get_flash();
> +
> +	*flash = plat_spi_flash;
> +
> +	return ret;
> +}
> +
> +static int sf_load_data(u32 offs, u32 size, void **data)
> +{
> +	struct spi_flash *flash;
> +	int ret;
> +
> +	ret = plat_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 = plat_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;
> +}
> +
> +#define PLAT_METADATA_OFFSET	0x510000

Meta data offsets based on DT is somewhere else.
I would expect that this is read from DT instead of hardcoding it here.

  124                 fwu-mdata {
  125                         compatible = "u-boot,fwu-mdata-mtd";
  126                         fwu-mdata-store = <&spi_flash>;
  127                         mdata-offsets = <0x500000 0x530000>;
  128                 };

Thanks,
Michal

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 20/23] FWU: synquacer: Generate dfu_alt_info from devicetree partition
  2022-06-09 12:30 ` [PATCH v5 20/23] FWU: synquacer: Generate dfu_alt_info from devicetree partition Sughosh Ganu
@ 2022-06-17 14:02   ` Michal Simek
  2022-07-18 14:49     ` Jassi Brar
  0 siblings, 1 reply; 104+ messages in thread
From: Michal Simek @ 2022-06-17 14:02 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Jassi Brar, Masami Hiramatsu



On 6/9/22 14:30, Sughosh Ganu wrote:
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> 
> Generate dfu_alt_info from the partition uuid information in the
> devicetree, and record the mapping of partition uuid and the
> index of dfu_alt_num.
> 
> This could be a reference implementation of the automatic DFU
> generation for FWU multi-bank update for non GPT firmware
> platforms.
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   .../synquacer-sc2a11-developerbox-u-boot.dtsi |   3 +
>   board/socionext/developerbox/Kconfig          |   1 +
>   board/socionext/developerbox/fwu_plat.c       |  79 ++++----
>   include/configs/synquacer.h                   |   6 +-
>   include/fwu.h                                 |   6 +
>   lib/fwu_updates/Makefile                      |   1 +
>   lib/fwu_updates/fwu_mtd.c                     | 173 ++++++++++++++++++
>   7 files changed, 221 insertions(+), 48 deletions(-)
>   create mode 100644 lib/fwu_updates/fwu_mtd.c
> 
> diff --git a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> index ab4e3d1c2b..c7ec8a0321 100644
> --- a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> +++ b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> @@ -36,6 +36,7 @@
>   				compatible = "fixed-partitions";
>   				#address-cells = <1>;
>   				#size-cells = <1>;
> +				uuid = "17e86d77-41f9-4fd7-87ec-a55df9842de5";
>   
>   				partition@0 {
>   					label = "BootStrap-BL1";
> @@ -88,10 +89,12 @@
>   				partition@600000 {
>   					label = "FIP-Bank0";
>   					reg = <0x600000 0x400000>;
> +					uuid = "5a66a702-99fd-4fef-a392-c26e261a2828";
>   				};
>   				partition@a00000 {
>   					label = "FIP-Bank1";
>   					reg = <0xa00000 0x400000>;
> +					uuid = "a8f868a1-6e5c-4757-878d-ce63375ef2c0";
>   				};
>   			};
>   		};
> diff --git a/board/socionext/developerbox/Kconfig b/board/socionext/developerbox/Kconfig
> index 7df6750baf..ad2a284f13 100644
> --- a/board/socionext/developerbox/Kconfig
> +++ b/board/socionext/developerbox/Kconfig
> @@ -38,6 +38,7 @@ config FWU_MULTI_BANK_UPDATE
>   	select DM_SPI_FLASH
>   	select DM_FWU_MDATA
>   	select BOARD_LATE_INIT
> +	select SET_DFU_ALT_INFO
>   
>   config FWU_NUM_BANKS
>   	default 2
> diff --git a/board/socionext/developerbox/fwu_plat.c b/board/socionext/developerbox/fwu_plat.c
> index fd6d0e3659..ff06eade7d 100644
> --- a/board/socionext/developerbox/fwu_plat.c
> +++ b/board/socionext/developerbox/fwu_plat.c
> @@ -10,8 +10,10 @@
>   #include <fwu_mdata.h>
>   #include <malloc.h>
>   #include <memalign.h>
> +#include <mtd.h>
>   #include <spi.h>
>   #include <spi_flash.h>
> +#include <uuid.h>
>   
>   #include <linux/errno.h>
>   #include <linux/types.h>
> @@ -94,6 +96,36 @@ static int sf_save_data(u32 offs, u32 size, void *data)
>   	return ret;
>   }
>   
> +#define DFU_ALT_BUF_LEN 256
> +#define DFU_ALT_NUM_MAX (CONFIG_FWU_NUM_IMAGES_PER_BANK * CONFIG_FWU_NUM_BANKS)
> +
> +/* Generate dfu_alt_info from partitions */
> +void set_dfu_alt_info(char *interface, char *devstr)
> +{
> +	int ret;
> +	struct mtd_info *mtd;
> +	static char *buf = NULL;
> +
> +	if (!buf) {
> +		buf = malloc_cache_aligned(DFU_ALT_BUF_LEN);
> +		memset(buf, 0, DFU_ALT_BUF_LEN);
> +
> +		mtd_probe_devices();
> +
> +		mtd = get_mtd_device_nm("nor1");
> +		if (IS_ERR_OR_NULL(mtd))
> +			return;
> +
> +		ret = fwu_gen_alt_info_from_mtd(buf, DFU_ALT_BUF_LEN, mtd);
> +		if (ret < 0) {
> +			log_err("Error: Failed to generate dfu_alt_info. (%d)\n", ret);
> +			return;
> +		}
> +		log_debug("Make dfu_alt_info: '%s'\n", buf);
> +	}
> +	env_set("dfu_alt_info", buf);
> +}
> +
>   #define PLAT_METADATA_OFFSET	0x510000
>   #define PLAT_METADATA_SIZE	(sizeof(struct devbox_metadata))
>   
> @@ -105,49 +137,7 @@ struct __packed devbox_metadata {
>   int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
>   			 efi_guid_t *image_id, int *alt_num)
>   {
> -	struct fwu_image_bank_info *bank;
> -	struct fwu_mdata *mdata;
> -	int i, ret;
> -
> -	ret = fwu_get_mdata(&mdata);
> -	if (ret < 0)
> -		return ret;
> -
> -	/*
> -	 * DeveloperBox FWU expects Bank:Image = 1:1, and the dfu_alt_info
> -	 * only has the entries for banks. Thus the alt_no should be equal
> -	 * to the bank index number.
> -	 */
> -	ret = -ENOENT;
> -	for (i = 0; i < CONFIG_FWU_NUM_BANKS; i++) {
> -		bank = &mdata->img_entry[0].img_bank_info[i];
> -		if (guidcmp(image_id, &bank->image_uuid) == 0) {
> -			*alt_num = i;
> -			ret = 0;
> -			break;
> -		}
> -	}
> -
> -	free(mdata);
> -
> -	return ret;
> -}
> -
> -/* This assumes that user doesn't change system default dfu_alt_info */
> -efi_status_t fill_image_type_guid_array(const efi_guid_t __always_unused
> -					*default_guid,
> -					efi_guid_t **part_guid_arr)
> -{
> -	int i;
> -
> -	*part_guid_arr = malloc(sizeof(efi_guid_t) * DEFAULT_DFU_ALT_NUM);
> -	if (!*part_guid_arr)
> -		return EFI_OUT_OF_RESOURCES;
> -
> -	for (i = 0; i < DEFAULT_DFU_ALT_NUM; i++)
> -		guidcpy((*part_guid_arr + i), &devbox_fip_image_type_guid);
> -
> -	return EFI_SUCCESS;
> +	return fwu_get_mtd_alt_num(image_id, alt_num, "nor1", 0);
>   }
>   
>   int fwu_plat_get_update_index(u32 *update_idx)
> @@ -188,6 +178,9 @@ int board_late_init(void)
>   {
>   	int ret;
>   
> +	/* Make mmc available for EFI */
> +	run_command("mmc dev 0", 0);
> +

What is this for?

And I can't see any single note about in commit message.

Thanks,
Michal

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-06-09 12:30 ` [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox Sughosh Ganu
  2022-06-17 14:00   ` Michal Simek
@ 2022-06-20  8:23   ` Michal Simek
  2022-07-18 14:43     ` Jassi Brar
  1 sibling, 1 reply; 104+ messages in thread
From: Michal Simek @ 2022-06-20  8:23 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Jassi Brar, Masami Hiramatsu



On 6/9/22 14:30, Sughosh Ganu wrote:
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> 
> The DeveloperBox platform can support the FWU Multi bank
> update. SCP firmware will switch the boot mode by DSW3-4
> and load the Multi bank update supported TF-A BL2 from
> 0x600000 offset on the SPI flash. Thus it can co-exist
> with the legacy boot mode (legacy U-Boot or EDK2).
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>

I am looking at this code again while trying on xilinx HW.

> ---
>   Changes in v3:
>    - Change devicetree to add partitions.
>    - Update fwu_plat_get_alt_num() to find the alt number from the bank index.
>    - Use only 2 partitions for AB update.
>    - Clear platform-mdata's boot_count to finish platform trial boot.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   .../synquacer-sc2a11-developerbox-u-boot.dtsi |  15 +-
>   board/socionext/developerbox/Kconfig          |  13 ++
>   board/socionext/developerbox/Makefile         |   1 +
>   board/socionext/developerbox/fwu_plat.c       | 207 ++++++++++++++++++
>   include/configs/synquacer.h                   |   8 +
>   5 files changed, 241 insertions(+), 3 deletions(-)
>   create mode 100644 board/socionext/developerbox/fwu_plat.c
> 
> diff --git a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> index 095727e03c..ab4e3d1c2b 100644
> --- a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> +++ b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> @@ -23,7 +23,7 @@
>   		active_clk_edges;
>   		chipselect_num = <1>;
>   
> -		spi-flash@0 {
> +		spi_flash: spi-flash@0 {
>   			#address-cells = <1>;
>   			#size-cells = <1>;
>   			compatible = "jedec,spi-nor";
> @@ -84,11 +84,15 @@
>   					label = "UBoot-Env";
>   					reg = <0x580000 0x80000>;
>   				};
> -
> +				/* FWU Multi bank update partitions */
>   				partition@600000 {
> -					label = "FIP";
> +					label = "FIP-Bank0";
>   					reg = <0x600000 0x400000>;
>   				};
> +				partition@a00000 {
> +					label = "FIP-Bank1";
> +					reg = <0xa00000 0x400000>;
> +				};
>   			};
>   		};
>   	};
> @@ -114,6 +118,11 @@
>   		optee {
>   			status = "okay";
>   		};
> +		fwu-mdata {
> +			compatible = "u-boot,fwu-mdata-mtd";
> +			fwu-mdata-store = <&spi_flash>;
> +			mdata-offsets = <0x500000 0x530000>;
> +		};
>   	};
>   };
>   
> diff --git a/board/socionext/developerbox/Kconfig b/board/socionext/developerbox/Kconfig
> index c181d26a44..7df6750baf 100644
> --- a/board/socionext/developerbox/Kconfig
> +++ b/board/socionext/developerbox/Kconfig
> @@ -32,4 +32,17 @@ config SYS_CONFIG_NAME
>   	default "synquacer"
>   
>   endif
> +
> +config FWU_MULTI_BANK_UPDATE
> +	select FWU_MDATA_MTD
> +	select DM_SPI_FLASH
> +	select DM_FWU_MDATA
> +	select BOARD_LATE_INIT
> +
> +config FWU_NUM_BANKS
> +	default 2
> +
> +config FWU_NUM_IMAGES_PER_BANK
> +	default 1
> +
>   endif
> diff --git a/board/socionext/developerbox/Makefile b/board/socionext/developerbox/Makefile
> index 4a46de995a..9b80ee38e7 100644
> --- a/board/socionext/developerbox/Makefile
> +++ b/board/socionext/developerbox/Makefile
> @@ -7,3 +7,4 @@
>   #
>   
>   obj-y	:= developerbox.o
> +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_plat.o
> diff --git a/board/socionext/developerbox/fwu_plat.c b/board/socionext/developerbox/fwu_plat.c
> new file mode 100644
> index 0000000000..fd6d0e3659
> --- /dev/null
> +++ b/board/socionext/developerbox/fwu_plat.c
> @@ -0,0 +1,207 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2021, Linaro Limited
> + */
> +
> +#include <dfu.h>
> +#include <efi_loader.h>
> +#include <flash.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <malloc.h>
> +#include <memalign.h>
> +#include <spi.h>
> +#include <spi_flash.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <u-boot/crc.h>
> +
> +/* SPI Flash accessors */
> +static struct spi_flash *plat_spi_flash;
> +
> +static int __plat_sf_get_flash(void)
> +{
> +	/* TODO: define platform spi-flash somewhere. */
> +	plat_spi_flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
> +					 CONFIG_SF_DEFAULT_CS,
> +					 CONFIG_SF_DEFAULT_SPEED,
> +					 CONFIG_SF_DEFAULT_MODE);
> +
> +	return 0;

What about if spi_flash_probe() fails?

You are returning 0 here all the time and below you are propagating it that 
everything is fine.




> +}
> +
> +static int plat_sf_get_flash(struct spi_flash **flash)
> +{
> +	int ret = 0;
> +
> +	if (!plat_spi_flash)
> +		ret = __plat_sf_get_flash();
> +
> +	*flash = plat_spi_flash;
> +
> +	return ret;
> +}
> +
> +static int sf_load_data(u32 offs, u32 size, void **data)
> +{
> +	struct spi_flash *flash;
> +	int ret;
> +
> +	ret = plat_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 = plat_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);

What it is interesting here that framework itself is using mtd infrastructure 
but this platform driver is calling spi functions directly.
It looks a little bit nonstandard way. What's the reason for it?


> +	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;
> +}
> +
> +#define PLAT_METADATA_OFFSET	0x510000
> +#define PLAT_METADATA_SIZE	(sizeof(struct devbox_metadata))
> +
> +struct __packed devbox_metadata {
> +	u32 boot_index;
> +	u32 boot_count;

There is the whole bootcount infrastructure for this. I think it would be much 
better to use that framework instead of creating parallel one.

Thanks,
Michal

-- 
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata
  2022-06-09 12:29 ` [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata Sughosh Ganu
  2022-06-10 12:07   ` Ilias Apalodimas
@ 2022-06-20 12:53   ` Michal Simek
  2022-06-21 12:07   ` Patrick DELAUNAY
  2 siblings, 0 replies; 104+ messages in thread
From: Michal Simek @ 2022-06-20 12:53 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Etienne Carriere, Jassi Brar



On 6/9/22 14:29, Sughosh Ganu wrote:
> Add a command to read the metadata as specified in the FWU
> specification and print the fields of the metadata.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   cmd/Kconfig     |  7 +++++
>   cmd/Makefile    |  1 +
>   cmd/fwu_mdata.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 82 insertions(+)
>   create mode 100644 cmd/fwu_mdata.c
> 
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 09193b61b9..275becd837 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -144,6 +144,13 @@ config CMD_CPU
>   	  internal name) and clock frequency. Other information may be
>   	  available depending on the CPU driver.
>   
> +config CMD_FWU_METADATA
> +	bool "fwu metadata read"
> +	depends on FWU_MULTI_BANK_UPDATE
> +	default y if FWU_MULTI_BANK_UPDATE
> +	help
> +	  Command to read the metadata and dump it's contents
> +
>   config CMD_LICENSE
>   	bool "license"
>   	select BUILD_BIN2C
> diff --git a/cmd/Makefile b/cmd/Makefile
> index 5e43a1e022..259a93bc65 100644
> --- a/cmd/Makefile
> +++ b/cmd/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_CMD_FPGA) += fpga.o
>   obj-$(CONFIG_CMD_FPGAD) += fpgad.o
>   obj-$(CONFIG_CMD_FS_GENERIC) += fs.o
>   obj-$(CONFIG_CMD_FUSE) += fuse.o
> +obj-$(CONFIG_CMD_FWU_METADATA) += fwu_mdata.o
>   obj-$(CONFIG_CMD_GETTIME) += gettime.o
>   obj-$(CONFIG_CMD_GPIO) += gpio.o
>   obj-$(CONFIG_CMD_HVC) += smccc.o
> diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c
> new file mode 100644
> index 0000000000..bc20ca26a3
> --- /dev/null
> +++ b/cmd/fwu_mdata.c
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <command.h>
> +#include <dm.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <log.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include <linux/types.h>
> +
> +static void print_mdata(struct fwu_mdata *mdata)
> +{
> +	int i, j;
> +	struct fwu_image_entry *img_entry;
> +	struct fwu_image_bank_info *img_info;
> +	u32 nimages, nbanks;
> +
> +	printf("\tFWU Metadata\n");
> +	printf("crc32: %#x\n", mdata->crc32);
> +	printf("version: %#x\n", mdata->version);
> +	printf("active_index: %#x\n", mdata->active_index);
> +	printf("previous_active_index: %#x\n", mdata->previous_active_index);
> +
> +	nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> +	nbanks = CONFIG_FWU_NUM_BANKS;
> +	printf("\tImage Info\n");
> +	for (i = 0; i < nimages; i++) {
> +		img_entry = &mdata->img_entry[i];
> +		printf("\nImage Type Guid: %pUL\n", &img_entry->image_type_uuid);
> +		printf("Location Guid: %pUL\n", &img_entry->location_uuid);
> +		for (j = 0; j < nbanks; j++) {
> +			img_info = &img_entry->img_bank_info[j];
> +			printf("Image Guid:  %pUL\n", &img_info->image_uuid);
> +			printf("Image Acceptance: %#x\n", img_info->accepted);
> +		}
> +	}
> +}
> +
> +int do_fwu_mdata_read(struct cmd_tbl *cmdtp, int flag,
> +		     int argc, char * const argv[])
> +{
> +	struct udevice *dev;
> +	int ret = CMD_RET_SUCCESS;
> +	struct fwu_mdata *mdata = NULL;
> +
> +	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> +		log_err("Unable to get FWU metadata device\n");
> +		return CMD_RET_FAILURE;
> +	}
> +
> +	ret = fwu_get_mdata(&mdata);
> +	if (ret < 0) {
> +		log_err("Unable to get valid FWU metadata\n");
> +		ret = CMD_RET_FAILURE;
> +		goto out;
> +	}

I think here would be a need to also check data you get back.
I am playing with it and if I rewrite one copy and second copy is different I 
don't get any error message and I think it is wrong.
You should IMHO use mdata_check hooks to check that what you get is correct and 
aligned.

Thanks,
Michal

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support
  2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (22 preceding siblings ...)
  2022-06-09 12:30 ` [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox Sughosh Ganu
@ 2022-06-20 18:12 ` Patrick DELAUNAY
  2022-06-21  9:23   ` Sughosh Ganu
  23 siblings, 1 reply; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-20 18:12 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi,

On 6/9/22 14:29, Sughosh Ganu wrote:
> The patchset adds support for the FWU Multi Bank Update[1]
> feature. Certain aspects of the Dependable Boot[2] specification have
> also been implemented.
>
> The FWU multi bank update feature is used for supporting multiple
> sets(also called banks) of firmware image(s), allowing the platform to
> boot from a different bank, in case it fails to boot from the active
> bank. This functionality is supported by keeping the relevant
> information in a structure called metadata, which provides information
> on the images. Among other parameters, the metadata structure contains
> information on the currect active bank that is being used to boot
> image(s).
>
> Functionality is being added to work with the UEFI capsule driver in
> u-boot. The metadata is read to gather information on the update bank,
> which is the bank to which the firmware images would be flashed to. On
> a successful completion of the update of all components, the active
> bank field in the metadata is updated, to reflect the bank from which
> the platform will boot on the subsequent boots.
>
> Currently, the feature is being enabled on the STM32MP157C-DK2 and
> Synquacer boards. The DK2 board boots a FIP image from a uSD card
> partitioned with the GPT partioning scheme, while the Synquacer board
> boots a FIP image from a MTD partitioned SPI NOR flash device.
>
> This feature also requires changes in a previous stage of
> bootloader, which parses the metadata and selects the bank to boot the
> image(s) from. Support has being added in tf-a(BL2 stage) for the
> STM32MP157C-DK2 board to boot the active bank images. These changes
> have been merged to the upstream tf-a repository.
>
> Earlier, two separate patchsets were being sent. The patchset sent by
> me was adding support for the feature, and enabling the feature on the
> ST board. The other set of patches were being sent by Masami
> Hiramatsu, which were enabling the feature on the Synquacer
> platform. This patchset contains both set of patches, along with the
> associated documentation and the python test script for testing the
> feature.
>
> The upstreaming effort for this feature had been put on a temporary
> hold to address the fixing of some issues in the capsule update code,
> primarily using a per platform image GUID for the updatable
> images. Now that the series has been merged, upstreaming effort for
> the FWU update feature is being resumed. Hence, this version does not
> have any review comments being addressed.
>
>
> [1] - https://developer.arm.com/documentation/den0118/a
> [2] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
>
> Jassi Brar (1):
>    developerbox: synquacer: Use FIP as the updatable image
>
> Masami Hiramatsu (9):
>    FWU: Add FWU metadata access driver for non-GPT MTD devices
>    dt/bindings: firmware: Add FWU metadata on MTD devices binding
>    tools: Add mkfwumdata tool for FWU metadata image
>    FWU: doc: Update documentation for the FWU non-GPT MTD
>    synquacer: Update for TBBR (BL2) based new FIP layout
>    FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
>    FWU: synquacer: Generate dfu_alt_info from devicetree partition
>    doc: synquacer: Add how to enable FWU Multi Bank Update
>    [TEMP]configs: synquacer: Add FWU support for DeveloperBox
>
> Sughosh Ganu (13):
>    dt/bindings: Add bindings for FWU Metadata storage device
>    FWU: Add FWU metadata structure and driver for accessing metadata
>    FWU: Add FWU metadata access driver for GPT partitioned block devices
>    stm32mp1: dk2: Add a node for the FWU metadata device
>    stm32mp1: dk2: Add image information for capsule updates
>    FWU: stm32mp1: Add helper functions for accessing FWU metadata
>    FWU: STM32MP1: Add support to read boot index from backup register
>    FWU: Add boot time checks as highlighted by the FWU specification
>    FWU: Add support for the FWU Multi Bank Update feature
>    FWU: cmd: Add a command to read FWU metadata
>    mkeficapsule: Add support for generating empty capsules
>    FWU: doc: Add documentation for the FWU feature
>    sandbox: fwu: Add support for testing FWU feature on sandbox
>
>   arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi      |   7 +
>   .../synquacer-sc2a11-developerbox-u-boot.dtsi |  40 +-
>   arch/arm/mach-stm32mp/include/mach/stm32.h    |   4 +
>   arch/sandbox/Kconfig                          |   6 +
>   arch/sandbox/dts/test.dts                     |  45 +-
>   board/sandbox/sandbox.c                       |  49 ++
>   board/socionext/developerbox/Kconfig          |  14 +
>   board/socionext/developerbox/Makefile         |   1 +
>   board/socionext/developerbox/developerbox.c   |  17 +-
>   board/socionext/developerbox/fwu_plat.c       | 200 ++++++++
>   board/st/stm32mp1/stm32mp1.c                  | 141 ++++++
>   cmd/Kconfig                                   |   7 +
>   cmd/Makefile                                  |   1 +
>   cmd/fwu_mdata.c                               |  74 +++
>   common/board_r.c                              |   5 +
>   configs/sandbox64_defconfig                   |  12 +-
>   configs/synquacer_developerbox_defconfig      |  10 +-
>   doc/board/socionext/developerbox.rst          | 110 +++++
>   doc/develop/uefi/fwu_updates.rst              | 200 ++++++++
>   doc/develop/uefi/index.rst                    |   1 +
>   doc/develop/uefi/uefi.rst                     |   2 +
>   .../firmware/fwu-mdata.txt                    |  18 +
>   .../firmware/uboot,fwu-mdata-mtd.yaml         |  38 ++
>   doc/mkeficapsule.1                            |  29 +-
>   drivers/Kconfig                               |   2 +
>   drivers/Makefile                              |   1 +
>   drivers/fwu-mdata/Kconfig                     |  24 +
>   drivers/fwu-mdata/Makefile                    |   8 +
>   drivers/fwu-mdata/fwu-mdata-uclass.c          | 459 ++++++++++++++++++
>   drivers/fwu-mdata/fwu_mdata_gpt_blk.c         | 404 +++++++++++++++
>   drivers/fwu-mdata/fwu_mdata_mtd.c             | 308 ++++++++++++
>   include/configs/stm32mp15_common.h            |   4 +
>   include/configs/synquacer.h                   |  21 +-
>   include/dm/uclass-id.h                        |   1 +
>   include/fwu.h                                 |  74 +++
>   include/fwu_mdata.h                           |  67 +++
>   lib/Kconfig                                   |   6 +
>   lib/Makefile                                  |   1 +
>   lib/efi_loader/efi_capsule.c                  | 231 ++++++++-
>   lib/efi_loader/efi_setup.c                    |   3 +-
>   lib/fwu_updates/Kconfig                       |  31 ++
>   lib/fwu_updates/Makefile                      |   7 +
>   lib/fwu_updates/fwu.c                         | 206 ++++++++
>   lib/fwu_updates/fwu_mtd.c                     | 173 +++++++
>   .../test_capsule_firmware_fit.py              |   1 -
>   .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
>   test/py/tests/test_fwu_updates/conftest.py    |  78 +++
>   .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++
>   tools/Kconfig                                 |   9 +
>   tools/Makefile                                |   4 +
>   tools/eficapsule.h                            |   8 +
>   tools/mkeficapsule.c                          | 139 +++++-
>   tools/mkfwumdata.c                            | 298 ++++++++++++
>   53 files changed, 3903 insertions(+), 73 deletions(-)
>   create mode 100644 board/socionext/developerbox/fwu_plat.c
>   create mode 100644 cmd/fwu_mdata.c
>   create mode 100644 doc/develop/uefi/fwu_updates.rst
>   create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt
>   create mode 100644 doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
>   create mode 100644 drivers/fwu-mdata/Kconfig
>   create mode 100644 drivers/fwu-mdata/Makefile
>   create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
>   create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c
>   create mode 100644 drivers/fwu-mdata/fwu_mdata_mtd.c
>   create mode 100644 include/fwu.h
>   create mode 100644 include/fwu_mdata.h
>   create mode 100644 lib/fwu_updates/Kconfig
>   create mode 100644 lib/fwu_updates/Makefile
>   create mode 100644 lib/fwu_updates/fwu.c
>   create mode 100644 lib/fwu_updates/fwu_mtd.c
>   create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
>   create mode 100644 test/py/tests/test_fwu_updates/conftest.py
>   create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
>   create mode 100644 tools/mkfwumdata.c
>

Minor remark for all the added files with SPDX-License-Identifier

"GPL-2.0+" is obsolete are replaced by "GPL-2.0-or-later"

Reference: _https://spdx.dev/ids/_ <https://spdx.dev/ids/>:
*_GNU licenses_*
For GNU licenses, do not use just the bare license ID, such as “GPL-2.0”.
Instead, always use either the suffix “-only“ or the suffix “-or-later“ 
with GNU licenses.


regards

Patrick



^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support
  2022-06-20 18:12 ` [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Patrick DELAUNAY
@ 2022-06-21  9:23   ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-21  9:23 UTC (permalink / raw)
  To: Patrick DELAUNAY
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

hi,

On Mon, 20 Jun 2022 at 23:42, Patrick DELAUNAY
<patrick.delaunay@foss.st.com> wrote:
>
> Hi,
>
> On 6/9/22 14:29, Sughosh Ganu wrote:
> > The patchset adds support for the FWU Multi Bank Update[1]
> > feature. Certain aspects of the Dependable Boot[2] specification have
> > also been implemented.
> >
> > The FWU multi bank update feature is used for supporting multiple
> > sets(also called banks) of firmware image(s), allowing the platform to
> > boot from a different bank, in case it fails to boot from the active
> > bank. This functionality is supported by keeping the relevant
> > information in a structure called metadata, which provides information
> > on the images. Among other parameters, the metadata structure contains
> > information on the currect active bank that is being used to boot
> > image(s).
> >
> > Functionality is being added to work with the UEFI capsule driver in
> > u-boot. The metadata is read to gather information on the update bank,
> > which is the bank to which the firmware images would be flashed to. On
> > a successful completion of the update of all components, the active
> > bank field in the metadata is updated, to reflect the bank from which
> > the platform will boot on the subsequent boots.
> >
> > Currently, the feature is being enabled on the STM32MP157C-DK2 and
> > Synquacer boards. The DK2 board boots a FIP image from a uSD card
> > partitioned with the GPT partioning scheme, while the Synquacer board
> > boots a FIP image from a MTD partitioned SPI NOR flash device.
> >
> > This feature also requires changes in a previous stage of
> > bootloader, which parses the metadata and selects the bank to boot the
> > image(s) from. Support has being added in tf-a(BL2 stage) for the
> > STM32MP157C-DK2 board to boot the active bank images. These changes
> > have been merged to the upstream tf-a repository.
> >
> > Earlier, two separate patchsets were being sent. The patchset sent by
> > me was adding support for the feature, and enabling the feature on the
> > ST board. The other set of patches were being sent by Masami
> > Hiramatsu, which were enabling the feature on the Synquacer
> > platform. This patchset contains both set of patches, along with the
> > associated documentation and the python test script for testing the
> > feature.
> >
> > The upstreaming effort for this feature had been put on a temporary
> > hold to address the fixing of some issues in the capsule update code,
> > primarily using a per platform image GUID for the updatable
> > images. Now that the series has been merged, upstreaming effort for
> > the FWU update feature is being resumed. Hence, this version does not
> > have any review comments being addressed.
> >
> >
> > [1] - https://developer.arm.com/documentation/den0118/a
> > [2] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
> >
> > Jassi Brar (1):
> >    developerbox: synquacer: Use FIP as the updatable image
> >
> > Masami Hiramatsu (9):
> >    FWU: Add FWU metadata access driver for non-GPT MTD devices
> >    dt/bindings: firmware: Add FWU metadata on MTD devices binding
> >    tools: Add mkfwumdata tool for FWU metadata image
> >    FWU: doc: Update documentation for the FWU non-GPT MTD
> >    synquacer: Update for TBBR (BL2) based new FIP layout
> >    FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
> >    FWU: synquacer: Generate dfu_alt_info from devicetree partition
> >    doc: synquacer: Add how to enable FWU Multi Bank Update
> >    [TEMP]configs: synquacer: Add FWU support for DeveloperBox
> >
> > Sughosh Ganu (13):
> >    dt/bindings: Add bindings for FWU Metadata storage device
> >    FWU: Add FWU metadata structure and driver for accessing metadata
> >    FWU: Add FWU metadata access driver for GPT partitioned block devices
> >    stm32mp1: dk2: Add a node for the FWU metadata device
> >    stm32mp1: dk2: Add image information for capsule updates
> >    FWU: stm32mp1: Add helper functions for accessing FWU metadata
> >    FWU: STM32MP1: Add support to read boot index from backup register
> >    FWU: Add boot time checks as highlighted by the FWU specification
> >    FWU: Add support for the FWU Multi Bank Update feature
> >    FWU: cmd: Add a command to read FWU metadata
> >    mkeficapsule: Add support for generating empty capsules
> >    FWU: doc: Add documentation for the FWU feature
> >    sandbox: fwu: Add support for testing FWU feature on sandbox
> >
> >   arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi      |   7 +
> >   .../synquacer-sc2a11-developerbox-u-boot.dtsi |  40 +-
> >   arch/arm/mach-stm32mp/include/mach/stm32.h    |   4 +
> >   arch/sandbox/Kconfig                          |   6 +
> >   arch/sandbox/dts/test.dts                     |  45 +-
> >   board/sandbox/sandbox.c                       |  49 ++
> >   board/socionext/developerbox/Kconfig          |  14 +
> >   board/socionext/developerbox/Makefile         |   1 +
> >   board/socionext/developerbox/developerbox.c   |  17 +-
> >   board/socionext/developerbox/fwu_plat.c       | 200 ++++++++
> >   board/st/stm32mp1/stm32mp1.c                  | 141 ++++++
> >   cmd/Kconfig                                   |   7 +
> >   cmd/Makefile                                  |   1 +
> >   cmd/fwu_mdata.c                               |  74 +++
> >   common/board_r.c                              |   5 +
> >   configs/sandbox64_defconfig                   |  12 +-
> >   configs/synquacer_developerbox_defconfig      |  10 +-
> >   doc/board/socionext/developerbox.rst          | 110 +++++
> >   doc/develop/uefi/fwu_updates.rst              | 200 ++++++++
> >   doc/develop/uefi/index.rst                    |   1 +
> >   doc/develop/uefi/uefi.rst                     |   2 +
> >   .../firmware/fwu-mdata.txt                    |  18 +
> >   .../firmware/uboot,fwu-mdata-mtd.yaml         |  38 ++
> >   doc/mkeficapsule.1                            |  29 +-
> >   drivers/Kconfig                               |   2 +
> >   drivers/Makefile                              |   1 +
> >   drivers/fwu-mdata/Kconfig                     |  24 +
> >   drivers/fwu-mdata/Makefile                    |   8 +
> >   drivers/fwu-mdata/fwu-mdata-uclass.c          | 459 ++++++++++++++++++
> >   drivers/fwu-mdata/fwu_mdata_gpt_blk.c         | 404 +++++++++++++++
> >   drivers/fwu-mdata/fwu_mdata_mtd.c             | 308 ++++++++++++
> >   include/configs/stm32mp15_common.h            |   4 +
> >   include/configs/synquacer.h                   |  21 +-
> >   include/dm/uclass-id.h                        |   1 +
> >   include/fwu.h                                 |  74 +++
> >   include/fwu_mdata.h                           |  67 +++
> >   lib/Kconfig                                   |   6 +
> >   lib/Makefile                                  |   1 +
> >   lib/efi_loader/efi_capsule.c                  | 231 ++++++++-
> >   lib/efi_loader/efi_setup.c                    |   3 +-
> >   lib/fwu_updates/Kconfig                       |  31 ++
> >   lib/fwu_updates/Makefile                      |   7 +
> >   lib/fwu_updates/fwu.c                         | 206 ++++++++
> >   lib/fwu_updates/fwu_mtd.c                     | 173 +++++++
> >   .../test_capsule_firmware_fit.py              |   1 -
> >   .../py/tests/test_fwu_updates/capsule_defs.py |  10 +
> >   test/py/tests/test_fwu_updates/conftest.py    |  78 +++
> >   .../test_fwu_updates/test_fwu_updates.py      | 367 ++++++++++++++
> >   tools/Kconfig                                 |   9 +
> >   tools/Makefile                                |   4 +
> >   tools/eficapsule.h                            |   8 +
> >   tools/mkeficapsule.c                          | 139 +++++-
> >   tools/mkfwumdata.c                            | 298 ++++++++++++
> >   53 files changed, 3903 insertions(+), 73 deletions(-)
> >   create mode 100644 board/socionext/developerbox/fwu_plat.c
> >   create mode 100644 cmd/fwu_mdata.c
> >   create mode 100644 doc/develop/uefi/fwu_updates.rst
> >   create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt
> >   create mode 100644 doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
> >   create mode 100644 drivers/fwu-mdata/Kconfig
> >   create mode 100644 drivers/fwu-mdata/Makefile
> >   create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
> >   create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> >   create mode 100644 drivers/fwu-mdata/fwu_mdata_mtd.c
> >   create mode 100644 include/fwu.h
> >   create mode 100644 include/fwu_mdata.h
> >   create mode 100644 lib/fwu_updates/Kconfig
> >   create mode 100644 lib/fwu_updates/Makefile
> >   create mode 100644 lib/fwu_updates/fwu.c
> >   create mode 100644 lib/fwu_updates/fwu_mtd.c
> >   create mode 100644 test/py/tests/test_fwu_updates/capsule_defs.py
> >   create mode 100644 test/py/tests/test_fwu_updates/conftest.py
> >   create mode 100644 test/py/tests/test_fwu_updates/test_fwu_updates.py
> >   create mode 100644 tools/mkfwumdata.c
> >
>
> Minor remark for all the added files with SPDX-License-Identifier
>
> "GPL-2.0+" is obsolete are replaced by "GPL-2.0-or-later"
>
> Reference: _https://spdx.dev/ids/_ <https://spdx.dev/ids/>:
> *_GNU licenses_*
> For GNU licenses, do not use just the bare license ID, such as “GPL-2.0”.
> Instead, always use either the suffix “-only“ or the suffix “-or-later“
> with GNU licenses.

Will change in the next version. Thanks.

-sughosh

>
>
> regards
>
> Patrick
>
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices
  2022-06-09 12:29 ` [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices Sughosh Ganu
@ 2022-06-21  9:34   ` Patrick DELAUNAY
  2022-06-22 12:39     ` Patrick DELAUNAY
  2022-06-28 10:01     ` Sughosh Ganu
  2022-06-21 10:55   ` Etienne Carriere
  1 sibling, 2 replies; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21  9:34 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi,

On 6/9/22 14:29, Sughosh Ganu wrote:
> In the FWU Multi Bank Update feature, the information about the
> updatable images is stored as part of the metadata, on a separate
> partition. Add a driver for reading from and writing to the metadata
> when the updatable images and the metadata are stored on a block
> device which is formated with GPT based partition scheme.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   drivers/fwu-mdata/Kconfig             |   9 +
>   drivers/fwu-mdata/Makefile            |   1 +
>   drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 404 ++++++++++++++++++++++++++
>   include/fwu.h                         |   2 +
>   4 files changed, 416 insertions(+)
>   create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c
>
> diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
> index d6a21c8e19..d5edef19d6 100644
> --- a/drivers/fwu-mdata/Kconfig
> +++ b/drivers/fwu-mdata/Kconfig
> @@ -5,3 +5,12 @@ config DM_FWU_MDATA
>   	  Enable support for accessing FWU Metadata partitions. The
>   	  FWU Metadata partitions reside on the same storage device
>   	  which contains the other FWU updatable firmware images.
> +
> +config FWU_MDATA_GPT_BLK
> +	bool "FWU Metadata access for GPT partitioned Block devices"
> +	select PARTITION_TYPE_GUID
> +	select PARTITION_UUIDS
> +	depends on DM && HAVE_BLOCK_DEVICE && EFI_PARTITION
> +	help
> +	  Enable support for accessing FWU Metadata on GPT partitioned
> +	  block devices.
> diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
> index 7fec7171f4..12a5b4fe04 100644
> --- a/drivers/fwu-mdata/Makefile
> +++ b/drivers/fwu-mdata/Makefile
> @@ -4,3 +4,4 @@
>   #
>   
>   obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
> +obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o


It is strange to have '_' and '-' in file name for the same directory

=> to be coherent = fwu-mdata-gpt-blk.c


> diff --git a/drivers/fwu-mdata/fwu_mdata_gpt_blk.c b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> new file mode 100644
> index 0000000000..329bd3779b
> --- /dev/null
> +++ b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> @@ -0,0 +1,404 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <blk.h>
> +#include <dm.h>
> +#include <efi_loader.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <log.h>
> +#include <malloc.h>
> +#include <memalign.h>
> +#include <part.h>
> +#include <part_efi.h>
> +
> +#include <dm/device-internal.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <u-boot/crc.h>
> +
> +#define PRIMARY_PART		BIT(0)
> +#define SECONDARY_PART		BIT(1)
> +#define BOTH_PARTS		(PRIMARY_PART | SECONDARY_PART)
> +
> +#define MDATA_READ		BIT(0)
> +#define MDATA_WRITE		BIT(1)
> +
> +


[...]

> +
> +int fwu_gpt_mdata_check(struct udevice *dev)
> +{
> +	/*
> +	 * Check if both the copies of the FWU metadata are
> +	 * valid. If one has gone bad, restore it from the
> +	 * other good copy.
> +	 */
> +	return gpt_check_mdata_validity(dev);
> +}
> +
> +int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata **mdata)
> +{
> +	struct blk_desc *desc;
> +
> +	desc = dev_get_uclass_plat(dev_get_priv(dev));

as dev = fwu_mdata_gpt_blk(UCLASS_FWU_MDATA)

dev_get_priv(dev) => get value saved in dev_set_priv(dev, mdata_dev);

even if it is OK, it not clear here.

can you add a struct to prepare addition of other elements in privdata:

struct fwu_mdata_gpt_blk_priv {
	struct udevice *blk_dev;
}


+ struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);

+ struct blk_desc *desc;

+ desc = dev_get_uclass_plat(priv->blk_dev);


> +	if (!desc) {
> +		log_err("Block device not found\n");
> +		return -ENODEV;
> +	}
> +
> +	return gpt_get_mdata(desc, mdata);
> +}
> +
> +int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev)
> +{
> +	u32 phandle;
> +	int ret, size;
> +	struct udevice *parent, *child;
> +	const fdt32_t *phandle_p = NULL;
> +
> +	phandle_p = ofnode_get_property(dev_ofnode(dev), "fwu-mdata-store",
> +					&size);

phandle_p = dev_read_prop(dev, "fwu-mdata-store", &size);


it is more simple


> +	if (!phandle_p) {
> +		log_err("fwu-mdata-store property not found\n");
> +		return -ENOENT;
> +	}
> +
> +	phandle = fdt32_to_cpu(*phandle_p);


or phandle can be read directly by

+ ret =dev_read_phandle_with_args(dev, "fwu-mdata-store", NULL, 0, 0, 
phandle_p)

+	if (ret) {
+		log_err("fwu-mdata-store property not found\n");
+		return ret;
+	}

> +
> +	ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
> +					  &parent);
> +	if (ret)
> +		return ret;
> +
> +	ret = -ENODEV;
> +	for (device_find_first_child(parent, &child); child;
> +	     device_find_next_child(&child)) {
> +		if (device_get_uclass_id(child) == UCLASS_BLK) {
> +			*mdata_dev = child;
> +			ret = 0;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int fwu_mdata_gpt_blk_probe(struct udevice *dev)
> +{
> +	int ret;
> +	struct udevice *mdata_dev = NULL;
> +
> +	ret = fwu_get_mdata_device(dev, &mdata_dev);
> +	if (ret)
> +		return ret;
> +
> +	dev_set_priv(dev, mdata_dev);

Avoid to use dev_set_priv() in driver :

/**
  * dev_set_priv() - Set the private data for a device
  *
  * This is normally handled by driver model, which automatically allocates
  * private data when an 'auto' size if provided by the driver.
  *
  * Use this function to override normal operation for special 
situations, such
  * as needing to allocate a variable amount of data.
  *

...

+ struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);

+ priv->blk_dev = mdata_dev;

> +
> +	return 0;
> +}
> +
> +static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
> +	.mdata_check = fwu_gpt_mdata_check,
> +	.get_mdata = fwu_gpt_get_mdata,
> +	.update_mdata = fwu_gpt_update_mdata,
> +};
> +
> +static const struct udevice_id fwu_mdata_ids[] = {
> +	{ .compatible = "u-boot,fwu-mdata-gpt" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
> +	.name		= "fwu-mdata-gpt-blk",
> +	.id		= UCLASS_FWU_MDATA,
> +	.of_match	= fwu_mdata_ids,
> +	.ops		= &fwu_gpt_blk_ops,
> +	.probe		= fwu_mdata_gpt_blk_probe,


+ .priv_auto    = sizeof(struct fwu_mdata_gpt_blk_priv),


> +};
> diff --git a/include/fwu.h b/include/fwu.h
> index f9e44e7b39..3b1ee4e83e 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -39,6 +39,8 @@ int fwu_get_active_index(u32 *active_idx);
>   int fwu_update_active_index(u32 active_idx);
>   int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
>   			  int *alt_num);
> +int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev);
> +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part);
>   int fwu_mdata_check(void);
>   int fwu_revert_boot_index(void);
>   int fwu_accept_image(efi_guid_t *img_type_id, u32 bank);


Regards

Patrick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 04/23] stm32mp1: dk2: Add a node for the FWU metadata device
  2022-06-09 12:29 ` [PATCH v5 04/23] stm32mp1: dk2: Add a node for the FWU metadata device Sughosh Ganu
@ 2022-06-21  9:36   ` Patrick DELAUNAY
  0 siblings, 0 replies; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21  9:36 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi,

On 6/9/22 14:29, Sughosh Ganu wrote:
> The FWU metadata structure is accessed through the driver model
> interface. On the stm32mp157c-dk2 board, the FWU metadata is stored on
> the uSD card. Add the fwu-mdata node on the u-boot specifc dtsi file
> for accessing the metadata structure.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 +++++++
>   1 file changed, 7 insertions(+)
>
> diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi
> index 06ef3a4095..24f86209db 100644
> --- a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi
> +++ b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi
> @@ -4,3 +4,10 @@
>    */
>   
>   #include "stm32mp157a-dk1-u-boot.dtsi"
> +
> +/ {
> +	fwu-mdata {
> +		compatible = "u-boot,fwu-mdata-gpt";
> +		fwu-mdata-store = <&sdmmc1>;
> +	};
> +};


Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>

Thanks
Patrick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata
  2022-06-09 12:29 ` [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata Sughosh Ganu
  2022-06-10 11:53   ` Ilias Apalodimas
@ 2022-06-21  9:49   ` Patrick DELAUNAY
  2022-06-23  6:04     ` Sughosh Ganu
  1 sibling, 1 reply; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21  9:49 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi,

On 6/9/22 14:29, Sughosh Ganu wrote:
> Add helper functions needed for accessing the FWU metadata which
> contains information on the updatable images. These functions have
> been added for the STM32MP157C-DK2 board which has the updatable
> images on the uSD card, formatted as GPT partitions.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   board/st/stm32mp1/stm32mp1.c | 115 +++++++++++++++++++++++++++++++++++
>   include/fwu.h                |   2 +
>   2 files changed, 117 insertions(+)
>
> diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> index 62d98ad776..e68bf09955 100644
> --- a/board/st/stm32mp1/stm32mp1.c
> +++ b/board/st/stm32mp1/stm32mp1.c
> @@ -7,9 +7,11 @@
>   
>   #include <common.h>
>   #include <adc.h>
> +#include <blk.h>
>   #include <bootm.h>
>   #include <clk.h>
>   #include <config.h>
> +#include <dfu.h>
>   #include <dm.h>
>   #include <efi_loader.h>
>   #include <env.h>
> @@ -25,9 +27,11 @@
>   #include <log.h>
>   #include <malloc.h>
>   #include <misc.h>
> +#include <mmc.h>
>   #include <mtd_node.h>
>   #include <net.h>
>   #include <netdev.h>
> +#include <part.h>
>   #include <phy.h>
>   #include <remoteproc.h>
>   #include <reset.h>
> @@ -967,3 +971,114 @@ static void board_copro_image_process(ulong fw_image, size_t fw_size)
>   }
>   
>   U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_COPRO, board_copro_image_process);
> +
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +
[...]
> +
> +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> diff --git a/include/fwu.h b/include/fwu.h
> index 3b1ee4e83e..36e58afa29 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -46,6 +46,8 @@ int fwu_revert_boot_index(void);
>   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);
>   
> +


Added empty line


>   int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
>   			 int *alt_num);
> +int fwu_plat_get_update_index(u32 *update_idx);
>   #endif /* _FWU_H_ */


And I am agree with Ilias remark, should be generic

=> search on the current UCLASS_FWU_MDATA

        perhaps need a new ops in u-class ? as implementation can be 
different for GPT and MTD.


Patrick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 02/23] FWU: Add FWU metadata structure and driver for accessing metadata
  2022-06-09 12:29 ` [PATCH v5 02/23] FWU: Add FWU metadata structure and driver for accessing metadata Sughosh Ganu
@ 2022-06-21 10:54   ` Etienne Carriere
  2022-06-23  6:24     ` Sughosh Ganu
  0 siblings, 1 reply; 104+ messages in thread
From: Etienne Carriere @ 2022-06-21 10:54 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

Hello Sughosh,



On Thu, 9 Jun 2022 at 14:30, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> In the FWU Multi Bank Update feature, the information about the
> updatable images is stored as part of the metadata, which is stored on
> a dedicated partition. Add the metadata structure, and a driver model
> uclass which provides functions to access the metadata. These are
> generic API's, and implementations can be added based on parameters
> like how the metadata partition is accessed and what type of storage
> device houses the metadata.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  drivers/Kconfig                      |   2 +
>  drivers/Makefile                     |   1 +
>  drivers/fwu-mdata/Kconfig            |   7 +
>  drivers/fwu-mdata/Makefile           |   6 +
>  drivers/fwu-mdata/fwu-mdata-uclass.c | 459 +++++++++++++++++++++++++++
>  include/dm/uclass-id.h               |   1 +
>  include/fwu.h                        |  49 +++
>  include/fwu_mdata.h                  |  67 ++++
>  8 files changed, 592 insertions(+)
>  create mode 100644 drivers/fwu-mdata/Kconfig
>  create mode 100644 drivers/fwu-mdata/Makefile
>  create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
>  create mode 100644 include/fwu.h
>  create mode 100644 include/fwu_mdata.h
>
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index b26ca8cf70..adc6079ecf 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig"
>
>  source "drivers/fpga/Kconfig"
>
> +source "drivers/fwu-mdata/Kconfig"
> +
>  source "drivers/gpio/Kconfig"
>
>  source "drivers/hwspinlock/Kconfig"
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 67c8af7442..901150bb35 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -83,6 +83,7 @@ obj-y += cache/
>  obj-$(CONFIG_CPU) += cpu/
>  obj-y += crypto/
>  obj-$(CONFIG_FASTBOOT) += fastboot/
> +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/
>  obj-y += misc/
>  obj-$(CONFIG_MMC) += mmc/
>  obj-$(CONFIG_NVME) += nvme/
> diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
> new file mode 100644
> index 0000000000..d6a21c8e19
> --- /dev/null
> +++ b/drivers/fwu-mdata/Kconfig
> @@ -0,0 +1,7 @@
> +config DM_FWU_MDATA
> +       bool "Driver support for accessing FWU Metadata"
> +       depends on DM
> +       help
> +         Enable support for accessing FWU Metadata partitions. The
> +         FWU Metadata partitions reside on the same storage device
> +         which contains the other FWU updatable firmware images.
> diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
> new file mode 100644
> index 0000000000..7fec7171f4
> --- /dev/null
> +++ b/drivers/fwu-mdata/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# Copyright (c) 2022, Linaro Limited
> +#
> +
> +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
> diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c
> new file mode 100644
> index 0000000000..1530ceb01d
> --- /dev/null
> +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c
> @@ -0,0 +1,459 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <efi_loader.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <log.h>
> +#include <malloc.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <u-boot/crc.h>
> +
> +#define IMAGE_ACCEPT_SET       BIT(0)
> +#define IMAGE_ACCEPT_CLEAR     BIT(1)
> +
> +static int fwu_get_dev_ops(struct udevice **dev,
> +                          const struct fwu_mdata_ops **ops)
> +{
> +       int ret;
> +
> +       ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev);
> +       if (ret) {
> +               log_debug("Cannot find fwu device\n");
> +               return ret;
> +       }
> +
> +       if ((*ops = device_get_ops(*dev)) == NULL) {
> +               log_debug("Cannot get fwu device ops\n");
> +               return -ENOSYS;
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * fwu_verify_mdata() - Verify the FWU metadata
> + * @mdata: FWU metadata structure
> + * @pri_part: FWU metadata partition is primary or secondary
> + *
> + * Verify the FWU metadata by computing the CRC32 for the metadata
> + * structure and comparing it against the CRC32 value stored as part
> + * of the structure.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part)
> +{
> +       u32 calc_crc32;
> +       void *buf;
> +
> +       buf = &mdata->version;
> +       calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
> +
> +       if (calc_crc32 != mdata->crc32) {
> +               log_err("crc32 check failed for %s FWU metadata partition\n",
> +                       pri_part ? "primary" : "secondary");
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * fwu_get_active_index() - Get active_index from the FWU metadata
> + * @active_idx: active_index value to be read
> + *
> + * Read the active_index field from the FWU metadata and place it in
> + * the variable pointed to be the function argument.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_get_active_index(u32 *active_idx)
> +{
> +       int ret;
> +       struct fwu_mdata *mdata = NULL;
> +
> +       ret = fwu_get_mdata(&mdata);
> +       if (ret < 0) {
> +               log_err("Unable to get valid FWU metadata\n");
> +               goto out;
> +       }
> +
> +       /*
> +        * Found the FWU metadata partition, now read the active_index
> +        * value
> +        */
> +       *active_idx = mdata->active_index;
> +       if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
> +               log_err("Active index value read is incorrect\n");
> +               ret = -EINVAL;
> +       }
> +
> +out:
> +       free(mdata);
> +
> +       return ret;
> +}
> +
> +/**
> + * fwu_update_active_index() - Update active_index from the FWU metadata
> + * @active_idx: active_index value to be updated
> + *
> + * Update the active_index field in the FWU metadata
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_update_active_index(u32 active_idx)
> +{
> +       int ret;
> +       struct fwu_mdata *mdata = NULL;
> +
> +       if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
> +               log_err("Active index value to be updated is incorrect\n");
> +               return -1;
> +       }
> +
> +       ret = fwu_get_mdata(&mdata);
> +       if (ret < 0) {
> +               log_err("Unable to get valid FWU metadata\n");
> +               goto out;
> +       }
> +
> +       /*
> +        * Update the active index and previous_active_index fields
> +        * in the FWU metadata
> +        */
> +       mdata->previous_active_index = mdata->active_index;
> +       mdata->active_index = active_idx;
> +
> +       /*
> +        * Now write this updated FWU metadata to both the
> +        * FWU metadata partitions
> +        */
> +       ret = fwu_update_mdata(mdata);
> +       if (ret < 0) {> +               log_err("Failed to update FWU metadata partitions\n");
> +               ret = -EIO;
> +       }
> +
> +out:
> +       free(mdata);
> +
> +       return ret;
> +}
> +
> +/**
> + * fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update
> + * @image_type_id: pointer to the image guid as passed in the capsule
> + * @update_bank: Bank to which the update is to be made
> + * @alt_num: The alt_num for the image
> + *
> + * Based on the guid value passed in the capsule, along with the bank to which the
> + * image needs to be updated, get the dfu alt number which will be used for the
> + * capsule update
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
> +                         int *alt_num)
> +{
> +       int ret, i;
> +       efi_guid_t *image_guid;
> +       struct udevice *dev = NULL;
> +       struct fwu_mdata *mdata = NULL;
> +       struct fwu_image_entry *img_entry;
> +       const struct fwu_mdata_ops *ops = NULL;
> +       struct fwu_image_bank_info *img_bank_info;
> +
> +       ret = fwu_get_dev_ops(&dev, &ops);
> +       if (ret)
> +               return ret;
> +
> +       ret = fwu_get_mdata(&mdata);
> +       if (ret) {
> +               log_err("Unable to get valid FWU metadata\n");
> +               goto out;
> +       }
> +
> +       /*
> +        * The FWU metadata has been read. Now get the image_uuid for the
> +        * image with the update_bank.
> +        */
> +       for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
> +               if (!guidcmp(image_type_id,
> +                            &mdata->img_entry[i].image_type_uuid)) {
> +                       img_entry = &mdata->img_entry[i];
> +                       img_bank_info = &img_entry->img_bank_info[update_bank];
> +                       image_guid = &img_bank_info->image_uuid;
> +                       ret = fwu_plat_get_alt_num(dev_get_priv(dev),
> +                                                  image_guid, alt_num);
> +                       break;
> +               }
> +       }
> +
> +       if (i == CONFIG_FWU_NUM_IMAGES_PER_BANK) {
> +               log_err("Partition with the image type %pUs not found\n",
> +                       image_type_id);
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       if (!ret) {
> +               log_debug("alt_num %d for partition %pUs\n",
> +                         *alt_num, &image_guid);

s/&image_guid/image_guid/
Ditto in trace below.

> +       } else {
> +               log_err("alt_num not found for partition with GUID %pUs\n",
> +                       &image_guid);
> +               ret = -EINVAL;
> +       }
> +
> +out:
> +       free(mdata);
> +
> +       return ret;
> +}
> +
> +/**
> + * fwu_mdata_check() - Check if the FWU metadata is valid
> + *
> + * Validate both copies of the FWU metadata. If one of the copies
> + * has gone bad, restore it from the other bad copy.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_mdata_check(void)
> +{
> +       int ret;
> +       struct udevice *dev = NULL;
> +       const struct fwu_mdata_ops *ops = NULL;
> +
> +       ret = fwu_get_dev_ops(&dev, &ops);
> +       if (ret)
> +               return ret;
> +
> +       if (!ops->mdata_check) {
> +               log_err("mdata_check() method not defined\n");
> +               return -ENOSYS;
> +       }
> +
> +       return ops->mdata_check(dev);
> +}
> +
> +/**
> + * fwu_revert_boot_index() - Revert the active index in the FWU metadata
> + *
> + * Revert the active_index value in the FWU metadata, by swapping the values
> + * of active_index and previous_active_index in both copies of the
> + * FWU metadata.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_revert_boot_index(void)
> +{
> +       int ret;
> +       u32 cur_active_index;
> +       struct fwu_mdata *mdata = NULL;
> +
> +       ret = fwu_get_mdata(&mdata);
> +       if (ret < 0) {
> +               log_err("Unable to get valid FWU metadata\n");
> +               goto out;
> +       }
> +
> +       /*
> +        * Swap the active index and previous_active_index fields
> +        * in the FWU metadata
> +        */
> +       cur_active_index = mdata->active_index;
> +       mdata->active_index = mdata->previous_active_index;
> +       mdata->previous_active_index = cur_active_index;
> +
> +       /*
> +        * Now write this updated FWU metadata to both the
> +        * FWU metadata partitions
> +        */
> +       ret = fwu_update_mdata(mdata);
> +       if (ret < 0) {
> +               log_err("Failed to update FWU metadata partitions\n");
> +               ret = -EIO;
> +       }
> +
> +out:
> +       free(mdata);
> +
> +       return ret;
> +}
> +
> +/**
> + * fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image
> + * @img_type_id: Guid of the image type for which the accepted bit is to be
> + *               set or cleared
> + * @bank: Bank of which the image's Accept bit is to be set or cleared
> + * @action: Action which specifies whether image's Accept bit is to be set or
> + *          cleared
> + *
> + * Set/Clear the accepted bit for the image specified by the img_guid parameter.
> + * This indicates acceptance or rejection of image for subsequent boots by some
> + * governing component like OS(or firmware).
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +static int fwu_set_clear_image_accept(efi_guid_t *img_type_id,
> +                                     u32 bank, u8 action)
> +{
> +       int ret, i;
> +       u32 nimages;
> +       struct fwu_mdata *mdata = NULL;
> +       struct fwu_image_entry *img_entry;
> +       struct fwu_image_bank_info *img_bank_info;
> +
> +       ret = fwu_get_mdata(&mdata);
> +       if (ret < 0) {
> +               log_err("Unable to get valid FWU metadata\n");
> +               goto out;
> +       }
> +
> +       nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> +       img_entry = &mdata->img_entry[0];
> +       for (i = 0; i < nimages; i++) {
> +               if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
> +                       img_bank_info = &img_entry[i].img_bank_info[bank];
> +                       if (action == IMAGE_ACCEPT_SET)
> +                               img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
> +                       else
> +                               img_bank_info->accepted = 0;
> +
> +                       ret = fwu_update_mdata(mdata);
> +                       goto out;
> +               }
> +       }
> +
> +       /* Image not found */
> +       ret = -EINVAL;
> +
> +out:
> +       free(mdata);
> +
> +       return ret;
> +}
> +
> +/**
> + * fwu_accept_image() - Set the Acceptance bit for the image
> + * @img_type_id: Guid of the image type for which the accepted bit is to be
> + *               cleared
> + * @bank: Bank of which the image's Accept bit is to be set
> + *
> + * Set the accepted bit for the image specified by the img_guid parameter. This
> + * indicates acceptance of image for subsequent boots by some governing component
> + * like OS(or firmware).
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank)
> +{
> +       return fwu_set_clear_image_accept(img_type_id, bank,
> +                                         IMAGE_ACCEPT_SET);
> +}
> +
> +/**
> + * fwu_clear_accept_image() - Clear the Acceptance bit for the image
> + * @img_type_id: Guid of the image type for which the accepted bit is to be
> + *               cleared
> + * @bank: Bank of which the image's Accept bit is to be cleared
> + *
> + * Clear the accepted bit for the image type specified by the img_type_id parameter.
> + * This function is called after the image has been updated. The accepted bit is
> + * cleared to be set subsequently after passing the image acceptance criteria, by
> + * either the OS(or firmware)
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank)
> +{
> +       return fwu_set_clear_image_accept(img_type_id, bank,
> +                                         IMAGE_ACCEPT_CLEAR);
> +}
> +
> +/**
> + * fwu_get_mdata() - Get a FWU metadata copy
> + * @mdata: Copy of the FWU metadata
> + *
> + * Get a valid copy of the FWU metadata.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_get_mdata(struct fwu_mdata **mdata)

Is there a real need for this function to allocate an instance of struct mdata.
I think it would be clearer if it was the caller's responsibility to
allocate/free the structure.

Or maybe rename this function fwu_alloc_and_copy_mdata() to highlight
that the function gives an allocated copy of the data.
One should be careful when calling these API functions as some act on
a local copy (retrieved from fw_get_mdata()) while other functions
modify straight fwu-mdata in the storage media.

Br,
etienne



> +{
> +       int ret;
> +       struct udevice *dev = NULL;
> +       const struct fwu_mdata_ops *ops = NULL;
> +
> +       ret = fwu_get_dev_ops(&dev, &ops);
> +       if (ret)
> +               return ret;
> +
> +       if (!ops->get_mdata) {
> +               log_err("get_mdata() method not defined\n");
> +               return -ENOSYS;
> +       }
> +
> +       return ops->get_mdata(dev, mdata);
> +}
> +
> +/**
> + * fwu_update_mdata() - Update the FWU metadata
> + * @mdata: Copy of the FWU metadata
> + *
> + * Update the FWU metadata structure by writing to the
> + * FWU metadata partitions.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_update_mdata(struct fwu_mdata *mdata)
> +{
> +       int ret;
> +       void *buf;
> +       struct udevice *dev = NULL;
> +       const struct fwu_mdata_ops *ops = NULL;
> +
> +       ret = fwu_get_dev_ops(&dev, &ops);
> +       if (ret)
> +               return ret;
> +
> +       if (!ops->update_mdata) {
> +               log_err("get_mdata() method not defined\n");
> +               return -ENOSYS;
> +       }
> +
> +       /*
> +        * Calculate the crc32 for the updated FWU metadata
> +        * and put the updated value in the FWU metadata crc32
> +        * field
> +        */
> +       buf = &mdata->version;
> +       mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
> +
> +       return ops->update_mdata(dev, mdata);
> +}
> +
> +UCLASS_DRIVER(fwu_mdata) = {
> +       .id             = UCLASS_FWU_MDATA,
> +       .name           = "fwu-mdata",
> +};
> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
> index 3ba69ad9a0..7da719c048 100644
> --- a/include/dm/uclass-id.h
> +++ b/include/dm/uclass-id.h
> @@ -57,6 +57,7 @@ enum uclass_id {
>         UCLASS_ETH_PHY,         /* Ethernet PHY device */
>         UCLASS_FIRMWARE,        /* Firmware */
>         UCLASS_FS_FIRMWARE_LOADER,              /* Generic loader */
> +       UCLASS_FWU_MDATA,       /* FWU Metadata Access */
>         UCLASS_GPIO,            /* Bank of general-purpose I/O pins */
>         UCLASS_HASH,            /* Hash device */
>         UCLASS_HWSPINLOCK,      /* Hardware semaphores */
> diff --git a/include/fwu.h b/include/fwu.h
> new file mode 100644
> index 0000000000..f9e44e7b39
> --- /dev/null
> +++ b/include/fwu.h
> @@ -0,0 +1,49 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#if !defined _FWU_H_
> +#define _FWU_H_
> +
> +#include <blk.h>
> +#include <efi.h>
> +
> +#include <linux/types.h>
> +
> +struct fwu_mdata;
> +struct udevice;
> +
> +/**
> + * @mdata_check: check the validity of the FWU metadata partitions
> + * @get_mdata() - Get a FWU metadata copy
> + * @update_mdata() - Update the FWU metadata copy
> + */
> +struct fwu_mdata_ops {
> +       int (*mdata_check)(struct udevice *dev);
> +
> +       int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata);
> +
> +       int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
> +};
> +
> +#define FWU_MDATA_VERSION      0x1
> +
> +#define FWU_MDATA_GUID \
> +       EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
> +                0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
> +
> +int fwu_get_mdata(struct fwu_mdata **mdata);
> +int fwu_update_mdata(struct fwu_mdata *mdata);
> +int fwu_get_active_index(u32 *active_idx);
> +int fwu_update_active_index(u32 active_idx);
> +int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
> +                         int *alt_num);
> +int fwu_mdata_check(void);
> +int fwu_revert_boot_index(void);
> +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_alt_num(struct udevice *dev, efi_guid_t *image_guid,
> +                        int *alt_num);
> +#endif /* _FWU_H_ */
> diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h
> new file mode 100644
> index 0000000000..701efbba03
> --- /dev/null
> +++ b/include/fwu_mdata.h
> @@ -0,0 +1,67 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#if !defined _FWU_MDATA_H_
> +#define _FWU_MDATA_H_
> +
> +#include <efi.h>
> +
> +/**
> + * struct fwu_image_bank_info - firmware image information
> + * @image_uuid: Guid value of the image in this bank
> + * @accepted: Acceptance status of the image
> + * @reserved: Reserved
> + *
> + * The structure contains image specific fields which are
> + * used to identify the image and to specify the image's
> + * acceptance status
> + */
> +struct fwu_image_bank_info {
> +       efi_guid_t  image_uuid;
> +       uint32_t accepted;
> +       uint32_t reserved;
> +} __attribute__((__packed__));
> +
> +/**
> + * struct fwu_image_entry - information for a particular type of image
> + * @image_type_uuid: Guid value for identifying the image type
> + * @location_uuid: Guid of the storage volume where the image is located
> + * @img_bank_info: Array containing properties of images
> + *
> + * This structure contains information on various types of updatable
> + * firmware images. Each image type then contains an array of image
> + * information per bank.
> + */
> +struct fwu_image_entry {
> +       efi_guid_t image_type_uuid;
> +       efi_guid_t location_uuid;
> +       struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
> +} __attribute__((__packed__));
> +
> +/**
> + * struct fwu_mdata - FWU metadata structure for multi-bank updates
> + * @crc32: crc32 value for the FWU metadata
> + * @version: FWU metadata version
> + * @active_index: Index of the bank currently used for booting images
> + * @previous_active_inde: Index of the bank used before the current bank
> + *                        being used for booting
> + * @img_entry: Array of information on various firmware images that can
> + *             be updated
> + *
> + * This structure is used to store all the needed information for performing
> + * multi bank updates on the platform. This contains info on the bank being
> + * used to boot along with the information needed for identification of
> + * individual images
> + */
> +struct fwu_mdata {
> +       uint32_t crc32;
> +       uint32_t version;
> +       uint32_t active_index;
> +       uint32_t previous_active_index;
> +
> +       struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
> +} __attribute__((__packed__));
> +
> +#endif /* _FWU_MDATA_H_ */
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices
  2022-06-09 12:29 ` [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices Sughosh Ganu
  2022-06-21  9:34   ` Patrick DELAUNAY
@ 2022-06-21 10:55   ` Etienne Carriere
  2022-06-28 10:11     ` Sughosh Ganu
  1 sibling, 1 reply; 104+ messages in thread
From: Etienne Carriere @ 2022-06-21 10:55 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

Hello Sughosh,

On Thu, 9 Jun 2022 at 14:30, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> In the FWU Multi Bank Update feature, the information about the
> updatable images is stored as part of the metadata, on a separate
> partition. Add a driver for reading from and writing to the metadata
> when the updatable images and the metadata are stored on a block
> device which is formated with GPT based partition scheme.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  drivers/fwu-mdata/Kconfig             |   9 +
>  drivers/fwu-mdata/Makefile            |   1 +
>  drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 404 ++++++++++++++++++++++++++
>  include/fwu.h                         |   2 +
>  4 files changed, 416 insertions(+)
>  create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c
>
> diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
> index d6a21c8e19..d5edef19d6 100644
> --- a/drivers/fwu-mdata/Kconfig
> +++ b/drivers/fwu-mdata/Kconfig
> @@ -5,3 +5,12 @@ config DM_FWU_MDATA
>           Enable support for accessing FWU Metadata partitions. The
>           FWU Metadata partitions reside on the same storage device
>           which contains the other FWU updatable firmware images.
> +
> +config FWU_MDATA_GPT_BLK
> +       bool "FWU Metadata access for GPT partitioned Block devices"
> +       select PARTITION_TYPE_GUID
> +       select PARTITION_UUIDS
> +       depends on DM && HAVE_BLOCK_DEVICE && EFI_PARTITION
> +       help
> +         Enable support for accessing FWU Metadata on GPT partitioned
> +         block devices.
> diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
> index 7fec7171f4..12a5b4fe04 100644
> --- a/drivers/fwu-mdata/Makefile
> +++ b/drivers/fwu-mdata/Makefile
> @@ -4,3 +4,4 @@
>  #
>
>  obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
> +obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o
> diff --git a/drivers/fwu-mdata/fwu_mdata_gpt_blk.c b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> new file mode 100644
> index 0000000000..329bd3779b
> --- /dev/null
> +++ b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> @@ -0,0 +1,404 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <blk.h>
> +#include <dm.h>
> +#include <efi_loader.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <log.h>
> +#include <malloc.h>
> +#include <memalign.h>
> +#include <part.h>
> +#include <part_efi.h>
> +
> +#include <dm/device-internal.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <u-boot/crc.h>
> +
> +#define PRIMARY_PART           BIT(0)
> +#define SECONDARY_PART         BIT(1)
> +#define BOTH_PARTS             (PRIMARY_PART | SECONDARY_PART)
> +
> +#define MDATA_READ             BIT(0)
> +#define MDATA_WRITE            BIT(1)
> +
> +static int gpt_get_mdata_partitions(struct blk_desc *desc,
> +                                   u16 *primary_mpart,
> +                                   u16 *secondary_mpart)
> +{
> +       int i, ret;
> +       u32 mdata_parts;
> +       efi_guid_t part_type_guid;
> +       struct disk_partition info;
> +       const efi_guid_t fwu_mdata_guid = FWU_MDATA_GUID;
> +
> +       mdata_parts = 0;
> +       for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) {
> +               if (part_get_info(desc, i, &info))
> +                       continue;
> +               uuid_str_to_bin(info.type_guid, part_type_guid.b,
> +                               UUID_STR_FORMAT_GUID);
> +
> +               if (!guidcmp(&fwu_mdata_guid, &part_type_guid)) {
> +                       ++mdata_parts;
> +                       if (!*primary_mpart)
> +                               *primary_mpart = i;
> +                       else
> +                               *secondary_mpart = i;
> +               }
> +       }
> +
> +       if (mdata_parts != 2) {
> +               log_err("Expect two copies of the FWU metadata instead of %d\n",
> +                       mdata_parts);
> +               ret = -EINVAL;
> +       } else {
> +               ret = 0;
> +       }
> +
> +       return ret;
> +}
> +
> +static int gpt_get_mdata_disk_part(struct blk_desc *desc,
> +                                  struct disk_partition *info,
> +                                  u32 part_num)
> +{
> +       int ret;
> +       char *mdata_guid_str = "8a7a84a0-8387-40f6-ab41-a8b9a5a60d23";
> +
> +       ret = part_get_info(desc, part_num, info);
> +       if (ret < 0) {
> +               log_err("Unable to get the partition info for the FWU metadata part %d",
> +                       part_num);
> +               return -1;
> +       }
> +
> +       /* Check that it is indeed the FWU metadata partition */
> +       if (!strncmp(info->type_guid, mdata_guid_str, UUID_STR_LEN)) {
> +               /* Found the FWU metadata partition */
> +               return 0;
> +       }
> +
> +       return -1;
> +}
> +
> +static int gpt_read_write_mdata(struct blk_desc *desc,
> +                               struct fwu_mdata *mdata,
> +                               u8 access, u32 part_num)
> +{
> +       int ret;
> +       u32 len, blk_start, blkcnt;
> +       struct disk_partition info;
> +
> +       ALLOC_CACHE_ALIGN_BUFFER_PAD(struct fwu_mdata, mdata_aligned, 1,
> +                                    desc->blksz);
> +
> +       ret = gpt_get_mdata_disk_part(desc, &info, part_num);
> +       if (ret < 0) {
> +               printf("Unable to get the FWU metadata partition\n");
> +               return -ENODEV;
> +       }
> +
> +       len = sizeof(*mdata);
> +       blkcnt = BLOCK_CNT(len, desc);
> +       if (blkcnt > info.size) {
> +               log_err("Block count exceeds FWU metadata partition size\n");
> +               return -ERANGE;
> +       }
> +
> +       blk_start = info.start;
> +       if (access == MDATA_READ) {
> +               if (blk_dread(desc, blk_start, blkcnt, mdata_aligned) != blkcnt) {
> +                       log_err("Error reading FWU metadata from the device\n");
> +                       return -EIO;
> +               }
> +               memcpy(mdata, mdata_aligned, sizeof(struct fwu_mdata));
> +       } else {
> +               if (blk_dwrite(desc, blk_start, blkcnt, mdata) != blkcnt) {
> +                       log_err("Error writing FWU metadata to the device\n");
> +                       return -EIO;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int gpt_read_mdata(struct blk_desc *desc,
> +                         struct fwu_mdata *mdata, u32 part_num)
> +{
> +       return gpt_read_write_mdata(desc, mdata, MDATA_READ, part_num);
> +}
> +
> +static int gpt_write_mdata_partition(struct blk_desc *desc,
> +                                       struct fwu_mdata *mdata,
> +                                       u32 part_num)
> +{
> +       return gpt_read_write_mdata(desc, mdata, MDATA_WRITE, part_num);
> +}
> +
> +static int fwu_gpt_update_mdata(struct udevice * dev, struct fwu_mdata *mdata)
> +{
> +       int ret;
> +       struct blk_desc *desc;
> +       u16 primary_mpart = 0, secondary_mpart = 0;
> +
> +       desc = dev_get_uclass_plat(dev_get_priv(dev));
> +       if (!desc) {
> +               log_err("Block device not found\n");
> +               return -ENODEV;
> +       }
> +
> +       ret = gpt_get_mdata_partitions(desc, &primary_mpart,
> +                                      &secondary_mpart);
> +
> +       if (ret < 0) {
> +               log_err("Error getting the FWU metadata partitions\n");
> +               return -ENODEV;
> +       }
> +
> +       /* First write the primary partition*/
> +       ret = gpt_write_mdata_partition(desc, mdata, primary_mpart);
> +       if (ret < 0) {
> +               log_err("Updating primary FWU metadata partition failed\n");
> +               return ret;
> +       }
> +
> +       /* And now the replica */
> +       ret = gpt_write_mdata_partition(desc, mdata, secondary_mpart);
> +       if (ret < 0) {
> +               log_err("Updating secondary FWU metadata partition failed\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int gpt_get_mdata(struct blk_desc *desc, struct fwu_mdata **mdata)
> +{
> +       int ret;
> +       u16 primary_mpart = 0, secondary_mpart = 0;
> +
> +       ret = gpt_get_mdata_partitions(desc, &primary_mpart,
> +                                      &secondary_mpart);
> +
> +       if (ret < 0) {
> +               log_err("Error getting the FWU metadata partitions\n");
> +               return -ENODEV;
> +       }
> +
> +       *mdata = malloc(sizeof(struct fwu_mdata));
> +       if (!*mdata) {
> +               log_err("Unable to allocate memory for reading FWU metadata\n");
> +               return -ENOMEM;
> +       }
> +
> +       ret = gpt_read_mdata(desc, *mdata, primary_mpart);
> +       if (ret < 0) {
> +               log_err("Failed to read the FWU metadata from the device\n");
> +               return -EIO;
> +       }
> +
> +       ret = fwu_verify_mdata(*mdata, 1);
> +       if (!ret)

Upon success, I think this function should also either ensure
secondary_part contains a valid copy of primary part,
Maybe this function should call gpt_check_mdata_validity() and then
read mdata content.

> +               return 0;
> +
> +       /*
> +        * Verification of the primary FWU metadata copy failed.
> +        * Try to read the replica.
> +        */
> +       memset(*mdata, 0, sizeof(struct fwu_mdata));
> +       ret = gpt_read_mdata(desc, *mdata, secondary_mpart);
> +       if (ret < 0) {
> +               log_err("Failed to read the FWU metadata from the device\n");
> +               return -EIO;
> +       }
> +
> +       ret = fwu_verify_mdata(*mdata, 0);
> +       if (!ret)
> +               return 0;
> +
> +       /* Both the FWU metadata copies are corrupted. */
> +       return -1;
> +}
> +
> +static int gpt_check_mdata_validity(struct udevice *dev)
> +{
> +       int ret;
> +       struct blk_desc *desc;
> +       struct fwu_mdata pri_mdata;
> +       struct fwu_mdata secondary_mdata;
> +       u16 primary_mpart = 0, secondary_mpart = 0;
> +       u16 valid_partitions, invalid_partitions;
> +
> +       desc = dev_get_uclass_plat(dev_get_priv(dev));
> +       if (!desc) {
> +               log_err("Block device not found\n");
> +               return -ENODEV;
> +       }
> +
> +       /*
> +        * Two FWU metadata partitions are expected.
> +        * If we don't have two, user needs to create
> +        * them first
> +        */
> +       valid_partitions = 0;
> +       ret = gpt_get_mdata_partitions(desc, &primary_mpart,
> +                                      &secondary_mpart);
> +
> +       if (ret < 0) {
> +               log_err("Error getting the FWU metadata partitions\n");
> +               return -ENODEV;
> +       }
> +
> +       ret = gpt_read_mdata(desc, &pri_mdata, primary_mpart);
> +       if (ret < 0) {
> +               log_err("Failed to read the FWU metadata from the device\n");
> +               goto secondary_read;
> +       }
> +
> +       ret = fwu_verify_mdata(&pri_mdata, 1);
> +       if (!ret)
> +               valid_partitions |= PRIMARY_PART;
> +
> +secondary_read:
> +       /* Now check the secondary partition */
> +       ret = gpt_read_mdata(desc, &secondary_mdata, secondary_mpart);
> +       if (ret < 0) {
> +               log_err("Failed to read the FWU metadata from the device\n");
> +               goto mdata_restore;
> +       }
> +
> +       ret = fwu_verify_mdata(&secondary_mdata, 0);
> +       if (!ret)
> +               valid_partitions |= SECONDARY_PART;
> +
> +mdata_restore:
> +       if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) {
> +               ret = -1;
> +               /*
> +                * Before returning, check that both the
> +                * FWU metadata copies are the same. If not,
> +                * the FWU metadata copies need to be
> +                * re-populated.
> +                */
> +               if (!memcmp(&pri_mdata, &secondary_mdata,
> +                           sizeof(struct fwu_mdata))) {
> +                       ret = 0;
> +               } else {
> +                       log_err("Both FWU metadata copies are valid but do not match. Please check!\n");

I think this function should select one of the part and copies to the
other, e.g. assume primary is fine, copy primary to secondary and
return upon success.

> +               }
> +               goto out;
> +       }
> +
> +       ret = -1;
> +       if (!(valid_partitions & BOTH_PARTS))
> +               goto out;
> +
> +       invalid_partitions = valid_partitions ^ BOTH_PARTS;
> +       ret = gpt_write_mdata_partition(desc,
> +                                       (invalid_partitions == PRIMARY_PART) ?
> +                                       &secondary_mdata : &pri_mdata,
> +                                       (invalid_partitions == PRIMARY_PART) ?
> +                                       primary_mpart : secondary_mpart);
> +
> +       if (ret < 0)
> +               log_err("Restoring %s FWU metadata partition failed\n",
> +                       (invalid_partitions == PRIMARY_PART) ?
> +                       "primary" : "secondary");
> +
> +out:
> +       return ret;
> +}
> +
> +int fwu_gpt_mdata_check(struct udevice *dev)

Function should be static.

> +{
> +       /*
> +        * Check if both the copies of the FWU metadata are
> +        * valid. If one has gone bad, restore it from the
> +        * other good copy.
> +        */
> +       return gpt_check_mdata_validity(dev);
> +}
> +
> +int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata **mdata)

Function should be static.

> +{
> +       struct blk_desc *desc;
> +
> +       desc = dev_get_uclass_plat(dev_get_priv(dev));
> +       if (!desc) {
> +               log_err("Block device not found\n");
> +               return -ENODEV;
> +       }
> +
> +       return gpt_get_mdata(desc, mdata);
> +}
> +
> +int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev)

Function could be static (and declaration removed from fwu.h).

> +{
> +       u32 phandle;
> +       int ret, size;
> +       struct udevice *parent, *child;
> +       const fdt32_t *phandle_p = NULL;
> +
> +       phandle_p = ofnode_get_property(dev_ofnode(dev), "fwu-mdata-store",
> +                                       &size);

Should this be retrieved from driver's ::of_to_plat method?

Br,
etienne


> +       if (!phandle_p) {
> +               log_err("fwu-mdata-store property not found\n");
> +               return -ENOENT;
> +       }
> +
> +       phandle = fdt32_to_cpu(*phandle_p);
> +
> +       ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
> +                                         &parent);
> +       if (ret)
> +               return ret;
> +
> +       ret = -ENODEV;
> +       for (device_find_first_child(parent, &child); child;
> +            device_find_next_child(&child)) {
> +               if (device_get_uclass_id(child) == UCLASS_BLK) {
> +                       *mdata_dev = child;
> +                       ret = 0;
> +               }
> +       }
> +
> +       return ret;
> +}
> +
> +static int fwu_mdata_gpt_blk_probe(struct udevice *dev)
> +{
> +       int ret;
> +       struct udevice *mdata_dev = NULL;
> +
> +       ret = fwu_get_mdata_device(dev, &mdata_dev);
> +       if (ret)
> +               return ret;
> +
> +       dev_set_priv(dev, mdata_dev);
> +
> +       return 0;
> +}
> +
> +static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
> +       .mdata_check = fwu_gpt_mdata_check,
> +       .get_mdata = fwu_gpt_get_mdata,
> +       .update_mdata = fwu_gpt_update_mdata,
> +};
> +
> +static const struct udevice_id fwu_mdata_ids[] = {
> +       { .compatible = "u-boot,fwu-mdata-gpt" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
> +       .name           = "fwu-mdata-gpt-blk",
> +       .id             = UCLASS_FWU_MDATA,
> +       .of_match       = fwu_mdata_ids,
> +       .ops            = &fwu_gpt_blk_ops,
> +       .probe          = fwu_mdata_gpt_blk_probe,
> +};
> diff --git a/include/fwu.h b/include/fwu.h
> index f9e44e7b39..3b1ee4e83e 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -39,6 +39,8 @@ int fwu_get_active_index(u32 *active_idx);
>  int fwu_update_active_index(u32 active_idx);
>  int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
>                           int *alt_num);
> +int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev);
> +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part);
>  int fwu_mdata_check(void);
>  int fwu_revert_boot_index(void);
>  int fwu_accept_image(efi_guid_t *img_type_id, u32 bank);
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification
  2022-06-09 12:29 ` [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
  2022-06-15  6:34   ` Heinrich Schuchardt
@ 2022-06-21 10:56   ` Etienne Carriere
  2022-06-23  9:45     ` Sughosh Ganu
  2022-06-21 11:46   ` Patrick DELAUNAY
  2 siblings, 1 reply; 104+ messages in thread
From: Etienne Carriere @ 2022-06-21 10:56 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

Hi Sughosh,

On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> The FWU Multi Bank Update specification requires the Update Agent to
> carry out certain checks at the time of platform boot. The Update
> Agent is the component which is responsible for updating the firmware
> components and maintaining and keeping the metadata in sync.
>
> The spec requires that the Update Agent perform the following checks
> at the time of boot
> * Sanity check of both the metadata copies maintained by the platform.
> * Get the boot index passed to U-Boot by the prior stage bootloader
>   and use this value for metadata bookkeeping.
> * Check if the system is booting in Trial State. If the system boots
>   in the Trial State for more than a specified number of boot counts,
>   change the Active Bank to be booting the platform from.
>
> Add these checks in the board initialisation sequence, invoked after
> relocation.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  common/board_r.c      |   5 ++
>  include/fwu.h         |   3 +
>  lib/fwu_updates/fwu.c | 170 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 178 insertions(+)
>  create mode 100644 lib/fwu_updates/fwu.c
>
> diff --git a/common/board_r.c b/common/board_r.c
> index 6f4aca2077..33a600715d 100644
> --- a/common/board_r.c
> +++ b/common/board_r.c
> @@ -15,6 +15,7 @@
>  #include <cpu_func.h>
>  #include <exports.h>
>  #include <flash.h>
> +#include <fwu.h>
>  #include <hang.h>
>  #include <image.h>
>  #include <irq_func.h>
> @@ -797,6 +798,10 @@ static init_fnc_t init_sequence_r[] = {
>  #if defined(CONFIG_PRAM)
>         initr_mem,
>  #endif
> +
> +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
> +       fwu_boottime_checks,
> +#endif
>         run_main_loop,
>  };
>
> diff --git a/include/fwu.h b/include/fwu.h
> index 41774ff9e2..8fbd91b463 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -33,6 +33,9 @@ struct fwu_mdata_ops {
>         EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
>                  0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
>
> +int fwu_boottime_checks(void);
> +u8 fwu_update_checks_pass(void);
> +
>  int fwu_get_mdata(struct fwu_mdata **mdata);
>  int fwu_update_mdata(struct fwu_mdata *mdata);
>  int fwu_get_active_index(u32 *active_idx);
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> new file mode 100644
> index 0000000000..af884439fb
> --- /dev/null
> +++ b/lib/fwu_updates/fwu.c
> @@ -0,0 +1,170 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <dm.h>
> +#include <efi.h>
> +#include <efi_loader.h>
> +#include <efi_variable.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <malloc.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
> +static u8 trial_state;
> +static u8 boottime_check;
> +
> +static int fwu_trial_state_check(void)
> +{
> +       int ret, i;
> +       efi_status_t status;
> +       efi_uintn_t var_size;
> +       u16 trial_state_ctr;
> +       u32 nimages, active_bank, var_attributes, active_idx;
> +       struct fwu_mdata *mdata = NULL;
> +       struct fwu_image_entry *img_entry;
> +       struct fwu_image_bank_info *img_bank_info;
> +
> +       ret = fwu_get_mdata(&mdata);
> +       if (ret)
> +               return ret;
> +
> +       ret = 0;
> +       nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> +       active_bank = mdata->active_index;
> +       img_entry = &mdata->img_entry[0];
> +       for (i = 0; i < nimages; i++) {
> +               img_bank_info = &img_entry[i].img_bank_info[active_bank];
> +               if (!img_bank_info->accepted) {
> +                       trial_state = 1;
> +                       break;
> +               }
> +       }
> +
> +       if (trial_state) {
> +               var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> +               log_info("System booting in Trial State\n");
> +               var_attributes = EFI_VARIABLE_NON_VOLATILE |
> +                       EFI_VARIABLE_BOOTSERVICE_ACCESS;
> +               status = efi_get_variable_int(L"TrialStateCtr",
> +                                             &efi_global_variable_guid,
> +                                             &var_attributes,
> +                                             &var_size, &trial_state_ctr,
> +                                             NULL);
> +               if (status != EFI_SUCCESS) {
> +                       log_err("Unable to read TrialStateCtr variable\n");
> +                       ret = -1;
> +                       goto out;
> +               }
> +
> +               ++trial_state_ctr;
> +               if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
> +                       log_info("Trial State count exceeded. Revert back to previous_active_index\n");
> +                       active_idx = mdata->active_index;
> +                       ret = fwu_revert_boot_index();
> +                       if (ret) {
> +                               log_err("Unable to revert active_index\n");
> +                               goto out;
> +                       }
> +
> +                       trial_state_ctr = 0;
> +                       status = efi_set_variable_int(L"TrialStateCtr",
> +                                                     &efi_global_variable_guid,
> +                                                     var_attributes,
> +                                                     0,

s/0/var_size/ ?
Ditto 24 lines below.

> +                                                     &trial_state_ctr, false);
> +                       if (status != EFI_SUCCESS) {
> +                               log_err("Unable to clear TrialStateCtr variable\n");
> +                               ret = -1;
> +                               goto out;
> +                       }
> +               } else {
> +                       status = efi_set_variable_int(L"TrialStateCtr",
> +                                                     &efi_global_variable_guid,
> +                                                     var_attributes,
> +                                                     var_size,
> +                                                     &trial_state_ctr, false);
> +                       if (status != EFI_SUCCESS) {
> +                               log_err("Unable to increment TrialStateCtr variable\n");
> +                               ret = -1;
> +                               goto out;
> +                       }
> +               }
> +       } else {
> +               trial_state_ctr = 0;
> +               status = efi_set_variable_int(L"TrialStateCtr",
> +                                             &efi_global_variable_guid,
> +                                             0,
> +                                             0, &trial_state_ctr,
> +                                             NULL);

check status value.


> +       }
> +
> +out:
> +       free(mdata);
> +       return ret;
> +}
> +
> +u8 fwu_update_checks_pass(void)
> +{
> +       return !trial_state && boottime_check;
> +}
> +
> +int fwu_boottime_checks(void)
> +{
> +       int ret;
> +       struct udevice *dev;
> +       u32 boot_idx, active_idx;
> +
> +       if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> +               log_err("FWU Metadata device not found\n");
> +               return 0;
> +       }
> +
> +       ret = fwu_mdata_check();
> +       if (ret) {
> +               return 0;
> +       }
> +
> +       /*
> +        * Get the Boot Index, i.e. the bank from
> +        * which the platform has booted. This value
> +        * gets passed from the ealier stage bootloader
> +        * which booted u-boot, e.g. tf-a. If the
> +        * boot index is not the same as the
> +        * active_index read from the FWU metadata,
> +        * update the active_index.
> +        */
> +       fwu_plat_get_bootidx(&boot_idx);
> +       if (boot_idx >= CONFIG_FWU_NUM_BANKS) {
> +               log_err("Received incorrect value of boot_index\n");
> +               return 0;
> +       }
> +
> +       ret = fwu_get_active_index(&active_idx);
> +       if (ret) {
> +               log_err("Unable to read active_index\n");
> +               return 0;
> +       }
> +
> +       if (boot_idx != active_idx) {
> +               log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
> +                        boot_idx, active_idx);
> +               ret = fwu_update_active_index(boot_idx);
> +               if (!ret)
> +                       boottime_check = 1;
> +
> +               return 0;
> +       }
> +
> +       if (efi_init_obj_list() != EFI_SUCCESS)
> +               return 0;
> +
> +       ret = fwu_trial_state_check();
> +       if (!ret)
> +               boottime_check = 1;
> +
> +       return 0;
> +}
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 09/23] FWU: Add support for the FWU Multi Bank Update feature
  2022-06-09 12:29 ` [PATCH v5 09/23] FWU: Add support for the FWU Multi Bank Update feature Sughosh Ganu
@ 2022-06-21 10:56   ` Etienne Carriere
  2022-06-21 11:55   ` Patrick DELAUNAY
  1 sibling, 0 replies; 104+ messages in thread
From: Etienne Carriere @ 2022-06-21 10:56 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> The FWU Multi Bank Update feature supports updation of firmware images
> to one of multiple sets(also called banks) of images. The firmware
> images are clubbed together in banks, with the system booting images
> from the active bank. Information on the images such as which bank
> they belong to is stored as part of the metadata structure, which is
> stored on the same storage media as the firmware images on a dedicated
> partition.
>
> At the time of update, the metadata is read to identify the bank to
> which the images need to be flashed(update bank). On a successful
> update, the metadata is modified to set the updated bank as active
> bank to subsequently boot from.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  include/fwu.h                |  12 +-
>  lib/Kconfig                  |   6 +
>  lib/Makefile                 |   1 +
>  lib/efi_loader/efi_capsule.c | 231 ++++++++++++++++++++++++++++++++++-
>  lib/efi_loader/efi_setup.c   |   3 +-
>  lib/fwu_updates/Kconfig      |  31 +++++
>  lib/fwu_updates/Makefile     |   6 +
>  lib/fwu_updates/fwu.c        |  26 ++++
>  8 files changed, 309 insertions(+), 7 deletions(-)
>  create mode 100644 lib/fwu_updates/Kconfig
>  create mode 100644 lib/fwu_updates/Makefile
>
> diff --git a/include/fwu.h b/include/fwu.h
> index 8fbd91b463..9c8012407b 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -28,13 +28,23 @@ struct fwu_mdata_ops {
>  };
>
>  #define FWU_MDATA_VERSION      0x1
> +#define FWU_IMAGE_ACCEPTED     0x1
>
>  #define FWU_MDATA_GUID \
>         EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
>                  0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
>
> -int fwu_boottime_checks(void);
> +#define FWU_OS_REQUEST_FW_REVERT_GUID \
> +       EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
> +                0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
> +
> +#define FWU_OS_REQUEST_FW_ACCEPT_GUID \
> +       EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
> +                0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
> +
>  u8 fwu_update_checks_pass(void);
> +int fwu_boottime_checks(void);
> +int fwu_trial_state_ctr_start(void);
>
>  int fwu_get_mdata(struct fwu_mdata **mdata);
>  int fwu_update_mdata(struct fwu_mdata *mdata);
> diff --git a/lib/Kconfig b/lib/Kconfig
> index acc0ac081a..4ca6ea226b 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -966,3 +966,9 @@ config PHANDLE_CHECK_SEQ
>           phandles in fdtdec_get_alias_seq() function.
>
>  endmenu
> +
> +menu "FWU Multi Bank Updates"
> +
> +source lib/fwu_updates/Kconfig
> +
> +endmenu
> diff --git a/lib/Makefile b/lib/Makefile
> index d9b1811f75..0cf8527c2d 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_EFI) += efi/
>  obj-$(CONFIG_EFI_LOADER) += efi_driver/
>  obj-$(CONFIG_EFI_LOADER) += efi_loader/
>  obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/
> +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_updates/
>  obj-$(CONFIG_LZMA) += lzma/
>  obj-$(CONFIG_BZIP2) += bzip2/
>  obj-$(CONFIG_TIZEN) += tizen/
> diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
> index c76a5f3570..8ca041e6a2 100644
> --- a/lib/efi_loader/efi_capsule.c
> +++ b/lib/efi_loader/efi_capsule.c
> @@ -14,6 +14,7 @@
>  #include <env.h>
>  #include <fdtdec.h>
>  #include <fs.h>
> +#include <fwu.h>
>  #include <hang.h>
>  #include <malloc.h>
>  #include <mapmem.h>
> @@ -32,6 +33,17 @@ static const efi_guid_t efi_guid_firmware_management_capsule_id =
>                 EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
>  const efi_guid_t efi_guid_firmware_management_protocol =
>                 EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
> +const efi_guid_t fwu_guid_os_request_fw_revert =
> +               FWU_OS_REQUEST_FW_REVERT_GUID;
> +const efi_guid_t fwu_guid_os_request_fw_accept =
> +               FWU_OS_REQUEST_FW_ACCEPT_GUID;
> +
> +#define FW_ACCEPT_OS   (u32)0x8000
> +
> +__maybe_unused static u32 update_index;
> +__maybe_unused static bool capsule_update;
> +__maybe_unused static bool fw_accept_os;
> +static bool image_index_check = true;
>
>  #ifdef CONFIG_EFI_CAPSULE_ON_DISK
>  /* for file system access */
> @@ -205,7 +217,8 @@ efi_fmp_find(efi_guid_t *image_type, u8 image_index, u64 instance,
>                         log_debug("+++ desc[%d] index: %d, name: %ls\n",
>                                   j, desc->image_index, desc->image_id_name);
>                         if (!guidcmp(&desc->image_type_id, image_type) &&
> -                           (desc->image_index == image_index) &&
> +                           (!image_index_check ||
> +                            desc->image_index == image_index) &&
>                             (!instance ||
>                              !desc->hardware_instance ||
>                               desc->hardware_instance == instance))
> @@ -388,6 +401,87 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s
>  }
>  #endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
>
> +static bool fwu_empty_capsule(struct efi_capsule_header *capsule)
> +{
> +       return !guidcmp(&capsule->capsule_guid,
> +                       &fwu_guid_os_request_fw_revert) ||
> +               !guidcmp(&capsule->capsule_guid,
> +                        &fwu_guid_os_request_fw_accept);
> +}
> +
> +static efi_status_t fwu_empty_capsule_process(
> +       struct efi_capsule_header *capsule)
> +{
> +       int status;
> +       u32 active_idx;
> +       efi_status_t ret;
> +       efi_guid_t *image_guid;
> +
> +       if (!guidcmp(&capsule->capsule_guid,
> +                    &fwu_guid_os_request_fw_revert)) {
> +               /*
> +                * One of the previously updated image has
> +                * failed the OS acceptance test. OS has
> +                * requested to revert back to the earlier
> +                * boot index
> +                */
> +               status = fwu_revert_boot_index();
> +               if (status < 0) {
> +                       log_err("Failed to revert the FWU boot index\n");
> +                       if (status == -ENODEV ||
> +                           status == -ERANGE ||
> +                           status == -EIO)
> +                               ret = EFI_DEVICE_ERROR;
> +                       else if (status == -EINVAL)
> +                               ret = EFI_INVALID_PARAMETER;
> +                       else
> +                               ret = EFI_OUT_OF_RESOURCES;
> +               } else {
> +                       ret = EFI_SUCCESS;
> +                       log_err("Reverted the FWU active_index. Recommend rebooting the system\n");
> +               }
> +       } else {
> +               /*
> +                * Image accepted by the OS. Set the acceptance
> +                * status for the image.
> +                */
> +               image_guid = (void *)(char *)capsule +
> +                       capsule->header_size;
> +
> +               status = fwu_get_active_index(&active_idx);
> +               if (status < 0) {
> +                       log_err("Unable to get the active_index from the FWU metadata\n");
> +                       if (status == -ENODEV ||
> +                           status == -ERANGE ||
> +                           status == -EIO)
> +                               ret = EFI_DEVICE_ERROR;
> +                       else if (status == -EINVAL)
> +                               ret = EFI_INVALID_PARAMETER;
> +                       else
> +                               ret = EFI_OUT_OF_RESOURCES;
> +
> +                       return ret;
> +               }
> +
> +               status = fwu_accept_image(image_guid, active_idx);
> +               if (status < 0) {
> +                       log_err("Unable to set the Accept bit for the image %pUs\n",
> +                               image_guid);
> +                       if (status == -ENODEV ||
> +                           status == -ERANGE ||
> +                           status == -EIO)
> +                               ret = EFI_DEVICE_ERROR;
> +                       else if (status == -EINVAL)
> +                               ret = EFI_INVALID_PARAMETER;
> +                       else
> +                               ret = EFI_OUT_OF_RESOURCES;
> +               } else {
> +                       ret = EFI_SUCCESS;
> +               }
> +       }
> +
> +       return ret;
> +}
>
>  /**
>   * efi_capsule_update_firmware - update firmware from capsule
> @@ -407,10 +501,42 @@ static efi_status_t efi_capsule_update_firmware(
>         void *image_binary, *vendor_code;
>         efi_handle_t *handles;
>         efi_uintn_t no_handles;
> -       int item;
> +       int item, alt_no;
>         struct efi_firmware_management_protocol *fmp;
>         u16 *abort_reason;
> +       efi_guid_t image_type_id;
>         efi_status_t ret = EFI_SUCCESS;
> +       int status;
> +       u8 image_index;
> +
> +       if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
> +               if (!fwu_empty_capsule(capsule_data) &&
> +                   !fwu_update_checks_pass()) {
> +                       log_err("FWU checks failed. Cannot start update\n");
> +                       return EFI_INVALID_PARAMETER;
> +               }
> +
> +               if (fwu_empty_capsule(capsule_data)) {
> +                       capsule_update = false;
> +                       return fwu_empty_capsule_process(capsule_data);
> +               } else {
> +                       capsule_update = true;
> +               }
> +
> +               /* Obtain the update_index from the platform */
> +               status = fwu_plat_get_update_index(&update_index);
> +               if (status < 0) {
> +                       log_err("Failed to get the FWU update_index value\n");
> +                       return EFI_DEVICE_ERROR;
> +               }
> +
> +               fw_accept_os = capsule_data->flags & FW_ACCEPT_OS ? 0x1 : 0x0;
> +               /*
> +                * For Multi Bank updates, the image index is determined at
> +                * runtime based on the value of the update bank.
> +                */
> +               image_index_check = false;
> +       }
>
>         /* sanity check */
>         if (capsule_data->header_size < sizeof(*capsule) ||
> @@ -485,8 +611,36 @@ static efi_status_t efi_capsule_update_firmware(
>                                 goto out;
>                 }
>
> +               if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
> +                       /*
> +                        * Based on the value of update_image_type_id,
> +                        * derive the alt number value. This will be
> +                        * passed as update_image_index to the
> +                        * set_image function.
> +                        */
> +                       image_type_id = image->update_image_type_id;
> +                       status = fwu_get_image_alt_num(&image_type_id,
> +                                                      update_index,
> +                                                      &alt_no);
> +                       if (status < 0) {
> +                               log_err("Unable to get the alt no for the image type %pUs\n",
> +                                       &image_type_id);
> +                               if (status == -ENODEV || status == -EIO)
> +                                       ret = EFI_DEVICE_ERROR;
> +                               else if (status == -ENOMEM)
> +                                       ret = EFI_OUT_OF_RESOURCES;
> +                               else if (status == -ERANGE || status == -EINVAL)
> +                                       ret = EFI_INVALID_PARAMETER;
> +                               goto out;
> +                       }
> +                       log_debug("alt_no %u for Image Type Id %pUs\n",
> +                                 alt_no, &image_type_id);
> +                       image_index = alt_no + 1;
> +               } else {
> +                       image_index = image->update_image_index;
> +               }
>                 abort_reason = NULL;
> -               ret = EFI_CALL(fmp->set_image(fmp, image->update_image_index,
> +               ret = EFI_CALL(fmp->set_image(fmp, image_index,
>                                               image_binary,
>                                               image_binary_size,
>                                               vendor_code, NULL,
> @@ -497,6 +651,38 @@ static efi_status_t efi_capsule_update_firmware(
>                         efi_free_pool(abort_reason);
>                         goto out;
>                 }
> +
> +               if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
> +                       if (!fw_accept_os) {
> +                               /*
> +                                * The OS will not be accepting the firmware
> +                                * images. Set the accept bit of all the
> +                                * images contained in this capsule.
> +                                */
> +                               status = fwu_accept_image(&image_type_id,
> +                                                         update_index);
> +                       } else {
> +                               status = fwu_clear_accept_image(&image_type_id,
> +                                                               update_index);
> +                       }
> +
> +                       if (status < 0) {
> +                               log_err("Unable to %s the accept bit for the image %pUs\n",
> +                                       fw_accept_os ? "clear" : "set",
> +                                       &image_type_id);
> +                               if (status == -ENODEV || status == -EIO)
> +                                       ret = EFI_DEVICE_ERROR;
> +                               else if (status == -ENOMEM)
> +                                       ret = EFI_OUT_OF_RESOURCES;
> +                               else if (status == -ERANGE || status == -EINVAL)
> +                                       ret = EFI_INVALID_PARAMETER;
> +                               goto out;
> +                       }
> +                       log_debug("%s the accepted bit for Image %pUs\n",
> +                                 fw_accept_os ? "Cleared" : "Set",
> +                                 &image_type_id);
> +               }
> +
>         }
>
>  out:
> @@ -1101,8 +1287,10 @@ efi_status_t efi_launch_capsules(void)
>  {
>         struct efi_capsule_header *capsule = NULL;
>         u16 **files;
> +       int status;
>         unsigned int nfiles, index, i;
>         efi_status_t ret;
> +       bool update_status = true;
>
>         if (check_run_capsules() != EFI_SUCCESS)
>                 return EFI_SUCCESS;
> @@ -1130,12 +1318,14 @@ efi_status_t efi_launch_capsules(void)
>                 ret = efi_capsule_read_file(files[i], &capsule);
>                 if (ret == EFI_SUCCESS) {
>                         ret = efi_capsule_update_firmware(capsule);
> -                       if (ret != EFI_SUCCESS)
> +                       if (ret != EFI_SUCCESS) {
>                                 log_err("Applying capsule %ls failed.\n",
>                                         files[i]);
> -                       else
> +                               update_status = false;
> +                       } else {
>                                 log_info("Applying capsule %ls succeeded.\n",
>                                          files[i]);
> +                       }
>
>                         /* create CapsuleXXXX */
>                         set_capsule_result(index, capsule, ret);
> @@ -1143,6 +1333,7 @@ efi_status_t efi_launch_capsules(void)
>                         free(capsule);
>                 } else {
>                         log_err("Reading capsule %ls failed\n", files[i]);
> +                       update_status = false;
>                 }
>                 /* delete a capsule either in case of success or failure */
>                 ret = efi_capsule_delete_file(files[i]);
> @@ -1150,7 +1341,37 @@ efi_status_t efi_launch_capsules(void)
>                         log_err("Deleting capsule %ls failed\n",
>                                 files[i]);
>         }
> +
>         efi_capsule_scan_done();
> +       if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
> +               if (update_status == true && capsule_update == true) {
> +                       /*
> +                        * All the capsules have been updated successfully,
> +                        * update the FWU metadata.
> +                        */
> +                       log_debug("Update Complete. Now updating active_index to %u\n",
> +                                 update_index);
> +                       status = fwu_update_active_index(update_index);
> +                       if (status < 0) {
> +                               log_err("Failed to update FWU metadata index values\n");
> +                               if (status == -EINVAL || status == -ERANGE)
> +                                       ret = EFI_INVALID_PARAMETER;
> +                               else if (status == -ENODEV || status == -EIO)
> +                                       ret = EFI_DEVICE_ERROR;
> +                               else if (status == -ENOMEM)
> +                                       ret = EFI_OUT_OF_RESOURCES;
> +                       } else {
> +                               log_debug("Successfully updated the active_index\n");
> +                               status = fwu_trial_state_ctr_start();
> +                               if (status < 0)
> +                                       ret = EFI_DEVICE_ERROR;
> +                               else
> +                                       ret = EFI_SUCCESS;
> +                       }
> +               } else if (capsule_update == true && update_status == false) {
> +                       log_err("All capsules were not updated. Not updating FWU metadata\n");
> +               }
> +       }
>
>         for (i = 0; i < nfiles; i++)
>                 free(files[i]);
> diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
> index 250eeb2fcd..8658ebf56a 100644
> --- a/lib/efi_loader/efi_setup.c
> +++ b/lib/efi_loader/efi_setup.c
> @@ -346,7 +346,8 @@ efi_status_t efi_init_obj_list(void)
>                 goto out;
>
>         /* Execute capsules after reboot */
> -       if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) &&
> +       if (!IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE) &&
> +           IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) &&
>             !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
>                 ret = efi_launch_capsules();
>  out:
> diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
> new file mode 100644
> index 0000000000..6de28e0c9c
> --- /dev/null
> +++ b/lib/fwu_updates/Kconfig
> @@ -0,0 +1,31 @@
> +config FWU_MULTI_BANK_UPDATE
> +       bool "Enable FWU Multi Bank Update Feature"
> +       depends on EFI_HAVE_CAPSULE_SUPPORT
> +       select PARTITION_TYPE_GUID
> +       select EFI_SETUP_EARLY
> +       help
> +         Feature for updating firmware images on platforms having
> +         multiple banks(copies) of the firmware images. One of the
> +         bank is selected for updating all the firmware components
> +
> +config FWU_NUM_BANKS
> +       int "Number of Banks defined by the platform"
> +       depends on FWU_MULTI_BANK_UPDATE
> +       help
> +         Define the number of banks of firmware images on a platform
> +
> +config FWU_NUM_IMAGES_PER_BANK
> +       int "Number of firmware images per bank"
> +       depends on FWU_MULTI_BANK_UPDATE
> +       help
> +         Define the number of firmware images per bank. This value
> +         should be the same for all the banks.
> +
> +config FWU_TRIAL_STATE_CNT
> +       int "Number of times system boots in Trial State"
> +       depends on FWU_MULTI_BANK_UPDATE
> +       default 3
> +       help
> +         With FWU Multi Bank Update feature enabled, number of times
> +         the platform is allowed to boot in Trial State after an
> +         update.
> diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile
> new file mode 100644
> index 0000000000..74e37014e2
> --- /dev/null
> +++ b/lib/fwu_updates/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# Copyright (c) 2022, Linaro Limited
> +#
> +
> +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> index af884439fb..422ef58661 100644
> --- a/lib/fwu_updates/fwu.c
> +++ b/lib/fwu_updates/fwu.c
> @@ -112,6 +112,32 @@ u8 fwu_update_checks_pass(void)
>         return !trial_state && boottime_check;
>  }
>
> +int fwu_trial_state_ctr_start(void)
> +{
> +       int ret;
> +       u32 var_attributes;
> +       efi_status_t status;
> +       efi_uintn_t var_size;
> +       u16 trial_state_ctr;
> +
> +       var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> +       var_attributes = EFI_VARIABLE_NON_VOLATILE |
> +               EFI_VARIABLE_BOOTSERVICE_ACCESS;
> +
> +       trial_state_ctr = ret = 0;
> +       status = efi_set_variable_int(L"TrialStateCtr",
> +                                     &efi_global_variable_guid,
> +                                     var_attributes,
> +                                     var_size,
> +                                     &trial_state_ctr, false);
> +       if (status != EFI_SUCCESS) {
> +               log_err("Unable to increment TrialStateCtr variable\n");
> +               ret = -1;
> +       }
> +
> +       return ret;
> +}
> +
>  int fwu_boottime_checks(void)
>  {
>         int ret;
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 13/23] FWU: Add FWU metadata access driver for non-GPT MTD devices
  2022-06-09 12:30 ` [PATCH v5 13/23] FWU: Add FWU metadata access driver for non-GPT MTD devices Sughosh Ganu
@ 2022-06-21 10:56   ` Etienne Carriere
  2022-06-21 12:39   ` Patrick DELAUNAY
  1 sibling, 0 replies; 104+ messages in thread
From: Etienne Carriere @ 2022-06-21 10:56 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar, Masami Hiramatsu

On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
>
> For the platform which doesn't have GPT partitions for the firmware
> but on MTD devices, the FWU metadata is stored on MTD device as raw
> image at specific offset. This driver gives the access methods
> for the FWU metadata information on such MTD devices.
>
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  drivers/fwu-mdata/Kconfig         |   8 +
>  drivers/fwu-mdata/Makefile        |   1 +
>  drivers/fwu-mdata/fwu_mdata_mtd.c | 308 ++++++++++++++++++++++++++++++
>  3 files changed, 317 insertions(+)
>  create mode 100644 drivers/fwu-mdata/fwu_mdata_mtd.c
>
> diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
> index d5edef19d6..a8fa9ad783 100644
> --- a/drivers/fwu-mdata/Kconfig
> +++ b/drivers/fwu-mdata/Kconfig
> @@ -14,3 +14,11 @@ config FWU_MDATA_GPT_BLK
>         help
>           Enable support for accessing FWU Metadata on GPT partitioned
>           block devices.
> +
> +config FWU_MDATA_MTD
> +       bool "FWU Metadata access for non-GPT MTD devices"
> +       depends on DM_FWU_MDATA && MTD
> +       help
> +         Enable support for accessing FWU Metadata on non-partitioned
> +         (or non-GPT partitioned, e.g. partition nodes in devicetree)
> +         MTD devices.
> diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
> index 12a5b4fe04..c574c59be2 100644
> --- a/drivers/fwu-mdata/Makefile
> +++ b/drivers/fwu-mdata/Makefile
> @@ -5,3 +5,4 @@
>
>  obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
>  obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o
> +obj-$(CONFIG_FWU_MDATA_MTD) += fwu_mdata_mtd.o
> diff --git a/drivers/fwu-mdata/fwu_mdata_mtd.c b/drivers/fwu-mdata/fwu_mdata_mtd.c
> new file mode 100644
> index 0000000000..9eb471e73e
> --- /dev/null
> +++ b/drivers/fwu-mdata/fwu_mdata_mtd.c
> @@ -0,0 +1,308 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2022, 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>
> +
> +struct fwu_mdata_mtd_priv {
> +       struct mtd_info *mtd;
> +       u32 pri_offset;
> +       u32 sec_offset;
> +};

Add an inline description of the fields.

> +
> +enum fwu_mtd_op {
> +       FWU_MTD_READ,
> +       FWU_MTD_WRITE,
> +};
> +
> +static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
> +{
> +       return !do_div(size, mtd->erasesize);
> +}
> +
> +static int mtd_io_data(struct mtd_info *mtd, u32 offs, u32 size, void *data,
> +                      enum fwu_mtd_op op)
> +{
> +       struct mtd_oob_ops io_op ={};
> +       u64 lock_offs, lock_len;
> +       size_t len;
> +       void *buf;
> +       int ret;
> +
> +       if (!mtd_is_aligned_with_block_size(mtd, offs))
> +               return -EINVAL;
> +       lock_offs = offs;
> +       lock_len = round_up(size, mtd->erasesize);
> +
> +       ret = mtd_unlock(mtd, lock_offs, lock_len);
> +       if (ret && ret != -EOPNOTSUPP)
> +               return ret;
> +
> +       if (op == FWU_MTD_WRITE) {
> +               struct erase_info erase_op = {};
> +
> +               /* This will expand erase size to align with the block size */
> +               erase_op.mtd = mtd;
> +               erase_op.addr = lock_offs;
> +               erase_op.len = lock_len;
> +               erase_op.scrub = 0;
> +
> +               ret = mtd_erase(mtd, &erase_op);
> +               if (ret)
> +                       goto lock_out;
> +       }
> +
> +       /* Also, expand the write size to align with the write size */
> +       len = round_up(size, mtd->writesize);
> +
> +       buf = memalign(ARCH_DMA_MINALIGN, len);
> +       if (!buf) {
> +               ret = -ENOMEM;
> +               goto lock_out;
> +       }
> +       io_op.mode = MTD_OPS_AUTO_OOB;
> +       io_op.len = len;
> +       io_op.ooblen = 0;
> +       io_op.datbuf = buf;
> +       io_op.oobbuf = NULL;
> +
> +       if (op == FWU_MTD_WRITE) {
> +               memcpy(buf, data, size);
> +               ret = mtd_write_oob(mtd, offs, &io_op);
> +       } else {
> +               ret = mtd_read_oob(mtd, offs, &io_op);
> +               if (!ret)
> +                       memcpy(data, buf, size);
> +       }
> +       free(buf);
> +
> +lock_out:
> +       mtd_lock(mtd, lock_offs, lock_len);
> +
> +       return ret;
> +}
> +
> +static int fwu_mtd_load_mdata(struct mtd_info *mtd, struct fwu_mdata **mdata,
> +                             u32 offs, bool primary)
> +{
> +       size_t size = sizeof(struct fwu_mdata);
> +       int ret;
> +
> +       *mdata = malloc(size);
> +       if (!*mdata)
> +               return -ENOMEM;
> +
> +       ret = mtd_io_data(mtd, offs, size, (void *)*mdata, FWU_MTD_READ);
> +       if (ret >= 0) {
> +               ret = fwu_verify_mdata(*mdata, primary);
> +               if (ret < 0) {
> +                       free(*mdata);
> +                       *mdata = NULL;
> +               }
> +       }
> +
> +       return ret;
> +}
> +
> +static int fwu_mtd_load_primary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +                                    struct fwu_mdata **mdata)
> +{
> +       return fwu_mtd_load_mdata(mtd_priv->mtd, mdata, mtd_priv->pri_offset, true);
> +}
> +
> +static int fwu_mtd_load_secondary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +                                      struct fwu_mdata **mdata)
> +{
> +       return fwu_mtd_load_mdata(mtd_priv->mtd, mdata, mtd_priv->sec_offset, false);
> +}
> +
> +static int fwu_mtd_save_primary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +                                    struct fwu_mdata *mdata)
> +{
> +       return mtd_io_data(mtd_priv->mtd, mtd_priv->pri_offset,
> +                          sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE);
> +}
> +
> +static int fwu_mtd_save_secondary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +                                      struct fwu_mdata *mdata)
> +{
> +       return mtd_io_data(mtd_priv->mtd, mtd_priv->sec_offset,
> +                          sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE);
> +}
> +
> +static int fwu_mtd_get_valid_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +                                 struct fwu_mdata **mdata)
> +{
> +       if (fwu_mtd_load_primary_mdata(mtd_priv, mdata) == 0)
> +               return 0;

Is it possible  this can fail knowing that content of both images were
checked at probe time?
If it can fail, then, as for the GPT case, i think this function
should ensure the primary and secondary images, in the boot media, are
valid and consistent (sae data).
For example calling back fwu_mtd_mdata_check() for that purpose.
Otherwise, if fwu_mtd_update_mdata() is interrupted (e.g. power loss),
it would leave no valid fwu_mdata in the storage, preventing the
system from rebooting.


> +
> +       log_err("Failed to load/verify primary mdata. Try secondary.\n");
> +
> +       if (fwu_mtd_load_secondary_mdata(mtd_priv, mdata) == 0)
> +               return 0;
> +
> +       log_err("Failed to load/verify secondary mdata.\n");
> +
> +       return -1;
> +}
> +
> +static int fwu_mtd_update_mdata(struct udevice *dev, struct fwu_mdata *mdata)
> +{
> +       struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> +       int ret;
> +
> +       /* Update mdata crc32 field */
> +       mdata->crc32 = crc32(0, (void *)&mdata->version,
> +                            sizeof(*mdata) - sizeof(u32));
> +
> +       /* First write the primary mdata */
> +       ret = fwu_mtd_save_primary_mdata(mtd_priv, mdata);
> +       if (ret < 0) {
> +               log_err("Failed to update the primary mdata.\n");
> +               return ret;
> +       }
> +
> +       /* And now the replica */
> +       ret = fwu_mtd_save_secondary_mdata(mtd_priv, mdata);
> +       if (ret < 0) {
> +               log_err("Failed to update the secondary mdata.\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int fwu_mtd_mdata_check(struct udevice *dev)
> +{
> +       struct fwu_mdata *primary = NULL, *secondary = NULL;
> +       struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> +       int ret;
> +
> +       ret = fwu_mtd_load_primary_mdata(mtd_priv, &primary);
> +       if (ret < 0)
> +               log_err("Failed to read the primary mdata: %d\n", ret);
> +
> +       ret = fwu_mtd_load_secondary_mdata(mtd_priv, &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_mtd_save_secondary_mdata(mtd_priv, primary);
> +               if (ret < 0)
> +                       log_err("Restoring secondary mdata partition failed\n");
> +       } else if (secondary) {
> +               ret = fwu_mtd_save_primary_mdata(mtd_priv, secondary);
> +               if (ret < 0)
> +                       log_err("Restoring primary mdata partition failed\n");
> +       }
> +
> +       free(primary);
> +       free(secondary);
> +       return ret;
> +}
> +
> +static int fwu_mtd_get_mdata(struct udevice *dev, struct fwu_mdata **mdata)
> +{
> +       struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> +
> +       return fwu_mtd_get_valid_mdata(mtd_priv, mdata);
> +}
> +
> +/**
> + * fwu_mdata_mtd_of_to_plat() - Translate from DT to fwu mdata device
> + */
> +static int fwu_mdata_mtd_of_to_plat(struct udevice *dev)
> +{
> +       struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> +       const fdt32_t *phandle_p = NULL;
> +       struct udevice *mtd_dev;
> +       struct mtd_info *mtd;
> +       int ret, size;
> +       u32 phandle;
> +
> +       /* Find the FWU mdata storage device */
> +       phandle_p = ofnode_get_property(dev_ofnode(dev),
> +                                       "fwu-mdata-store", &size);
> +       if (!phandle_p) {
> +               log_err("fwu-mdata-store property not found\n");
> +               return -ENOENT;
> +       }
> +
> +       phandle = fdt32_to_cpu(*phandle_p);
> +
> +       ret = device_get_global_by_ofnode(
> +               ofnode_get_by_phandle(phandle),
> +               &mtd_dev);
> +       if (ret)
> +               return ret;
> +
> +       mtd_probe_devices();
> +
> +       mtd_for_each_device(mtd) {
> +               if (mtd->dev == mtd_dev) {
> +                       mtd_priv->mtd = mtd;
> +                       log_debug("Found the FWU mdata mtd device %s\n", mtd->name);
> +                       break;
> +               }
> +       }
> +       if (!mtd_priv->mtd) {
> +               log_err("Failed to find mtd device by fwu-mdata-store\n");
> +               return -ENOENT;
> +       }
> +
> +       /* Get the offset of primary and seconday mdata */
> +       ret = ofnode_read_u32_index(dev_ofnode(dev), "mdata-offsets", 0,
> +                                   &mtd_priv->pri_offset);
> +       if (ret)
> +               return ret;
> +       ret = ofnode_read_u32_index(dev_ofnode(dev), "mdata-offsets", 1,
> +                                   &mtd_priv->sec_offset);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int fwu_mdata_mtd_probe(struct udevice *dev)
> +{
> +       /* Ensure the metadata can be read. */
> +       return fwu_mtd_mdata_check(dev);
> +}
> +
> +static struct fwu_mdata_ops fwu_mtd_ops = {
> +       .mdata_check = fwu_mtd_mdata_check,
> +       .get_mdata = fwu_mtd_get_mdata,
> +       .update_mdata = fwu_mtd_update_mdata,
> +};
> +
> +static const struct udevice_id fwu_mdata_ids[] = {
> +       { .compatible = "u-boot,fwu-mdata-mtd" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(fwu_mdata_mtd) = {
> +       .name           = "fwu-mdata-mtd",
> +       .id             = UCLASS_FWU_MDATA,
> +       .of_match       = fwu_mdata_ids,
> +       .ops            = &fwu_mtd_ops,
> +       .probe          = fwu_mdata_mtd_probe,
> +       .of_to_plat     = fwu_mdata_mtd_of_to_plat,
> +       .priv_auto      = sizeof(struct fwu_mdata_mtd_priv),
> +};
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 14/23] dt/bindings: firmware: Add FWU metadata on MTD devices binding
  2022-06-09 12:30 ` [PATCH v5 14/23] dt/bindings: firmware: Add FWU metadata on MTD devices binding Sughosh Ganu
@ 2022-06-21 10:56   ` Etienne Carriere
  2022-06-21 12:26   ` Patrick DELAUNAY
  1 sibling, 0 replies; 104+ messages in thread
From: Etienne Carriere @ 2022-06-21 10:56 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar, Masami Hiramatsu

On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
>
> Add a devicetree-binding YAML file for the FWU metadata on MTD
> devices without GPT.
>
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  .../firmware/uboot,fwu-mdata-mtd.yaml         | 38 +++++++++++++++++++
>  1 file changed, 38 insertions(+)
>  create mode 100644 doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
>
> diff --git a/doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml b/doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
> new file mode 100644
> index 0000000000..4f5404f999
> --- /dev/null
> +++ b/doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
> @@ -0,0 +1,38 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/firmware/u-boot,fwu-mdata-sf.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: FWU metadata on MTD device without GPT
> +
> +maintainers:
> + - Masami Hiramatsu <masami.hiramatsu@linaro.org>
> +
> +properties:
> +  compatible:
> +    items:
> +      - const: u-boot,fwu-mdata-mtd
> +
> +  fwu-mdata-store:
> +    maxItems: 1
> +    description: Phandle of the MTD device which contains the FWU medatata.
> +
> +  mdata-offsets:
> +    minItems: 2
> +    description: Offsets of the primary and secondary FWU metadata in the NOR flash.
> +
> +required:
> +  - compatible
> +  - fwu-mdata-store
> +  - mdata-offsets
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    fwu-mdata {
> +        compatible = "u-boot,fwu-mdata-mtd";
> +        fwu-mdata-store = <&spi-flash>;
> +        mdata-offsets = <0x500000 0x530000>;

Is a single 32bit value sufficient to define a block offset in an MTD
device? I was thinking of NAND with a density > 4GByte.

> +    };

> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 15/23] tools: Add mkfwumdata tool for FWU metadata image
  2022-06-09 12:30 ` [PATCH v5 15/23] tools: Add mkfwumdata tool for FWU metadata image Sughosh Ganu
@ 2022-06-21 10:57   ` Etienne Carriere
  2022-06-21 12:59     ` Michal Simek
  2022-06-21 12:55   ` Patrick DELAUNAY
  1 sibling, 1 reply; 104+ messages in thread
From: Etienne Carriere @ 2022-06-21 10:57 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar, Masami Hiramatsu

On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
>
> Add 'mkfwumdata' tool which can generate an image of the FWU metadata
> which is required for initializing the platform.
>
> Usage:
>   mkfwumdata -i NR_IMAGES -b NR_BANKS [--guid] \
>     LOCATION_UUID0,IMAGE_TYPE_UUID0,BANK0_IMAGE_UUID[,BANK1_IMAGE_UUID[,...]] \
>     LOCATION_UUID1,... \
>     IMAGE_FILE
>
> '-i' takes the number of images and '-b' takes the number of
> banks. This takes lists of uuids for the images on arguments,
> and the last argument must be the output image file name.
>
> '--guid' (or '-g' in short) allows user to specify the location UUID
> and image IDs in GUID instead of UUID. This option is useful if the
> platform uses GPT partiotion. In this case, the UUID list
> (for an image) becomes;
>
>     DiskGUID,ParitionTypeGUID,UniquePartitionGUID,...
>
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  tools/Kconfig      |   9 ++
>  tools/Makefile     |   4 +
>  tools/mkfwumdata.c | 298 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 311 insertions(+)
>  create mode 100644 tools/mkfwumdata.c
>
> diff --git a/tools/Kconfig b/tools/Kconfig
> index 117c921da3..3484be99d0 100644
> --- a/tools/Kconfig
> +++ b/tools/Kconfig
> @@ -98,4 +98,13 @@ config TOOLS_MKEFICAPSULE
>           optionally sign that file. If you want to enable UEFI capsule
>           update feature on your target, you certainly need this.
>
> +config TOOLS_MKFWUMDATA
> +       bool "Build mkfwumdata command"
> +       default y if FWU_MULTI_BANK_UPDATE
> +       help
> +         This command allows users to create a raw image of the FWU
> +         metadata for initial installation of the FWU multi bank
> +         update on the board. The installation method depends on
> +         the platform.
> +
>  endmenu
> diff --git a/tools/Makefile b/tools/Makefile
> index 9f2339666a..cd39e5ff6f 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -245,6 +245,10 @@ HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
>  HOSTLDLIBS_mkeficapsule += -lgnutls -luuid
>  hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
>
> +mkfwumdata-objs := mkfwumdata.o lib/crc32.o
> +HOSTLDLIBS_mkfwumdata += -luuid
> +hostprogs-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata
> +
>  # We build some files with extra pedantic flags to try to minimize things
>  # that won't build on some weird host compiler -- though there are lots of
>  # exceptions for files that aren't complaint.
> diff --git a/tools/mkfwumdata.c b/tools/mkfwumdata.c
> new file mode 100644
> index 0000000000..4eb304cae3
> --- /dev/null
> +++ b/tools/mkfwumdata.c
> @@ -0,0 +1,298 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#include <errno.h>
> +#include <getopt.h>
> +#include <stdio.h>
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <u-boot/crc.h>
> +#include <unistd.h>
> +#include <uuid/uuid.h>
> +
> +/* This will dynamically allocate the fwu_mdata */
> +#define CONFIG_FWU_NUM_BANKS           0
> +#define CONFIG_FWU_NUM_IMAGES_PER_BANK 0
> +
> +/* Since we can not include fwu.h, redefine version here. */
> +#define FWU_MDATA_VERSION              1
> +
> +typedef uint8_t u8;
> +typedef int16_t s16;
> +typedef uint16_t u16;
> +typedef uint32_t u32;
> +typedef uint64_t u64;
> +
> +#include <fwu_mdata.h>
> +
> +/* TODO: Endianess conversion may be required for some arch. */
> +
> +static const char *opts_short = "b:i:a:gh";
> +
> +static struct option options[] = {
> +       {"banks", required_argument, NULL, 'b'},
> +       {"images", required_argument, NULL, 'i'},
> +       {"guid", required_argument, NULL, 'g'},
> +       {"active-bank", required_argument, NULL, 'a'},
> +       {"help", no_argument, NULL, 'h'},
> +       {NULL, 0, NULL, 0},
> +};
> +
> +static void print_usage(void)
> +{
> +       fprintf(stderr, "Usage: mkfwumdata [options] <UUIDs list> [<UUIDs list>...] <output file>\n");
> +       fprintf(stderr, "Options:\n"
> +               "\t-i, --images <num>          Number of images\n"
> +               "\t-b, --banks  <num>          Number of banks\n"
> +               "\t-a, --active-bank  <num>    Active bank\n"
> +               "\t-g, --guid                  Use GUID instead of UUID\n"
> +               "\t-h, --help                  print a help message\n"
> +               );
> +       fprintf(stderr, "UUIDs list syntax:\n"
> +               "\t<location uuid>,<image type uuid>,<image uuid>[,<image uuid>]\n"
> +               "\n\tYou must specify # of banks of image-uuid and # of images of the lists.\n"

It's not really explicit how many ',<image uuid>' occurrences are needed.
Maybe:
   In a <UUIDs list> item, there must be as many <image uuid>
occurrences as the given number of banks.
   There must be as many <UUIDs list> items as the given number of images.

> +               "\tIf the location uuid and image uuid are '0', those are filled with null uuid.\n"
> +              );
> +}
> +
> +static bool __use_guid;
> +static u32 active_bank;
> +
> +struct fwu_mdata_object {
> +       size_t images;
> +       size_t banks;
> +       size_t size;
> +       struct fwu_mdata *mdata;
> +};
> +
> +struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks)
> +{
> +       struct fwu_mdata_object *mobj;
> +
> +       mobj = malloc(sizeof(*mobj));

calloc()?

> +       if (!mobj)
> +               return NULL;
> +       mobj->size = sizeof(struct fwu_mdata) +
> +               (sizeof(struct fwu_image_entry) +
> +                sizeof(struct fwu_image_bank_info) * banks) * images;
> +       mobj->images = images;
> +       mobj->banks = banks;
> +       mobj->mdata = malloc(mobj->size);

calloc()?

> +       if (!mobj->mdata) {
> +               free(mobj);
> +               return NULL;
> +       }
> +       memset(mobj->mdata, 0, mobj->size);
> +
> +       return mobj;
> +}
> +
> +struct fwu_image_entry *fwu_get_image(struct fwu_mdata_object *mobj, size_t idx)
> +{
> +       size_t offset;
> +
> +       offset = sizeof(struct fwu_mdata) +
> +               (sizeof(struct fwu_image_entry) +
> +                sizeof(struct fwu_image_bank_info) * mobj->banks) * idx;
> +
> +       return (struct fwu_image_entry *)((char *)mobj->mdata + offset);
> +}
> +
> +struct fwu_image_bank_info *fwu_get_bank(struct fwu_mdata_object *mobj,
> +                                        size_t img_idx, size_t bnk_idx)
> +{
> +       size_t offset;
> +
> +       offset = sizeof(struct fwu_mdata) +
> +               (sizeof(struct fwu_image_entry) +
> +                sizeof(struct fwu_image_bank_info) * mobj->banks) * img_idx +
> +               sizeof(struct fwu_image_entry) +
> +               sizeof(struct fwu_image_bank_info) * bnk_idx;
> +
> +       return (struct fwu_image_bank_info *)((char *)mobj->mdata + offset);
> +}
> +
> +/**
> + * convert_uuid_to_guid() - convert UUID to GUID
> + * @buf:       UUID binary
> + *
> + * UUID and GUID have the same data structure, but their binary
> + * formats are different due to the endianness. See lib/uuid.c.
> + * Since uuid_parse() can handle only UUID, this function must
> + * be called to get correct data for GUID when parsing a string.
> + *
> + * The correct data will be returned in @buf.
> + */
> +void convert_uuid_to_guid(unsigned char *buf)
> +{
> +       unsigned char c;
> +
> +       c = buf[0];
> +       buf[0] = buf[3];
> +       buf[3] = c;
> +       c = buf[1];
> +       buf[1] = buf[2];
> +       buf[2] = c;
> +
> +       c = buf[4];
> +       buf[4] = buf[5];
> +       buf[5] = c;
> +
> +       c = buf[6];
> +       buf[6] = buf[7];
> +       buf[7] = c;
> +}
> +
> +int uuid_guid_parse(char *uuidstr, unsigned char *uuid)
> +{
> +       int ret;
> +
> +       ret = uuid_parse(uuidstr, uuid);
> +       if (ret < 0)
> +               return ret;
> +
> +       if (__use_guid)
> +               convert_uuid_to_guid(uuid);
> +
> +       return ret;
> +}
> +
> +int fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj,
> +                             size_t idx, char *uuids)
> +{
> +       struct fwu_image_entry *image = fwu_get_image(mobj, idx);
> +       struct fwu_image_bank_info *bank;
> +       char *p = uuids, *uuid;
> +       int i;
> +
> +       if (!image)
> +               return -ENOENT;
> +
> +       /* Image location UUID */
> +       uuid = strsep(&p, ",");
> +       if (!uuid)
> +               return -EINVAL;
> +
> +       if (strcmp(uuid, "0") &&
> +           uuid_guid_parse(uuid, (unsigned char *)&image->location_uuid) < 0)
> +               return -EINVAL;
> +
> +       /* Image type UUID */
> +       uuid = strsep(&p, ",");
> +       if (!uuid)
> +               return -EINVAL;
> +
> +       if (uuid_guid_parse(uuid, (unsigned char *)&image->image_type_uuid) < 0)
> +               return -EINVAL;
> +
> +       /* Fill bank image-UUID */
> +       for (i = 0; i < mobj->banks; i++) {
> +               bank = fwu_get_bank(mobj, idx, i);
> +               if (!bank)
> +                       return -ENOENT;
> +               bank->accepted = 1;
> +               uuid = strsep(&p, ",");
> +               if (!uuid)
> +                       return -EINVAL;
> +
> +               if (strcmp(uuid, "0") &&
> +                   uuid_guid_parse(uuid, (unsigned char *)&bank->image_uuid) < 0)
> +                       return -EINVAL;
> +       }
> +       return 0;
> +}
> +
> +/* Caller must ensure that @uuids[] has @mobj->images entries. */
> +int fwu_parse_fill_uuids(struct fwu_mdata_object *mobj, char *uuids[])
> +{
> +       struct fwu_mdata *mdata = mobj->mdata;
> +       int i, ret;
> +
> +       mdata->version = FWU_MDATA_VERSION;
> +       mdata->active_index = active_bank;
> +       mdata->previous_active_index = active_bank ? 0 :
> +               (uint32_t)(mobj->banks - 1);

This looks platform specific (see fwu_plat_get_update_index() is
platform specific). Maybe a dedicated argument to this tool should
define the alternate/previous active index.

> +
> +       for (i = 0; i < mobj->images; i++) {
> +               ret = fwu_parse_fill_image_uuid(mobj, i, uuids[i]);
> +               if (ret < 0)
> +                       return ret;
> +       }
> +
> +       mdata->crc32 = crc32(0, (const unsigned char *)&mdata->version,
> +                             mobj->size - sizeof(uint32_t));
> +
> +       return 0;
> +}
> +
> +int fwu_make_mdata(size_t images, size_t banks, char *uuids[], char *output)
> +{
> +       struct fwu_mdata_object *mobj;
> +       FILE *file;
> +       int ret;
> +
> +       mobj = fwu_alloc_mdata(images, banks);
> +       if (!mobj)
> +               return -ENOMEM;
> +
> +       ret = fwu_parse_fill_uuids(mobj, uuids);
> +       if (ret < 0)

I think  this error case and those below should also free the memory
allocated by fwu_alloc_mdata().

> +               return ret;
> +
> +       file = fopen(output, "w");
> +       if (!file)
> +               return -errno;
> +
> +       ret = fwrite(mobj->mdata, mobj->size, 1, file);
> +       if (ret != mobj->size)
> +               ret = -errno;
> +       else
> +               ret = 0;
> +
> +       fclose(file);
> +       return ret;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +       unsigned long banks = 0, images = 0;
> +       int c, ret;
> +
> +       do {
> +               c = getopt_long(argc, argv, opts_short, options, NULL);
> +               switch (c) {
> +               case 'h':
> +                       print_usage();
> +                       return 0;
> +               case 'b':
> +                       banks = strtoul(optarg, NULL, 0);
> +                       break;
> +               case 'i':
> +                       images = strtoul(optarg, NULL, 0);
> +                       break;
> +               case 'g':
> +                       __use_guid = true;
> +                       break;
> +               case 'a':
> +                       active_bank = strtoul(optarg, NULL, 0);
> +                       break;
> +               }
> +       } while (c != -1);
> +
> +       if (!banks || !images) {
> +               fprintf(stderr, "Error: The number of banks and images must not be 0.\n");
> +               return -EINVAL;
> +       }
> +
> +       /* This command takes UUIDs * images and output file. */
> +       if (optind + images + 1 != argc) {
> +               fprintf(stderr, "Error: UUID list or output file is not specified or too much.\n");
> +               print_usage();
> +               return -ERANGE;
> +       }
> +       ret = fwu_make_mdata(images, banks, argv + optind, argv[argc - 1]);
> +       if (ret < 0)
> +               fprintf(stderr, "Error: Failed to parse and write image: %s\n",
> +                       strerror(-ret));
> +       return ret;
> +}
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules
  2022-06-09 12:29 ` [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules Sughosh Ganu
  2022-06-09 16:27   ` Heinrich Schuchardt
  2022-06-15  5:11   ` Takahiro Akashi
@ 2022-06-21 10:58   ` Etienne Carriere
  2 siblings, 0 replies; 104+ messages in thread
From: Etienne Carriere @ 2022-06-21 10:58 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> The Dependable Boot specification[1] describes the structure of the
> firmware accept and revert capsules. These are empty capsules which
> are used for signalling the acceptance or rejection of the updated
> firmware by the OS. Add support for generating these empty capsules.
>
> [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>  doc/mkeficapsule.1   |  29 ++++++---
>  tools/eficapsule.h   |   8 +++
>  tools/mkeficapsule.c | 139 +++++++++++++++++++++++++++++++++++++------
>  3 files changed, 151 insertions(+), 25 deletions(-)
>
> diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
> index 09bdc24295..77ca061efd 100644
> --- a/doc/mkeficapsule.1
> +++ b/doc/mkeficapsule.1
> @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
>
>  .SH SYNOPSIS
>  .B mkeficapsule
> -.RI [ options "] " image-blob " " capsule-file
> +.RI [ options ] " " [ image-blob ] " " capsule-file
>
>  .SH "DESCRIPTION"
>  .B mkeficapsule
> @@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
>  In this case, the update will be authenticated by verifying the signature
>  before applying.
>
> +Additionally, an empty capsule file can be generated for acceptance or
> +rejection of firmware images by a governing component like an Operating
> +System. The empty capsules do not require an image-blob input file.
> +
> +
>  .B mkeficapsule
> -takes any type of image files, including:
> +takes any type of image files when generating non empty capsules, including:
>  .TP
>  .I raw image
>  format is a single binary blob of any type of firmware.
> @@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
>  This type of image file can be generated by
>  .BR mkimage .
>
> -.PP
> -If you want to use other types than above two, you should explicitly
> -specify a guid for the FMP driver.
> -
>  .SH "OPTIONS"
> +
>  .TP
>  .BI "-g\fR,\fB --guid " guid-string
>  Specify guid for image blob type. The format is:
>      xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
>
>  The first three elements are in little endian, while the rest
> -is in big endian.
> +is in big endian. The option must be specified for all non empty and
> +image acceptance capsules
>
>  .TP
>  .BI "-i\fR,\fB --index " index
> @@ -57,6 +60,18 @@ Specify an image index
>  .BI "-I\fR,\fB --instance " instance
>  Specify a hardware instance
>
> +.PP
> +For generation of firmware accept empty capsule
> +.BR --guid
> +is mandatory
> +.TP
> +.BI "-A\fR,\fB --fw-accept "
> +Generate a firmware acceptance empty capsule
> +
> +.TP
> +.BI "-R\fR,\fB --fw-revert "
> +Generate a firmware revert empty capsule
> +
>  .TP
>  .BR -h ", " --help
>  Print a help message
> diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> index d63b831443..072a4b5598 100644
> --- a/tools/eficapsule.h
> +++ b/tools/eficapsule.h
> @@ -41,6 +41,14 @@ typedef struct {
>         EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
>                  0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
>
> +#define FW_ACCEPT_OS_GUID \
> +       EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
> +                0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
> +
> +#define FW_REVERT_OS_GUID \
> +       EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
> +                0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
> +
>  /* flags */
>  #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
>
> diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> index 5f74d23b9e..e8eb6b070d 100644
> --- a/tools/mkeficapsule.c
> +++ b/tools/mkeficapsule.c
> @@ -29,7 +29,16 @@ static const char *tool_name = "mkeficapsule";
>  efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
>  efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
>
> -static const char *opts_short = "g:i:I:v:p:c:m:dh";
> +static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
> +
> +static bool empty_capsule;
> +static unsigned char capsule;

Local function create_fwbin() defines a local variable with that same label.
Should be ok to remove this 'capsule' variable if only using
'capsule_type' as suggested by Takahiro-san.


> +
> +enum {
> +       CAPSULE_NORMAL_BLOB = 0,
> +       CAPSULE_ACCEPT,
> +       CAPSULE_REVERT,
> +} capsule_type;
>
>  static struct option options[] = {
>         {"guid", required_argument, NULL, 'g'},
> @@ -39,24 +48,47 @@ static struct option options[] = {
>         {"certificate", required_argument, NULL, 'c'},
>         {"monotonic-count", required_argument, NULL, 'm'},
>         {"dump-sig", no_argument, NULL, 'd'},
> +       {"fw-accept", no_argument, NULL, 'A'},
> +       {"fw-revert", no_argument, NULL, 'R'},
>         {"help", no_argument, NULL, 'h'},
>         {NULL, 0, NULL, 0},
>  };
>
>  static void print_usage(void)
>  {
> -       fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> -               "Options:\n"
> -
> -               "\t-g, --guid <guid string>    guid for image blob type\n"
> -               "\t-i, --index <index>         update image index\n"
> -               "\t-I, --instance <instance>   update hardware instance\n"
> -               "\t-p, --private-key <privkey file>  private key file\n"
> -               "\t-c, --certificate <cert file>     signer's certificate file\n"
> -               "\t-m, --monotonic-count <count>     monotonic count\n"
> -               "\t-d, --dump_sig              dump signature (*.p7)\n"
> -               "\t-h, --help                  print a help message\n",
> -               tool_name);
> +       if (empty_capsule) {
> +               if (capsule == CAPSULE_ACCEPT) {
> +                       fprintf(stderr, "Usage: %s [options] <output file>\n",
> +                               tool_name);
> +                       fprintf(stderr, "Options:\n"
> +                               "\t-A, --fw-accept             firmware accept capsule\n"
> +                               "\t-g, --guid <guid string>    guid for image blob type\n"
> +                               "\t-h, --help                  print a help message\n"
> +                               );
> +               } else {
> +                       fprintf(stderr, "Usage: %s [options] <output file>\n",
> +                               tool_name);
> +                       fprintf(stderr, "Options:\n"
> +                               "\t-R, --fw-revert             firmware revert capsule\n"
> +                               "\t-h, --help                  print a help message\n"
> +                               );
> +               }
> +       } else {
> +               fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
> +                       "Options:\n"
> +
> +                       "\t-g, --guid <guid string>    guid for image blob type\n"
> +                       "\t-i, --index <index>         update image index\n"
> +                       "\t-I, --instance <instance>   update hardware instance\n"
> +                       "\t-p, --private-key <privkey file>  private key file\n"
> +                       "\t-c, --certificate <cert file>     signer's certificate file\n"
> +                       "\t-m, --monotonic-count <count>     monotonic count\n"
> +                       "\t-d, --dump_sig              dump signature (*.p7)\n"
> +                       "\t-A, --fw-accept             firmware accept capsule\n"
> +                       "\t-R, --fw-revert             firmware revert capsule\n"
> +                       "\t-h, --help                  print a help message\n",
> +                       tool_name);
> +       }
>  }
>
>  /**
> @@ -564,6 +596,50 @@ void convert_uuid_to_guid(unsigned char *buf)
>         buf[7] = c;
>  }
>
> +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> +{
> +       struct efi_capsule_header header;

It would be better to initialize the header to known value, e.g. = { }; here.

> +       FILE *f = NULL;
> +       int ret = -1;
> +       efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
> +       efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
> +       efi_guid_t payload, capsule_guid;
> +
> +       f = fopen(path, "w");
> +       if (!f) {
> +               fprintf(stderr, "cannot open %s\n", path);
> +               goto err;
> +       }
> +
> +       capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
> +
> +       memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
> +       header.header_size = sizeof(header);
> +       header.flags = 0;
> +
> +       header.capsule_image_size = fw_accept ?
> +               sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
> +
> +       if (write_capsule_file(f, &header, sizeof(header),
> +                              "Capsule header"))
> +               goto err;
> +
> +       if (fw_accept) {
> +               memcpy(&payload, guid, sizeof(efi_guid_t));
> +               if (write_capsule_file(f, &payload, sizeof(payload),
> +                                      "FW Accept Capsule Payload"))

nitpicking: is payload temp variable needed? could pass guid as argument.

> +                       goto err;
> +       }
> +
> +       ret = 0;
> +
> +err:
> +       if (f)
> +               fclose(f);
> +
> +       return ret;
> +}
> +
>  /**
>   * main - main entry function of mkeficapsule
>   * @argc:      Number of arguments
> @@ -639,22 +715,49 @@ int main(int argc, char **argv)
>                 case 'd':
>                         dump_sig = 1;
>                         break;
> +               case 'A':
> +                       capsule |= CAPSULE_ACCEPT;
> +                       break;
> +               case 'R':
> +                       capsule |= CAPSULE_REVERT;
> +                       break;
>                 case 'h':
>                         print_usage();
>                         exit(EXIT_SUCCESS);
>                 }
>         }
>
> +       if (capsule == (CAPSULE_ACCEPT | CAPSULE_REVERT)) {
> +               fprintf(stderr,
> +                       "Select either of Accept or Revert capsule generation\n");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       empty_capsule = (capsule == CAPSULE_ACCEPT ||
> +                        capsule == CAPSULE_REVERT);
> +
>         /* check necessary parameters */
> -       if ((argc != optind + 2) || !guid ||
> -           ((privkey_file && !cert_file) ||
> -            (!privkey_file && cert_file))) {
> +       if ((!empty_capsule &&
> +           ((argc != optind + 2) || !guid ||
> +            ((privkey_file && !cert_file) ||
> +             (!privkey_file && cert_file)))) ||
> +           (empty_capsule &&
> +           ((argc != optind + 1) ||
> +            ((capsule == CAPSULE_ACCEPT) && !guid) ||
> +            ((capsule == CAPSULE_REVERT) && guid)))) {
>                 print_usage();
>                 exit(EXIT_FAILURE);
>         }
>
> -       if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
> -                        mcount, privkey_file, cert_file) < 0) {
> +       if (empty_capsule) {
> +               if (create_empty_capsule(argv[argc - 1], guid,
> +                                        capsule == CAPSULE_ACCEPT) < 0) {
> +                       fprintf(stderr, "Creating empty capsule failed\n");
> +                       exit(EXIT_FAILURE);
> +               }
> +       } else  if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
> +                                index, instance, mcount, privkey_file,
> +                                cert_file) < 0) {
>                 fprintf(stderr, "Creating firmware capsule failed\n");
>                 exit(EXIT_FAILURE);
>         }
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 07/23] FWU: STM32MP1: Add support to read boot index from backup register
  2022-06-09 12:29 ` [PATCH v5 07/23] FWU: STM32MP1: Add support to read boot index from backup register Sughosh Ganu
  2022-06-10 12:02   ` Ilias Apalodimas
@ 2022-06-21 11:27   ` Patrick DELAUNAY
  2022-06-23  6:30     ` Sughosh Ganu
  1 sibling, 1 reply; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21 11:27 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi,

On 6/9/22 14:29, Sughosh Ganu wrote:
> The FWU Multi Bank Update feature allows the platform to boot the
> firmware images from one of the partitions(banks). The first stage
> bootloader(fsbl) passes the value of the boot index, i.e. the bank
> from which the firmware images were booted from to U-Boot. On the
> STM32MP157C-DK2 board, this value is passed through one of the SoC's
> backup register. Add a function to read the boot index value from the
> backup register.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   arch/arm/mach-stm32mp/include/mach/stm32.h | 4 ++++
>   board/st/stm32mp1/stm32mp1.c               | 7 +++++++
>   include/fwu.h                              | 2 +-
>   3 files changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h
> index 47e88fc3dc..40995ee142 100644
> --- a/arch/arm/mach-stm32mp/include/mach/stm32.h
> +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h
> @@ -100,6 +100,7 @@ enum boot_device {
>   #define TAMP_BACKUP_REGISTER(x)		(STM32_TAMP_BASE + 0x100 + 4 * x)
>   #define TAMP_BACKUP_MAGIC_NUMBER	TAMP_BACKUP_REGISTER(4)
>   #define TAMP_BACKUP_BRANCH_ADDRESS	TAMP_BACKUP_REGISTER(5)
> +#define TAMP_FWU_BOOT_INFO_REG		TAMP_BACKUP_REGISTER(10)
>   #define TAMP_COPRO_RSC_TBL_ADDRESS	TAMP_BACKUP_REGISTER(17)
>   #define TAMP_COPRO_STATE		TAMP_BACKUP_REGISTER(18)
>   #define TAMP_BOOT_CONTEXT		TAMP_BACKUP_REGISTER(20)
> @@ -118,6 +119,9 @@ enum boot_device {
>   #define TAMP_BOOT_INSTANCE_MASK		GENMASK(3, 0)
>   #define TAMP_BOOT_FORCED_MASK		GENMASK(7, 0)
>   #define TAMP_BOOT_DEBUG_ON		BIT(16)
> +#define TAMP_FWU_BOOT_IDX_MASK		GENMASK(3, 0)
> +
> +#define TAMP_FWU_BOOT_IDX_OFFSET	0
>   


please don't mix the 2 TAMP_FWU defines with define and enum for TAMP_BOOT

=> move the 2 defines before TAMP_COPRO defines.


#define TAMP_BACKUP_MAGIC_NUMBER    TAMP_BACKUP_REGISTER(4)
#define TAMP_BACKUP_BRANCH_ADDRESS    TAMP_BACKUP_REGISTER(5)
+ #define TAMP_FWU_BOOT_INFO_REG        TAMP_BACKUP_REGISTER(10)
#define TAMP_COPRO_RSC_TBL_ADDRESS    TAMP_BACKUP_REGISTER(17)
#define TAMP_COPRO_STATE        TAMP_BACKUP_REGISTER(18)
#define TAMP_BOOT_CONTEXT        TAMP_BACKUP_REGISTER(20)
#define TAMP_BOOTCOUNT            TAMP_BACKUP_REGISTER(21)

+

+#define TAMP_FWU_BOOT_IDX_MASK GENMASK(3, 0)

+ #define TAMP_FWU_BOOT_IDX_OFFSET 0


#define TAMP_COPRO_STATE_OFF        0
#define TAMP_COPRO_STATE_INIT        1


>   enum forced_boot_mode {
>   	BOOT_NORMAL = 0x00,
> diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> index e68bf09955..dff41ed6f6 100644
> --- a/board/st/stm32mp1/stm32mp1.c
> +++ b/board/st/stm32mp1/stm32mp1.c
> @@ -1081,4 +1081,11 @@ int fwu_plat_get_update_index(u32 *update_idx)
>   	return ret;
>   }
>   
> +void fwu_plat_get_bootidx(void *boot_idx)
> +{
> +	u32 *bootidx = boot_idx;
> +
> +	*bootidx = (readl(TAMP_FWU_BOOT_INFO_REG) >>
> +		    TAMP_FWU_BOOT_IDX_OFFSET) & TAMP_FWU_BOOT_IDX_MASK;
> +}
>   #endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> diff --git a/include/fwu.h b/include/fwu.h
> index 36e58afa29..41774ff9e2 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -46,7 +46,7 @@ int fwu_revert_boot_index(void);
>   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);
>   
> -
> +void fwu_plat_get_bootidx(void *boot_idx);
>   int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
>   			 int *alt_num);
>   int fwu_plat_get_update_index(u32 *update_idx);

With the modifications:

Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>

Thanks
Patrick



^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification
  2022-06-09 12:29 ` [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
  2022-06-15  6:34   ` Heinrich Schuchardt
  2022-06-21 10:56   ` Etienne Carriere
@ 2022-06-21 11:46   ` Patrick DELAUNAY
  2022-06-23  9:49     ` Sughosh Ganu
  2 siblings, 1 reply; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21 11:46 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi,


On 6/9/22 14:29, Sughosh Ganu wrote:
> The FWU Multi Bank Update specification requires the Update Agent to
> carry out certain checks at the time of platform boot. The Update
> Agent is the component which is responsible for updating the firmware
> components and maintaining and keeping the metadata in sync.
>
> The spec requires that the Update Agent perform the following checks
> at the time of boot
> * Sanity check of both the metadata copies maintained by the platform.
> * Get the boot index passed to U-Boot by the prior stage bootloader
>    and use this value for metadata bookkeeping.
> * Check if the system is booting in Trial State. If the system boots
>    in the Trial State for more than a specified number of boot counts,
>    change the Active Bank to be booting the platform from.
>
> Add these checks in the board initialisation sequence, invoked after
> relocation.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   common/board_r.c      |   5 ++
>   include/fwu.h         |   3 +
>   lib/fwu_updates/fwu.c | 170 ++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 178 insertions(+)
>   create mode 100644 lib/fwu_updates/fwu.c
>
> diff --git a/common/board_r.c b/common/board_r.c
> index 6f4aca2077..33a600715d 100644
> --- a/common/board_r.c
> +++ b/common/board_r.c
> @@ -15,6 +15,7 @@
>   #include <cpu_func.h>
>   #include <exports.h>
>   #include <flash.h>
> +#include <fwu.h>
>   #include <hang.h>
>   #include <image.h>
>   #include <irq_func.h>
> @@ -797,6 +798,10 @@ static init_fnc_t init_sequence_r[] = {
>   #if defined(CONFIG_PRAM)
>   	initr_mem,
>   #endif
> +
> +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
> +	fwu_boottime_checks,
> +#endif
>   	run_main_loop,
>   };
>   
> diff --git a/include/fwu.h b/include/fwu.h
> index 41774ff9e2..8fbd91b463 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -33,6 +33,9 @@ struct fwu_mdata_ops {
>   	EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
>   		 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
>   
> +int fwu_boottime_checks(void);
> +u8 fwu_update_checks_pass(void);
> +
>   int fwu_get_mdata(struct fwu_mdata **mdata);
>   int fwu_update_mdata(struct fwu_mdata *mdata);
>   int fwu_get_active_index(u32 *active_idx);
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> new file mode 100644
> index 0000000000..af884439fb
> --- /dev/null
> +++ b/lib/fwu_updates/fwu.c
> @@ -0,0 +1,170 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <dm.h>
> +#include <efi.h>
> +#include <efi_loader.h>
> +#include <efi_variable.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <malloc.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
> +static u8 trial_state;
> +static u8 boottime_check;
> +
> +static int fwu_trial_state_check(void)
> +{
> +	int ret, i;
> +	efi_status_t status;
> +	efi_uintn_t var_size;
> +	u16 trial_state_ctr;
> +	u32 nimages, active_bank, var_attributes, active_idx;
> +	struct fwu_mdata *mdata = NULL;
> +	struct fwu_image_entry *img_entry;
> +	struct fwu_image_bank_info *img_bank_info;
> +
> +	ret = fwu_get_mdata(&mdata);
> +	if (ret)
> +		return ret;
> +
> +	ret = 0;
> +	nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> +	active_bank = mdata->active_index;
> +	img_entry = &mdata->img_entry[0];
> +	for (i = 0; i < nimages; i++) {
> +		img_bank_info = &img_entry[i].img_bank_info[active_bank];
> +		if (!img_bank_info->accepted) {
> +			trial_state = 1;
> +			break;
> +		}
> +	}
> +
> +	if (trial_state) {
> +		var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> +		log_info("System booting in Trial State\n");
> +		var_attributes = EFI_VARIABLE_NON_VOLATILE |
> +			EFI_VARIABLE_BOOTSERVICE_ACCESS;
> +		status = efi_get_variable_int(L"TrialStateCtr",
> +					      &efi_global_variable_guid,
> +					      &var_attributes,
> +					      &var_size, &trial_state_ctr,
> +					      NULL);

for 'L"TrialStateCtr"' => wide characters for unicode

L string is really needed here ?

cf= 
http://patchwork.ozlabs.org/project/uboot/patch/20220123195514.3152022-5-sjg@chromium.org/

same for all the other string L"TrialStateCtr" in the file...


> +		if (status != EFI_SUCCESS) {
> +			log_err("Unable to read TrialStateCtr variable\n");
> +			ret = -1;
> +			goto out;
> +		}
> +
> +		++trial_state_ctr;
> +		if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
> +			log_info("Trial State count exceeded. Revert back to previous_active_index\n");
> +			active_idx = mdata->active_index;
> +			ret = fwu_revert_boot_index();
> +			if (ret) {
> +				log_err("Unable to revert active_index\n");
> +				goto out;
> +			}
> +
> +			trial_state_ctr = 0;
> +			status = efi_set_variable_int(L"TrialStateCtr",
> +						      &efi_global_variable_guid,
> +						      var_attributes,
> +						      0,
> +						      &trial_state_ctr, false);
> +			if (status != EFI_SUCCESS) {
> +				log_err("Unable to clear TrialStateCtr variable\n");
> +				ret = -1;
> +				goto out;
> +			}
> +		} else {
> +			status = efi_set_variable_int(L"TrialStateCtr",
> +						      &efi_global_variable_guid,
> +						      var_attributes,
> +						      var_size,
> +						      &trial_state_ctr, false);
> +			if (status != EFI_SUCCESS) {
> +				log_err("Unable to increment TrialStateCtr variable\n");
> +				ret = -1;
> +				goto out;
> +			}
> +		}
> +	} else {
> +		trial_state_ctr = 0;
> +		status = efi_set_variable_int(L"TrialStateCtr",
> +					      &efi_global_variable_guid,
> +					      0,
> +					      0, &trial_state_ctr,
> +					      NULL);
> +	}
> +
> +out:
> +	free(mdata);
> +	return ret;
> +}
> +
> +u8 fwu_update_checks_pass(void)
> +{
> +	return !trial_state && boottime_check;
> +}
> +
> +int fwu_boottime_checks(void)
> +{
> +	int ret;
> +	struct udevice *dev;
> +	u32 boot_idx, active_idx;
> +
> +	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> +		log_err("FWU Metadata device not found\n");
> +		return 0;
> +	}
> +

This call of "uclass_get_device(UCLASS_FWU_MDATA, 0, &dev)"

is not needed => it is already done in

fwu_mdata_check() => fwu_get_dev_ops()


> +	ret = fwu_mdata_check();
> +	if (ret) {
> +		return 0;
> +	}
> +
> +	/*
> +	 * Get the Boot Index, i.e. the bank from
> +	 * which the platform has booted. This value
> +	 * gets passed from the ealier stage bootloader
> +	 * which booted u-boot, e.g. tf-a. If the
> +	 * boot index is not the same as the
> +	 * active_index read from the FWU metadata,
> +	 * update the active_index.
> +	 */
> +	fwu_plat_get_bootidx(&boot_idx);
> +	if (boot_idx >= CONFIG_FWU_NUM_BANKS) {
> +		log_err("Received incorrect value of boot_index\n");
> +		return 0;
> +	}
> +
> +	ret = fwu_get_active_index(&active_idx);
> +	if (ret) {
> +		log_err("Unable to read active_index\n");
> +		return 0;
> +	}
> +
> +	if (boot_idx != active_idx) {
> +		log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
> +			 boot_idx, active_idx);
> +		ret = fwu_update_active_index(boot_idx);
> +		if (!ret)
> +			boottime_check = 1;
> +
> +		return 0;
> +	}
> +
> +	if (efi_init_obj_list() != EFI_SUCCESS)
> +		return 0;
> +
> +	ret = fwu_trial_state_check();
> +	if (!ret)
> +		boottime_check = 1;
> +
> +	return 0;
> +}


Regards

Patrick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 09/23] FWU: Add support for the FWU Multi Bank Update feature
  2022-06-09 12:29 ` [PATCH v5 09/23] FWU: Add support for the FWU Multi Bank Update feature Sughosh Ganu
  2022-06-21 10:56   ` Etienne Carriere
@ 2022-06-21 11:55   ` Patrick DELAUNAY
  1 sibling, 0 replies; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21 11:55 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi,

On 6/9/22 14:29, Sughosh Ganu wrote:
> The FWU Multi Bank Update feature supports updation of firmware images
> to one of multiple sets(also called banks) of images. The firmware
> images are clubbed together in banks, with the system booting images
> from the active bank. Information on the images such as which bank
> they belong to is stored as part of the metadata structure, which is
> stored on the same storage media as the firmware images on a dedicated
> partition.
>
> At the time of update, the metadata is read to identify the bank to
> which the images need to be flashed(update bank). On a successful
> update, the metadata is modified to set the updated bank as active
> bank to subsequently boot from.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   include/fwu.h                |  12 +-
>   lib/Kconfig                  |   6 +
>   lib/Makefile                 |   1 +
>   lib/efi_loader/efi_capsule.c | 231 ++++++++++++++++++++++++++++++++++-
>   lib/efi_loader/efi_setup.c   |   3 +-
>   lib/fwu_updates/Kconfig      |  31 +++++
>   lib/fwu_updates/Makefile     |   6 +
>   lib/fwu_updates/fwu.c        |  26 ++++
>   8 files changed, 309 insertions(+), 7 deletions(-)
>   create mode 100644 lib/fwu_updates/Kconfig
>   create mode 100644 lib/fwu_updates/Makefile
>

[...]


> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> index af884439fb..422ef58661 100644
> --- a/lib/fwu_updates/fwu.c
> +++ b/lib/fwu_updates/fwu.c
> @@ -112,6 +112,32 @@ u8 fwu_update_checks_pass(void)
>   	return !trial_state && boottime_check;
>   }
>   
> +int fwu_trial_state_ctr_start(void)
> +{
> +	int ret;
> +	u32 var_attributes;
> +	efi_status_t status;
> +	efi_uintn_t var_size;
> +	u16 trial_state_ctr;
> +
> +	var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> +	var_attributes = EFI_VARIABLE_NON_VOLATILE |
> +		EFI_VARIABLE_BOOTSERVICE_ACCESS;
> +
> +	trial_state_ctr = ret = 0;
> +	status = efi_set_variable_int(L"TrialStateCtr",
> +				      &efi_global_variable_guid,
> +				      var_attributes,
> +				      var_size,
> +				      &trial_state_ctr, false);


u"TrialStateCtr",

if USC2 is not mandatory.

> +	if (status != EFI_SUCCESS) {
> +		log_err("Unable to increment TrialStateCtr variable\n");
> +		ret = -1;
> +	}
> +
> +	return ret;
> +}
> +
>   int fwu_boottime_checks(void)
>   {
>   	int ret;


Regards


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata
  2022-06-09 12:29 ` [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata Sughosh Ganu
  2022-06-10 12:07   ` Ilias Apalodimas
  2022-06-20 12:53   ` Michal Simek
@ 2022-06-21 12:07   ` Patrick DELAUNAY
  2 siblings, 0 replies; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21 12:07 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar


On 6/9/22 14:29, Sughosh Ganu wrote:
> Add a command to read the metadata as specified in the FWU
> specification and print the fields of the metadata.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   cmd/Kconfig     |  7 +++++
>   cmd/Makefile    |  1 +
>   cmd/fwu_mdata.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 82 insertions(+)
>   create mode 100644 cmd/fwu_mdata.c
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 09193b61b9..275becd837 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -144,6 +144,13 @@ config CMD_CPU
>   	  internal name) and clock frequency. Other information may be
>   	  available depending on the CPU driver.
>   
> +config CMD_FWU_METADATA
> +	bool "fwu metadata read"
> +	depends on FWU_MULTI_BANK_UPDATE
> +	default y if FWU_MULTI_BANK_UPDATE

+ default y

it is enough with the depends on

> +	help
> +	  Command to read the metadata and dump it's contents
> +
>   config CMD_LICENSE
>   	bool "license"
>   	select BUILD_BIN2C
> diff --git a/cmd/Makefile b/cmd/Makefile
> index 5e43a1e022..259a93bc65 100644
> --- a/cmd/Makefile
> +++ b/cmd/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_CMD_FPGA) += fpga.o
>   obj-$(CONFIG_CMD_FPGAD) += fpgad.o
>   obj-$(CONFIG_CMD_FS_GENERIC) += fs.o
>   obj-$(CONFIG_CMD_FUSE) += fuse.o
> +obj-$(CONFIG_CMD_FWU_METADATA) += fwu_mdata.o
>   obj-$(CONFIG_CMD_GETTIME) += gettime.o
>   obj-$(CONFIG_CMD_GPIO) += gpio.o
>   obj-$(CONFIG_CMD_HVC) += smccc.o
> diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c
> new file mode 100644
> index 0000000000..bc20ca26a3
> --- /dev/null
> +++ b/cmd/fwu_mdata.c
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <command.h>
> +#include <dm.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <log.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include <linux/types.h>
> +
> +static void print_mdata(struct fwu_mdata *mdata)
> +{
> +	int i, j;
> +	struct fwu_image_entry *img_entry;
> +	struct fwu_image_bank_info *img_info;
> +	u32 nimages, nbanks;
> +
> +	printf("\tFWU Metadata\n");
> +	printf("crc32: %#x\n", mdata->crc32);
> +	printf("version: %#x\n", mdata->version);
> +	printf("active_index: %#x\n", mdata->active_index);
> +	printf("previous_active_index: %#x\n", mdata->previous_active_index);
> +
> +	nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> +	nbanks = CONFIG_FWU_NUM_BANKS;
> +	printf("\tImage Info\n");
> +	for (i = 0; i < nimages; i++) {
> +		img_entry = &mdata->img_entry[i];
> +		printf("\nImage Type Guid: %pUL\n", &img_entry->image_type_uuid);
> +		printf("Location Guid: %pUL\n", &img_entry->location_uuid);
> +		for (j = 0; j < nbanks; j++) {
> +			img_info = &img_entry->img_bank_info[j];
> +			printf("Image Guid:  %pUL\n", &img_info->image_uuid);
> +			printf("Image Acceptance: %#x\n", img_info->accepted);
> +		}
> +	}
> +}
> +
> +int do_fwu_mdata_read(struct cmd_tbl *cmdtp, int flag,
> +		     int argc, char * const argv[])
> +{
> +	struct udevice *dev;
> +	int ret = CMD_RET_SUCCESS;
> +	struct fwu_mdata *mdata = NULL;
> +
> +	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> +		log_err("Unable to get FWU metadata device\n");
> +		return CMD_RET_FAILURE;
> +	}
> +

ret is reused here ?

so the default value is overwrite

I think it is better to have 2 variables

ret => cmd result

res => result of fwu_get_mdata() ?

> +	ret = fwu_get_mdata(&mdata);
> +	if (ret < 0) {
> +		log_err("Unable to get valid FWU metadata\n");
> +		ret = CMD_RET_FAILURE;
> +		goto out;
> +	}

+	res = fwu_get_mdata(&mdata);
+	if (res < 0) {
+		log_err("Unable to get valid FWU metadata\n");
+		ret = CMD_RET_FAILURE;
+		goto out;
+	}



> +
> +	print_mdata(mdata);
> +
> +out:
> +	free(mdata);
> +	return ret;
> +}
> +
> +U_BOOT_CMD(
> +	fwu_mdata_read,	1,	1,	do_fwu_mdata_read,
> +	"Read and print FWU metadata",
> +	""
> +);

regards

Patrick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 12/23] FWU: doc: Add documentation for the FWU feature
  2022-06-09 12:29 ` [PATCH v5 12/23] FWU: doc: Add documentation for the FWU feature Sughosh Ganu
@ 2022-06-21 12:12   ` Patrick DELAUNAY
  0 siblings, 0 replies; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21 12:12 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi,


Two minor issues.


On 6/9/22 14:29, Sughosh Ganu wrote:
> Add documentattion for the FWU Multi Bank Update feature. The document

s/documentattio/documentation


> describes the steps needed for setting up the platform for the
> feature, as well as steps for enabling the feature on the platform.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   doc/develop/uefi/fwu_updates.rst | 142 +++++++++++++++++++++++++++++++
>   doc/develop/uefi/index.rst       |   1 +
>   doc/develop/uefi/uefi.rst        |   2 +
>   3 files changed, 145 insertions(+)
>   create mode 100644 doc/develop/uefi/fwu_updates.rst
>
> diff --git a/doc/develop/uefi/fwu_updates.rst b/doc/develop/uefi/fwu_updates.rst
> new file mode 100644
> index 0000000000..1c34beb7d5
> --- /dev/null
> +++ b/doc/develop/uefi/fwu_updates.rst
> @@ -0,0 +1,142 @@
> +.. SPDX-License-Identifier: GPL-2.0+
> +.. Copyright (c) 2022 Linaro Limited
> +
> +FWU Multi Bank Updates in U-Boot
> +================================
> +
> +The FWU Multi Bank Update feature implements the firmware update
> +mechanism described in the PSA Firmware Update for A-profile Arm
> +Architecture specification[1]. Certain aspects of the Dependable
> +Boot specification[2] are also implemented. The feature provides a
> +mechanism to have multiple banks of updatable firmware images and for
> +updating the firmware images on the non-booted bank. On a successful
> +update, the platform boots from the updated bank on subsequent
> +boot. The UEFI capsule-on-disk update feature is used for performing
> +the actual updates of the updatable firmware images.
> +
> +The bookkeeping of the updatable images is done through a structure
> +called metadata. Currently, the FWU metadata supports identification
> +of images based on image GUIDs stored on a GPT partitioned storage
> +media. There are plans to extend the metadata structure for non GPT
> +partitioned devices as well.
> +
> +Accessing the FWU metadata is done through generic API's which are
> +defined in a driver which complies with the u-boot's driver model. A
> +new uclass UCLASS_FWU_MDATA has been added for accessing the FWU
> +metadata. Individual drivers can be added based on the type of storage
> +media, and it's partitioning method. Details of the storage device
> +containing the FWU metadata partitions are specified through a U-Boot
> +specific device tree property `fwu-mdata-store`. Please refer to
> +U-Boot `doc <doc/device-tree-bindings/firmware/fwu-mdata.txt>`__ for
> +the device tree bindings.
> +
> +Enabling the FWU Multi Bank Update feature
> +------------------------------------------
> +
> +The feature can be enabled by specifying the following configs::
> +
> +    CONFIG_EFI_CAPSULE_ON_DISK=y
> +    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y
> +    CONFIG_EFI_CAPSULE_FIRMWARE=y
> +    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
> +
> +    CONFIG_FWU_MULTI_BANK_UPDATE=y
> +    CONFIG_CMD_FWU_METADATA=y
> +    CONFIG_DM_FWU_MDATA=y
> +    CONFIG_FWU_MDATA_GPT_BLK=y
> +    CONFIG_FWU_NUM_BANKS=<val>
> +    CONFIG_FWU_NUM_IMAGES_PER_BANK=<val>
> +
> +in the .config file
> +
> +The first group of configs enable the UEFI capsule-on-disk update
> +functionality. The second group of configs enable the FWU Multi Bank
> +Update functionality. Please refer to the section
> +:ref:`uefi_capsule_update_ref` for more details on generation of the
> +UEFI capsule.
> +
> +Setting up the device for GPT partitioned storage
> +-------------------------------------------------
> +
> +Before enabling the functionality in U-Boot, certain changes are
> +required to be done on the storage device. Assuming a GPT partitioned
> +storage device, the storage media needs to be partitioned with the
> +correct number of partitions, given the number of banks and number of
> +images per bank that the platform is going to support. Each updatable
> +firmware image will be stored on an separate partition. In addition,
> +the two copies of the FWU metadata will be stored on two separate
> +partitions.
> +
> +As an example, a platform supporting two banks with each bank
> +containing three images would need to have 2 * 3 = 6 parititions plus

s/parititions/partitions/


> +the two metadata partitions, or 8 partitions. In addition the storage
> +media can have additional partitions of non-updatable images, like the
> +EFI System Partition(ESP), a partition for the root file system etc.
> +
> +When generating the partitions, a few aspects need to be taken care
> +of. Each GPT partition entry in the GPT header has two GUIDs::
> +
> +    *PartitionTypeGUID*
> +    *UniquePartitionGUID*
> +
> +The PartitionTypeGUID value should correspond to the *image_type_uuid*
> +field of the FWU metadata. This field is used to identify a given type
> +of updatable firmware image, e.g. u-boot, op-tee, FIP etc. This GUID
> +should also be used for specifying the `--guid` parameter when
> +generating the capsule.
> +
> +The UniquePartitionGUID value should correspond to the *image_uuid*
> +field in the FWU metadata. This GUID is used to identify images of a
> +given image type in different banks.
> +
> +Similarly, the FWU specifications defines the GUID value to be used
> +for the metadata partitions. This would be the PartitionTypeGUID for
> +the metadata partitions.
> +
> +When generating the metadata, the *image_type_uuid* and the
> +*image_uuid* values should match the *PartitionTypeGUID* and the
> +*UniquePartitionGUID* values respectively.
> +
> +Performing the Update
> +---------------------
> +
> +Once the storage media has been partitioned and populated with the
> +metadata partitions, the UEFI capsule-on-disk update functionality can
> +be used for performing the update. Refer to the section
> +:ref:`uefi_capsule_update_ref` for details on how the update can be
> +invoked.
> +
> +On a successful update, the FWU metadata gets updated to reflect the
> +bank from which the platform would be booting on subsequent boot.
> +
> +Based on the value of bit15 of the Flags member of the capsule header,
> +the updated images would either be accepted by the u-boot's UEFI
> +implementation, or by the Operating System. If the Operating System is
> +accepting the firmware images, it does so by generating an empty
> +*accept* capsule. The Operating System can also reject the updated
> +firmware by generating a *revert* capsule. The empty capsule can be
> +applied by using the exact same procedure used for performing the
> +capsule-on-disk update.
> +
> +Generating an empty capsule
> +---------------------------
> +
> +The empty capsule can be generated using the mkeficapsule utility. To
> +build the tool, enable::
> +
> +    CONFIG_TOOLS_MKEFICAPSULE=y
> +
> +Run the following commands to generate the accept/revert capsules::
> +
> +.. code-block:: bash
> +
> +    $ ./tools/mkeficapsule \
> +      [--fw-accept --guid <image guid>] | \
> +      [--fw-revert] \
> +      <capsule_file_name>
> +
> +Links
> +-----
> +
> +* [1] https://developer.arm.com/documentation/den0118/a/ - FWU Specification
> +* [2] https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf - Dependable Boot Specification
> diff --git a/doc/develop/uefi/index.rst b/doc/develop/uefi/index.rst
> index 7e65dbc5d5..e26b1fbe05 100644
> --- a/doc/develop/uefi/index.rst
> +++ b/doc/develop/uefi/index.rst
> @@ -13,3 +13,4 @@ can be run an UEFI payload.
>      uefi.rst
>      u-boot_on_efi.rst
>      iscsi.rst
> +   fwu_updates.rst
> diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst
> index 941e427093..536b278dd9 100644
> --- a/doc/develop/uefi/uefi.rst
> +++ b/doc/develop/uefi/uefi.rst
> @@ -277,6 +277,8 @@ Enable ``CONFIG_OPTEE``, ``CONFIG_CMD_OPTEE_RPMB`` and ``CONFIG_EFI_MM_COMM_TEE`
>   
>   [1] https://optee.readthedocs.io/en/latest/building/efi_vars/stmm.html
>   
> +.. _uefi_capsule_update_ref:
> +
>   Enabling UEFI Capsule Update feature
>   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>   


Regards

Patrick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 14/23] dt/bindings: firmware: Add FWU metadata on MTD devices binding
  2022-06-09 12:30 ` [PATCH v5 14/23] dt/bindings: firmware: Add FWU metadata on MTD devices binding Sughosh Ganu
  2022-06-21 10:56   ` Etienne Carriere
@ 2022-06-21 12:26   ` Patrick DELAUNAY
  1 sibling, 0 replies; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21 12:26 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar, Masami Hiramatsu

Hi,

On 6/9/22 14:30, Sughosh Ganu wrote:
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
>
> Add a devicetree-binding YAML file for the FWU metadata on MTD
> devices without GPT.
>
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   .../firmware/uboot,fwu-mdata-mtd.yaml         | 38 +++++++++++++++++++
>   1 file changed, 38 insertions(+)
>   create mode 100644 doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
>
> diff --git a/doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml b/doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
> new file mode 100644
> index 0000000000..4f5404f999
> --- /dev/null
> +++ b/doc/device-tree-bindings/firmware/uboot,fwu-mdata-mtd.yaml
> @@ -0,0 +1,38 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/firmware/u-boot,fwu-mdata-sf.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: FWU metadata on MTD device without GPT
> +
> +maintainers:
> + - Masami Hiramatsu <masami.hiramatsu@linaro.org>
> +
> +properties:
> +  compatible:
> +    items:
> +      - const: u-boot,fwu-mdata-mtd
> +
> +  fwu-mdata-store:
> +    maxItems: 1
> +    description: Phandle of the MTD device which contains the FWU medatata.
> +
> +  mdata-offsets:
> +    minItems: 2
> +    description: Offsets of the primary and secondary FWU metadata in the NOR flash.
> +
> +required:
> +  - compatible
> +  - fwu-mdata-store
> +  - mdata-offsets
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    fwu-mdata {
> +        compatible = "u-boot,fwu-mdata-mtd";
> +        fwu-mdata-store = <&spi-flash>;
> +        mdata-offsets = <0x500000 0x530000>;
> +    };

Do you need to have offset her => normally it is already managed by mtd 
partition


     spi-flash@0 {
         #address-cells = <1>;
         #size-cells = <1>;
         compatible = "spi-flash", "jedec,spi-nor";
....
         metadata1: partition@metadata1 {
             reg = <0x500000 0x30000>;
             label = "metadata1";
         };
         metadata2: partition@metadata2 {
             reg = <0x530000 0x30000>;
             label = "metadata2";
         };
....
     };


So the needed offset information can be found with 2 handles

to the MTD partitions in the device tree !

+    fwu-mdata {
+        compatible = "u-boot,fwu-mdata-mtd";
+        fwu-mdata-store = <&metadata1>, <&metadata2>;
+    };


This proposal can simplify the binding

+  fwu-mdata-store:
+    maxItems: 2
+    description: Phandle of the two MTD partitions which contains the FWU medatata.

+required:
+  - compatible
+  - fwu-mdata-store

Patrick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 13/23] FWU: Add FWU metadata access driver for non-GPT MTD devices
  2022-06-09 12:30 ` [PATCH v5 13/23] FWU: Add FWU metadata access driver for non-GPT MTD devices Sughosh Ganu
  2022-06-21 10:56   ` Etienne Carriere
@ 2022-06-21 12:39   ` Patrick DELAUNAY
  1 sibling, 0 replies; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21 12:39 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar, Masami Hiramatsu

Hi,

On 6/9/22 14:30, Sughosh Ganu wrote:
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
>
> For the platform which doesn't have GPT partitions for the firmware
> but on MTD devices, the FWU metadata is stored on MTD device as raw
> image at specific offset. This driver gives the access methods
> for the FWU metadata information on such MTD devices.
>
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   drivers/fwu-mdata/Kconfig         |   8 +
>   drivers/fwu-mdata/Makefile        |   1 +
>   drivers/fwu-mdata/fwu_mdata_mtd.c | 308 ++++++++++++++++++++++++++++++
>   3 files changed, 317 insertions(+)
>   create mode 100644 drivers/fwu-mdata/fwu_mdata_mtd.c
>
> diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
> index d5edef19d6..a8fa9ad783 100644
> --- a/drivers/fwu-mdata/Kconfig
> +++ b/drivers/fwu-mdata/Kconfig
> @@ -14,3 +14,11 @@ config FWU_MDATA_GPT_BLK
>   	help
>   	  Enable support for accessing FWU Metadata on GPT partitioned
>   	  block devices.
> +
> +config FWU_MDATA_MTD
> +	bool "FWU Metadata access for non-GPT MTD devices"
> +	depends on DM_FWU_MDATA && MTD
> +	help
> +	  Enable support for accessing FWU Metadata on non-partitioned
> +	  (or non-GPT partitioned, e.g. partition nodes in devicetree)
> +	  MTD devices.
> diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
> index 12a5b4fe04..c574c59be2 100644
> --- a/drivers/fwu-mdata/Makefile
> +++ b/drivers/fwu-mdata/Makefile
> @@ -5,3 +5,4 @@
>   
>   obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
>   obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o
> +obj-$(CONFIG_FWU_MDATA_MTD) += fwu_mdata_mtd.o
> diff --git a/drivers/fwu-mdata/fwu_mdata_mtd.c b/drivers/fwu-mdata/fwu_mdata_mtd.c
> new file mode 100644
> index 0000000000..9eb471e73e
> --- /dev/null
> +++ b/drivers/fwu-mdata/fwu_mdata_mtd.c
> @@ -0,0 +1,308 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +

+ #define LOG_CATEGORY UCLASS_FWU_MDATA

it is requested for log command to filter by uclass


the next include is not needed ?

#include <common.h>

> +#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>
> +
> +struct fwu_mdata_mtd_priv {
> +	struct mtd_info *mtd;
> +	u32 pri_offset;
> +	u32 sec_offset;
> +};
> +
> +enum fwu_mtd_op {
> +	FWU_MTD_READ,
> +	FWU_MTD_WRITE,
> +};
> +
> +static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
> +{
> +	return !do_div(size, mtd->erasesize);
> +}
> +
> +static int mtd_io_data(struct mtd_info *mtd, u32 offs, u32 size, void *data,
> +		       enum fwu_mtd_op op)
> +{
> +	struct mtd_oob_ops io_op ={};


missing space : ' = {};'

> +	u64 lock_offs, lock_len;
> +	size_t len;
> +	void *buf;
> +	int ret;
> +
> +	if (!mtd_is_aligned_with_block_size(mtd, offs))
> +		return -EINVAL;
> +	lock_offs = offs;
> +	lock_len = round_up(size, mtd->erasesize);
> +
> +	ret = mtd_unlock(mtd, lock_offs, lock_len);
> +	if (ret && ret != -EOPNOTSUPP)
> +		return ret;
> +
> +	if (op == FWU_MTD_WRITE) {
> +		struct erase_info erase_op = {};
> +
> +		/* This will expand erase size to align with the block size */
> +		erase_op.mtd = mtd;
> +		erase_op.addr = lock_offs;
> +		erase_op.len = lock_len;
> +		erase_op.scrub = 0;
> +
> +		ret = mtd_erase(mtd, &erase_op);
> +		if (ret)
> +			goto lock_out;
> +	}
> +
> +	/* Also, expand the write size to align with the write size */
> +	len = round_up(size, mtd->writesize);
> +
> +	buf = memalign(ARCH_DMA_MINALIGN, len);
> +	if (!buf) {
> +		ret = -ENOMEM;
> +		goto lock_out;
> +	}
> +	io_op.mode = MTD_OPS_AUTO_OOB;
> +	io_op.len = len;
> +	io_op.ooblen = 0;
> +	io_op.datbuf = buf;
> +	io_op.oobbuf = NULL;
> +
> +	if (op == FWU_MTD_WRITE) {
> +		memcpy(buf, data, size);
> +		ret = mtd_write_oob(mtd, offs, &io_op);
> +	} else {
> +		ret = mtd_read_oob(mtd, offs, &io_op);
> +		if (!ret)
> +			memcpy(data, buf, size);
> +	}
> +	free(buf);
> +
> +lock_out:
> +	mtd_lock(mtd, lock_offs, lock_len);
> +
> +	return ret;
> +}
> +
> +static int fwu_mtd_load_mdata(struct mtd_info *mtd, struct fwu_mdata **mdata,
> +			      u32 offs, bool primary)
> +{
> +	size_t size = sizeof(struct fwu_mdata);
> +	int ret;
> +
> +	*mdata = malloc(size);
> +	if (!*mdata)
> +		return -ENOMEM;
> +
> +	ret = mtd_io_data(mtd, offs, size, (void *)*mdata, FWU_MTD_READ);
> +	if (ret >= 0) {
> +		ret = fwu_verify_mdata(*mdata, primary);
> +		if (ret < 0) {
> +			free(*mdata);
> +			*mdata = NULL;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int fwu_mtd_load_primary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +				     struct fwu_mdata **mdata)
> +{
> +	return fwu_mtd_load_mdata(mtd_priv->mtd, mdata, mtd_priv->pri_offset, true);
> +}
> +
> +static int fwu_mtd_load_secondary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +				       struct fwu_mdata **mdata)
> +{
> +	return fwu_mtd_load_mdata(mtd_priv->mtd, mdata, mtd_priv->sec_offset, false);
> +}
> +
> +static int fwu_mtd_save_primary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +				     struct fwu_mdata *mdata)
> +{
> +	return mtd_io_data(mtd_priv->mtd, mtd_priv->pri_offset,
> +			   sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE);
> +}
> +
> +static int fwu_mtd_save_secondary_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +				       struct fwu_mdata *mdata)
> +{
> +	return mtd_io_data(mtd_priv->mtd, mtd_priv->sec_offset,
> +			   sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE);
> +}
> +
> +static int fwu_mtd_get_valid_mdata(struct fwu_mdata_mtd_priv *mtd_priv,
> +				  struct fwu_mdata **mdata)
> +{
> +	if (fwu_mtd_load_primary_mdata(mtd_priv, mdata) == 0)
> +		return 0;
> +
> +	log_err("Failed to load/verify primary mdata. Try secondary.\n");
> +
> +	if (fwu_mtd_load_secondary_mdata(mtd_priv, mdata) == 0)
> +		return 0;
> +
> +	log_err("Failed to load/verify secondary mdata.\n");
> +
> +	return -1;
> +}
> +
> +static int fwu_mtd_update_mdata(struct udevice *dev, struct fwu_mdata *mdata)
> +{
> +	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> +	int ret;
> +
> +	/* Update mdata crc32 field */
> +	mdata->crc32 = crc32(0, (void *)&mdata->version,
> +			     sizeof(*mdata) - sizeof(u32));
> +
> +	/* First write the primary mdata */
> +	ret = fwu_mtd_save_primary_mdata(mtd_priv, mdata);
> +	if (ret < 0) {
> +		log_err("Failed to update the primary mdata.\n");
> +		return ret;
> +	}
> +
> +	/* And now the replica */
> +	ret = fwu_mtd_save_secondary_mdata(mtd_priv, mdata);
> +	if (ret < 0) {
> +		log_err("Failed to update the secondary mdata.\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int fwu_mtd_mdata_check(struct udevice *dev)
> +{
> +	struct fwu_mdata *primary = NULL, *secondary = NULL;
> +	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> +	int ret;
> +
> +	ret = fwu_mtd_load_primary_mdata(mtd_priv, &primary);
> +	if (ret < 0)
> +		log_err("Failed to read the primary mdata: %d\n", ret);
dev_err(dev,
> +
> +	ret = fwu_mtd_load_secondary_mdata(mtd_priv, &secondary);
> +	if (ret < 0)
> +		log_err("Failed to read the secondary mdata: %d\n", ret);
dev_err(dev,
> +
> +	if (primary && secondary) {
> +		if (memcmp(primary, secondary, sizeof(struct fwu_mdata))) {
> +			log_err("The primary and the secondary mdata are different\n");
dev_err(dev,
> +			ret = -1;
> +		}
> +	} else if (primary) {
> +		ret = fwu_mtd_save_secondary_mdata(mtd_priv, primary);
> +		if (ret < 0)
> +			log_err("Restoring secondary mdata partition failed\n");
dev_err(dev,
> +	} else if (secondary) {
> +		ret = fwu_mtd_save_primary_mdata(mtd_priv, secondary);
> +		if (ret < 0)
> +			log_err("Restoring primary mdata partition failed\n");
dev_err(dev,
> +	}
> +
> +	free(primary);
> +	free(secondary);
> +	return ret;
> +}
> +
> +static int fwu_mtd_get_mdata(struct udevice *dev, struct fwu_mdata **mdata)
> +{
> +	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> +
> +	return fwu_mtd_get_valid_mdata(mtd_priv, mdata);
> +}
> +
> +/**
> + * fwu_mdata_mtd_of_to_plat() - Translate from DT to fwu mdata device
> + */
> +static int fwu_mdata_mtd_of_to_plat(struct udevice *dev)
> +{
> +	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> +	const fdt32_t *phandle_p = NULL;
> +	struct udevice *mtd_dev;
> +	struct mtd_info *mtd;
> +	int ret, size;
> +	u32 phandle;
> +
> +	/* Find the FWU mdata storage device */
> +	phandle_p = ofnode_get_property(dev_ofnode(dev),
> +					"fwu-mdata-store", &size);

phandle_p = dev_read_prop(dev, "fwu-mdata-store", &size);


> +	if (!phandle_p) {
> +		log_err("fwu-mdata-store property not found\n");
> +		return -ENOENT;
> +	}
> +
> +	phandle = fdt32_to_cpu(*phandle_p);
> +

or directly use dev_read_phandle_with_args() ?

ret = dev_read_phandle_with_args(dev, "fwu-mdata-store", NULL, 0, 0, 
&phandle_args);

and using = phandle_args.node


> +	ret = device_get_global_by_ofnode(
> +		ofnode_get_by_phandle(phandle),
> +		&mtd_dev);
> +	if (ret)
> +		return ret;
> +
> +	mtd_probe_devices();
> +
> +	mtd_for_each_device(mtd) {
> +		if (mtd->dev == mtd_dev) {
> +			mtd_priv->mtd = mtd;
> +			log_debug("Found the FWU mdata mtd device %s\n", mtd->name);
> +			break;
> +		}
> +	}
> +	if (!mtd_priv->mtd) {
> +		log_err("Failed to find mtd device by fwu-mdata-store\n");
> +		return -ENOENT;
> +	}
> +
> +	/* Get the offset of primary and seconday mdata */
> +	ret = ofnode_read_u32_index(dev_ofnode(dev), "mdata-offsets", 0,
> +				    &mtd_priv->pri_offset);


can be replaced by dev_read_u32_index()

ret = dev_read_u32_index(dev, "mdata-offsets", 0, &mtd_priv->pri_offset);


> +	if (ret)
> +		return ret;
> +	ret = ofnode_read_u32_index(dev_ofnode(dev), "mdata-offsets", 1,
> +				    &mtd_priv->sec_offset);


ret = dev_read_u32_index(dev, "mdata-offsets", 1, &mtd_priv->sec_offset);


> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int fwu_mdata_mtd_probe(struct udevice *dev)
> +{
> +	/* Ensure the metadata can be read. */
> +	return fwu_mtd_mdata_check(dev);
> +}
> +
> +static struct fwu_mdata_ops fwu_mtd_ops = {
> +	.mdata_check = fwu_mtd_mdata_check,
> +	.get_mdata = fwu_mtd_get_mdata,
> +	.update_mdata = fwu_mtd_update_mdata,
> +};
> +
> +static const struct udevice_id fwu_mdata_ids[] = {
> +	{ .compatible = "u-boot,fwu-mdata-mtd" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(fwu_mdata_mtd) = {
> +	.name		= "fwu-mdata-mtd",
> +	.id		= UCLASS_FWU_MDATA,
> +	.of_match	= fwu_mdata_ids,
> +	.ops		= &fwu_mtd_ops,
> +	.probe		= fwu_mdata_mtd_probe,
> +	.of_to_plat	= fwu_mdata_mtd_of_to_plat,
> +	.priv_auto	= sizeof(struct fwu_mdata_mtd_priv),
> +};

regards

Patrick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 15/23] tools: Add mkfwumdata tool for FWU metadata image
  2022-06-09 12:30 ` [PATCH v5 15/23] tools: Add mkfwumdata tool for FWU metadata image Sughosh Ganu
  2022-06-21 10:57   ` Etienne Carriere
@ 2022-06-21 12:55   ` Patrick DELAUNAY
  1 sibling, 0 replies; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-21 12:55 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar, Masami Hiramatsu

Hi,

one minor remark.

On 6/9/22 14:30, Sughosh Ganu wrote:
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
>
> Add 'mkfwumdata' tool which can generate an image of the FWU metadata
> which is required for initializing the platform.
>
> Usage:
>    mkfwumdata -i NR_IMAGES -b NR_BANKS [--guid] \
>      LOCATION_UUID0,IMAGE_TYPE_UUID0,BANK0_IMAGE_UUID[,BANK1_IMAGE_UUID[,...]] \
>      LOCATION_UUID1,... \
>      IMAGE_FILE
>
> '-i' takes the number of images and '-b' takes the number of
> banks. This takes lists of uuids for the images on arguments,
> and the last argument must be the output image file name.
>
> '--guid' (or '-g' in short) allows user to specify the location UUID
> and image IDs in GUID instead of UUID. This option is useful if the
> platform uses GPT partiotion. In this case, the UUID list
> (for an image) becomes;
>
>      DiskGUID,ParitionTypeGUID,UniquePartitionGUID,...
>
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>   tools/Kconfig      |   9 ++
>   tools/Makefile     |   4 +
>   tools/mkfwumdata.c | 298 +++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 311 insertions(+)
>   create mode 100644 tools/mkfwumdata.c
>
> diff --git a/tools/Kconfig b/tools/Kconfig
> index 117c921da3..3484be99d0 100644
> --- a/tools/Kconfig
> +++ b/tools/Kconfig
> @@ -98,4 +98,13 @@ config TOOLS_MKEFICAPSULE
>   	  optionally sign that file. If you want to enable UEFI capsule
>   	  update feature on your target, you certainly need this.
>   
> +config TOOLS_MKFWUMDATA
> +	bool "Build mkfwumdata command"
> +	default y if FWU_MULTI_BANK_UPDATE
> +	help
> +	  This command allows users to create a raw image of the FWU
> +	  metadata for initial installation of the FWU multi bank
> +	  update on the board. The installation method depends on
> +	  the platform.
> +
>   endmenu
> diff --git a/tools/Makefile b/tools/Makefile
> index 9f2339666a..cd39e5ff6f 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -245,6 +245,10 @@ HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
>   HOSTLDLIBS_mkeficapsule += -lgnutls -luuid
>   hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
>   
> +mkfwumdata-objs := mkfwumdata.o lib/crc32.o
> +HOSTLDLIBS_mkfwumdata += -luuid
> +hostprogs-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata
> +
>   # We build some files with extra pedantic flags to try to minimize things
>   # that won't build on some weird host compiler -- though there are lots of
>   # exceptions for files that aren't complaint.
> diff --git a/tools/mkfwumdata.c b/tools/mkfwumdata.c
> new file mode 100644
> index 0000000000..4eb304cae3
> --- /dev/null
> +++ b/tools/mkfwumdata.c
> @@ -0,0 +1,298 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#include <errno.h>
> +#include <getopt.h>
> +#include <stdio.h>
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <u-boot/crc.h>
> +#include <unistd.h>
> +#include <uuid/uuid.h>
> +
> +/* This will dynamically allocate the fwu_mdata */
> +#define CONFIG_FWU_NUM_BANKS		0
> +#define CONFIG_FWU_NUM_IMAGES_PER_BANK	0
> +
> +/* Since we can not include fwu.h, redefine version here. */
> +#define FWU_MDATA_VERSION		1
> +

adding typedef should be avoided

can you include "asm/types.h"  or "linux/types.h" to use the generic define

> +typedef uint8_t u8;
> +typedef int16_t s16;
> +typedef uint16_t u16;
> +typedef uint32_t u32;
> +typedef uint64_t u64;
> +
> +#include <fwu_mdata.h>
> +
> +/* TODO: Endianess conversion may be required for some arch. */
> +
> +static const char *opts_short = "b:i:a:gh";
> +
> +static struct option options[] = {
> +	{"banks", required_argument, NULL, 'b'},
> +	{"images", required_argument, NULL, 'i'},
> +	{"guid", required_argument, NULL, 'g'},
> +	{"active-bank", required_argument, NULL, 'a'},
> +	{"help", no_argument, NULL, 'h'},
> +	{NULL, 0, NULL, 0},
> +};
> +

[...]

Regards

Patrick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 15/23] tools: Add mkfwumdata tool for FWU metadata image
  2022-06-21 10:57   ` Etienne Carriere
@ 2022-06-21 12:59     ` Michal Simek
  0 siblings, 0 replies; 104+ messages in thread
From: Michal Simek @ 2022-06-21 12:59 UTC (permalink / raw)
  To: Etienne Carriere, Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Jassi Brar, Masami Hiramatsu



On 6/21/22 12:57, Etienne Carriere wrote:
> On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>>
>> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
>>
>> Add 'mkfwumdata' tool which can generate an image of the FWU metadata
>> which is required for initializing the platform.
>>
>> Usage:
>>    mkfwumdata -i NR_IMAGES -b NR_BANKS [--guid] \
>>      LOCATION_UUID0,IMAGE_TYPE_UUID0,BANK0_IMAGE_UUID[,BANK1_IMAGE_UUID[,...]] \
>>      LOCATION_UUID1,... \
>>      IMAGE_FILE
>>
>> '-i' takes the number of images and '-b' takes the number of
>> banks. This takes lists of uuids for the images on arguments,
>> and the last argument must be the output image file name.
>>
>> '--guid' (or '-g' in short) allows user to specify the location UUID
>> and image IDs in GUID instead of UUID. This option is useful if the
>> platform uses GPT partiotion. In this case, the UUID list
>> (for an image) becomes;
>>
>>      DiskGUID,ParitionTypeGUID,UniquePartitionGUID,...
>>
>> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
>> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
>> ---
>>   tools/Kconfig      |   9 ++
>>   tools/Makefile     |   4 +
>>   tools/mkfwumdata.c | 298 +++++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 311 insertions(+)
>>   create mode 100644 tools/mkfwumdata.c
>>
>> diff --git a/tools/Kconfig b/tools/Kconfig
>> index 117c921da3..3484be99d0 100644
>> --- a/tools/Kconfig
>> +++ b/tools/Kconfig
>> @@ -98,4 +98,13 @@ config TOOLS_MKEFICAPSULE
>>            optionally sign that file. If you want to enable UEFI capsule
>>            update feature on your target, you certainly need this.
>>
>> +config TOOLS_MKFWUMDATA
>> +       bool "Build mkfwumdata command"
>> +       default y if FWU_MULTI_BANK_UPDATE
>> +       help
>> +         This command allows users to create a raw image of the FWU
>> +         metadata for initial installation of the FWU multi bank
>> +         update on the board. The installation method depends on
>> +         the platform.
>> +
>>   endmenu
>> diff --git a/tools/Makefile b/tools/Makefile
>> index 9f2339666a..cd39e5ff6f 100644
>> --- a/tools/Makefile
>> +++ b/tools/Makefile
>> @@ -245,6 +245,10 @@ HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
>>   HOSTLDLIBS_mkeficapsule += -lgnutls -luuid
>>   hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
>>
>> +mkfwumdata-objs := mkfwumdata.o lib/crc32.o
>> +HOSTLDLIBS_mkfwumdata += -luuid
>> +hostprogs-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata
>> +
>>   # We build some files with extra pedantic flags to try to minimize things
>>   # that won't build on some weird host compiler -- though there are lots of
>>   # exceptions for files that aren't complaint.
>> diff --git a/tools/mkfwumdata.c b/tools/mkfwumdata.c
>> new file mode 100644
>> index 0000000000..4eb304cae3
>> --- /dev/null
>> +++ b/tools/mkfwumdata.c
>> @@ -0,0 +1,298 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +
>> +#include <errno.h>
>> +#include <getopt.h>
>> +#include <stdio.h>
>> +#include <stdint.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <u-boot/crc.h>
>> +#include <unistd.h>
>> +#include <uuid/uuid.h>
>> +
>> +/* This will dynamically allocate the fwu_mdata */
>> +#define CONFIG_FWU_NUM_BANKS           0
>> +#define CONFIG_FWU_NUM_IMAGES_PER_BANK 0
>> +
>> +/* Since we can not include fwu.h, redefine version here. */
>> +#define FWU_MDATA_VERSION              1
>> +
>> +typedef uint8_t u8;
>> +typedef int16_t s16;
>> +typedef uint16_t u16;
>> +typedef uint32_t u32;
>> +typedef uint64_t u64;
>> +
>> +#include <fwu_mdata.h>
>> +
>> +/* TODO: Endianess conversion may be required for some arch. */
>> +
>> +static const char *opts_short = "b:i:a:gh";
>> +
>> +static struct option options[] = {
>> +       {"banks", required_argument, NULL, 'b'},
>> +       {"images", required_argument, NULL, 'i'},
>> +       {"guid", required_argument, NULL, 'g'},
>> +       {"active-bank", required_argument, NULL, 'a'},
>> +       {"help", no_argument, NULL, 'h'},
>> +       {NULL, 0, NULL, 0},
>> +};
>> +
>> +static void print_usage(void)
>> +{
>> +       fprintf(stderr, "Usage: mkfwumdata [options] <UUIDs list> [<UUIDs list>...] <output file>\n");
>> +       fprintf(stderr, "Options:\n"
>> +               "\t-i, --images <num>          Number of images\n"
>> +               "\t-b, --banks  <num>          Number of banks\n"
>> +               "\t-a, --active-bank  <num>    Active bank\n"
>> +               "\t-g, --guid                  Use GUID instead of UUID\n"
>> +               "\t-h, --help                  print a help message\n"
>> +               );
>> +       fprintf(stderr, "UUIDs list syntax:\n"
>> +               "\t<location uuid>,<image type uuid>,<image uuid>[,<image uuid>]\n"
>> +               "\n\tYou must specify # of banks of image-uuid and # of images of the lists.\n"
> 
> It's not really explicit how many ',<image uuid>' occurrences are needed.
> Maybe:
>     In a <UUIDs list> item, there must be as many <image uuid>
> occurrences as the given number of banks.
>     There must be as many <UUIDs list> items as the given number of images.

+1 on this.
I was trying 2 bank 2 image configuration and it is not clear how it should be 
specified. Better description would be good.

Thanks,
Michal


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices
  2022-06-21  9:34   ` Patrick DELAUNAY
@ 2022-06-22 12:39     ` Patrick DELAUNAY
  2022-06-28 10:01     ` Sughosh Ganu
  1 sibling, 0 replies; 104+ messages in thread
From: Patrick DELAUNAY @ 2022-06-22 12:39 UTC (permalink / raw)
  To: Sughosh Ganu, u-boot
  Cc: Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

Hi

On 6/21/22 11:34, Patrick DELAUNAY wrote:
> Hi,
>
> On 6/9/22 14:29, Sughosh Ganu wrote:
>> In the FWU Multi Bank Update feature, the information about the
>> updatable images is stored as part of the metadata, on a separate
>> partition. Add a driver for reading from and writing to the metadata
>> when the updatable images and the metadata are stored on a block
>> device which is formated with GPT based partition scheme.
>>
>> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
>> ---
>>   drivers/fwu-mdata/Kconfig             |   9 +
>>   drivers/fwu-mdata/Makefile            |   1 +
>>   drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 404 ++++++++++++++++++++++++++
>>   include/fwu.h                         |   2 +
>>   4 files changed, 416 insertions(+)
>>   create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c
>>
>> diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
>> index d6a21c8e19..d5edef19d6 100644
>> --- a/drivers/fwu-mdata/Kconfig
>> +++ b/drivers/fwu-mdata/Kconfig
>> @@ -5,3 +5,12 @@ config DM_FWU_MDATA
>>         Enable support for accessing FWU Metadata partitions. The
>>         FWU Metadata partitions reside on the same storage device
>>         which contains the other FWU updatable firmware images.
>> +
>> +config FWU_MDATA_GPT_BLK
>> +    bool "FWU Metadata access for GPT partitioned Block devices"
>> +    select PARTITION_TYPE_GUID
>> +    select PARTITION_UUIDS
>> +    depends on DM && HAVE_BLOCK_DEVICE && EFI_PARTITION
>> +    help
>> +      Enable support for accessing FWU Metadata on GPT partitioned
>> +      block devices.
>> diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
>> index 7fec7171f4..12a5b4fe04 100644
>> --- a/drivers/fwu-mdata/Makefile
>> +++ b/drivers/fwu-mdata/Makefile
>> @@ -4,3 +4,4 @@
>>   #
>>     obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
>> +obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o
>
>
> It is strange to have '_' and '-' in file name for the same directory
>
> => to be coherent = fwu-mdata-gpt-blk.c
>
>
>> diff --git a/drivers/fwu-mdata/fwu_mdata_gpt_blk.c 
>> b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
>> new file mode 100644
>> index 0000000000..329bd3779b
>> --- /dev/null
>> +++ b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
>> @@ -0,0 +1,404 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (c) 2022, Linaro Limited
>> + */


+ #define LOG_CATEGORY UCLASS_FWU_MDATA

For command log filtering by uclass

>> +#include <blk.h>
>> +#include <dm.h>
>> +#include <efi_loader.h>
>> +#include <fwu.h>
>> +#include <fwu_mdata.h>
>> +#include <log.h>
>> +#include <malloc.h>
>> +#include <memalign.h>
>> +#include <part.h>
>> +#include <part_efi.h>
>> +
[...]
>
> Regards
>
> Patrick
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata
  2022-06-21  9:49   ` Patrick DELAUNAY
@ 2022-06-23  6:04     ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-23  6:04 UTC (permalink / raw)
  To: Patrick DELAUNAY
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

On Tue, 21 Jun 2022 at 15:19, Patrick DELAUNAY
<patrick.delaunay@foss.st.com> wrote:
>
> Hi,
>
> On 6/9/22 14:29, Sughosh Ganu wrote:
> > Add helper functions needed for accessing the FWU metadata which
> > contains information on the updatable images. These functions have
> > been added for the STM32MP157C-DK2 board which has the updatable
> > images on the uSD card, formatted as GPT partitions.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >   board/st/stm32mp1/stm32mp1.c | 115 +++++++++++++++++++++++++++++++++++
> >   include/fwu.h                |   2 +
> >   2 files changed, 117 insertions(+)
> >
> > diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> > index 62d98ad776..e68bf09955 100644
> > --- a/board/st/stm32mp1/stm32mp1.c
> > +++ b/board/st/stm32mp1/stm32mp1.c
> > @@ -7,9 +7,11 @@
> >
> >   #include <common.h>
> >   #include <adc.h>
> > +#include <blk.h>
> >   #include <bootm.h>
> >   #include <clk.h>
> >   #include <config.h>
> > +#include <dfu.h>
> >   #include <dm.h>
> >   #include <efi_loader.h>
> >   #include <env.h>
> > @@ -25,9 +27,11 @@
> >   #include <log.h>
> >   #include <malloc.h>
> >   #include <misc.h>
> > +#include <mmc.h>
> >   #include <mtd_node.h>
> >   #include <net.h>
> >   #include <netdev.h>
> > +#include <part.h>
> >   #include <phy.h>
> >   #include <remoteproc.h>
> >   #include <reset.h>
> > @@ -967,3 +971,114 @@ static void board_copro_image_process(ulong fw_image, size_t fw_size)
> >   }
> >
> >   U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_COPRO, board_copro_image_process);
> > +
> > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +
> [...]
> > +
> > +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> > diff --git a/include/fwu.h b/include/fwu.h
> > index 3b1ee4e83e..36e58afa29 100644
> > --- a/include/fwu.h
> > +++ b/include/fwu.h
> > @@ -46,6 +46,8 @@ int fwu_revert_boot_index(void);
> >   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);
> >
> > +
>
>
> Added empty line

Will remove

>
>
> >   int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
> >                        int *alt_num);
> > +int fwu_plat_get_update_index(u32 *update_idx);
> >   #endif /* _FWU_H_ */
>
>
> And I am agree with Ilias remark, should be generic
>
> => search on the current UCLASS_FWU_MDATA
>
>         perhaps need a new ops in u-class ? as implementation can be
> different for GPT and MTD.

My understanding of Ilias's comments was that the function can be
generic for all GPT based platforms. But I will check if this can be
reused for both GPT and MTD devices, on the lines that you mention
above. Thanks.

-sughosh

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 02/23] FWU: Add FWU metadata structure and driver for accessing metadata
  2022-06-21 10:54   ` Etienne Carriere
@ 2022-06-23  6:24     ` Sughosh Ganu
  2022-06-23 11:55       ` Etienne Carriere
  0 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-23  6:24 UTC (permalink / raw)
  To: Etienne Carriere
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

hi Etienne,

On Tue, 21 Jun 2022 at 16:24, Etienne Carriere
<etienne.carriere@linaro.org> wrote:
>
> Hello Sughosh,
>
>
>
> On Thu, 9 Jun 2022 at 14:30, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
> >
> > In the FWU Multi Bank Update feature, the information about the
> > updatable images is stored as part of the metadata, which is stored on
> > a dedicated partition. Add the metadata structure, and a driver model
> > uclass which provides functions to access the metadata. These are
> > generic API's, and implementations can be added based on parameters
> > like how the metadata partition is accessed and what type of storage
> > device houses the metadata.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  drivers/Kconfig                      |   2 +
> >  drivers/Makefile                     |   1 +
> >  drivers/fwu-mdata/Kconfig            |   7 +
> >  drivers/fwu-mdata/Makefile           |   6 +
> >  drivers/fwu-mdata/fwu-mdata-uclass.c | 459 +++++++++++++++++++++++++++
> >  include/dm/uclass-id.h               |   1 +
> >  include/fwu.h                        |  49 +++
> >  include/fwu_mdata.h                  |  67 ++++
> >  8 files changed, 592 insertions(+)
> >  create mode 100644 drivers/fwu-mdata/Kconfig
> >  create mode 100644 drivers/fwu-mdata/Makefile
> >  create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
> >  create mode 100644 include/fwu.h
> >  create mode 100644 include/fwu_mdata.h
> >

<snip>

> > diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c
> > new file mode 100644
> > index 0000000000..1530ceb01d
> > --- /dev/null
> > +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c
> > @@ -0,0 +1,459 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <efi_loader.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +#include <log.h>
> > +#include <malloc.h>
> > +
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +#include <u-boot/crc.h>
> > +
> > +#define IMAGE_ACCEPT_SET       BIT(0)
> > +#define IMAGE_ACCEPT_CLEAR     BIT(1)
> > +
> > +static int fwu_get_dev_ops(struct udevice **dev,
> > +                          const struct fwu_mdata_ops **ops)
> > +{
> > +       int ret;
> > +
> > +       ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev);
> > +       if (ret) {
> > +               log_debug("Cannot find fwu device\n");
> > +               return ret;
> > +       }
> > +
> > +       if ((*ops = device_get_ops(*dev)) == NULL) {
> > +               log_debug("Cannot get fwu device ops\n");
> > +               return -ENOSYS;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * fwu_verify_mdata() - Verify the FWU metadata
> > + * @mdata: FWU metadata structure
> > + * @pri_part: FWU metadata partition is primary or secondary
> > + *
> > + * Verify the FWU metadata by computing the CRC32 for the metadata
> > + * structure and comparing it against the CRC32 value stored as part
> > + * of the structure.
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part)
> > +{
> > +       u32 calc_crc32;
> > +       void *buf;
> > +
> > +       buf = &mdata->version;
> > +       calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
> > +
> > +       if (calc_crc32 != mdata->crc32) {
> > +               log_err("crc32 check failed for %s FWU metadata partition\n",
> > +                       pri_part ? "primary" : "secondary");
> > +               return -1;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * fwu_get_active_index() - Get active_index from the FWU metadata
> > + * @active_idx: active_index value to be read
> > + *
> > + * Read the active_index field from the FWU metadata and place it in
> > + * the variable pointed to be the function argument.
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_get_active_index(u32 *active_idx)
> > +{
> > +       int ret;
> > +       struct fwu_mdata *mdata = NULL;
> > +
> > +       ret = fwu_get_mdata(&mdata);
> > +       if (ret < 0) {
> > +               log_err("Unable to get valid FWU metadata\n");
> > +               goto out;
> > +       }
> > +
> > +       /*
> > +        * Found the FWU metadata partition, now read the active_index
> > +        * value
> > +        */
> > +       *active_idx = mdata->active_index;
> > +       if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
> > +               log_err("Active index value read is incorrect\n");
> > +               ret = -EINVAL;
> > +       }
> > +
> > +out:
> > +       free(mdata);
> > +
> > +       return ret;
> > +}
> > +
> > +/**
> > + * fwu_update_active_index() - Update active_index from the FWU metadata
> > + * @active_idx: active_index value to be updated
> > + *
> > + * Update the active_index field in the FWU metadata
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_update_active_index(u32 active_idx)
> > +{
> > +       int ret;
> > +       struct fwu_mdata *mdata = NULL;
> > +
> > +       if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
> > +               log_err("Active index value to be updated is incorrect\n");
> > +               return -1;
> > +       }
> > +
> > +       ret = fwu_get_mdata(&mdata);
> > +       if (ret < 0) {
> > +               log_err("Unable to get valid FWU metadata\n");
> > +               goto out;
> > +       }
> > +
> > +       /*
> > +        * Update the active index and previous_active_index fields
> > +        * in the FWU metadata
> > +        */
> > +       mdata->previous_active_index = mdata->active_index;
> > +       mdata->active_index = active_idx;
> > +
> > +       /*
> > +        * Now write this updated FWU metadata to both the
> > +        * FWU metadata partitions
> > +        */
> > +       ret = fwu_update_mdata(mdata);
> > +       if (ret < 0) {> +               log_err("Failed to update FWU metadata partitions\n");
> > +               ret = -EIO;
> > +       }
> > +
> > +out:
> > +       free(mdata);
> > +
> > +       return ret;
> > +}
> > +
> > +/**
> > + * fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update
> > + * @image_type_id: pointer to the image guid as passed in the capsule
> > + * @update_bank: Bank to which the update is to be made
> > + * @alt_num: The alt_num for the image
> > + *
> > + * Based on the guid value passed in the capsule, along with the bank to which the
> > + * image needs to be updated, get the dfu alt number which will be used for the
> > + * capsule update
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
> > +                         int *alt_num)
> > +{
> > +       int ret, i;
> > +       efi_guid_t *image_guid;
> > +       struct udevice *dev = NULL;
> > +       struct fwu_mdata *mdata = NULL;
> > +       struct fwu_image_entry *img_entry;
> > +       const struct fwu_mdata_ops *ops = NULL;
> > +       struct fwu_image_bank_info *img_bank_info;
> > +
> > +       ret = fwu_get_dev_ops(&dev, &ops);
> > +       if (ret)
> > +               return ret;
> > +
> > +       ret = fwu_get_mdata(&mdata);
> > +       if (ret) {
> > +               log_err("Unable to get valid FWU metadata\n");
> > +               goto out;
> > +       }
> > +
> > +       /*
> > +        * The FWU metadata has been read. Now get the image_uuid for the
> > +        * image with the update_bank.
> > +        */
> > +       for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
> > +               if (!guidcmp(image_type_id,
> > +                            &mdata->img_entry[i].image_type_uuid)) {
> > +                       img_entry = &mdata->img_entry[i];
> > +                       img_bank_info = &img_entry->img_bank_info[update_bank];
> > +                       image_guid = &img_bank_info->image_uuid;
> > +                       ret = fwu_plat_get_alt_num(dev_get_priv(dev),
> > +                                                  image_guid, alt_num);
> > +                       break;
> > +               }
> > +       }
> > +
> > +       if (i == CONFIG_FWU_NUM_IMAGES_PER_BANK) {
> > +               log_err("Partition with the image type %pUs not found\n",
> > +                       image_type_id);
> > +               ret = -EINVAL;
> > +               goto out;
> > +       }
> > +
> > +       if (!ret) {
> > +               log_debug("alt_num %d for partition %pUs\n",
> > +                         *alt_num, &image_guid);
>
> s/&image_guid/image_guid/
> Ditto in trace below.

Will fix both.

>
> > +       } else {
> > +               log_err("alt_num not found for partition with GUID %pUs\n",
> > +                       &image_guid);
> > +               ret = -EINVAL;
> > +       }
> > +
> > +out:
> > +       free(mdata);
> > +
> > +       return ret;
> > +}
> > +
> > +/**
> > + * fwu_mdata_check() - Check if the FWU metadata is valid
> > + *
> > + * Validate both copies of the FWU metadata. If one of the copies
> > + * has gone bad, restore it from the other bad copy.
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_mdata_check(void)
> > +{
> > +       int ret;
> > +       struct udevice *dev = NULL;
> > +       const struct fwu_mdata_ops *ops = NULL;
> > +
> > +       ret = fwu_get_dev_ops(&dev, &ops);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (!ops->mdata_check) {
> > +               log_err("mdata_check() method not defined\n");
> > +               return -ENOSYS;
> > +       }
> > +
> > +       return ops->mdata_check(dev);
> > +}
> > +
> > +/**
> > + * fwu_revert_boot_index() - Revert the active index in the FWU metadata
> > + *
> > + * Revert the active_index value in the FWU metadata, by swapping the values
> > + * of active_index and previous_active_index in both copies of the
> > + * FWU metadata.
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_revert_boot_index(void)
> > +{
> > +       int ret;
> > +       u32 cur_active_index;
> > +       struct fwu_mdata *mdata = NULL;
> > +
> > +       ret = fwu_get_mdata(&mdata);
> > +       if (ret < 0) {
> > +               log_err("Unable to get valid FWU metadata\n");
> > +               goto out;
> > +       }
> > +
> > +       /*
> > +        * Swap the active index and previous_active_index fields
> > +        * in the FWU metadata
> > +        */
> > +       cur_active_index = mdata->active_index;
> > +       mdata->active_index = mdata->previous_active_index;
> > +       mdata->previous_active_index = cur_active_index;
> > +
> > +       /*
> > +        * Now write this updated FWU metadata to both the
> > +        * FWU metadata partitions
> > +        */
> > +       ret = fwu_update_mdata(mdata);
> > +       if (ret < 0) {
> > +               log_err("Failed to update FWU metadata partitions\n");
> > +               ret = -EIO;
> > +       }
> > +
> > +out:
> > +       free(mdata);
> > +
> > +       return ret;
> > +}
> > +
> > +/**
> > + * fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image
> > + * @img_type_id: Guid of the image type for which the accepted bit is to be
> > + *               set or cleared
> > + * @bank: Bank of which the image's Accept bit is to be set or cleared
> > + * @action: Action which specifies whether image's Accept bit is to be set or
> > + *          cleared
> > + *
> > + * Set/Clear the accepted bit for the image specified by the img_guid parameter.
> > + * This indicates acceptance or rejection of image for subsequent boots by some
> > + * governing component like OS(or firmware).
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +static int fwu_set_clear_image_accept(efi_guid_t *img_type_id,
> > +                                     u32 bank, u8 action)
> > +{
> > +       int ret, i;
> > +       u32 nimages;
> > +       struct fwu_mdata *mdata = NULL;
> > +       struct fwu_image_entry *img_entry;
> > +       struct fwu_image_bank_info *img_bank_info;
> > +
> > +       ret = fwu_get_mdata(&mdata);
> > +       if (ret < 0) {
> > +               log_err("Unable to get valid FWU metadata\n");
> > +               goto out;
> > +       }
> > +
> > +       nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> > +       img_entry = &mdata->img_entry[0];
> > +       for (i = 0; i < nimages; i++) {
> > +               if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
> > +                       img_bank_info = &img_entry[i].img_bank_info[bank];
> > +                       if (action == IMAGE_ACCEPT_SET)
> > +                               img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
> > +                       else
> > +                               img_bank_info->accepted = 0;
> > +
> > +                       ret = fwu_update_mdata(mdata);
> > +                       goto out;
> > +               }
> > +       }
> > +
> > +       /* Image not found */
> > +       ret = -EINVAL;
> > +
> > +out:
> > +       free(mdata);
> > +
> > +       return ret;
> > +}
> > +
> > +/**
> > + * fwu_accept_image() - Set the Acceptance bit for the image
> > + * @img_type_id: Guid of the image type for which the accepted bit is to be
> > + *               cleared
> > + * @bank: Bank of which the image's Accept bit is to be set
> > + *
> > + * Set the accepted bit for the image specified by the img_guid parameter. This
> > + * indicates acceptance of image for subsequent boots by some governing component
> > + * like OS(or firmware).
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank)
> > +{
> > +       return fwu_set_clear_image_accept(img_type_id, bank,
> > +                                         IMAGE_ACCEPT_SET);
> > +}
> > +
> > +/**
> > + * fwu_clear_accept_image() - Clear the Acceptance bit for the image
> > + * @img_type_id: Guid of the image type for which the accepted bit is to be
> > + *               cleared
> > + * @bank: Bank of which the image's Accept bit is to be cleared
> > + *
> > + * Clear the accepted bit for the image type specified by the img_type_id parameter.
> > + * This function is called after the image has been updated. The accepted bit is
> > + * cleared to be set subsequently after passing the image acceptance criteria, by
> > + * either the OS(or firmware)
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank)
> > +{
> > +       return fwu_set_clear_image_accept(img_type_id, bank,
> > +                                         IMAGE_ACCEPT_CLEAR);
> > +}
> > +
> > +/**
> > + * fwu_get_mdata() - Get a FWU metadata copy
> > + * @mdata: Copy of the FWU metadata
> > + *
> > + * Get a valid copy of the FWU metadata.
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_get_mdata(struct fwu_mdata **mdata)
>
> Is there a real need for this function to allocate an instance of struct mdata.
> I think it would be clearer if it was the caller's responsibility to
> allocate/free the structure.
>
> Or maybe rename this function fwu_alloc_and_copy_mdata() to highlight
> that the function gives an allocated copy of the data.

I guess I can put a comment in the function description saying that
the function is responsible for the allocation of the metadata
structure.

> One should be careful when calling these API functions as some act on
> a local copy (retrieved from fw_get_mdata()) while other functions
> modify straight fwu-mdata in the storage media.

Did you find any function which is modifying the metadata on the
storage device directly. The API fwu_update_mdata() is supposed to be
doing that. If you have come across any function which is directly
modifying the metadata on the storage media, please let me know and I
will fix it.

-sughosh

>
> Br,
> etienne
>
>
>
> > +{
> > +       int ret;
> > +       struct udevice *dev = NULL;
> > +       const struct fwu_mdata_ops *ops = NULL;
> > +
> > +       ret = fwu_get_dev_ops(&dev, &ops);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (!ops->get_mdata) {
> > +               log_err("get_mdata() method not defined\n");
> > +               return -ENOSYS;
> > +       }
> > +
> > +       return ops->get_mdata(dev, mdata);
> > +}
> > +
> > +/**
> > + * fwu_update_mdata() - Update the FWU metadata
> > + * @mdata: Copy of the FWU metadata
> > + *
> > + * Update the FWU metadata structure by writing to the
> > + * FWU metadata partitions.
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_update_mdata(struct fwu_mdata *mdata)
> > +{
> > +       int ret;
> > +       void *buf;
> > +       struct udevice *dev = NULL;
> > +       const struct fwu_mdata_ops *ops = NULL;
> > +
> > +       ret = fwu_get_dev_ops(&dev, &ops);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (!ops->update_mdata) {
> > +               log_err("get_mdata() method not defined\n");
> > +               return -ENOSYS;
> > +       }
> > +
> > +       /*
> > +        * Calculate the crc32 for the updated FWU metadata
> > +        * and put the updated value in the FWU metadata crc32
> > +        * field
> > +        */
> > +       buf = &mdata->version;
> > +       mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
> > +
> > +       return ops->update_mdata(dev, mdata);
> > +}
> > +
> > +UCLASS_DRIVER(fwu_mdata) = {
> > +       .id             = UCLASS_FWU_MDATA,
> > +       .name           = "fwu-mdata",
> > +};
> > diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
> > index 3ba69ad9a0..7da719c048 100644
> > --- a/include/dm/uclass-id.h
> > +++ b/include/dm/uclass-id.h
> > @@ -57,6 +57,7 @@ enum uclass_id {
> >         UCLASS_ETH_PHY,         /* Ethernet PHY device */
> >         UCLASS_FIRMWARE,        /* Firmware */
> >         UCLASS_FS_FIRMWARE_LOADER,              /* Generic loader */
> > +       UCLASS_FWU_MDATA,       /* FWU Metadata Access */
> >         UCLASS_GPIO,            /* Bank of general-purpose I/O pins */
> >         UCLASS_HASH,            /* Hash device */
> >         UCLASS_HWSPINLOCK,      /* Hardware semaphores */
> > diff --git a/include/fwu.h b/include/fwu.h
> > new file mode 100644
> > index 0000000000..f9e44e7b39
> > --- /dev/null
> > +++ b/include/fwu.h
> > @@ -0,0 +1,49 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#if !defined _FWU_H_
> > +#define _FWU_H_
> > +
> > +#include <blk.h>
> > +#include <efi.h>
> > +
> > +#include <linux/types.h>
> > +
> > +struct fwu_mdata;
> > +struct udevice;
> > +
> > +/**
> > + * @mdata_check: check the validity of the FWU metadata partitions
> > + * @get_mdata() - Get a FWU metadata copy
> > + * @update_mdata() - Update the FWU metadata copy
> > + */
> > +struct fwu_mdata_ops {
> > +       int (*mdata_check)(struct udevice *dev);
> > +
> > +       int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata);
> > +
> > +       int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
> > +};
> > +
> > +#define FWU_MDATA_VERSION      0x1
> > +
> > +#define FWU_MDATA_GUID \
> > +       EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
> > +                0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
> > +
> > +int fwu_get_mdata(struct fwu_mdata **mdata);
> > +int fwu_update_mdata(struct fwu_mdata *mdata);
> > +int fwu_get_active_index(u32 *active_idx);
> > +int fwu_update_active_index(u32 active_idx);
> > +int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
> > +                         int *alt_num);
> > +int fwu_mdata_check(void);
> > +int fwu_revert_boot_index(void);
> > +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_alt_num(struct udevice *dev, efi_guid_t *image_guid,
> > +                        int *alt_num);
> > +#endif /* _FWU_H_ */
> > diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h
> > new file mode 100644
> > index 0000000000..701efbba03
> > --- /dev/null
> > +++ b/include/fwu_mdata.h
> > @@ -0,0 +1,67 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#if !defined _FWU_MDATA_H_
> > +#define _FWU_MDATA_H_
> > +
> > +#include <efi.h>
> > +
> > +/**
> > + * struct fwu_image_bank_info - firmware image information
> > + * @image_uuid: Guid value of the image in this bank
> > + * @accepted: Acceptance status of the image
> > + * @reserved: Reserved
> > + *
> > + * The structure contains image specific fields which are
> > + * used to identify the image and to specify the image's
> > + * acceptance status
> > + */
> > +struct fwu_image_bank_info {
> > +       efi_guid_t  image_uuid;
> > +       uint32_t accepted;
> > +       uint32_t reserved;
> > +} __attribute__((__packed__));
> > +
> > +/**
> > + * struct fwu_image_entry - information for a particular type of image
> > + * @image_type_uuid: Guid value for identifying the image type
> > + * @location_uuid: Guid of the storage volume where the image is located
> > + * @img_bank_info: Array containing properties of images
> > + *
> > + * This structure contains information on various types of updatable
> > + * firmware images. Each image type then contains an array of image
> > + * information per bank.
> > + */
> > +struct fwu_image_entry {
> > +       efi_guid_t image_type_uuid;
> > +       efi_guid_t location_uuid;
> > +       struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
> > +} __attribute__((__packed__));
> > +
> > +/**
> > + * struct fwu_mdata - FWU metadata structure for multi-bank updates
> > + * @crc32: crc32 value for the FWU metadata
> > + * @version: FWU metadata version
> > + * @active_index: Index of the bank currently used for booting images
> > + * @previous_active_inde: Index of the bank used before the current bank
> > + *                        being used for booting
> > + * @img_entry: Array of information on various firmware images that can
> > + *             be updated
> > + *
> > + * This structure is used to store all the needed information for performing
> > + * multi bank updates on the platform. This contains info on the bank being
> > + * used to boot along with the information needed for identification of
> > + * individual images
> > + */
> > +struct fwu_mdata {
> > +       uint32_t crc32;
> > +       uint32_t version;
> > +       uint32_t active_index;
> > +       uint32_t previous_active_index;
> > +
> > +       struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
> > +} __attribute__((__packed__));
> > +
> > +#endif /* _FWU_MDATA_H_ */
> > --
> > 2.25.1
> >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 07/23] FWU: STM32MP1: Add support to read boot index from backup register
  2022-06-21 11:27   ` Patrick DELAUNAY
@ 2022-06-23  6:30     ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-23  6:30 UTC (permalink / raw)
  To: Patrick DELAUNAY
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

On Tue, 21 Jun 2022 at 16:57, Patrick DELAUNAY
<patrick.delaunay@foss.st.com> wrote:
>
> Hi,
>
> On 6/9/22 14:29, Sughosh Ganu wrote:
> > The FWU Multi Bank Update feature allows the platform to boot the
> > firmware images from one of the partitions(banks). The first stage
> > bootloader(fsbl) passes the value of the boot index, i.e. the bank
> > from which the firmware images were booted from to U-Boot. On the
> > STM32MP157C-DK2 board, this value is passed through one of the SoC's
> > backup register. Add a function to read the boot index value from the
> > backup register.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >   arch/arm/mach-stm32mp/include/mach/stm32.h | 4 ++++
> >   board/st/stm32mp1/stm32mp1.c               | 7 +++++++
> >   include/fwu.h                              | 2 +-
> >   3 files changed, 12 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h
> > index 47e88fc3dc..40995ee142 100644
> > --- a/arch/arm/mach-stm32mp/include/mach/stm32.h
> > +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h
> > @@ -100,6 +100,7 @@ enum boot_device {
> >   #define TAMP_BACKUP_REGISTER(x)             (STM32_TAMP_BASE + 0x100 + 4 * x)
> >   #define TAMP_BACKUP_MAGIC_NUMBER    TAMP_BACKUP_REGISTER(4)
> >   #define TAMP_BACKUP_BRANCH_ADDRESS  TAMP_BACKUP_REGISTER(5)
> > +#define TAMP_FWU_BOOT_INFO_REG               TAMP_BACKUP_REGISTER(10)
> >   #define TAMP_COPRO_RSC_TBL_ADDRESS  TAMP_BACKUP_REGISTER(17)
> >   #define TAMP_COPRO_STATE            TAMP_BACKUP_REGISTER(18)
> >   #define TAMP_BOOT_CONTEXT           TAMP_BACKUP_REGISTER(20)
> > @@ -118,6 +119,9 @@ enum boot_device {
> >   #define TAMP_BOOT_INSTANCE_MASK             GENMASK(3, 0)
> >   #define TAMP_BOOT_FORCED_MASK               GENMASK(7, 0)
> >   #define TAMP_BOOT_DEBUG_ON          BIT(16)
> > +#define TAMP_FWU_BOOT_IDX_MASK               GENMASK(3, 0)
> > +
> > +#define TAMP_FWU_BOOT_IDX_OFFSET     0
> >
>
>
> please don't mix the 2 TAMP_FWU defines with define and enum for TAMP_BOOT
>
> => move the 2 defines before TAMP_COPRO defines.
>
>
> #define TAMP_BACKUP_MAGIC_NUMBER    TAMP_BACKUP_REGISTER(4)
> #define TAMP_BACKUP_BRANCH_ADDRESS    TAMP_BACKUP_REGISTER(5)
> + #define TAMP_FWU_BOOT_INFO_REG        TAMP_BACKUP_REGISTER(10)
> #define TAMP_COPRO_RSC_TBL_ADDRESS    TAMP_BACKUP_REGISTER(17)
> #define TAMP_COPRO_STATE        TAMP_BACKUP_REGISTER(18)
> #define TAMP_BOOT_CONTEXT        TAMP_BACKUP_REGISTER(20)
> #define TAMP_BOOTCOUNT            TAMP_BACKUP_REGISTER(21)
>
> +
>
> +#define TAMP_FWU_BOOT_IDX_MASK GENMASK(3, 0)
>
> + #define TAMP_FWU_BOOT_IDX_OFFSET 0

Will change as per your suggestion. Thanks.

-sughosh

>
>
> #define TAMP_COPRO_STATE_OFF        0
> #define TAMP_COPRO_STATE_INIT        1
>
>
> >   enum forced_boot_mode {
> >       BOOT_NORMAL = 0x00,
> > diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> > index e68bf09955..dff41ed6f6 100644
> > --- a/board/st/stm32mp1/stm32mp1.c
> > +++ b/board/st/stm32mp1/stm32mp1.c
> > @@ -1081,4 +1081,11 @@ int fwu_plat_get_update_index(u32 *update_idx)
> >       return ret;
> >   }
> >
> > +void fwu_plat_get_bootidx(void *boot_idx)
> > +{
> > +     u32 *bootidx = boot_idx;
> > +
> > +     *bootidx = (readl(TAMP_FWU_BOOT_INFO_REG) >>
> > +                 TAMP_FWU_BOOT_IDX_OFFSET) & TAMP_FWU_BOOT_IDX_MASK;
> > +}
> >   #endif /* CONFIG_FWU_MULTI_BANK_UPDATE */
> > diff --git a/include/fwu.h b/include/fwu.h
> > index 36e58afa29..41774ff9e2 100644
> > --- a/include/fwu.h
> > +++ b/include/fwu.h
> > @@ -46,7 +46,7 @@ int fwu_revert_boot_index(void);
> >   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);
> >
> > -
> > +void fwu_plat_get_bootidx(void *boot_idx);
> >   int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
> >                        int *alt_num);
> >   int fwu_plat_get_update_index(u32 *update_idx);
>
> With the modifications:
>
> Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
>
> Thanks
> Patrick
>
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification
  2022-06-21 10:56   ` Etienne Carriere
@ 2022-06-23  9:45     ` Sughosh Ganu
  2022-06-23 12:32       ` Etienne Carriere
  0 siblings, 1 reply; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-23  9:45 UTC (permalink / raw)
  To: Etienne Carriere
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

hi Etienne,

On Tue, 21 Jun 2022 at 16:26, Etienne Carriere
<etienne.carriere@linaro.org> wrote:
>
> Hi Sughosh,
>
> On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
> >
> > The FWU Multi Bank Update specification requires the Update Agent to
> > carry out certain checks at the time of platform boot. The Update
> > Agent is the component which is responsible for updating the firmware
> > components and maintaining and keeping the metadata in sync.
> >
> > The spec requires that the Update Agent perform the following checks
> > at the time of boot
> > * Sanity check of both the metadata copies maintained by the platform.
> > * Get the boot index passed to U-Boot by the prior stage bootloader
> >   and use this value for metadata bookkeeping.
> > * Check if the system is booting in Trial State. If the system boots
> >   in the Trial State for more than a specified number of boot counts,
> >   change the Active Bank to be booting the platform from.
> >
> > Add these checks in the board initialisation sequence, invoked after
> > relocation.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  common/board_r.c      |   5 ++
> >  include/fwu.h         |   3 +
> >  lib/fwu_updates/fwu.c | 170 ++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 178 insertions(+)
> >  create mode 100644 lib/fwu_updates/fwu.c

<snip>

> > --- /dev/null
> > +++ b/lib/fwu_updates/fwu.c
> > @@ -0,0 +1,170 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#include <dm.h>
> > +#include <efi.h>
> > +#include <efi_loader.h>
> > +#include <efi_variable.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +#include <malloc.h>
> > +
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +
> > +static u8 trial_state;
> > +static u8 boottime_check;
> > +
> > +static int fwu_trial_state_check(void)
> > +{
> > +       int ret, i;
> > +       efi_status_t status;
> > +       efi_uintn_t var_size;
> > +       u16 trial_state_ctr;
> > +       u32 nimages, active_bank, var_attributes, active_idx;
> > +       struct fwu_mdata *mdata = NULL;
> > +       struct fwu_image_entry *img_entry;
> > +       struct fwu_image_bank_info *img_bank_info;
> > +
> > +       ret = fwu_get_mdata(&mdata);
> > +       if (ret)
> > +               return ret;
> > +
> > +       ret = 0;
> > +       nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> > +       active_bank = mdata->active_index;
> > +       img_entry = &mdata->img_entry[0];
> > +       for (i = 0; i < nimages; i++) {
> > +               img_bank_info = &img_entry[i].img_bank_info[active_bank];
> > +               if (!img_bank_info->accepted) {
> > +                       trial_state = 1;
> > +                       break;
> > +               }
> > +       }
> > +
> > +       if (trial_state) {
> > +               var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> > +               log_info("System booting in Trial State\n");
> > +               var_attributes = EFI_VARIABLE_NON_VOLATILE |
> > +                       EFI_VARIABLE_BOOTSERVICE_ACCESS;
> > +               status = efi_get_variable_int(L"TrialStateCtr",
> > +                                             &efi_global_variable_guid,
> > +                                             &var_attributes,
> > +                                             &var_size, &trial_state_ctr,
> > +                                             NULL);
> > +               if (status != EFI_SUCCESS) {
> > +                       log_err("Unable to read TrialStateCtr variable\n");
> > +                       ret = -1;
> > +                       goto out;
> > +               }
> > +
> > +               ++trial_state_ctr;
> > +               if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
> > +                       log_info("Trial State count exceeded. Revert back to previous_active_index\n");
> > +                       active_idx = mdata->active_index;
> > +                       ret = fwu_revert_boot_index();
> > +                       if (ret) {
> > +                               log_err("Unable to revert active_index\n");
> > +                               goto out;
> > +                       }
> > +
> > +                       trial_state_ctr = 0;
> > +                       status = efi_set_variable_int(L"TrialStateCtr",
> > +                                                     &efi_global_variable_guid,
> > +                                                     var_attributes,
> > +                                                     0,
>
> s/0/var_size/ ?
> Ditto 24 lines below.

The variable size is 0 since the variable is being deleted here and
the other instance that you mention. Maybe I can put a comment in the
two places.

>
> > +                                                     &trial_state_ctr, false);
> > +                       if (status != EFI_SUCCESS) {
> > +                               log_err("Unable to clear TrialStateCtr variable\n");
> > +                               ret = -1;
> > +                               goto out;
> > +                       }
> > +               } else {
> > +                       status = efi_set_variable_int(L"TrialStateCtr",
> > +                                                     &efi_global_variable_guid,
> > +                                                     var_attributes,
> > +                                                     var_size,
> > +                                                     &trial_state_ctr, false);
> > +                       if (status != EFI_SUCCESS) {
> > +                               log_err("Unable to increment TrialStateCtr variable\n");
> > +                               ret = -1;
> > +                               goto out;
> > +                       }
> > +               }
> > +       } else {
> > +               trial_state_ctr = 0;
> > +               status = efi_set_variable_int(L"TrialStateCtr",
> > +                                             &efi_global_variable_guid,
> > +                                             0,
> > +                                             0, &trial_state_ctr,
> > +                                             NULL);
>
> check status value.

Okay, I can put a log mentioning the error. There is not much use of
the status apart from this.

-sughosh

>
>
> > +       }
> > +
> > +out:
> > +       free(mdata);
> > +       return ret;
> > +}
> > +
> > +u8 fwu_update_checks_pass(void)
> > +{
> > +       return !trial_state && boottime_check;
> > +}
> > +
> > +int fwu_boottime_checks(void)
> > +{
> > +       int ret;
> > +       struct udevice *dev;
> > +       u32 boot_idx, active_idx;
> > +
> > +       if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> > +               log_err("FWU Metadata device not found\n");
> > +               return 0;
> > +       }
> > +
> > +       ret = fwu_mdata_check();
> > +       if (ret) {
> > +               return 0;
> > +       }
> > +
> > +       /*
> > +        * Get the Boot Index, i.e. the bank from
> > +        * which the platform has booted. This value
> > +        * gets passed from the ealier stage bootloader
> > +        * which booted u-boot, e.g. tf-a. If the
> > +        * boot index is not the same as the
> > +        * active_index read from the FWU metadata,
> > +        * update the active_index.
> > +        */
> > +       fwu_plat_get_bootidx(&boot_idx);
> > +       if (boot_idx >= CONFIG_FWU_NUM_BANKS) {
> > +               log_err("Received incorrect value of boot_index\n");
> > +               return 0;
> > +       }
> > +
> > +       ret = fwu_get_active_index(&active_idx);
> > +       if (ret) {
> > +               log_err("Unable to read active_index\n");
> > +               return 0;
> > +       }
> > +
> > +       if (boot_idx != active_idx) {
> > +               log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
> > +                        boot_idx, active_idx);
> > +               ret = fwu_update_active_index(boot_idx);
> > +               if (!ret)
> > +                       boottime_check = 1;
> > +
> > +               return 0;
> > +       }
> > +
> > +       if (efi_init_obj_list() != EFI_SUCCESS)
> > +               return 0;
> > +
> > +       ret = fwu_trial_state_check();
> > +       if (!ret)
> > +               boottime_check = 1;
> > +
> > +       return 0;
> > +}
> > --
> > 2.25.1
> >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification
  2022-06-21 11:46   ` Patrick DELAUNAY
@ 2022-06-23  9:49     ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-23  9:49 UTC (permalink / raw)
  To: Patrick DELAUNAY
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

hi Patrick,

On Tue, 21 Jun 2022 at 17:16, Patrick DELAUNAY
<patrick.delaunay@foss.st.com> wrote:
>
> Hi,
>
>
> On 6/9/22 14:29, Sughosh Ganu wrote:
> > The FWU Multi Bank Update specification requires the Update Agent to
> > carry out certain checks at the time of platform boot. The Update
> > Agent is the component which is responsible for updating the firmware
> > components and maintaining and keeping the metadata in sync.
> >
> > The spec requires that the Update Agent perform the following checks
> > at the time of boot
> > * Sanity check of both the metadata copies maintained by the platform.
> > * Get the boot index passed to U-Boot by the prior stage bootloader
> >    and use this value for metadata bookkeeping.
> > * Check if the system is booting in Trial State. If the system boots
> >    in the Trial State for more than a specified number of boot counts,
> >    change the Active Bank to be booting the platform from.
> >
> > Add these checks in the board initialisation sequence, invoked after
> > relocation.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >   common/board_r.c      |   5 ++
> >   include/fwu.h         |   3 +
> >   lib/fwu_updates/fwu.c | 170 ++++++++++++++++++++++++++++++++++++++++++
> >   3 files changed, 178 insertions(+)
> >   create mode 100644 lib/fwu_updates/fwu.c
> >
> > diff --git a/common/board_r.c b/common/board_r.c
> > index 6f4aca2077..33a600715d 100644
> > --- a/common/board_r.c
> > +++ b/common/board_r.c
> > @@ -15,6 +15,7 @@
> >   #include <cpu_func.h>
> >   #include <exports.h>
> >   #include <flash.h>
> > +#include <fwu.h>
> >   #include <hang.h>
> >   #include <image.h>
> >   #include <irq_func.h>
> > @@ -797,6 +798,10 @@ static init_fnc_t init_sequence_r[] = {
> >   #if defined(CONFIG_PRAM)
> >       initr_mem,
> >   #endif
> > +
> > +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
> > +     fwu_boottime_checks,
> > +#endif
> >       run_main_loop,
> >   };
> >
> > diff --git a/include/fwu.h b/include/fwu.h
> > index 41774ff9e2..8fbd91b463 100644
> > --- a/include/fwu.h
> > +++ b/include/fwu.h
> > @@ -33,6 +33,9 @@ struct fwu_mdata_ops {
> >       EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
> >                0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
> >
> > +int fwu_boottime_checks(void);
> > +u8 fwu_update_checks_pass(void);
> > +
> >   int fwu_get_mdata(struct fwu_mdata **mdata);
> >   int fwu_update_mdata(struct fwu_mdata *mdata);
> >   int fwu_get_active_index(u32 *active_idx);
> > diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> > new file mode 100644
> > index 0000000000..af884439fb
> > --- /dev/null
> > +++ b/lib/fwu_updates/fwu.c
> > @@ -0,0 +1,170 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#include <dm.h>
> > +#include <efi.h>
> > +#include <efi_loader.h>
> > +#include <efi_variable.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +#include <malloc.h>
> > +
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +
> > +static u8 trial_state;
> > +static u8 boottime_check;
> > +
> > +static int fwu_trial_state_check(void)
> > +{
> > +     int ret, i;
> > +     efi_status_t status;
> > +     efi_uintn_t var_size;
> > +     u16 trial_state_ctr;
> > +     u32 nimages, active_bank, var_attributes, active_idx;
> > +     struct fwu_mdata *mdata = NULL;
> > +     struct fwu_image_entry *img_entry;
> > +     struct fwu_image_bank_info *img_bank_info;
> > +
> > +     ret = fwu_get_mdata(&mdata);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = 0;
> > +     nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> > +     active_bank = mdata->active_index;
> > +     img_entry = &mdata->img_entry[0];
> > +     for (i = 0; i < nimages; i++) {
> > +             img_bank_info = &img_entry[i].img_bank_info[active_bank];
> > +             if (!img_bank_info->accepted) {
> > +                     trial_state = 1;
> > +                     break;
> > +             }
> > +     }
> > +
> > +     if (trial_state) {
> > +             var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> > +             log_info("System booting in Trial State\n");
> > +             var_attributes = EFI_VARIABLE_NON_VOLATILE |
> > +                     EFI_VARIABLE_BOOTSERVICE_ACCESS;
> > +             status = efi_get_variable_int(L"TrialStateCtr",
> > +                                           &efi_global_variable_guid,
> > +                                           &var_attributes,
> > +                                           &var_size, &trial_state_ctr,
> > +                                           NULL);
>
> for 'L"TrialStateCtr"' => wide characters for unicode
>
> L string is really needed here ?
>
> cf=
> http://patchwork.ozlabs.org/project/uboot/patch/20220123195514.3152022-5-sjg@chromium.org/
>
> same for all the other string L"TrialStateCtr" in the file...

Will change.

>
>
> > +             if (status != EFI_SUCCESS) {
> > +                     log_err("Unable to read TrialStateCtr variable\n");
> > +                     ret = -1;
> > +                     goto out;
> > +             }
> > +
> > +             ++trial_state_ctr;
> > +             if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
> > +                     log_info("Trial State count exceeded. Revert back to previous_active_index\n");
> > +                     active_idx = mdata->active_index;
> > +                     ret = fwu_revert_boot_index();
> > +                     if (ret) {
> > +                             log_err("Unable to revert active_index\n");
> > +                             goto out;
> > +                     }
> > +
> > +                     trial_state_ctr = 0;
> > +                     status = efi_set_variable_int(L"TrialStateCtr",
> > +                                                   &efi_global_variable_guid,
> > +                                                   var_attributes,
> > +                                                   0,
> > +                                                   &trial_state_ctr, false);
> > +                     if (status != EFI_SUCCESS) {
> > +                             log_err("Unable to clear TrialStateCtr variable\n");
> > +                             ret = -1;
> > +                             goto out;
> > +                     }
> > +             } else {
> > +                     status = efi_set_variable_int(L"TrialStateCtr",
> > +                                                   &efi_global_variable_guid,
> > +                                                   var_attributes,
> > +                                                   var_size,
> > +                                                   &trial_state_ctr, false);
> > +                     if (status != EFI_SUCCESS) {
> > +                             log_err("Unable to increment TrialStateCtr variable\n");
> > +                             ret = -1;
> > +                             goto out;
> > +                     }
> > +             }
> > +     } else {
> > +             trial_state_ctr = 0;
> > +             status = efi_set_variable_int(L"TrialStateCtr",
> > +                                           &efi_global_variable_guid,
> > +                                           0,
> > +                                           0, &trial_state_ctr,
> > +                                           NULL);
> > +     }
> > +
> > +out:
> > +     free(mdata);
> > +     return ret;
> > +}
> > +
> > +u8 fwu_update_checks_pass(void)
> > +{
> > +     return !trial_state && boottime_check;
> > +}
> > +
> > +int fwu_boottime_checks(void)
> > +{
> > +     int ret;
> > +     struct udevice *dev;
> > +     u32 boot_idx, active_idx;
> > +
> > +     if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> > +             log_err("FWU Metadata device not found\n");
> > +             return 0;
> > +     }
> > +
>
> This call of "uclass_get_device(UCLASS_FWU_MDATA, 0, &dev)"
>
> is not needed => it is already done in
>
> fwu_mdata_check() => fwu_get_dev_ops()

Yes, will remove this call. Thanks.

-sughosh

>
>
> > +     ret = fwu_mdata_check();
> > +     if (ret) {
> > +             return 0;
> > +     }
> > +
> > +     /*
> > +      * Get the Boot Index, i.e. the bank from
> > +      * which the platform has booted. This value
> > +      * gets passed from the ealier stage bootloader
> > +      * which booted u-boot, e.g. tf-a. If the
> > +      * boot index is not the same as the
> > +      * active_index read from the FWU metadata,
> > +      * update the active_index.
> > +      */
> > +     fwu_plat_get_bootidx(&boot_idx);
> > +     if (boot_idx >= CONFIG_FWU_NUM_BANKS) {
> > +             log_err("Received incorrect value of boot_index\n");
> > +             return 0;
> > +     }
> > +
> > +     ret = fwu_get_active_index(&active_idx);
> > +     if (ret) {
> > +             log_err("Unable to read active_index\n");
> > +             return 0;
> > +     }
> > +
> > +     if (boot_idx != active_idx) {
> > +             log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
> > +                      boot_idx, active_idx);
> > +             ret = fwu_update_active_index(boot_idx);
> > +             if (!ret)
> > +                     boottime_check = 1;
> > +
> > +             return 0;
> > +     }
> > +
> > +     if (efi_init_obj_list() != EFI_SUCCESS)
> > +             return 0;
> > +
> > +     ret = fwu_trial_state_check();
> > +     if (!ret)
> > +             boottime_check = 1;
> > +
> > +     return 0;
> > +}
>
>
> Regards
>
> Patrick
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 02/23] FWU: Add FWU metadata structure and driver for accessing metadata
  2022-06-23  6:24     ` Sughosh Ganu
@ 2022-06-23 11:55       ` Etienne Carriere
  0 siblings, 0 replies; 104+ messages in thread
From: Etienne Carriere @ 2022-06-23 11:55 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

Hi Sughosh,

On Thu, 23 Jun 2022 at 08:24, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> hi Etienne,
>
> On Tue, 21 Jun 2022 at 16:24, Etienne Carriere
> <etienne.carriere@linaro.org> wrote:
> >
> > Hello Sughosh,
> >
> >
> >
> > On Thu, 9 Jun 2022 at 14:30, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
> > >
> > > In the FWU Multi Bank Update feature, the information about the
> > > updatable images is stored as part of the metadata, which is stored on
> > > a dedicated partition. Add the metadata structure, and a driver model
> > > uclass which provides functions to access the metadata. These are
> > > generic API's, and implementations can be added based on parameters
> > > like how the metadata partition is accessed and what type of storage
> > > device houses the metadata.
> > >
> > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > ---
> > >  drivers/Kconfig                      |   2 +
> > >  drivers/Makefile                     |   1 +
> > >  drivers/fwu-mdata/Kconfig            |   7 +
> > >  drivers/fwu-mdata/Makefile           |   6 +
> > >  drivers/fwu-mdata/fwu-mdata-uclass.c | 459 +++++++++++++++++++++++++++
> > >  include/dm/uclass-id.h               |   1 +
> > >  include/fwu.h                        |  49 +++
> > >  include/fwu_mdata.h                  |  67 ++++
> > >  8 files changed, 592 insertions(+)
> > >  create mode 100644 drivers/fwu-mdata/Kconfig
> > >  create mode 100644 drivers/fwu-mdata/Makefile
> > >  create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
> > >  create mode 100644 include/fwu.h
> > >  create mode 100644 include/fwu_mdata.h
> > >
>
> <snip>
>
> > > diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c
> > > new file mode 100644
> > > index 0000000000..1530ceb01d
> > > --- /dev/null
> > > +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c

<snip>

> > > +/**
> > > + * fwu_get_mdata() - Get a FWU metadata copy
> > > + * @mdata: Copy of the FWU metadata
> > > + *
> > > + * Get a valid copy of the FWU metadata.
> > > + *
> > > + * Return: 0 if OK, -ve on error
> > > + *
> > > + */
> > > +int fwu_get_mdata(struct fwu_mdata **mdata)
> >
> > Is there a real need for this function to allocate an instance of struct mdata.
> > I think it would be clearer if it was the caller's responsibility to
> > allocate/free the structure.
> >
> > Or maybe rename this function fwu_alloc_and_copy_mdata() to highlight
> > that the function gives an allocated copy of the data.
>
> I guess I can put a comment in the function description saying that
> the function is responsible for the allocation of the metadata
> structure.

I think it would be better.

>
> > One should be careful when calling these API functions as some act on
> > a local copy (retrieved from fw_get_mdata()) while other functions
> > modify straight fwu-mdata in the storage media.
>
> Did you find any function which is modifying the metadata on the
> storage device directly. The API fwu_update_mdata() is supposed to be
> doing that. If you have come across any function which is directly
> modifying the metadata on the storage media, please let me know and I
> will fix it.

Many functions do so: fwu_clear_accept_image(),
fwu_clear_accept_image(), fwu_resert_boot_index(), etc... Actually all
generic functions do so while only fwu_get_mdata() and
fwu_update_mdata() act on a RAM copy.

Maybe fwu-mdata ops should have a status field for when a RAM copy was
exported and used to prevent direct updates to mdata in storage until
caller releases (fw_put_mdata()?) the exposed copy. Would this scheme
be overkilling...

Or maybe fwu_clear_accept_image() and other helper functions could
also require a mdata RAM reference to act on, letting the caller also
go through fwu_get_mdata()/fwu_update_mdata().

etienne

<snip>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification
  2022-06-23  9:45     ` Sughosh Ganu
@ 2022-06-23 12:32       ` Etienne Carriere
  2022-06-28 10:42         ` Sughosh Ganu
  0 siblings, 1 reply; 104+ messages in thread
From: Etienne Carriere @ 2022-06-23 12:32 UTC (permalink / raw)
  To: Sughosh Ganu
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

Hi Sughosh,

On Thu, 23 Jun 2022 at 11:46, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> hi Etienne,
>
> On Tue, 21 Jun 2022 at 16:26, Etienne Carriere
> <etienne.carriere@linaro.org> wrote:
> >
> > Hi Sughosh,
> >
> > On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
> > >
> > > The FWU Multi Bank Update specification requires the Update Agent to
> > > carry out certain checks at the time of platform boot. The Update
> > > Agent is the component which is responsible for updating the firmware
> > > components and maintaining and keeping the metadata in sync.
> > >
> > > The spec requires that the Update Agent perform the following checks
> > > at the time of boot
> > > * Sanity check of both the metadata copies maintained by the platform.
> > > * Get the boot index passed to U-Boot by the prior stage bootloader
> > >   and use this value for metadata bookkeeping.
> > > * Check if the system is booting in Trial State. If the system boots
> > >   in the Trial State for more than a specified number of boot counts,
> > >   change the Active Bank to be booting the platform from.
> > >
> > > Add these checks in the board initialisation sequence, invoked after
> > > relocation.
> > >
> > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > ---
> > >  common/board_r.c      |   5 ++
> > >  include/fwu.h         |   3 +
> > >  lib/fwu_updates/fwu.c | 170 ++++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 178 insertions(+)
> > >  create mode 100644 lib/fwu_updates/fwu.c
>
> <snip>
>
> > > --- /dev/null
> > > +++ b/lib/fwu_updates/fwu.c
> > > @@ -0,0 +1,170 @@
> > > +// SPDX-License-Identifier: GPL-2.0+
> > > +/*
> > > + * Copyright (c) 2022, Linaro Limited
> > > + */
> > > +
> > > +#include <dm.h>
> > > +#include <efi.h>
> > > +#include <efi_loader.h>
> > > +#include <efi_variable.h>
> > > +#include <fwu.h>
> > > +#include <fwu_mdata.h>
> > > +#include <malloc.h>
> > > +
> > > +#include <linux/errno.h>
> > > +#include <linux/types.h>
> > > +
> > > +static u8 trial_state;
> > > +static u8 boottime_check;
> > > +
> > > +static int fwu_trial_state_check(void)
> > > +{
> > > +       int ret, i;
> > > +       efi_status_t status;
> > > +       efi_uintn_t var_size;
> > > +       u16 trial_state_ctr;
> > > +       u32 nimages, active_bank, var_attributes, active_idx;
> > > +       struct fwu_mdata *mdata = NULL;
> > > +       struct fwu_image_entry *img_entry;
> > > +       struct fwu_image_bank_info *img_bank_info;
> > > +
> > > +       ret = fwu_get_mdata(&mdata);
> > > +       if (ret)
> > > +               return ret;
> > > +
> > > +       ret = 0;
> > > +       nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> > > +       active_bank = mdata->active_index;
> > > +       img_entry = &mdata->img_entry[0];
> > > +       for (i = 0; i < nimages; i++) {
> > > +               img_bank_info = &img_entry[i].img_bank_info[active_bank];
> > > +               if (!img_bank_info->accepted) {
> > > +                       trial_state = 1;
> > > +                       break;
> > > +               }
> > > +       }
> > > +
> > > +       if (trial_state) {
> > > +               var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> > > +               log_info("System booting in Trial State\n");
> > > +               var_attributes = EFI_VARIABLE_NON_VOLATILE |
> > > +                       EFI_VARIABLE_BOOTSERVICE_ACCESS;
> > > +               status = efi_get_variable_int(L"TrialStateCtr",
> > > +                                             &efi_global_variable_guid,
> > > +                                             &var_attributes,
> > > +                                             &var_size, &trial_state_ctr,
> > > +                                             NULL);
> > > +               if (status != EFI_SUCCESS) {
> > > +                       log_err("Unable to read TrialStateCtr variable\n");
> > > +                       ret = -1;
> > > +                       goto out;
> > > +               }
> > > +
> > > +               ++trial_state_ctr;
> > > +               if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
> > > +                       log_info("Trial State count exceeded. Revert back to previous_active_index\n");
> > > +                       active_idx = mdata->active_index;
> > > +                       ret = fwu_revert_boot_index();
> > > +                       if (ret) {
> > > +                               log_err("Unable to revert active_index\n");
> > > +                               goto out;
> > > +                       }
> > > +
> > > +                       trial_state_ctr = 0;
> > > +                       status = efi_set_variable_int(L"TrialStateCtr",
> > > +                                                     &efi_global_variable_guid,
> > > +                                                     var_attributes,
> > > +                                                     0,
> >
> > s/0/var_size/ ?
> > Ditto 24 lines below.
>
> The variable size is 0 since the variable is being deleted here and
> the other instance that you mention. Maybe I can put a comment in the
> two places.

The goal is to delete the variable or to reset it to 0?
If really deleting, this function should rather pass NULL instead of
&trial_state_ctr.

Regarding adding an inline comment, i guess you don't need to if
that's part of efi_set_variable_int() API.
By the way, it would help if this behaviour was described in the
function declaration, but that's another story.

>
> >
> > > +                                                     &trial_state_ctr, false);
> > > +                       if (status != EFI_SUCCESS) {
> > > +                               log_err("Unable to clear TrialStateCtr variable\n");
> > > +                               ret = -1;
> > > +                               goto out;
> > > +                       }
> > > +               } else {
> > > +                       status = efi_set_variable_int(L"TrialStateCtr",
> > > +                                                     &efi_global_variable_guid,
> > > +                                                     var_attributes,
> > > +                                                     var_size,
> > > +                                                     &trial_state_ctr, false);
> > > +                       if (status != EFI_SUCCESS) {
> > > +                               log_err("Unable to increment TrialStateCtr variable\n");
> > > +                               ret = -1;
> > > +                               goto out;
> > > +                       }
> > > +               }
> > > +       } else {
> > > +               trial_state_ctr = 0;
> > > +               status = efi_set_variable_int(L"TrialStateCtr",
> > > +                                             &efi_global_variable_guid,
> > > +                                             0,
> > > +                                             0, &trial_state_ctr,
> > > +                                             NULL);
> >
> > check status value.
>
> Okay, I can put a log mentioning the error. There is not much use of
> the status apart from this.

Failing to reset/delete TrialStateCtr is an error case and should be
reported when this function returns, no?

>
> -sughosh
>
> >
> >
> > > +       }
> > > +
> > > +out:
> > > +       free(mdata);
> > > +       return ret;
> > > +}
> > > +
> > > +u8 fwu_update_checks_pass(void)
> > > +{
> > > +       return !trial_state && boottime_check;
> > > +}
> > > +
> > > +int fwu_boottime_checks(void)
> > > +{
> > > +       int ret;
> > > +       struct udevice *dev;
> > > +       u32 boot_idx, active_idx;
> > > +
> > > +       if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> > > +               log_err("FWU Metadata device not found\n");
> > > +               return 0;
> > > +       }
> > > +
> > > +       ret = fwu_mdata_check();
> > > +       if (ret) {
> > > +               return 0;
> > > +       }
> > > +
> > > +       /*
> > > +        * Get the Boot Index, i.e. the bank from
> > > +        * which the platform has booted. This value
> > > +        * gets passed from the ealier stage bootloader
> > > +        * which booted u-boot, e.g. tf-a. If the
> > > +        * boot index is not the same as the
> > > +        * active_index read from the FWU metadata,
> > > +        * update the active_index.
> > > +        */
> > > +       fwu_plat_get_bootidx(&boot_idx);
> > > +       if (boot_idx >= CONFIG_FWU_NUM_BANKS) {
> > > +               log_err("Received incorrect value of boot_index\n");
> > > +               return 0;
> > > +       }
> > > +
> > > +       ret = fwu_get_active_index(&active_idx);
> > > +       if (ret) {
> > > +               log_err("Unable to read active_index\n");
> > > +               return 0;
> > > +       }
> > > +
> > > +       if (boot_idx != active_idx) {
> > > +               log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
> > > +                        boot_idx, active_idx);
> > > +               ret = fwu_update_active_index(boot_idx);
> > > +               if (!ret)
> > > +                       boottime_check = 1;
> > > +
> > > +               return 0;
> > > +       }
> > > +
> > > +       if (efi_init_obj_list() != EFI_SUCCESS)
> > > +               return 0;
> > > +
> > > +       ret = fwu_trial_state_check();
> > > +       if (!ret)
> > > +               boottime_check = 1;
> > > +
> > > +       return 0;
> > > +}
> > > --
> > > 2.25.1
> > >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices
  2022-06-21  9:34   ` Patrick DELAUNAY
  2022-06-22 12:39     ` Patrick DELAUNAY
@ 2022-06-28 10:01     ` Sughosh Ganu
  1 sibling, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-28 10:01 UTC (permalink / raw)
  To: Patrick DELAUNAY
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere, Michal Simek, Jassi Brar

hi Patrick,
Apologies for the late reply. I had missed out replying to the review
comments on this patch. There are some review comments on the
Synquacer patches which need to be taken care of by another engineer.
Once those review comments are taken care of, I will be sending the
next version.

On Tue, 21 Jun 2022 at 15:04, Patrick DELAUNAY
<patrick.delaunay@foss.st.com> wrote:
>
> Hi,
>
> On 6/9/22 14:29, Sughosh Ganu wrote:
> > In the FWU Multi Bank Update feature, the information about the
> > updatable images is stored as part of the metadata, on a separate
> > partition. Add a driver for reading from and writing to the metadata
> > when the updatable images and the metadata are stored on a block
> > device which is formated with GPT based partition scheme.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >   drivers/fwu-mdata/Kconfig             |   9 +
> >   drivers/fwu-mdata/Makefile            |   1 +
> >   drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 404 ++++++++++++++++++++++++++
> >   include/fwu.h                         |   2 +
> >   4 files changed, 416 insertions(+)
> >   create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> >

<snip>

> > diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
> > index 7fec7171f4..12a5b4fe04 100644
> > --- a/drivers/fwu-mdata/Makefile
> > +++ b/drivers/fwu-mdata/Makefile
> > @@ -4,3 +4,4 @@
> >   #
> >
> >   obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
> > +obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o
>
>
> It is strange to have '_' and '-' in file name for the same directory
>
> => to be coherent = fwu-mdata-gpt-blk.c

I see this kind of naming style in many other directories under
drivers/. The uclass file is named using the foo-uclass.c, while the
other driver files are named bar_driver.c

>
>
> > diff --git a/drivers/fwu-mdata/fwu_mdata_gpt_blk.c b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> > new file mode 100644
> > index 0000000000..329bd3779b
> > --- /dev/null
> > +++ b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> > @@ -0,0 +1,404 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#include <blk.h>
> > +#include <dm.h>
> > +#include <efi_loader.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +#include <log.h>
> > +#include <malloc.h>
> > +#include <memalign.h>
> > +#include <part.h>
> > +#include <part_efi.h>
> > +
> > +#include <dm/device-internal.h>
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +#include <u-boot/crc.h>
> > +
> > +#define PRIMARY_PART         BIT(0)
> > +#define SECONDARY_PART               BIT(1)
> > +#define BOTH_PARTS           (PRIMARY_PART | SECONDARY_PART)
> > +
> > +#define MDATA_READ           BIT(0)
> > +#define MDATA_WRITE          BIT(1)
> > +
> > +
>
>
> [...]
>
> > +
> > +int fwu_gpt_mdata_check(struct udevice *dev)
> > +{
> > +     /*
> > +      * Check if both the copies of the FWU metadata are
> > +      * valid. If one has gone bad, restore it from the
> > +      * other good copy.
> > +      */
> > +     return gpt_check_mdata_validity(dev);
> > +}
> > +
> > +int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata **mdata)
> > +{
> > +     struct blk_desc *desc;
> > +
> > +     desc = dev_get_uclass_plat(dev_get_priv(dev));
>
> as dev = fwu_mdata_gpt_blk(UCLASS_FWU_MDATA)
>
> dev_get_priv(dev) => get value saved in dev_set_priv(dev, mdata_dev);
>
> even if it is OK, it not clear here.
>
> can you add a struct to prepare addition of other elements in privdata:
>
> struct fwu_mdata_gpt_blk_priv {
>         struct udevice *blk_dev;
> }
>
>
> + struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
>
> + struct blk_desc *desc;
>
> + desc = dev_get_uclass_plat(priv->blk_dev);

Okay. Will add a priv structure as you suggest.

>
>
> > +     if (!desc) {
> > +             log_err("Block device not found\n");
> > +             return -ENODEV;
> > +     }
> > +
> > +     return gpt_get_mdata(desc, mdata);
> > +}
> > +
> > +int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev)
> > +{
> > +     u32 phandle;
> > +     int ret, size;
> > +     struct udevice *parent, *child;
> > +     const fdt32_t *phandle_p = NULL;
> > +
> > +     phandle_p = ofnode_get_property(dev_ofnode(dev), "fwu-mdata-store",
> > +                                     &size);
>
> phandle_p = dev_read_prop(dev, "fwu-mdata-store", &size);
>
>
> it is more simple

Okay

>
>
> > +     if (!phandle_p) {
> > +             log_err("fwu-mdata-store property not found\n");
> > +             return -ENOENT;
> > +     }
> > +
> > +     phandle = fdt32_to_cpu(*phandle_p);
>
>
> or phandle can be read directly by
>
> + ret =dev_read_phandle_with_args(dev, "fwu-mdata-store", NULL, 0, 0,
> phandle_p)

I did not understand this review comment properly. In any case, I am
using the API, dev_read_prop that you suggested above to read the
phandle pointer.

>
> +       if (ret) {
> +               log_err("fwu-mdata-store property not found\n");
> +               return ret;
> +       }
>
> > +
> > +     ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
> > +                                       &parent);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = -ENODEV;
> > +     for (device_find_first_child(parent, &child); child;
> > +          device_find_next_child(&child)) {
> > +             if (device_get_uclass_id(child) == UCLASS_BLK) {
> > +                     *mdata_dev = child;
> > +                     ret = 0;
> > +             }
> > +     }
> > +
> > +     return ret;
> > +}
> > +
> > +static int fwu_mdata_gpt_blk_probe(struct udevice *dev)
> > +{
> > +     int ret;
> > +     struct udevice *mdata_dev = NULL;
> > +
> > +     ret = fwu_get_mdata_device(dev, &mdata_dev);
> > +     if (ret)
> > +             return ret;
> > +
> > +     dev_set_priv(dev, mdata_dev);
>
> Avoid to use dev_set_priv() in driver :
>
> /**
>   * dev_set_priv() - Set the private data for a device
>   *
>   * This is normally handled by driver model, which automatically allocates
>   * private data when an 'auto' size if provided by the driver.
>   *
>   * Use this function to override normal operation for special
> situations, such
>   * as needing to allocate a variable amount of data.
>   *
>
> ...
>
> + struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
>
> + priv->blk_dev = mdata_dev;

Okay

>
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
> > +     .mdata_check = fwu_gpt_mdata_check,
> > +     .get_mdata = fwu_gpt_get_mdata,
> > +     .update_mdata = fwu_gpt_update_mdata,
> > +};
> > +
> > +static const struct udevice_id fwu_mdata_ids[] = {
> > +     { .compatible = "u-boot,fwu-mdata-gpt" },
> > +     { }
> > +};
> > +
> > +U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
> > +     .name           = "fwu-mdata-gpt-blk",
> > +     .id             = UCLASS_FWU_MDATA,
> > +     .of_match       = fwu_mdata_ids,
> > +     .ops            = &fwu_gpt_blk_ops,
> > +     .probe          = fwu_mdata_gpt_blk_probe,
>
>
> + .priv_auto    = sizeof(struct fwu_mdata_gpt_blk_priv),

Okay. I have incorporated these review comments. Thanks.

-sughosh

>
>
> > +};
> > diff --git a/include/fwu.h b/include/fwu.h
> > index f9e44e7b39..3b1ee4e83e 100644
> > --- a/include/fwu.h
> > +++ b/include/fwu.h
> > @@ -39,6 +39,8 @@ int fwu_get_active_index(u32 *active_idx);
> >   int fwu_update_active_index(u32 active_idx);
> >   int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
> >                         int *alt_num);
> > +int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev);
> > +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part);
> >   int fwu_mdata_check(void);
> >   int fwu_revert_boot_index(void);
> >   int fwu_accept_image(efi_guid_t *img_type_id, u32 bank);
>
>
> Regards
>
> Patrick
>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices
  2022-06-21 10:55   ` Etienne Carriere
@ 2022-06-28 10:11     ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-28 10:11 UTC (permalink / raw)
  To: Etienne Carriere
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

hi Etienne,

On Tue, 21 Jun 2022 at 16:26, Etienne Carriere
<etienne.carriere@linaro.org> wrote:
>
> Hello Sughosh,
>
> On Thu, 9 Jun 2022 at 14:30, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
> >
> > In the FWU Multi Bank Update feature, the information about the
> > updatable images is stored as part of the metadata, on a separate
> > partition. Add a driver for reading from and writing to the metadata
> > when the updatable images and the metadata are stored on a block
> > device which is formated with GPT based partition scheme.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >  drivers/fwu-mdata/Kconfig             |   9 +
> >  drivers/fwu-mdata/Makefile            |   1 +
> >  drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 404 ++++++++++++++++++++++++++
> >  include/fwu.h                         |   2 +
> >  4 files changed, 416 insertions(+)
> >  create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> >
> > diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
> > index d6a21c8e19..d5edef19d6 100644
> > --- a/drivers/fwu-mdata/Kconfig
> > +++ b/drivers/fwu-mdata/Kconfig
> > @@ -5,3 +5,12 @@ config DM_FWU_MDATA
> >           Enable support for accessing FWU Metadata partitions. The
> >           FWU Metadata partitions reside on the same storage device
> >           which contains the other FWU updatable firmware images.
> > +
> > +config FWU_MDATA_GPT_BLK
> > +       bool "FWU Metadata access for GPT partitioned Block devices"
> > +       select PARTITION_TYPE_GUID
> > +       select PARTITION_UUIDS
> > +       depends on DM && HAVE_BLOCK_DEVICE && EFI_PARTITION
> > +       help
> > +         Enable support for accessing FWU Metadata on GPT partitioned
> > +         block devices.
> > diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
> > index 7fec7171f4..12a5b4fe04 100644
> > --- a/drivers/fwu-mdata/Makefile
> > +++ b/drivers/fwu-mdata/Makefile
> > @@ -4,3 +4,4 @@
> >  #
> >
> >  obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o
> > +obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o
> > diff --git a/drivers/fwu-mdata/fwu_mdata_gpt_blk.c b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> > new file mode 100644
> > index 0000000000..329bd3779b
> > --- /dev/null
> > +++ b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c
> > @@ -0,0 +1,404 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#include <blk.h>
> > +#include <dm.h>
> > +#include <efi_loader.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +#include <log.h>
> > +#include <malloc.h>
> > +#include <memalign.h>
> > +#include <part.h>
> > +#include <part_efi.h>
> > +
> > +#include <dm/device-internal.h>
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +#include <u-boot/crc.h>
> > +
> > +#define PRIMARY_PART           BIT(0)
> > +#define SECONDARY_PART         BIT(1)
> > +#define BOTH_PARTS             (PRIMARY_PART | SECONDARY_PART)
> > +
> > +#define MDATA_READ             BIT(0)
> > +#define MDATA_WRITE            BIT(1)
> > +

<snip>

> > +
> > +static int gpt_get_mdata(struct blk_desc *desc, struct fwu_mdata **mdata)
> > +{
> > +       int ret;
> > +       u16 primary_mpart = 0, secondary_mpart = 0;
> > +
> > +       ret = gpt_get_mdata_partitions(desc, &primary_mpart,
> > +                                      &secondary_mpart);
> > +
> > +       if (ret < 0) {
> > +               log_err("Error getting the FWU metadata partitions\n");
> > +               return -ENODEV;
> > +       }
> > +
> > +       *mdata = malloc(sizeof(struct fwu_mdata));
> > +       if (!*mdata) {
> > +               log_err("Unable to allocate memory for reading FWU metadata\n");
> > +               return -ENOMEM;
> > +       }
> > +
> > +       ret = gpt_read_mdata(desc, *mdata, primary_mpart);
> > +       if (ret < 0) {
> > +               log_err("Failed to read the FWU metadata from the device\n");
> > +               return -EIO;
> > +       }
> > +
> > +       ret = fwu_verify_mdata(*mdata, 1);
> > +       if (!ret)
>
> Upon success, I think this function should also either ensure
> secondary_part contains a valid copy of primary part,
> Maybe this function should call gpt_check_mdata_validity() and then
> read mdata content.

Okay

>
> > +               return 0;
> > +
> > +       /*
> > +        * Verification of the primary FWU metadata copy failed.
> > +        * Try to read the replica.
> > +        */
> > +       memset(*mdata, 0, sizeof(struct fwu_mdata));
> > +       ret = gpt_read_mdata(desc, *mdata, secondary_mpart);
> > +       if (ret < 0) {
> > +               log_err("Failed to read the FWU metadata from the device\n");
> > +               return -EIO;
> > +       }
> > +
> > +       ret = fwu_verify_mdata(*mdata, 0);
> > +       if (!ret)
> > +               return 0;
> > +
> > +       /* Both the FWU metadata copies are corrupted. */
> > +       return -1;
> > +}
> > +
> > +static int gpt_check_mdata_validity(struct udevice *dev)
> > +{
> > +       int ret;
> > +       struct blk_desc *desc;
> > +       struct fwu_mdata pri_mdata;
> > +       struct fwu_mdata secondary_mdata;
> > +       u16 primary_mpart = 0, secondary_mpart = 0;
> > +       u16 valid_partitions, invalid_partitions;
> > +
> > +       desc = dev_get_uclass_plat(dev_get_priv(dev));
> > +       if (!desc) {
> > +               log_err("Block device not found\n");
> > +               return -ENODEV;
> > +       }
> > +
> > +       /*
> > +        * Two FWU metadata partitions are expected.
> > +        * If we don't have two, user needs to create
> > +        * them first
> > +        */
> > +       valid_partitions = 0;
> > +       ret = gpt_get_mdata_partitions(desc, &primary_mpart,
> > +                                      &secondary_mpart);
> > +
> > +       if (ret < 0) {
> > +               log_err("Error getting the FWU metadata partitions\n");
> > +               return -ENODEV;
> > +       }
> > +
> > +       ret = gpt_read_mdata(desc, &pri_mdata, primary_mpart);
> > +       if (ret < 0) {
> > +               log_err("Failed to read the FWU metadata from the device\n");
> > +               goto secondary_read;
> > +       }
> > +
> > +       ret = fwu_verify_mdata(&pri_mdata, 1);
> > +       if (!ret)
> > +               valid_partitions |= PRIMARY_PART;
> > +
> > +secondary_read:
> > +       /* Now check the secondary partition */
> > +       ret = gpt_read_mdata(desc, &secondary_mdata, secondary_mpart);
> > +       if (ret < 0) {
> > +               log_err("Failed to read the FWU metadata from the device\n");
> > +               goto mdata_restore;
> > +       }
> > +
> > +       ret = fwu_verify_mdata(&secondary_mdata, 0);
> > +       if (!ret)
> > +               valid_partitions |= SECONDARY_PART;
> > +
> > +mdata_restore:
> > +       if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) {
> > +               ret = -1;
> > +               /*
> > +                * Before returning, check that both the
> > +                * FWU metadata copies are the same. If not,
> > +                * the FWU metadata copies need to be
> > +                * re-populated.
> > +                */
> > +               if (!memcmp(&pri_mdata, &secondary_mdata,
> > +                           sizeof(struct fwu_mdata))) {
> > +                       ret = 0;
> > +               } else {
> > +                       log_err("Both FWU metadata copies are valid but do not match. Please check!\n");
>
> I think this function should select one of the part and copies to the
> other, e.g. assume primary is fine, copy primary to secondary and
> return upon success.

In this case, I think there is some kind of an unexpected scenario
which has resulted in both the metadata partitions being valid but not
being the same. Should this not be flagged as an error for the user to
handle? Moreover, which metadata partition do we assume to be the
correct one . We are just calling one partition as primary, and
another one secondary. But the spec does not give any more importance
to one over the other -- the spec just says that both the copies
should be the same.


>
> > +               }
> > +               goto out;
> > +       }
> > +
> > +       ret = -1;
> > +       if (!(valid_partitions & BOTH_PARTS))
> > +               goto out;
> > +
> > +       invalid_partitions = valid_partitions ^ BOTH_PARTS;
> > +       ret = gpt_write_mdata_partition(desc,
> > +                                       (invalid_partitions == PRIMARY_PART) ?
> > +                                       &secondary_mdata : &pri_mdata,
> > +                                       (invalid_partitions == PRIMARY_PART) ?
> > +                                       primary_mpart : secondary_mpart);
> > +
> > +       if (ret < 0)
> > +               log_err("Restoring %s FWU metadata partition failed\n",
> > +                       (invalid_partitions == PRIMARY_PART) ?
> > +                       "primary" : "secondary");
> > +
> > +out:
> > +       return ret;
> > +}
> > +
> > +int fwu_gpt_mdata_check(struct udevice *dev)
>
> Function should be static.

Will change all the relevant functions as per your comment.

>
> > +{
> > +       /*
> > +        * Check if both the copies of the FWU metadata are
> > +        * valid. If one has gone bad, restore it from the
> > +        * other good copy.
> > +        */
> > +       return gpt_check_mdata_validity(dev);
> > +}
> > +
> > +int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata **mdata)
>
> Function should be static.
>
> > +{
> > +       struct blk_desc *desc;
> > +
> > +       desc = dev_get_uclass_plat(dev_get_priv(dev));
> > +       if (!desc) {
> > +               log_err("Block device not found\n");
> > +               return -ENODEV;
> > +       }
> > +
> > +       return gpt_get_mdata(desc, mdata);
> > +}
> > +
> > +int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev)
>
> Function could be static (and declaration removed from fwu.h).

Okay

>
> > +{
> > +       u32 phandle;
> > +       int ret, size;
> > +       struct udevice *parent, *child;
> > +       const fdt32_t *phandle_p = NULL;
> > +
> > +       phandle_p = ofnode_get_property(dev_ofnode(dev), "fwu-mdata-store",
> > +                                       &size);
>
> Should this be retrieved from driver's ::of_to_plat method?

Patrick has suggested another API for getting the phandle. Thanks.

-sughosh


>
> Br,
> etienne
>
>
> > +       if (!phandle_p) {
> > +               log_err("fwu-mdata-store property not found\n");
> > +               return -ENOENT;
> > +       }
> > +
> > +       phandle = fdt32_to_cpu(*phandle_p);
> > +
> > +       ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
> > +                                         &parent);
> > +       if (ret)
> > +               return ret;
> > +
> > +       ret = -ENODEV;
> > +       for (device_find_first_child(parent, &child); child;
> > +            device_find_next_child(&child)) {
> > +               if (device_get_uclass_id(child) == UCLASS_BLK) {
> > +                       *mdata_dev = child;
> > +                       ret = 0;
> > +               }
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> > +static int fwu_mdata_gpt_blk_probe(struct udevice *dev)
> > +{
> > +       int ret;
> > +       struct udevice *mdata_dev = NULL;
> > +
> > +       ret = fwu_get_mdata_device(dev, &mdata_dev);
> > +       if (ret)
> > +               return ret;
> > +
> > +       dev_set_priv(dev, mdata_dev);
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
> > +       .mdata_check = fwu_gpt_mdata_check,
> > +       .get_mdata = fwu_gpt_get_mdata,
> > +       .update_mdata = fwu_gpt_update_mdata,
> > +};
> > +
> > +static const struct udevice_id fwu_mdata_ids[] = {
> > +       { .compatible = "u-boot,fwu-mdata-gpt" },
> > +       { }
> > +};
> > +
> > +U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
> > +       .name           = "fwu-mdata-gpt-blk",
> > +       .id             = UCLASS_FWU_MDATA,
> > +       .of_match       = fwu_mdata_ids,
> > +       .ops            = &fwu_gpt_blk_ops,
> > +       .probe          = fwu_mdata_gpt_blk_probe,
> > +};
> > diff --git a/include/fwu.h b/include/fwu.h
> > index f9e44e7b39..3b1ee4e83e 100644
> > --- a/include/fwu.h
> > +++ b/include/fwu.h
> > @@ -39,6 +39,8 @@ int fwu_get_active_index(u32 *active_idx);
> >  int fwu_update_active_index(u32 active_idx);
> >  int fwu_get_image_alt_num(efi_guid_t *image_type_id, u32 update_bank,
> >                           int *alt_num);
> > +int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev);
> > +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part);
> >  int fwu_mdata_check(void);
> >  int fwu_revert_boot_index(void);
> >  int fwu_accept_image(efi_guid_t *img_type_id, u32 bank);
> > --
> > 2.25.1
> >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification
  2022-06-23 12:32       ` Etienne Carriere
@ 2022-06-28 10:42         ` Sughosh Ganu
  0 siblings, 0 replies; 104+ messages in thread
From: Sughosh Ganu @ 2022-06-28 10:42 UTC (permalink / raw)
  To: Etienne Carriere
  Cc: u-boot, Heinrich Schuchardt, Ilias Apalodimas, Takahiro Akashi,
	Patrick Delaunay, Patrice Chotard, Simon Glass, Bin Meng,
	Tom Rini, Michal Simek, Jassi Brar

hi Etienne,

On Thu, 23 Jun 2022 at 18:02, Etienne Carriere
<etienne.carriere@linaro.org> wrote:
>
> Hi Sughosh,
>
> On Thu, 23 Jun 2022 at 11:46, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
> >
> > hi Etienne,
> >
> > On Tue, 21 Jun 2022 at 16:26, Etienne Carriere
> > <etienne.carriere@linaro.org> wrote:
> > >
> > > Hi Sughosh,
> > >
> > > On Thu, 9 Jun 2022 at 14:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
> > > >
> > > > The FWU Multi Bank Update specification requires the Update Agent to
> > > > carry out certain checks at the time of platform boot. The Update
> > > > Agent is the component which is responsible for updating the firmware
> > > > components and maintaining and keeping the metadata in sync.
> > > >
> > > > The spec requires that the Update Agent perform the following checks
> > > > at the time of boot
> > > > * Sanity check of both the metadata copies maintained by the platform.
> > > > * Get the boot index passed to U-Boot by the prior stage bootloader
> > > >   and use this value for metadata bookkeeping.
> > > > * Check if the system is booting in Trial State. If the system boots
> > > >   in the Trial State for more than a specified number of boot counts,
> > > >   change the Active Bank to be booting the platform from.
> > > >
> > > > Add these checks in the board initialisation sequence, invoked after
> > > > relocation.
> > > >
> > > > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > > > ---
> > > >  common/board_r.c      |   5 ++
> > > >  include/fwu.h         |   3 +
> > > >  lib/fwu_updates/fwu.c | 170 ++++++++++++++++++++++++++++++++++++++++++
> > > >  3 files changed, 178 insertions(+)
> > > >  create mode 100644 lib/fwu_updates/fwu.c
> >
> > <snip>
> >
> > > > --- /dev/null
> > > > +++ b/lib/fwu_updates/fwu.c
> > > > @@ -0,0 +1,170 @@
> > > > +// SPDX-License-Identifier: GPL-2.0+
> > > > +/*
> > > > + * Copyright (c) 2022, Linaro Limited
> > > > + */
> > > > +
> > > > +#include <dm.h>
> > > > +#include <efi.h>
> > > > +#include <efi_loader.h>
> > > > +#include <efi_variable.h>
> > > > +#include <fwu.h>
> > > > +#include <fwu_mdata.h>
> > > > +#include <malloc.h>
> > > > +
> > > > +#include <linux/errno.h>
> > > > +#include <linux/types.h>
> > > > +
> > > > +static u8 trial_state;
> > > > +static u8 boottime_check;
> > > > +
> > > > +static int fwu_trial_state_check(void)
> > > > +{
> > > > +       int ret, i;
> > > > +       efi_status_t status;
> > > > +       efi_uintn_t var_size;
> > > > +       u16 trial_state_ctr;
> > > > +       u32 nimages, active_bank, var_attributes, active_idx;
> > > > +       struct fwu_mdata *mdata = NULL;
> > > > +       struct fwu_image_entry *img_entry;
> > > > +       struct fwu_image_bank_info *img_bank_info;
> > > > +
> > > > +       ret = fwu_get_mdata(&mdata);
> > > > +       if (ret)
> > > > +               return ret;
> > > > +
> > > > +       ret = 0;
> > > > +       nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
> > > > +       active_bank = mdata->active_index;
> > > > +       img_entry = &mdata->img_entry[0];
> > > > +       for (i = 0; i < nimages; i++) {
> > > > +               img_bank_info = &img_entry[i].img_bank_info[active_bank];
> > > > +               if (!img_bank_info->accepted) {
> > > > +                       trial_state = 1;
> > > > +                       break;
> > > > +               }
> > > > +       }
> > > > +
> > > > +       if (trial_state) {
> > > > +               var_size = (efi_uintn_t)sizeof(trial_state_ctr);
> > > > +               log_info("System booting in Trial State\n");
> > > > +               var_attributes = EFI_VARIABLE_NON_VOLATILE |
> > > > +                       EFI_VARIABLE_BOOTSERVICE_ACCESS;
> > > > +               status = efi_get_variable_int(L"TrialStateCtr",
> > > > +                                             &efi_global_variable_guid,
> > > > +                                             &var_attributes,
> > > > +                                             &var_size, &trial_state_ctr,
> > > > +                                             NULL);
> > > > +               if (status != EFI_SUCCESS) {
> > > > +                       log_err("Unable to read TrialStateCtr variable\n");
> > > > +                       ret = -1;
> > > > +                       goto out;
> > > > +               }
> > > > +
> > > > +               ++trial_state_ctr;
> > > > +               if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
> > > > +                       log_info("Trial State count exceeded. Revert back to previous_active_index\n");
> > > > +                       active_idx = mdata->active_index;
> > > > +                       ret = fwu_revert_boot_index();
> > > > +                       if (ret) {
> > > > +                               log_err("Unable to revert active_index\n");
> > > > +                               goto out;
> > > > +                       }
> > > > +
> > > > +                       trial_state_ctr = 0;
> > > > +                       status = efi_set_variable_int(L"TrialStateCtr",
> > > > +                                                     &efi_global_variable_guid,
> > > > +                                                     var_attributes,
> > > > +                                                     0,
> > >
> > > s/0/var_size/ ?
> > > Ditto 24 lines below.
> >
> > The variable size is 0 since the variable is being deleted here and
> > the other instance that you mention. Maybe I can put a comment in the
> > two places.
>
> The goal is to delete the variable or to reset it to 0?

The goal is to delete the variable.

> If really deleting, this function should rather pass NULL instead of
> &trial_state_ctr.

The efi_set_variable_int checks the values of the attributes and
data_size parameters to decide if the variable is to be deleted. The
value of the variable data is not considered. But I can see that this
can be confusing to someone reading the code. I will pass this as NULL
instead.


>
> Regarding adding an inline comment, i guess you don't need to if
> that's part of efi_set_variable_int() API.
> By the way, it would help if this behaviour was described in the
> function declaration, but that's another story.
>
> >
> > >
> > > > +                                                     &trial_state_ctr, false);
> > > > +                       if (status != EFI_SUCCESS) {
> > > > +                               log_err("Unable to clear TrialStateCtr variable\n");
> > > > +                               ret = -1;
> > > > +                               goto out;
> > > > +                       }
> > > > +               } else {
> > > > +                       status = efi_set_variable_int(L"TrialStateCtr",
> > > > +                                                     &efi_global_variable_guid,
> > > > +                                                     var_attributes,
> > > > +                                                     var_size,
> > > > +                                                     &trial_state_ctr, false);
> > > > +                       if (status != EFI_SUCCESS) {
> > > > +                               log_err("Unable to increment TrialStateCtr variable\n");
> > > > +                               ret = -1;
> > > > +                               goto out;
> > > > +                       }
> > > > +               }
> > > > +       } else {
> > > > +               trial_state_ctr = 0;
> > > > +               status = efi_set_variable_int(L"TrialStateCtr",
> > > > +                                             &efi_global_variable_guid,
> > > > +                                             0,
> > > > +                                             0, &trial_state_ctr,
> > > > +                                             NULL);
> > >
> > > check status value.
> >
> > Okay, I can put a log mentioning the error. There is not much use of
> > the status apart from this.
>
> Failing to reset/delete TrialStateCtr is an error case and should be
> reported when this function returns, no?

I do see your point. I was thinking that the inability to delete the
variable for any reason should not result in the boottime_check
variable being set to 0, as in that case, an update initiated would
not proceed. This may or may not be an issue since the ESP and the
firmware images might be on different storage devices. Please let me
know what would be your preference. Thanks.

-sughosh


>
> >
> > -sughosh
> >
> > >
> > >
> > > > +       }
> > > > +
> > > > +out:
> > > > +       free(mdata);
> > > > +       return ret;
> > > > +}
> > > > +
> > > > +u8 fwu_update_checks_pass(void)
> > > > +{
> > > > +       return !trial_state && boottime_check;
> > > > +}
> > > > +
> > > > +int fwu_boottime_checks(void)
> > > > +{
> > > > +       int ret;
> > > > +       struct udevice *dev;
> > > > +       u32 boot_idx, active_idx;
> > > > +
> > > > +       if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
> > > > +               log_err("FWU Metadata device not found\n");
> > > > +               return 0;
> > > > +       }
> > > > +
> > > > +       ret = fwu_mdata_check();
> > > > +       if (ret) {
> > > > +               return 0;
> > > > +       }
> > > > +
> > > > +       /*
> > > > +        * Get the Boot Index, i.e. the bank from
> > > > +        * which the platform has booted. This value
> > > > +        * gets passed from the ealier stage bootloader
> > > > +        * which booted u-boot, e.g. tf-a. If the
> > > > +        * boot index is not the same as the
> > > > +        * active_index read from the FWU metadata,
> > > > +        * update the active_index.
> > > > +        */
> > > > +       fwu_plat_get_bootidx(&boot_idx);
> > > > +       if (boot_idx >= CONFIG_FWU_NUM_BANKS) {
> > > > +               log_err("Received incorrect value of boot_index\n");
> > > > +               return 0;
> > > > +       }
> > > > +
> > > > +       ret = fwu_get_active_index(&active_idx);
> > > > +       if (ret) {
> > > > +               log_err("Unable to read active_index\n");
> > > > +               return 0;
> > > > +       }
> > > > +
> > > > +       if (boot_idx != active_idx) {
> > > > +               log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
> > > > +                        boot_idx, active_idx);
> > > > +               ret = fwu_update_active_index(boot_idx);
> > > > +               if (!ret)
> > > > +                       boottime_check = 1;
> > > > +
> > > > +               return 0;
> > > > +       }
> > > > +
> > > > +       if (efi_init_obj_list() != EFI_SUCCESS)
> > > > +               return 0;
> > > > +
> > > > +       ret = fwu_trial_state_check();
> > > > +       if (!ret)
> > > > +               boottime_check = 1;
> > > > +
> > > > +       return 0;
> > > > +}
> > > > --
> > > > 2.25.1
> > > >

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-06-20  8:23   ` Michal Simek
@ 2022-07-18 14:43     ` Jassi Brar
  2022-07-18 14:46       ` Ilias Apalodimas
  0 siblings, 1 reply; 104+ messages in thread
From: Jassi Brar @ 2022-07-18 14:43 UTC (permalink / raw)
  To: Michal Simek
  Cc: Sughosh Ganu, u-boot, Heinrich Schuchardt, Ilias Apalodimas,
	Takahiro Akashi, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Masami Hiramatsu

On Mon, 20 Jun 2022 at 03:23, Michal Simek <monstr@monstr.eu> wrote:
> On 6/9/22 14:30, Sughosh Ganu wrote:
> > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> >
....

> > +}
> > +
> > +static int plat_sf_get_flash(struct spi_flash **flash)
> > +{
> > +     int ret = 0;
> > +
> > +     if (!plat_spi_flash)
> > +             ret = __plat_sf_get_flash();
> > +
> > +     *flash = plat_spi_flash;
> > +
> > +     return ret;
> > +}
> > +
> > +static int sf_load_data(u32 offs, u32 size, void **data)
> > +{
> > +     struct spi_flash *flash;
> > +     int ret;
> > +
> > +     ret = plat_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 = plat_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);
>
> What it is interesting here that framework itself is using mtd infrastructure
> but this platform driver is calling spi functions directly.
> It looks a little bit nonstandard way. What's the reason for it?
>
Yup, this whole sf shebang is unnecessary, and removed for next revision.

> > +
> > +#define PLAT_METADATA_OFFSET 0x510000
> > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > +
> > +struct __packed devbox_metadata {
> > +     u32 boot_index;
> > +     u32 boot_count;
>
> There is the whole bootcount infrastructure for this. I think it would be much
> better to use that framework instead of creating parallel one.
>
Yes, this goes too.

Thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 14:43     ` Jassi Brar
@ 2022-07-18 14:46       ` Ilias Apalodimas
  2022-07-18 15:08         ` Jassi Brar
  0 siblings, 1 reply; 104+ messages in thread
From: Ilias Apalodimas @ 2022-07-18 14:46 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Michal Simek, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Takahiro Akashi, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Masami Hiramatsu

Hi all,

On Mon, 18 Jul 2022 at 17:43, Jassi Brar <jaswinder.singh@linaro.org> wrote:
>
> On Mon, 20 Jun 2022 at 03:23, Michal Simek <monstr@monstr.eu> wrote:
> > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> > >
> ....
>
> > > +}
> > > +
> > > +static int plat_sf_get_flash(struct spi_flash **flash)
> > > +{
> > > +     int ret = 0;
> > > +
> > > +     if (!plat_spi_flash)
> > > +             ret = __plat_sf_get_flash();
> > > +
> > > +     *flash = plat_spi_flash;
> > > +
> > > +     return ret;
> > > +}
> > > +
> > > +static int sf_load_data(u32 offs, u32 size, void **data)
> > > +{
> > > +     struct spi_flash *flash;
> > > +     int ret;
> > > +
> > > +     ret = plat_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 = plat_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);
> >
> > What it is interesting here that framework itself is using mtd infrastructure
> > but this platform driver is calling spi functions directly.
> > It looks a little bit nonstandard way. What's the reason for it?
> >
> Yup, this whole sf shebang is unnecessary, and removed for next revision.
>
> > > +
> > > +#define PLAT_METADATA_OFFSET 0x510000
> > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > +
> > > +struct __packed devbox_metadata {
> > > +     u32 boot_index;
> > > +     u32 boot_count;
> >
> > There is the whole bootcount infrastructure for this. I think it would be much
> > better to use that framework instead of creating parallel one.
> >
> Yes, this goes too.

Is bootcount really suited for this case?
AFAIK bootcount either requires device specific registers (which won't
reset on reboots), or an environment you can write data to.
But what if a user wants to disable writing the env variables and the
device doesn't have a set of registers we can use?

Thanks
/Ilias
>
> Thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 20/23] FWU: synquacer: Generate dfu_alt_info from devicetree partition
  2022-06-17 14:02   ` Michal Simek
@ 2022-07-18 14:49     ` Jassi Brar
  2022-07-20  1:13       ` Takahiro Akashi
  0 siblings, 1 reply; 104+ messages in thread
From: Jassi Brar @ 2022-07-18 14:49 UTC (permalink / raw)
  To: Michal Simek
  Cc: Sughosh Ganu, u-boot, Heinrich Schuchardt, Ilias Apalodimas,
	Takahiro Akashi, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Masami Hiramatsu

On Fri, 17 Jun 2022 at 09:02, Michal Simek <michal.simek@amd.com> wrote:
> On 6/9/22 14:30, Sughosh Ganu wrote:
> > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
.....

> >
> > @@ -188,6 +178,9 @@ int board_late_init(void)
> >   {
> >       int ret;
> >
> > +     /* Make mmc available for EFI */
> > +     run_command("mmc dev 0", 0);
> > +
>
> What is this for?
>
> And I can't see any single note about in commit message.
>
For some reason, we get "No EFI system partition" during bootup and
the mmc does not show up in 'efidebug devices' unless we manually run
this (or mmc part) command.
    Though not elegant, I found similar being done by some other
platforms....  grep run_command -rw board/*
I am happy to learn the proper way of doing it.

Thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 14:46       ` Ilias Apalodimas
@ 2022-07-18 15:08         ` Jassi Brar
  2022-07-18 15:16           ` Ilias Apalodimas
  0 siblings, 1 reply; 104+ messages in thread
From: Jassi Brar @ 2022-07-18 15:08 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: Michal Simek, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Takahiro Akashi, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Masami Hiramatsu

On Mon, 18 Jul 2022 at 09:47, Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>
> Hi all,
>
> On Mon, 18 Jul 2022 at 17:43, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> >
> > On Mon, 20 Jun 2022 at 03:23, Michal Simek <monstr@monstr.eu> wrote:
> > > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> > > >
> > ....
> >
> > > > +}
> > > > +
> > > > +static int plat_sf_get_flash(struct spi_flash **flash)
> > > > +{
> > > > +     int ret = 0;
> > > > +
> > > > +     if (!plat_spi_flash)
> > > > +             ret = __plat_sf_get_flash();
> > > > +
> > > > +     *flash = plat_spi_flash;
> > > > +
> > > > +     return ret;
> > > > +}
> > > > +
> > > > +static int sf_load_data(u32 offs, u32 size, void **data)
> > > > +{
> > > > +     struct spi_flash *flash;
> > > > +     int ret;
> > > > +
> > > > +     ret = plat_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 = plat_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);
> > >
> > > What it is interesting here that framework itself is using mtd infrastructure
> > > but this platform driver is calling spi functions directly.
> > > It looks a little bit nonstandard way. What's the reason for it?
> > >
> > Yup, this whole sf shebang is unnecessary, and removed for next revision.
> >
> > > > +
> > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > +
> > > > +struct __packed devbox_metadata {
> > > > +     u32 boot_index;
> > > > +     u32 boot_count;
> > >
> > > There is the whole bootcount infrastructure for this. I think it would be much
> > > better to use that framework instead of creating parallel one.
> > >
> > Yes, this goes too.
>
> Is bootcount really suited for this case?
> AFAIK bootcount either requires device specific registers (which won't
> reset on reboots), or an environment you can write data to.
> But what if a user wants to disable writing the env variables and the
> device doesn't have a set of registers we can use?
>
Maybe it should be moved in 'struct fwu_mdata' ?

thnx

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 15:08         ` Jassi Brar
@ 2022-07-18 15:16           ` Ilias Apalodimas
  2022-07-18 15:31             ` Jassi Brar
  0 siblings, 1 reply; 104+ messages in thread
From: Ilias Apalodimas @ 2022-07-18 15:16 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Michal Simek, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Takahiro Akashi, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Masami Hiramatsu

Hi Jassi

On Mon, 18 Jul 2022 at 18:08, Jassi Brar <jaswinder.singh@linaro.org> wrote:
>
> On Mon, 18 Jul 2022 at 09:47, Ilias Apalodimas
> <ilias.apalodimas@linaro.org> wrote:
> >
> > Hi all,
> >
> > On Mon, 18 Jul 2022 at 17:43, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > >
> > > On Mon, 20 Jun 2022 at 03:23, Michal Simek <monstr@monstr.eu> wrote:
> > > > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> > > > >
> > > ....
> > >
> > > > > +}
> > > > > +
> > > > > +static int plat_sf_get_flash(struct spi_flash **flash)
> > > > > +{
> > > > > +     int ret = 0;
> > > > > +
> > > > > +     if (!plat_spi_flash)
> > > > > +             ret = __plat_sf_get_flash();
> > > > > +
> > > > > +     *flash = plat_spi_flash;
> > > > > +
> > > > > +     return ret;
> > > > > +}
> > > > > +
> > > > > +static int sf_load_data(u32 offs, u32 size, void **data)
> > > > > +{
> > > > > +     struct spi_flash *flash;
> > > > > +     int ret;
> > > > > +
> > > > > +     ret = plat_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 = plat_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);
> > > >
> > > > What it is interesting here that framework itself is using mtd infrastructure
> > > > but this platform driver is calling spi functions directly.
> > > > It looks a little bit nonstandard way. What's the reason for it?
> > > >
> > > Yup, this whole sf shebang is unnecessary, and removed for next revision.
> > >
> > > > > +
> > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > +
> > > > > +struct __packed devbox_metadata {
> > > > > +     u32 boot_index;
> > > > > +     u32 boot_count;
> > > >
> > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > better to use that framework instead of creating parallel one.
> > > >
> > > Yes, this goes too.
> >
> > Is bootcount really suited for this case?
> > AFAIK bootcount either requires device specific registers (which won't
> > reset on reboots), or an environment you can write data to.
> > But what if a user wants to disable writing the env variables and the
> > device doesn't have a set of registers we can use?
> >
> Maybe it should be moved in 'struct fwu_mdata' ?

I was mostly thinking on moving this count as another 'bootcount'
method.  So in case the user has disabled writing evn variables but he
is booting with EFI he can use that.

Regards
/Ilias
>
> thnx

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 15:16           ` Ilias Apalodimas
@ 2022-07-18 15:31             ` Jassi Brar
  2022-07-18 15:34               ` Ilias Apalodimas
                                 ` (2 more replies)
  0 siblings, 3 replies; 104+ messages in thread
From: Jassi Brar @ 2022-07-18 15:31 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: Michal Simek, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Takahiro Akashi, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Masami Hiramatsu

Hi Ilias,

On Mon, 18 Jul 2022 at 10:16, Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>
> Hi Jassi
>
> On Mon, 18 Jul 2022 at 18:08, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> >
> > On Mon, 18 Jul 2022 at 09:47, Ilias Apalodimas
> > <ilias.apalodimas@linaro.org> wrote:
> > >
> > > Hi all,
> > >
> > > On Mon, 18 Jul 2022 at 17:43, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > > >
> > > > On Mon, 20 Jun 2022 at 03:23, Michal Simek <monstr@monstr.eu> wrote:
> > > > > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > > > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> > > > > >
> > > > ....
> > > >
> > > > > > +}
> > > > > > +
> > > > > > +static int plat_sf_get_flash(struct spi_flash **flash)
> > > > > > +{
> > > > > > +     int ret = 0;
> > > > > > +
> > > > > > +     if (!plat_spi_flash)
> > > > > > +             ret = __plat_sf_get_flash();
> > > > > > +
> > > > > > +     *flash = plat_spi_flash;
> > > > > > +
> > > > > > +     return ret;
> > > > > > +}
> > > > > > +
> > > > > > +static int sf_load_data(u32 offs, u32 size, void **data)
> > > > > > +{
> > > > > > +     struct spi_flash *flash;
> > > > > > +     int ret;
> > > > > > +
> > > > > > +     ret = plat_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 = plat_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);
> > > > >
> > > > > What it is interesting here that framework itself is using mtd infrastructure
> > > > > but this platform driver is calling spi functions directly.
> > > > > It looks a little bit nonstandard way. What's the reason for it?
> > > > >
> > > > Yup, this whole sf shebang is unnecessary, and removed for next revision.
> > > >
> > > > > > +
> > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > +
> > > > > > +struct __packed devbox_metadata {
> > > > > > +     u32 boot_index;
> > > > > > +     u32 boot_count;
> > > > >
> > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > better to use that framework instead of creating parallel one.
> > > > >
> > > > Yes, this goes too.
> > >
> > > Is bootcount really suited for this case?
> > > AFAIK bootcount either requires device specific registers (which won't
> > > reset on reboots), or an environment you can write data to.
> > > But what if a user wants to disable writing the env variables and the
> > > device doesn't have a set of registers we can use?
> > >
> > Maybe it should be moved in 'struct fwu_mdata' ?
>
> I was mostly thinking on moving this count as another 'bootcount'
> method.  So in case the user has disabled writing evn variables but he
> is booting with EFI he can use that.
>
Sorry, not sure I understand.... IIUIC there has to be some persistent storage.

Of the three options - registers, efi-env and mdata, I think the last
one is more robust.
For ex, if BL33 isn't reached after an update. We want BL2 (which may
not have access to efi variables)
to be able to revert the active index.

thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 15:31             ` Jassi Brar
@ 2022-07-18 15:34               ` Ilias Apalodimas
  2022-07-18 15:34               ` Jassi Brar
  2022-07-18 21:00               ` Tom Rini
  2 siblings, 0 replies; 104+ messages in thread
From: Ilias Apalodimas @ 2022-07-18 15:34 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Michal Simek, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Takahiro Akashi, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Masami Hiramatsu

Hi Jassi,

On Mon, 18 Jul 2022 at 18:32, Jassi Brar <jaswinder.singh@linaro.org> wrote:
>
> Hi Ilias,
>
> On Mon, 18 Jul 2022 at 10:16, Ilias Apalodimas
> <ilias.apalodimas@linaro.org> wrote:
> >
> > Hi Jassi
> >
> > On Mon, 18 Jul 2022 at 18:08, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > >
> > > On Mon, 18 Jul 2022 at 09:47, Ilias Apalodimas
> > > <ilias.apalodimas@linaro.org> wrote:
> > > >
> > > > Hi all,
> > > >
> > > > On Mon, 18 Jul 2022 at 17:43, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > > > >
> > > > > On Mon, 20 Jun 2022 at 03:23, Michal Simek <monstr@monstr.eu> wrote:
> > > > > > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > > > > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> > > > > > >
> > > > > ....
> > > > >
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int plat_sf_get_flash(struct spi_flash **flash)
> > > > > > > +{
> > > > > > > +     int ret = 0;
> > > > > > > +
> > > > > > > +     if (!plat_spi_flash)
> > > > > > > +             ret = __plat_sf_get_flash();
> > > > > > > +
> > > > > > > +     *flash = plat_spi_flash;
> > > > > > > +
> > > > > > > +     return ret;
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int sf_load_data(u32 offs, u32 size, void **data)
> > > > > > > +{
> > > > > > > +     struct spi_flash *flash;
> > > > > > > +     int ret;
> > > > > > > +
> > > > > > > +     ret = plat_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 = plat_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);
> > > > > >
> > > > > > What it is interesting here that framework itself is using mtd infrastructure
> > > > > > but this platform driver is calling spi functions directly.
> > > > > > It looks a little bit nonstandard way. What's the reason for it?
> > > > > >
> > > > > Yup, this whole sf shebang is unnecessary, and removed for next revision.
> > > > >
> > > > > > > +
> > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > +
> > > > > > > +struct __packed devbox_metadata {
> > > > > > > +     u32 boot_index;
> > > > > > > +     u32 boot_count;
> > > > > >
> > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > better to use that framework instead of creating parallel one.
> > > > > >
> > > > > Yes, this goes too.
> > > >
> > > > Is bootcount really suited for this case?
> > > > AFAIK bootcount either requires device specific registers (which won't
> > > > reset on reboots), or an environment you can write data to.
> > > > But what if a user wants to disable writing the env variables and the
> > > > device doesn't have a set of registers we can use?
> > > >
> > > Maybe it should be moved in 'struct fwu_mdata' ?
> >
> > I was mostly thinking on moving this count as another 'bootcount'
> > method.  So in case the user has disabled writing evn variables but he
> > is booting with EFI he can use that.
> >
> Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
>
> Of the three options - registers, efi-env and mdata, I think the last
> one is more robust.
> For ex, if BL33 isn't reached after an update. We want BL2 (which may
> not have access to efi variables)
> to be able to revert the active index.

I think BL2 has it's own set of internal counters for the number of
reboots already (and I think on the stmp32mp1 is based on a cpu
scratch register)
This is supposed with BL33 reboots only.  Sughosh do I remember this wrong?

Regards
/Ilias
>
> thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 15:31             ` Jassi Brar
  2022-07-18 15:34               ` Ilias Apalodimas
@ 2022-07-18 15:34               ` Jassi Brar
  2022-07-18 15:37                 ` Ilias Apalodimas
  2022-07-18 21:00               ` Tom Rini
  2 siblings, 1 reply; 104+ messages in thread
From: Jassi Brar @ 2022-07-18 15:34 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: Michal Simek, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Takahiro Akashi, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Masami Hiramatsu

On Mon, 18 Jul 2022 at 10:31, Jassi Brar <jaswinder.singh@linaro.org> wrote:
>
> Hi Ilias,
>
> On Mon, 18 Jul 2022 at 10:16, Ilias Apalodimas
> <ilias.apalodimas@linaro.org> wrote:
> >
> > Hi Jassi
> >
> > On Mon, 18 Jul 2022 at 18:08, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > >
> > > On Mon, 18 Jul 2022 at 09:47, Ilias Apalodimas
> > > <ilias.apalodimas@linaro.org> wrote:
> > > >
> > > > Hi all,
> > > >
> > > > On Mon, 18 Jul 2022 at 17:43, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > > > >
> > > > > On Mon, 20 Jun 2022 at 03:23, Michal Simek <monstr@monstr.eu> wrote:
> > > > > > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > > > > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> > > > > > >
> > > > > ....
> > > > >
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int plat_sf_get_flash(struct spi_flash **flash)
> > > > > > > +{
> > > > > > > +     int ret = 0;
> > > > > > > +
> > > > > > > +     if (!plat_spi_flash)
> > > > > > > +             ret = __plat_sf_get_flash();
> > > > > > > +
> > > > > > > +     *flash = plat_spi_flash;
> > > > > > > +
> > > > > > > +     return ret;
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int sf_load_data(u32 offs, u32 size, void **data)
> > > > > > > +{
> > > > > > > +     struct spi_flash *flash;
> > > > > > > +     int ret;
> > > > > > > +
> > > > > > > +     ret = plat_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 = plat_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);
> > > > > >
> > > > > > What it is interesting here that framework itself is using mtd infrastructure
> > > > > > but this platform driver is calling spi functions directly.
> > > > > > It looks a little bit nonstandard way. What's the reason for it?
> > > > > >
> > > > > Yup, this whole sf shebang is unnecessary, and removed for next revision.
> > > > >
> > > > > > > +
> > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > +
> > > > > > > +struct __packed devbox_metadata {
> > > > > > > +     u32 boot_index;
> > > > > > > +     u32 boot_count;
> > > > > >
> > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > better to use that framework instead of creating parallel one.
> > > > > >
> > > > > Yes, this goes too.
> > > >
> > > > Is bootcount really suited for this case?
> > > > AFAIK bootcount either requires device specific registers (which won't
> > > > reset on reboots), or an environment you can write data to.
> > > > But what if a user wants to disable writing the env variables and the
> > > > device doesn't have a set of registers we can use?
> > > >
> > > Maybe it should be moved in 'struct fwu_mdata' ?
> >
> > I was mostly thinking on moving this count as another 'bootcount'
> > method.  So in case the user has disabled writing evn variables but he
> > is booting with EFI he can use that.
> >
> Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
>
> Of the three options - registers, efi-env and mdata, I think the last
> one is more robust.
> For ex, if BL33 isn't reached after an update. We want BL2 (which may
> not have access to efi variables)
> to be able to revert the active index.
>
 and which requires a bootcount for each stage. hmm...
probably I am overlooking something.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 15:34               ` Jassi Brar
@ 2022-07-18 15:37                 ` Ilias Apalodimas
  0 siblings, 0 replies; 104+ messages in thread
From: Ilias Apalodimas @ 2022-07-18 15:37 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Michal Simek, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Takahiro Akashi, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere, Masami Hiramatsu

Hi Jassi

On Mon, 18 Jul 2022 at 18:34, Jassi Brar <jaswinder.singh@linaro.org> wrote:
>
> On Mon, 18 Jul 2022 at 10:31, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> >
> > Hi Ilias,
> >
> > On Mon, 18 Jul 2022 at 10:16, Ilias Apalodimas
> > <ilias.apalodimas@linaro.org> wrote:
> > >
> > > Hi Jassi
> > >
> > > On Mon, 18 Jul 2022 at 18:08, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > > >
> > > > On Mon, 18 Jul 2022 at 09:47, Ilias Apalodimas
> > > > <ilias.apalodimas@linaro.org> wrote:
> > > > >
> > > > > Hi all,
> > > > >
> > > > > On Mon, 18 Jul 2022 at 17:43, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > > > > >
> > > > > > On Mon, 20 Jun 2022 at 03:23, Michal Simek <monstr@monstr.eu> wrote:
> > > > > > > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > > > > > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> > > > > > > >
> > > > > > ....
> > > > > >
> > > > > > > > +}
> > > > > > > > +
> > > > > > > > +static int plat_sf_get_flash(struct spi_flash **flash)
> > > > > > > > +{
> > > > > > > > +     int ret = 0;
> > > > > > > > +
> > > > > > > > +     if (!plat_spi_flash)
> > > > > > > > +             ret = __plat_sf_get_flash();
> > > > > > > > +
> > > > > > > > +     *flash = plat_spi_flash;
> > > > > > > > +
> > > > > > > > +     return ret;
> > > > > > > > +}
> > > > > > > > +
> > > > > > > > +static int sf_load_data(u32 offs, u32 size, void **data)
> > > > > > > > +{
> > > > > > > > +     struct spi_flash *flash;
> > > > > > > > +     int ret;
> > > > > > > > +
> > > > > > > > +     ret = plat_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 = plat_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);
> > > > > > >
> > > > > > > What it is interesting here that framework itself is using mtd infrastructure
> > > > > > > but this platform driver is calling spi functions directly.
> > > > > > > It looks a little bit nonstandard way. What's the reason for it?
> > > > > > >
> > > > > > Yup, this whole sf shebang is unnecessary, and removed for next revision.
> > > > > >
> > > > > > > > +
> > > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > > +
> > > > > > > > +struct __packed devbox_metadata {
> > > > > > > > +     u32 boot_index;
> > > > > > > > +     u32 boot_count;
> > > > > > >
> > > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > > better to use that framework instead of creating parallel one.
> > > > > > >
> > > > > > Yes, this goes too.
> > > > >
> > > > > Is bootcount really suited for this case?
> > > > > AFAIK bootcount either requires device specific registers (which won't
> > > > > reset on reboots), or an environment you can write data to.
> > > > > But what if a user wants to disable writing the env variables and the
> > > > > device doesn't have a set of registers we can use?
> > > > >
> > > > Maybe it should be moved in 'struct fwu_mdata' ?
> > >
> > > I was mostly thinking on moving this count as another 'bootcount'
> > > method.  So in case the user has disabled writing evn variables but he
> > > is booting with EFI he can use that.
> > >
> > Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
> >
> > Of the three options - registers, efi-env and mdata, I think the last
> > one is more robust.
> > For ex, if BL33 isn't reached after an update. We want BL2 (which may
> > not have access to efi variables)
> > to be able to revert the active index.
> >
>  and which requires a bootcount for each stage. hmm...
> probably I am overlooking something.

Well it's indeed more complicated, but the reasoning was something
along the lines of
- What if BL2 crashes really early, before it can access storage?
- BL2 doesn't have code to write that data only read it (in some
cases, depends on how the data is stored)

So the solution was to have individual counters

Cheers
/Ilias

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 15:31             ` Jassi Brar
  2022-07-18 15:34               ` Ilias Apalodimas
  2022-07-18 15:34               ` Jassi Brar
@ 2022-07-18 21:00               ` Tom Rini
  2022-07-19 15:23                 ` Jassi Brar
  2022-07-19 15:27                 ` Jassi Brar
  2 siblings, 2 replies; 104+ messages in thread
From: Tom Rini @ 2022-07-18 21:00 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Ilias Apalodimas, Michal Simek, Sughosh Ganu, u-boot,
	Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Etienne Carriere,
	Masami Hiramatsu

[-- Attachment #1: Type: text/plain, Size: 4316 bytes --]

On Mon, Jul 18, 2022 at 10:31:56AM -0500, Jassi Brar wrote:
> Hi Ilias,
> 
> On Mon, 18 Jul 2022 at 10:16, Ilias Apalodimas
> <ilias.apalodimas@linaro.org> wrote:
> >
> > Hi Jassi
> >
> > On Mon, 18 Jul 2022 at 18:08, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > >
> > > On Mon, 18 Jul 2022 at 09:47, Ilias Apalodimas
> > > <ilias.apalodimas@linaro.org> wrote:
> > > >
> > > > Hi all,
> > > >
> > > > On Mon, 18 Jul 2022 at 17:43, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > > > >
> > > > > On Mon, 20 Jun 2022 at 03:23, Michal Simek <monstr@monstr.eu> wrote:
> > > > > > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > > > > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> > > > > > >
> > > > > ....
> > > > >
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int plat_sf_get_flash(struct spi_flash **flash)
> > > > > > > +{
> > > > > > > +     int ret = 0;
> > > > > > > +
> > > > > > > +     if (!plat_spi_flash)
> > > > > > > +             ret = __plat_sf_get_flash();
> > > > > > > +
> > > > > > > +     *flash = plat_spi_flash;
> > > > > > > +
> > > > > > > +     return ret;
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int sf_load_data(u32 offs, u32 size, void **data)
> > > > > > > +{
> > > > > > > +     struct spi_flash *flash;
> > > > > > > +     int ret;
> > > > > > > +
> > > > > > > +     ret = plat_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 = plat_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);
> > > > > >
> > > > > > What it is interesting here that framework itself is using mtd infrastructure
> > > > > > but this platform driver is calling spi functions directly.
> > > > > > It looks a little bit nonstandard way. What's the reason for it?
> > > > > >
> > > > > Yup, this whole sf shebang is unnecessary, and removed for next revision.
> > > > >
> > > > > > > +
> > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > +
> > > > > > > +struct __packed devbox_metadata {
> > > > > > > +     u32 boot_index;
> > > > > > > +     u32 boot_count;
> > > > > >
> > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > better to use that framework instead of creating parallel one.
> > > > > >
> > > > > Yes, this goes too.
> > > >
> > > > Is bootcount really suited for this case?
> > > > AFAIK bootcount either requires device specific registers (which won't
> > > > reset on reboots), or an environment you can write data to.
> > > > But what if a user wants to disable writing the env variables and the
> > > > device doesn't have a set of registers we can use?
> > > >
> > > Maybe it should be moved in 'struct fwu_mdata' ?
> >
> > I was mostly thinking on moving this count as another 'bootcount'
> > method.  So in case the user has disabled writing evn variables but he
> > is booting with EFI he can use that.
>
> Sorry, not sure I understand.... IIUIC there has to be some persistent storage.

No, there just has to be "somewhere" to do the counting.  We've got a
DDR backed driver, for example.  So yes, I think we should try and use
the bootcount framework here.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 21:00               ` Tom Rini
@ 2022-07-19 15:23                 ` Jassi Brar
  2022-07-20  1:17                   ` Tom Rini
  2022-07-19 15:27                 ` Jassi Brar
  1 sibling, 1 reply; 104+ messages in thread
From: Jassi Brar @ 2022-07-19 15:23 UTC (permalink / raw)
  To: Tom Rini
  Cc: Jassi Brar, Ilias Apalodimas, Michal Simek, Sughosh Ganu, u-boot,
	Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Etienne Carriere,
	Masami Hiramatsu

On Mon, Jul 18, 2022 at 4:00 PM Tom Rini <trini@konsulko.com> wrote:
> On Mon, Jul 18, 2022 at 10:31:56AM -0500, Jassi Brar wrote:

> > > > > > > > +
> > > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > > +
> > > > > > > > +struct __packed devbox_metadata {
> > > > > > > > +     u32 boot_index;
> > > > > > > > +     u32 boot_count;
> > > > > > >
> > > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > > better to use that framework instead of creating parallel one.
> > > > > > >
> > > > > > Yes, this goes too.
> > > > >
> > > > > Is bootcount really suited for this case?
> > > > > AFAIK bootcount either requires device specific registers (which won't
> > > > > reset on reboots), or an environment you can write data to.
> > > > > But what if a user wants to disable writing the env variables and the
> > > > > device doesn't have a set of registers we can use?
> > > > >
> > > > Maybe it should be moved in 'struct fwu_mdata' ?
> > >
> > > I was mostly thinking on moving this count as another 'bootcount'
> > > method.  So in case the user has disabled writing evn variables but he
> > > is booting with EFI he can use that.
> >
> > Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
>
> No, there just has to be "somewhere" to do the counting.  We've got a
> DDR backed driver, for example.  So yes, I think we should try and use
> the bootcount framework here.
>
OK, for platforms that can preserve ram across reboot, using
non-persistent storage can work.
My platform neither preserves ram, nor has any warmreset-proof
registers. So I have to choose between saving the bootcount in efi-env
or in vendor specific structure next to the metadata. I prefer
metadata because it is common to all stages of boot. Any corrections
to this approach?

Thanks

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-18 21:00               ` Tom Rini
  2022-07-19 15:23                 ` Jassi Brar
@ 2022-07-19 15:27                 ` Jassi Brar
  2022-07-20  7:53                   ` Ilias Apalodimas
  1 sibling, 1 reply; 104+ messages in thread
From: Jassi Brar @ 2022-07-19 15:27 UTC (permalink / raw)
  To: Tom Rini
  Cc: Ilias Apalodimas, Michal Simek, Sughosh Ganu, u-boot,
	Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Etienne Carriere

On Mon, 18 Jul 2022 at 16:00, Tom Rini <trini@konsulko.com> wrote:
> On Mon, Jul 18, 2022 at 10:31:56AM -0500, Jassi Brar wrote:

> > > > > >
> > > > > > > > +
> > > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > > +
> > > > > > > > +struct __packed devbox_metadata {
> > > > > > > > +     u32 boot_index;
> > > > > > > > +     u32 boot_count;
> > > > > > >
> > > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > > better to use that framework instead of creating parallel one.
> > > > > > >
> > > > > > Yes, this goes too.
> > > > >
> > > > > Is bootcount really suited for this case?
> > > > > AFAIK bootcount either requires device specific registers (which won't
> > > > > reset on reboots), or an environment you can write data to.
> > > > > But what if a user wants to disable writing the env variables and the
> > > > > device doesn't have a set of registers we can use?
> > > > >
> > > > Maybe it should be moved in 'struct fwu_mdata' ?
> > >
> > > I was mostly thinking on moving this count as another 'bootcount'
> > > method.  So in case the user has disabled writing evn variables but he
> > > is booting with EFI he can use that.
> >
> > Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
>
> No, there just has to be "somewhere" to do the counting.  We've got a
> DDR backed driver, for example.  So yes, I think we should try and use
> the bootcount framework here.
>
OK, for platforms that can preserve ram across reboot, using
non-persistent storage can work.
My platform neither preserves ram, nor has any warmreset-proof
registers. So I have to choose between saving the bootcount in efi-env
or in vendor specific structure next to the metadata. I prefer
metadata because it is common to all stages of boot. Any corrections
to this approach?

Thanks

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 20/23] FWU: synquacer: Generate dfu_alt_info from devicetree partition
  2022-07-18 14:49     ` Jassi Brar
@ 2022-07-20  1:13       ` Takahiro Akashi
  2022-07-20  3:16         ` Jassi Brar
  0 siblings, 1 reply; 104+ messages in thread
From: Takahiro Akashi @ 2022-07-20  1:13 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Michal Simek, Sughosh Ganu, u-boot, Heinrich Schuchardt,
	Ilias Apalodimas, Patrick Delaunay, Patrice Chotard, Simon Glass,
	Bin Meng, Tom Rini, Etienne Carriere

On Mon, Jul 18, 2022 at 09:49:56AM -0500, Jassi Brar wrote:
> On Fri, 17 Jun 2022 at 09:02, Michal Simek <michal.simek@amd.com> wrote:
> > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> .....
> 
> > >
> > > @@ -188,6 +178,9 @@ int board_late_init(void)
> > >   {
> > >       int ret;
> > >
> > > +     /* Make mmc available for EFI */
> > > +     run_command("mmc dev 0", 0);
> > > +
> >
> > What is this for?
> >
> > And I can't see any single note about in commit message.
> >
> For some reason, we get "No EFI system partition" during bootup and
> the mmc does not show up in 'efidebug devices' unless we manually run
> this (or mmc part) command.

As far as UEFI is concerned, any U-Boot block device will be
recognized as a UEFI disk(block_io) object *only* after device_probe()
is called.

-Takahiro Akashi


>     Though not elegant, I found similar being done by some other
> platforms....  grep run_command -rw board/*
> I am happy to learn the proper way of doing it.
> 
> Thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-19 15:23                 ` Jassi Brar
@ 2022-07-20  1:17                   ` Tom Rini
  0 siblings, 0 replies; 104+ messages in thread
From: Tom Rini @ 2022-07-20  1:17 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Jassi Brar, Ilias Apalodimas, Michal Simek, Sughosh Ganu, u-boot,
	Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Etienne Carriere,
	Masami Hiramatsu

[-- Attachment #1: Type: text/plain, Size: 2454 bytes --]

On Tue, Jul 19, 2022 at 10:23:08AM -0500, Jassi Brar wrote:
> On Mon, Jul 18, 2022 at 4:00 PM Tom Rini <trini@konsulko.com> wrote:
> > On Mon, Jul 18, 2022 at 10:31:56AM -0500, Jassi Brar wrote:
> 
> > > > > > > > > +
> > > > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > > > +
> > > > > > > > > +struct __packed devbox_metadata {
> > > > > > > > > +     u32 boot_index;
> > > > > > > > > +     u32 boot_count;
> > > > > > > >
> > > > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > > > better to use that framework instead of creating parallel one.
> > > > > > > >
> > > > > > > Yes, this goes too.
> > > > > >
> > > > > > Is bootcount really suited for this case?
> > > > > > AFAIK bootcount either requires device specific registers (which won't
> > > > > > reset on reboots), or an environment you can write data to.
> > > > > > But what if a user wants to disable writing the env variables and the
> > > > > > device doesn't have a set of registers we can use?
> > > > > >
> > > > > Maybe it should be moved in 'struct fwu_mdata' ?
> > > >
> > > > I was mostly thinking on moving this count as another 'bootcount'
> > > > method.  So in case the user has disabled writing evn variables but he
> > > > is booting with EFI he can use that.
> > >
> > > Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
> >
> > No, there just has to be "somewhere" to do the counting.  We've got a
> > DDR backed driver, for example.  So yes, I think we should try and use
> > the bootcount framework here.
> >
> OK, for platforms that can preserve ram across reboot, using
> non-persistent storage can work.
> My platform neither preserves ram, nor has any warmreset-proof
> registers. So I have to choose between saving the bootcount in efi-env
> or in vendor specific structure next to the metadata. I prefer
> metadata because it is common to all stages of boot. Any corrections
> to this approach?

What I'm trying to say is that we have an abstraction for counting the
number of times the system has booted since something reset the counter
to zero, to signal the system is up and functional.  I'll leave the
details of how it's used here, and how / what backend is used or created
for it up to everyone else on the thread.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 20/23] FWU: synquacer: Generate dfu_alt_info from devicetree partition
  2022-07-20  1:13       ` Takahiro Akashi
@ 2022-07-20  3:16         ` Jassi Brar
  0 siblings, 0 replies; 104+ messages in thread
From: Jassi Brar @ 2022-07-20  3:16 UTC (permalink / raw)
  To: Takahiro Akashi, Jassi Brar, Michal Simek, Sughosh Ganu, u-boot,
	Heinrich Schuchardt, Ilias Apalodimas, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Tom Rini,
	Etienne Carriere

On Tue, 19 Jul 2022 at 20:13, Takahiro Akashi
<takahiro.akashi@linaro.org> wrote:
>
> On Mon, Jul 18, 2022 at 09:49:56AM -0500, Jassi Brar wrote:
> > On Fri, 17 Jun 2022 at 09:02, Michal Simek <michal.simek@amd.com> wrote:
> > > On 6/9/22 14:30, Sughosh Ganu wrote:
> > > > From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> > .....
> >
> > > >
> > > > @@ -188,6 +178,9 @@ int board_late_init(void)
> > > >   {
> > > >       int ret;
> > > >
> > > > +     /* Make mmc available for EFI */
> > > > +     run_command("mmc dev 0", 0);
> > > > +
> > >
> > > What is this for?
> > >
> > > And I can't see any single note about in commit message.
> > >
> > For some reason, we get "No EFI system partition" during bootup and
> > the mmc does not show up in 'efidebug devices' unless we manually run
> > this (or mmc part) command.
>
> As far as UEFI is concerned, any U-Boot block device will be
> recognized as a UEFI disk(block_io) object *only* after device_probe()
> is called.
>
OK, thanks for the clarification.  And I shouldn't feel too bad about
the hack then :)

thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-19 15:27                 ` Jassi Brar
@ 2022-07-20  7:53                   ` Ilias Apalodimas
  2022-07-20 14:30                     ` Jassi Brar
  0 siblings, 1 reply; 104+ messages in thread
From: Ilias Apalodimas @ 2022-07-20  7:53 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Tom Rini, Michal Simek, Sughosh Ganu, u-boot,
	Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Etienne Carriere

Hi Jassi,

On Tue, 19 Jul 2022 at 18:27, Jassi Brar <jaswinder.singh@linaro.org> wrote:
>
> On Mon, 18 Jul 2022 at 16:00, Tom Rini <trini@konsulko.com> wrote:
> > On Mon, Jul 18, 2022 at 10:31:56AM -0500, Jassi Brar wrote:
>
> > > > > > >
> > > > > > > > > +
> > > > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > > > +
> > > > > > > > > +struct __packed devbox_metadata {
> > > > > > > > > +     u32 boot_index;
> > > > > > > > > +     u32 boot_count;
> > > > > > > >
> > > > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > > > better to use that framework instead of creating parallel one.
> > > > > > > >
> > > > > > > Yes, this goes too.
> > > > > >
> > > > > > Is bootcount really suited for this case?
> > > > > > AFAIK bootcount either requires device specific registers (which won't
> > > > > > reset on reboots), or an environment you can write data to.
> > > > > > But what if a user wants to disable writing the env variables and the
> > > > > > device doesn't have a set of registers we can use?
> > > > > >
> > > > > Maybe it should be moved in 'struct fwu_mdata' ?
> > > >
> > > > I was mostly thinking on moving this count as another 'bootcount'
> > > > method.  So in case the user has disabled writing evn variables but he
> > > > is booting with EFI he can use that.
> > >
> > > Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
> >
> > No, there just has to be "somewhere" to do the counting.  We've got a
> > DDR backed driver, for example.  So yes, I think we should try and use
> > the bootcount framework here.
> >
> OK, for platforms that can preserve ram across reboot, using
> non-persistent storage can work.
> My platform neither preserves ram, nor has any warmreset-proof
> registers. So I have to choose between saving the bootcount in efi-env
> or in vendor specific structure next to the metadata. I prefer
> metadata because it is common to all stages of boot. Any corrections
> to this approach?

The metadata is defined by a spec and they don't have a field for
bootcounting.  Once Sughosh resends his patches he'll include a
bootcount backend that reuses EFI variables.  Can't we just use that?

>
> Thanks

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-20  7:53                   ` Ilias Apalodimas
@ 2022-07-20 14:30                     ` Jassi Brar
  2022-07-22  8:37                       ` Ilias Apalodimas
  0 siblings, 1 reply; 104+ messages in thread
From: Jassi Brar @ 2022-07-20 14:30 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: Jassi Brar, Tom Rini, Michal Simek, Sughosh Ganu, u-boot,
	Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Etienne Carriere

On Wed, Jul 20, 2022 at 2:54 AM Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>
> Hi Jassi,
>
> On Tue, 19 Jul 2022 at 18:27, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> >
> > On Mon, 18 Jul 2022 at 16:00, Tom Rini <trini@konsulko.com> wrote:
> > > On Mon, Jul 18, 2022 at 10:31:56AM -0500, Jassi Brar wrote:
> >
> > > > > > > >
> > > > > > > > > > +
> > > > > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > > > > +
> > > > > > > > > > +struct __packed devbox_metadata {
> > > > > > > > > > +     u32 boot_index;
> > > > > > > > > > +     u32 boot_count;
> > > > > > > > >
> > > > > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > > > > better to use that framework instead of creating parallel one.
> > > > > > > > >
> > > > > > > > Yes, this goes too.
> > > > > > >
> > > > > > > Is bootcount really suited for this case?
> > > > > > > AFAIK bootcount either requires device specific registers (which won't
> > > > > > > reset on reboots), or an environment you can write data to.
> > > > > > > But what if a user wants to disable writing the env variables and the
> > > > > > > device doesn't have a set of registers we can use?
> > > > > > >
> > > > > > Maybe it should be moved in 'struct fwu_mdata' ?
> > > > >
> > > > > I was mostly thinking on moving this count as another 'bootcount'
> > > > > method.  So in case the user has disabled writing evn variables but he
> > > > > is booting with EFI he can use that.
> > > >
> > > > Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
> > >
> > > No, there just has to be "somewhere" to do the counting.  We've got a
> > > DDR backed driver, for example.  So yes, I think we should try and use
> > > the bootcount framework here.
> > >
> > OK, for platforms that can preserve ram across reboot, using
> > non-persistent storage can work.
> > My platform neither preserves ram, nor has any warmreset-proof
> > registers. So I have to choose between saving the bootcount in efi-env
> > or in vendor specific structure next to the metadata. I prefer
> > metadata because it is common to all stages of boot. Any corrections
> > to this approach?
>
> The metadata is defined by a spec and they don't have a field for
> bootcounting.  Once Sughosh resends his patches he'll include a
> bootcount backend that reuses EFI variables.  Can't we just use that?
>
Yes, I am aware metadata spec has no provision of vendor data. But
there is nothing illegal in appending vendor-data to metadata and that
is trivial to implement ... basically use   sizeof(struct fwu_mdata) +
sizeof(struct sni_vendor_mdata)  while read/write meta-data. That will
also be zero extra-overhead.

fwu-mdata {
           compatible = "u-boot,fwu-mdata-mtd";
           fwu-mdata-store = <&spi_flash>;
           mdata-offsets = <0x500000 0x530000>;
           vendor-data-size = <0x100>;   // optional
};

Sure we can use an efi variable, but I see more uses of vendor-data
:- shared among BL1/BL2/BL3x/OS so we can emulate reset-syndrome,
crash-logging, per-image bootcount etc when the h/w doesn't support
these features.

Ofcourse, please feel free to implement efi-variables still.

thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-20 14:30                     ` Jassi Brar
@ 2022-07-22  8:37                       ` Ilias Apalodimas
  2022-07-22 17:01                         ` Jassi Brar
  0 siblings, 1 reply; 104+ messages in thread
From: Ilias Apalodimas @ 2022-07-22  8:37 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Jassi Brar, Tom Rini, Michal Simek, Sughosh Ganu, u-boot,
	Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Etienne Carriere

Hi Jassi

On Wed, 20 Jul 2022 at 17:30, Jassi Brar <jassisinghbrar@gmail.com> wrote:
>
> On Wed, Jul 20, 2022 at 2:54 AM Ilias Apalodimas
> <ilias.apalodimas@linaro.org> wrote:
> >
> > Hi Jassi,
> >
> > On Tue, 19 Jul 2022 at 18:27, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > >
> > > On Mon, 18 Jul 2022 at 16:00, Tom Rini <trini@konsulko.com> wrote:
> > > > On Mon, Jul 18, 2022 at 10:31:56AM -0500, Jassi Brar wrote:
> > >
> > > > > > > > >
> > > > > > > > > > > +
> > > > > > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > > > > > +
> > > > > > > > > > > +struct __packed devbox_metadata {
> > > > > > > > > > > +     u32 boot_index;
> > > > > > > > > > > +     u32 boot_count;
> > > > > > > > > >
> > > > > > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > > > > > better to use that framework instead of creating parallel one.
> > > > > > > > > >
> > > > > > > > > Yes, this goes too.
> > > > > > > >
> > > > > > > > Is bootcount really suited for this case?
> > > > > > > > AFAIK bootcount either requires device specific registers (which won't
> > > > > > > > reset on reboots), or an environment you can write data to.
> > > > > > > > But what if a user wants to disable writing the env variables and the
> > > > > > > > device doesn't have a set of registers we can use?
> > > > > > > >
> > > > > > > Maybe it should be moved in 'struct fwu_mdata' ?
> > > > > >
> > > > > > I was mostly thinking on moving this count as another 'bootcount'
> > > > > > method.  So in case the user has disabled writing evn variables but he
> > > > > > is booting with EFI he can use that.
> > > > >
> > > > > Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
> > > >
> > > > No, there just has to be "somewhere" to do the counting.  We've got a
> > > > DDR backed driver, for example.  So yes, I think we should try and use
> > > > the bootcount framework here.
> > > >
> > > OK, for platforms that can preserve ram across reboot, using
> > > non-persistent storage can work.
> > > My platform neither preserves ram, nor has any warmreset-proof
> > > registers. So I have to choose between saving the bootcount in efi-env
> > > or in vendor specific structure next to the metadata. I prefer
> > > metadata because it is common to all stages of boot. Any corrections
> > > to this approach?
> >
> > The metadata is defined by a spec and they don't have a field for
> > bootcounting.  Once Sughosh resends his patches he'll include a
> > bootcount backend that reuses EFI variables.  Can't we just use that?
> >
> Yes, I am aware metadata spec has no provision of vendor data. But
> there is nothing illegal in appending vendor-data to metadata and that
> is trivial to implement ... basically use   sizeof(struct fwu_mdata) +
> sizeof(struct sni_vendor_mdata)  while read/write meta-data. That will
> also be zero extra-overhead.
>
> fwu-mdata {
>            compatible = "u-boot,fwu-mdata-mtd";
>            fwu-mdata-store = <&spi_flash>;
>            mdata-offsets = <0x500000 0x530000>;
>            vendor-data-size = <0x100>;   // optional
> };
>
> Sure we can use an efi variable, but I see more uses of vendor-data
> :- shared among BL1/BL2/BL3x/OS so we can emulate reset-syndrome,
> crash-logging, per-image bootcount etc when the h/w doesn't support
> these features.
>
> Ofcourse, please feel free to implement efi-variables still.

Ok, in that case, you'll still have to implement this as a 'special'
bootcount method since the A/B updates code will use that API to
get/set the values.

Thanks
/Ilias

>
> thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox
  2022-07-22  8:37                       ` Ilias Apalodimas
@ 2022-07-22 17:01                         ` Jassi Brar
  0 siblings, 0 replies; 104+ messages in thread
From: Jassi Brar @ 2022-07-22 17:01 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: Jassi Brar, Tom Rini, Michal Simek, Sughosh Ganu, u-boot,
	Heinrich Schuchardt, Takahiro Akashi, Patrick Delaunay,
	Patrice Chotard, Simon Glass, Bin Meng, Etienne Carriere

On Fri, Jul 22, 2022 at 3:37 AM Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>
> Hi Jassi
>
> On Wed, 20 Jul 2022 at 17:30, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> >
> > On Wed, Jul 20, 2022 at 2:54 AM Ilias Apalodimas
> > <ilias.apalodimas@linaro.org> wrote:
> > >
> > > Hi Jassi,
> > >
> > > On Tue, 19 Jul 2022 at 18:27, Jassi Brar <jaswinder.singh@linaro.org> wrote:
> > > >
> > > > On Mon, 18 Jul 2022 at 16:00, Tom Rini <trini@konsulko.com> wrote:
> > > > > On Mon, Jul 18, 2022 at 10:31:56AM -0500, Jassi Brar wrote:
> > > >
> > > > > > > > > >
> > > > > > > > > > > > +
> > > > > > > > > > > > +#define PLAT_METADATA_OFFSET 0x510000
> > > > > > > > > > > > +#define PLAT_METADATA_SIZE   (sizeof(struct devbox_metadata))
> > > > > > > > > > > > +
> > > > > > > > > > > > +struct __packed devbox_metadata {
> > > > > > > > > > > > +     u32 boot_index;
> > > > > > > > > > > > +     u32 boot_count;
> > > > > > > > > > >
> > > > > > > > > > > There is the whole bootcount infrastructure for this. I think it would be much
> > > > > > > > > > > better to use that framework instead of creating parallel one.
> > > > > > > > > > >
> > > > > > > > > > Yes, this goes too.
> > > > > > > > >
> > > > > > > > > Is bootcount really suited for this case?
> > > > > > > > > AFAIK bootcount either requires device specific registers (which won't
> > > > > > > > > reset on reboots), or an environment you can write data to.
> > > > > > > > > But what if a user wants to disable writing the env variables and the
> > > > > > > > > device doesn't have a set of registers we can use?
> > > > > > > > >
> > > > > > > > Maybe it should be moved in 'struct fwu_mdata' ?
> > > > > > >
> > > > > > > I was mostly thinking on moving this count as another 'bootcount'
> > > > > > > method.  So in case the user has disabled writing evn variables but he
> > > > > > > is booting with EFI he can use that.
> > > > > >
> > > > > > Sorry, not sure I understand.... IIUIC there has to be some persistent storage.
> > > > >
> > > > > No, there just has to be "somewhere" to do the counting.  We've got a
> > > > > DDR backed driver, for example.  So yes, I think we should try and use
> > > > > the bootcount framework here.
> > > > >
> > > > OK, for platforms that can preserve ram across reboot, using
> > > > non-persistent storage can work.
> > > > My platform neither preserves ram, nor has any warmreset-proof
> > > > registers. So I have to choose between saving the bootcount in efi-env
> > > > or in vendor specific structure next to the metadata. I prefer
> > > > metadata because it is common to all stages of boot. Any corrections
> > > > to this approach?
> > >
> > > The metadata is defined by a spec and they don't have a field for
> > > bootcounting.  Once Sughosh resends his patches he'll include a
> > > bootcount backend that reuses EFI variables.  Can't we just use that?
> > >
> > Yes, I am aware metadata spec has no provision of vendor data. But
> > there is nothing illegal in appending vendor-data to metadata and that
> > is trivial to implement ... basically use   sizeof(struct fwu_mdata) +
> > sizeof(struct sni_vendor_mdata)  while read/write meta-data. That will
> > also be zero extra-overhead.
> >
> > fwu-mdata {
> >            compatible = "u-boot,fwu-mdata-mtd";
> >            fwu-mdata-store = <&spi_flash>;
> >            mdata-offsets = <0x500000 0x530000>;
> >            vendor-data-size = <0x100>;   // optional
> > };
> >
> > Sure we can use an efi variable, but I see more uses of vendor-data
> > :- shared among BL1/BL2/BL3x/OS so we can emulate reset-syndrome,
> > crash-logging, per-image bootcount etc when the h/w doesn't support
> > these features.
> >
> > Ofcourse, please feel free to implement efi-variables still.
>
> Ok, in that case, you'll still have to implement this as a 'special'
> bootcount method since the A/B updates code will use that API to
> get/set the values.
>
I thought the bootcount mechanism would always be platform specific?
But ok.

thanks.

^ permalink raw reply	[flat|nested] 104+ messages in thread

end of thread, other threads:[~2022-07-22 17:01 UTC | newest]

Thread overview: 104+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-09 12:29 [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
2022-06-09 12:29 ` [PATCH v5 01/23] dt/bindings: Add bindings for FWU Metadata storage device Sughosh Ganu
2022-06-16 13:34   ` Michal Simek
2022-06-17  6:21     ` Sughosh Ganu
2022-06-09 12:29 ` [PATCH v5 02/23] FWU: Add FWU metadata structure and driver for accessing metadata Sughosh Ganu
2022-06-21 10:54   ` Etienne Carriere
2022-06-23  6:24     ` Sughosh Ganu
2022-06-23 11:55       ` Etienne Carriere
2022-06-09 12:29 ` [PATCH v5 03/23] FWU: Add FWU metadata access driver for GPT partitioned block devices Sughosh Ganu
2022-06-21  9:34   ` Patrick DELAUNAY
2022-06-22 12:39     ` Patrick DELAUNAY
2022-06-28 10:01     ` Sughosh Ganu
2022-06-21 10:55   ` Etienne Carriere
2022-06-28 10:11     ` Sughosh Ganu
2022-06-09 12:29 ` [PATCH v5 04/23] stm32mp1: dk2: Add a node for the FWU metadata device Sughosh Ganu
2022-06-21  9:36   ` Patrick DELAUNAY
2022-06-09 12:29 ` [PATCH v5 05/23] stm32mp1: dk2: Add image information for capsule updates Sughosh Ganu
2022-06-09 12:29 ` [PATCH v5 06/23] FWU: stm32mp1: Add helper functions for accessing FWU metadata Sughosh Ganu
2022-06-10 11:53   ` Ilias Apalodimas
2022-06-13 12:37     ` Sughosh Ganu
2022-06-21  9:49   ` Patrick DELAUNAY
2022-06-23  6:04     ` Sughosh Ganu
2022-06-09 12:29 ` [PATCH v5 07/23] FWU: STM32MP1: Add support to read boot index from backup register Sughosh Ganu
2022-06-10 12:02   ` Ilias Apalodimas
2022-06-21 11:27   ` Patrick DELAUNAY
2022-06-23  6:30     ` Sughosh Ganu
2022-06-09 12:29 ` [PATCH v5 08/23] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
2022-06-15  6:34   ` Heinrich Schuchardt
2022-06-15  6:39     ` Takahiro Akashi
2022-06-21 10:56   ` Etienne Carriere
2022-06-23  9:45     ` Sughosh Ganu
2022-06-23 12:32       ` Etienne Carriere
2022-06-28 10:42         ` Sughosh Ganu
2022-06-21 11:46   ` Patrick DELAUNAY
2022-06-23  9:49     ` Sughosh Ganu
2022-06-09 12:29 ` [PATCH v5 09/23] FWU: Add support for the FWU Multi Bank Update feature Sughosh Ganu
2022-06-21 10:56   ` Etienne Carriere
2022-06-21 11:55   ` Patrick DELAUNAY
2022-06-09 12:29 ` [PATCH v5 10/23] FWU: cmd: Add a command to read FWU metadata Sughosh Ganu
2022-06-10 12:07   ` Ilias Apalodimas
2022-06-13 12:38     ` Sughosh Ganu
2022-06-20 12:53   ` Michal Simek
2022-06-21 12:07   ` Patrick DELAUNAY
2022-06-09 12:29 ` [PATCH v5 11/23] mkeficapsule: Add support for generating empty capsules Sughosh Ganu
2022-06-09 16:27   ` Heinrich Schuchardt
2022-06-13 12:33     ` Sughosh Ganu
2022-06-15  5:11   ` Takahiro Akashi
2022-06-15 10:49     ` Sughosh Ganu
2022-06-16  1:01       ` Takahiro Akashi
2022-06-16  7:12         ` Sughosh Ganu
2022-06-17  0:46           ` Takahiro Akashi
2022-06-17  8:01             ` Sughosh Ganu
2022-06-21 10:58   ` Etienne Carriere
2022-06-09 12:29 ` [PATCH v5 12/23] FWU: doc: Add documentation for the FWU feature Sughosh Ganu
2022-06-21 12:12   ` Patrick DELAUNAY
2022-06-09 12:30 ` [PATCH v5 13/23] FWU: Add FWU metadata access driver for non-GPT MTD devices Sughosh Ganu
2022-06-21 10:56   ` Etienne Carriere
2022-06-21 12:39   ` Patrick DELAUNAY
2022-06-09 12:30 ` [PATCH v5 14/23] dt/bindings: firmware: Add FWU metadata on MTD devices binding Sughosh Ganu
2022-06-21 10:56   ` Etienne Carriere
2022-06-21 12:26   ` Patrick DELAUNAY
2022-06-09 12:30 ` [PATCH v5 15/23] tools: Add mkfwumdata tool for FWU metadata image Sughosh Ganu
2022-06-21 10:57   ` Etienne Carriere
2022-06-21 12:59     ` Michal Simek
2022-06-21 12:55   ` Patrick DELAUNAY
2022-06-09 12:30 ` [PATCH v5 16/23] FWU: doc: Update documentation for the FWU non-GPT MTD Sughosh Ganu
2022-06-09 12:30 ` [PATCH v5 17/23] synquacer: Update for TBBR (BL2) based new FIP layout Sughosh Ganu
2022-06-09 12:30 ` [PATCH v5 18/23] developerbox: synquacer: Use FIP as the updatable image Sughosh Ganu
2022-06-09 12:30 ` [PATCH v5 19/23] FWU: synquacer: Add FWU Multi bank update support for DeveloperBox Sughosh Ganu
2022-06-17 14:00   ` Michal Simek
2022-06-20  8:23   ` Michal Simek
2022-07-18 14:43     ` Jassi Brar
2022-07-18 14:46       ` Ilias Apalodimas
2022-07-18 15:08         ` Jassi Brar
2022-07-18 15:16           ` Ilias Apalodimas
2022-07-18 15:31             ` Jassi Brar
2022-07-18 15:34               ` Ilias Apalodimas
2022-07-18 15:34               ` Jassi Brar
2022-07-18 15:37                 ` Ilias Apalodimas
2022-07-18 21:00               ` Tom Rini
2022-07-19 15:23                 ` Jassi Brar
2022-07-20  1:17                   ` Tom Rini
2022-07-19 15:27                 ` Jassi Brar
2022-07-20  7:53                   ` Ilias Apalodimas
2022-07-20 14:30                     ` Jassi Brar
2022-07-22  8:37                       ` Ilias Apalodimas
2022-07-22 17:01                         ` Jassi Brar
2022-06-09 12:30 ` [PATCH v5 20/23] FWU: synquacer: Generate dfu_alt_info from devicetree partition Sughosh Ganu
2022-06-17 14:02   ` Michal Simek
2022-07-18 14:49     ` Jassi Brar
2022-07-20  1:13       ` Takahiro Akashi
2022-07-20  3:16         ` Jassi Brar
2022-06-09 12:30 ` [PATCH v5 21/23] doc: synquacer: Add how to enable FWU Multi Bank Update Sughosh Ganu
2022-06-17 13:59   ` Michal Simek
2022-06-09 12:30 ` [PATCH v5 22/23] [TEMP]configs: synquacer: Add FWU support for DeveloperBox Sughosh Ganu
2022-06-09 12:30 ` [PATCH v5 23/23] sandbox: fwu: Add support for testing FWU feature on sandbox Sughosh Ganu
2022-06-15  5:37   ` Takahiro Akashi
2022-06-15 12:10     ` Sughosh Ganu
2022-06-17  1:08       ` Takahiro Akashi
2022-06-17  7:57         ` Sughosh Ganu
2022-06-15  6:30   ` Takahiro Akashi
2022-06-15 12:13     ` Sughosh Ganu
2022-06-20 18:12 ` [PATCH v5 00/23] FWU: Add FWU Multi Bank Update feature support Patrick DELAUNAY
2022-06-21  9:23   ` Sughosh Ganu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.