All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support
@ 2022-09-28  9:29 Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 01/15] dt/bindings: Add bindings for GPT based FWU Metadata storage device Sughosh Ganu
                   ` (15 more replies)
  0 siblings, 16 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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.

The patch for adding a python test for the feature has been developed,
and was sent in the version 5 of the patches[3]. However, the test
script depends on adding support for the feature on MTD SPI NOR
devices, and that is being done as part of the Synquacer
patches. Hence these set of patches do not have the test script for
the feature. That will be added through the patches for adding support
for the feauture on Synquacer platform.

[1] - https://developer.arm.com/documentation/den0118/a
[2] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
[3] - https://lists.denx.de/pipermail/u-boot/2022-June/485992.html

Changes since V10:
* s/fwu_update_active_index/fwu_set_active_index as per comment from
  Jassi
* Change the argument type of fwu_set_active_index() to uint from u32
  as per comment from Jassi
* s/mdata_check/check_mdata as per comment from Jassi
* Fix the typo in the function comment of fwu_mdata_check()
* Use array for storing the metadata partition numbers as suggested by
  Ilias
* Skip a couple of goto's in gpt_check_mdata_validity() as suggested
  by Ilias
* Have the FWU_MDATA_GPT_BLK config symbol depend on FWU_MDATA and BLK
* Remove the comment in fwu_gpt_mdata_check() as it is already
  mentioned in the corresponding API comment
* Remove the casting of boot_idx to a u32 as suggested by Etienne
* Remove the spurious newline addition in efi_setup.c
* Move the assignment of trial_state outside the if() as suggested by
  Jassi
* Move the computation of the image index to the FMP set_image
  function as suggested by Takahiro
* Use true and false booleans for fw_accept_os as suggested by Jassi
* Simplify the logic in efi_capsule_update_firmware() to check for the
  empty capsules before checking for fwu_update_checks_pass() as
  suggested by Jassi
* Address a couple of nits from Jassi
* Fix review comments suggested by Etienne
* Add a paragraph in the capsule update section to highlight the
  difference in ImageIndex correlation with DFU alt num with FWU feature
  enabled


Sughosh Ganu (15):
  dt/bindings: Add bindings for GPT based 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: Add helper functions for accessing FWU metadata
  FWU: STM32MP1: Add support to read boot index from backup register
  event: Add an event for main_loop
  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
  test: dm: Add test cases for FWU Metadata uclass
  mkeficapsule: Add support for generating empty capsules
  mkeficapsule: Add support for setting OEM flags in capsule header
  FWU: doc: Add documentation for the FWU feature

 arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi      |   7 +
 arch/arm/mach-stm32mp/include/mach/stm32.h    |   5 +
 arch/sandbox/Kconfig                          |   6 +
 arch/sandbox/dts/test.dts                     |   7 +-
 board/sandbox/sandbox.c                       |   8 +
 board/st/stm32mp1/stm32mp1.c                  |  39 ++
 cmd/Kconfig                                   |   6 +
 cmd/Makefile                                  |   1 +
 cmd/fwu_mdata.c                               |  79 +++
 common/board_r.c                              |   3 +
 common/event.c                                |   3 +
 configs/sandbox64_defconfig                   |   5 +-
 doc/develop/uefi/fwu_updates.rst              | 173 +++++
 doc/develop/uefi/index.rst                    |   1 +
 doc/develop/uefi/uefi.rst                     |  10 +
 .../firmware/fwu-mdata-gpt.yaml               |  32 +
 doc/mkeficapsule.1                            |  33 +-
 doc/usage/cmd/fwu_mdata.rst                   |  43 ++
 doc/usage/index.rst                           |   1 +
 drivers/Kconfig                               |   2 +
 drivers/Makefile                              |   1 +
 drivers/fwu-mdata/Kconfig                     |  16 +
 drivers/fwu-mdata/Makefile                    |   8 +
 drivers/fwu-mdata/fwu-mdata-uclass.c          | 107 +++
 drivers/fwu-mdata/gpt_blk.c                   | 356 ++++++++++
 include/configs/stm32mp15_common.h            |   4 +
 include/dm/uclass-id.h                        |   1 +
 include/event.h                               |   3 +
 include/fwu.h                                 | 299 +++++++++
 include/fwu_mdata.h                           |  67 ++
 lib/Kconfig                                   |   6 +
 lib/Makefile                                  |   1 +
 lib/efi_loader/efi_capsule.c                  | 207 +++++-
 lib/efi_loader/efi_firmware.c                 |  14 +
 lib/fwu_updates/Kconfig                       |  33 +
 lib/fwu_updates/Makefile                      |   7 +
 lib/fwu_updates/fwu.c                         | 608 ++++++++++++++++++
 lib/fwu_updates/fwu_gpt.c                     | 114 ++++
 test/dm/Makefile                              |   1 +
 test/dm/fwu_mdata.c                           | 149 +++++
 test/dm/fwu_mdata_disk_image.h                | 112 ++++
 .../test_capsule_firmware_fit.py              |   1 -
 .../test_capsule_firmware_signed_fit.py       |   1 -
 tools/Makefile                                |   2 +-
 tools/eficapsule.h                            |   8 +
 tools/mkeficapsule.c                          | 109 +++-
 46 files changed, 2677 insertions(+), 22 deletions(-)
 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-gpt.yaml
 create mode 100644 doc/usage/cmd/fwu_mdata.rst
 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/gpt_blk.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_gpt.c
 create mode 100644 test/dm/fwu_mdata.c
 create mode 100644 test/dm/fwu_mdata_disk_image.h

-- 
2.34.1



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

* [PATCH v11 01/15] dt/bindings: Add bindings for GPT based FWU Metadata storage device
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 02/15] FWU: Add FWU metadata structure and driver for accessing metadata Sughosh Ganu
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
Changes since V10: None

 .../firmware/fwu-mdata-gpt.yaml               | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata-gpt.yaml

diff --git a/doc/device-tree-bindings/firmware/fwu-mdata-gpt.yaml b/doc/device-tree-bindings/firmware/fwu-mdata-gpt.yaml
new file mode 100644
index 0000000000..0735191ff1
--- /dev/null
+++ b/doc/device-tree-bindings/firmware/fwu-mdata-gpt.yaml
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/firmware/fwu-mdata-gpt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: FWU metadata on device with GPT partitioned layout
+
+maintainers:
+ - Sughosh Ganu <sughosh.ganu@linaro.org>
+
+properties:
+  compatible:
+    items:
+      - const: u-boot,fwu-mdata-gpt
+
+  fwu-mdata-store:
+    maxItems: 1
+    description: Phandle of the device which contains the FWU medatata partition.
+
+required:
+  - compatible
+  - fwu-mdata-store
+
+additionalProperties: false
+
+examples:
+  - |
+    fwu-mdata {
+        compatible = "u-boot,fwu-mdata-gpt";
+        fwu-mdata-store = <&sdmmc1>;
+    };
-- 
2.34.1


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

* [PATCH v11 02/15] FWU: Add FWU metadata structure and driver for accessing metadata
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 01/15] dt/bindings: Add bindings for GPT based FWU Metadata storage device Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-30  5:54   ` Etienne Carriere
  2022-09-28  9:29 ` [PATCH v11 03/15] FWU: Add FWU metadata access driver for GPT partitioned block devices Sughosh Ganu
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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>
Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
---
Changes since V10:
* s/fwu_update_active_index/fwu_set_active_index as per comment from
  Jassi
* Change the argument type of fwu_set_active_index() to uint from u32
  as per comment from Jassi
* s/mdata_check/check_mdata as per comment from Jassi
* Fix the typo in the function comment of fwu_mdata_check()

 drivers/fwu-mdata/fwu-mdata-uclass.c | 107 ++++++++
 include/dm/uclass-id.h               |   1 +
 include/fwu.h                        | 211 ++++++++++++++++
 include/fwu_mdata.h                  |  67 +++++
 lib/fwu_updates/fwu.c                | 363 +++++++++++++++++++++++++++
 5 files changed, 749 insertions(+)
 create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
 create mode 100644 include/fwu.h
 create mode 100644 include/fwu_mdata.h
 create mode 100644 lib/fwu_updates/fwu.c

diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c
new file mode 100644
index 0000000000..4237b89520
--- /dev/null
+++ b/drivers/fwu-mdata/fwu-mdata-uclass.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#define LOG_CATEGORY UCLASS_FWU_MDATA
+
+#include <common.h>
+#include <dm.h>
+#include <efi_loader.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <u-boot/crc.h>
+
+/**
+ * fwu_mdata_check() - Check if the FWU metadata is valid
+ * @dev: FWU metadata device
+ *
+ * Validate both copies of the FWU metadata. If one of the copies
+ * has gone bad, restore it from the other copy.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_mdata_check(struct udevice *dev)
+{
+	const struct fwu_mdata_ops *ops = device_get_ops(dev);
+
+	if (!ops->check_mdata) {
+		log_debug("check_mdata() method not defined\n");
+		return -ENOSYS;
+	}
+
+	return ops->check_mdata(dev);
+}
+
+/**
+ * fwu_get_mdata() - Get a FWU metadata copy
+ * @dev: FWU metadata device
+ * @mdata: Copy of the FWU metadata
+ *
+ * Get a valid copy of the FWU metadata.
+ *
+ * Note: This function is to be called first when modifying any fields
+ * in the metadata. The sequence of calls to modify any field in the
+ * metadata would  be 1) fwu_get_mdata 2) Modify metadata, followed by
+ * 3) fwu_update_mdata
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_get_mdata(struct udevice *dev, struct fwu_mdata *mdata)
+{
+	const struct fwu_mdata_ops *ops = device_get_ops(dev);
+
+	if (!ops->get_mdata) {
+		log_debug("get_mdata() method not defined\n");
+		return -ENOSYS;
+	}
+
+	return ops->get_mdata(dev, mdata);
+}
+
+/**
+ * fwu_update_mdata() - Update the FWU metadata
+ * @dev: FWU metadata device
+ * @mdata: Copy of the FWU metadata
+ *
+ * Update the FWU metadata structure by writing to the
+ * FWU metadata partitions.
+ *
+ * Note: This function is not to be called directly to update the
+ * metadata fields. The sequence of function calls should be
+ * 1) fwu_get_mdata() 2) Modify the medata fields 3) fwu_update_mdata()
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_update_mdata(struct udevice *dev, struct fwu_mdata *mdata)
+{
+	void *buf;
+	const struct fwu_mdata_ops *ops = device_get_ops(dev);
+
+	if (!ops->update_mdata) {
+		log_debug("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 a432e43871..598a8c10a0 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -58,6 +58,7 @@ enum uclass_id {
 	UCLASS_FIRMWARE,	/* Firmware */
 	UCLASS_FUZZING_ENGINE,	/* Fuzzing engine */
 	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..a4d2d35d9a
--- /dev/null
+++ b/include/fwu.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * 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 {
+	/**
+	 * check_mdata() - Check if the FWU metadata is valid
+	 * @dev:	FWU device
+	 *
+	 * Validate both copies of the FWU metadata. If one of the copies
+	 * has gone bad, restore it from the other copy.
+	 *
+	 * Return: 0 if OK, -ve on error
+	 */
+	int (*check_mdata)(struct udevice *dev);
+
+	/**
+	 * get_mdata() - Get a FWU metadata copy
+	 * @dev:	FWU device
+	 * @mdata:	Pointer to FWU metadata
+	 *
+	 * Get a valid copy of the FWU metadata.
+	 *
+	 * Return: 0 if OK, -ve on error
+	 */
+	int (*get_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
+
+	/**
+	 * update_mdata() - Update the FWU metadata
+	 * @dev:	FWU device
+	 * @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 (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
+};
+
+#define FWU_MDATA_VERSION	0x1
+
+/*
+* GUID value defined in the FWU specification for identification
+* of the FWU metadata partition.
+*/
+#define FWU_MDATA_GUID \
+	EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
+		 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+
+/**
+ * fwu_get_mdata() - Get a FWU metadata copy
+ * @dev: FWU metadata device
+ * @mdata: Copy of the FWU metadata
+ *
+ * Get a valid copy of the FWU metadata.
+ *
+ * Note: This function is to be called first when modifying any fields
+ * in the metadata. The sequence of calls to modify any field in the
+ * metadata would  be 1) fwu_get_mdata 2) Modify metadata, followed by
+ * 3) fwu_update_mdata
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_get_mdata(struct udevice *dev, struct fwu_mdata *mdata);
+
+/**
+ * fwu_update_mdata() - Update the FWU metadata
+ * @dev: FWU metadata device
+ * @mdata: Copy of the FWU metadata
+ *
+ * Update the FWU metadata structure by writing to the
+ * FWU metadata partitions.
+ *
+ * Note: This function is not to be called directly to update the
+ * metadata fields. The sequence of function calls should be
+ * 1) fwu_get_mdata() 2) Modify the medata fields 3) fwu_update_mdata()
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_update_mdata(struct udevice *dev, struct fwu_mdata *mdata);
+
+/**
+ * fwu_get_active_index() - Get active_index from the FWU metadata
+ * @active_idxp: 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(uint *active_idxp);
+
+/**
+ * fwu_set_active_index() - Set active_index in the FWU metadata
+ * @active_idx: active_index value to be set
+ *
+ * Update the active_index field in the FWU metadata
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_set_active_index(uint active_idx);
+
+/**
+ * fwu_get_image_index() - Get the Image Index to be used for capsule update
+ * @image_index: The Image Index for the image
+ *
+ * The FWU multi bank update feature computes the value of image_index at
+ * runtime, based on the bank to which the image needs to be written to.
+ * Derive the image_index value for the image.
+ *
+ * Currently, the capsule update driver uses the DFU framework for
+ * the updates. This function gets the DFU alt number which is to
+ * be used as the Image Index
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_get_image_index(u8 *image_index);
+
+/**
+ * fwu_mdata_check() - Check if the FWU metadata is valid
+ * @dev: FWU metadata device
+ *
+ * Validate both copies of the FWU metadata. If one of the copies
+ * has gone bad, restore it from the other copy.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_mdata_check(struct udevice *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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+#endif /* _FWU_H_ */
diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h
new file mode 100644
index 0000000000..8fda4f4ac2
--- /dev/null
+++ b/include/fwu_mdata.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * 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;
+};
+
+/**
+ * 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];
+};
+
+/**
+ * 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];
+};
+
+#endif /* _FWU_MDATA_H_ */
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
new file mode 100644
index 0000000000..fe8058bc37
--- /dev/null
+++ b/lib/fwu_updates/fwu.c
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <dm.h>
+#include <efi_loader.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.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_mdata(struct udevice **dev, struct fwu_mdata *mdata)
+
+{
+	int ret;
+
+	ret = uclass_first_device(UCLASS_FWU_MDATA, dev);
+	if (ret) {
+		log_debug("Cannot find fwu device\n");
+		return ret;
+	}
+
+	ret = fwu_get_mdata(*dev, mdata);
+	if (ret < 0)
+		log_debug("Unable to get valid FWU metadata\n");
+
+	return ret;
+}
+
+static int fwu_get_image_type_id(u8 *image_index, efi_guid_t *image_type_id)
+{
+	u8 index;
+	int i;
+	struct efi_fw_image *image;
+
+	index = *image_index;
+	image = update_info.images;
+	for (i = 0; i < num_image_type_guids; i++) {
+		if (index == image[i].image_index) {
+			guidcpy(image_type_id, &image[i].image_type_id);
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+/**
+ * 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_debug("crc32 check failed for %s FWU metadata partition\n",
+			  pri_part ? "primary" : "secondary");
+		return -EINVAL;
+	}
+
+	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(uint *active_idx)
+{
+	int ret;
+	struct udevice *dev;
+	struct fwu_mdata mdata = { 0 };
+
+	ret = fwu_get_dev_mdata(&dev, &mdata);
+	if (ret)
+		return ret;
+
+	/*
+	 * Found the FWU metadata partition, now read the active_index
+	 * value
+	 */
+	*active_idx = mdata.active_index;
+	if (*active_idx >= CONFIG_FWU_NUM_BANKS) {
+		log_debug("Active index value read is incorrect\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
+ * fwu_set_active_index() - Set active_index in the FWU metadata
+ * @active_idx: active_index value to be set
+ *
+ * Update the active_index field in the FWU metadata
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_set_active_index(uint active_idx)
+{
+	int ret;
+	struct udevice *dev;
+	struct fwu_mdata mdata = { 0 };
+
+	if (active_idx >= CONFIG_FWU_NUM_BANKS) {
+		log_debug("Invalid active index value\n");
+		return -EINVAL;
+	}
+
+	ret = fwu_get_dev_mdata(&dev, &mdata);
+	if (ret)
+		return ret;
+
+	/*
+	 * 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(dev, &mdata);
+	if (ret < 0) {
+		log_debug("Failed to update FWU metadata partitions\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+/**
+ * fwu_get_image_index() - Get the Image Index to be used for capsule update
+ * @image_index: The Image Index for the image
+ *
+ * The FWU multi bank update feature computes the value of image_index at
+ * runtime, based on the bank to which the image needs to be written to.
+ * Derive the image_index value for the image.
+ *
+ * Currently, the capsule update driver uses the DFU framework for
+ * the updates. This function gets the DFU alt number which is to
+ * be used as the Image Index
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_get_image_index(u8 *image_index)
+{
+	int ret, i;
+	u8 alt_num;
+	u32 update_bank;
+	efi_guid_t *image_guid, image_type_id;
+	struct udevice *dev;
+	struct fwu_mdata mdata = { 0 };
+	struct fwu_image_entry *img_entry;
+	struct fwu_image_bank_info *img_bank_info;
+
+	ret = fwu_get_dev_mdata(&dev, &mdata);
+	if (ret)
+		return ret;
+
+	ret = fwu_plat_get_update_index(&update_bank);
+	if (ret) {
+		log_debug("Failed to get the FWU update bank\n");
+		goto out;
+	}
+
+	ret = fwu_get_image_type_id(image_index, &image_type_id);
+	if (ret) {
+		log_debug("Unable to get image_type_id for image_index %u\n",
+			  *image_index);
+		goto out;
+	}
+
+	ret = -EINVAL;
+	/*
+	 * 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, image_guid, &alt_num);
+			if (ret) {
+				log_debug("alt_num not found for partition with GUID %pUs\n",
+					  image_guid);
+			} else {
+				log_debug("alt_num %d for partition %pUs\n",
+					  alt_num, image_guid);
+				*image_index = alt_num + 1;
+			}
+
+			goto out;
+		}
+	}
+
+	log_debug("Partition with the image type %pUs not found\n",
+		  &image_type_id);
+
+out:
+	return ret;
+}
+
+/**
+ * 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 udevice *dev;
+	struct fwu_mdata mdata = { 0 };
+
+	ret = fwu_get_dev_mdata(&dev, &mdata);
+	if (ret)
+		return ret;
+
+	/*
+	 * 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(dev, &mdata);
+	if (ret < 0) {
+		log_debug("Failed to update FWU metadata partitions\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+/**
+ * fwu_clrset_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_clrset_image_accept(efi_guid_t *img_type_id, u32 bank, u8 action)
+{
+	int ret, i;
+	struct udevice *dev;
+	struct fwu_mdata mdata = { 0 };
+	struct fwu_image_entry *img_entry;
+	struct fwu_image_bank_info *img_bank_info;
+
+	ret = fwu_get_dev_mdata(&dev, &mdata);
+	if (ret)
+		return ret;
+
+	img_entry = &mdata.img_entry[0];
+	for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; 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(dev, &mdata);
+			goto out;
+		}
+	}
+
+	/* Image not found */
+	ret = -ENOENT;
+
+out:
+	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_clrset_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_clrset_image_accept(img_type_id, bank,
+				       IMAGE_ACCEPT_CLEAR);
+}
-- 
2.34.1


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

* [PATCH v11 03/15] FWU: Add FWU metadata access driver for GPT partitioned block devices
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 01/15] dt/bindings: Add bindings for GPT based FWU Metadata storage device Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 02/15] FWU: Add FWU metadata structure and driver for accessing metadata Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-30  6:10   ` Etienne Carriere
  2022-09-28  9:29 ` [PATCH v11 04/15] stm32mp1: dk2: Add a node for the FWU metadata device Sughosh Ganu
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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 formatted with GPT based partition scheme.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
---
Changes since V10:
* Use array for storing the metadata partition numbers as suggested by
  Ilias
* Skip a couple of goto's in gpt_check_mdata_validity() as suggested
  by Ilias
* Have the FWU_MDATA_GPT_BLK config symbol depend on FWU_MDATA and BLK
* Remove the comment in fwu_gpt_mdata_check() as it is already
  mentioned in the corresponding API comment

 drivers/fwu-mdata/Kconfig   |  16 ++
 drivers/fwu-mdata/Makefile  |   8 +
 drivers/fwu-mdata/gpt_blk.c | 356 ++++++++++++++++++++++++++++++++++++
 include/fwu.h               |   4 +
 4 files changed, 384 insertions(+)
 create mode 100644 drivers/fwu-mdata/Kconfig
 create mode 100644 drivers/fwu-mdata/Makefile
 create mode 100644 drivers/fwu-mdata/gpt_blk.c

diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
new file mode 100644
index 0000000000..36c4479a59
--- /dev/null
+++ b/drivers/fwu-mdata/Kconfig
@@ -0,0 +1,16 @@
+config 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.
+
+config FWU_MDATA_GPT_BLK
+	bool "FWU Metadata access for GPT partitioned Block devices"
+	select PARTITION_TYPE_GUID
+	select PARTITION_UUIDS
+	depends on FWU_MDATA && BLK && 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
new file mode 100644
index 0000000000..3fee64c10c
--- /dev/null
+++ b/drivers/fwu-mdata/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2022, Linaro Limited
+#
+
+
+obj-$(CONFIG_FWU_MDATA) += fwu-mdata-uclass.o
+obj-$(CONFIG_FWU_MDATA_GPT_BLK) += gpt_blk.o
diff --git a/drivers/fwu-mdata/gpt_blk.c b/drivers/fwu-mdata/gpt_blk.c
new file mode 100644
index 0000000000..d20bb19d52
--- /dev/null
+++ b/drivers/fwu-mdata/gpt_blk.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#define LOG_CATEGORY UCLASS_FWU_MDATA
+
+#include <blk.h>
+#include <dm.h>
+#include <efi_loader.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+#include <memalign.h>
+#include <part.h>
+#include <part_efi.h>
+
+#include <dm/device-internal.h>
+#include <linux/errno.h>
+#include <linux/types.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,
+				    uint *mdata_parts)
+{
+	int i, ret;
+	u32 nparts;
+	efi_guid_t part_type_guid;
+	struct disk_partition info;
+	const efi_guid_t fwu_mdata_guid = FWU_MDATA_GUID;
+
+	nparts = 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 (nparts < 2 && !guidcmp(&fwu_mdata_guid, &part_type_guid)) {
+			mdata_parts[nparts] = i;
+			++nparts;
+		}
+	}
+
+	if (nparts != 2) {
+		log_debug("Expect two copies of the FWU metadata instead of %d\n",
+			  nparts);
+		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_debug("Unable to get the partition info for the FWU metadata part %d\n",
+			  part_num);
+		return -ENOENT;
+	}
+
+	/* 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 -ENOENT;
+}
+
+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 -ENOENT;
+	}
+
+	len = sizeof(*mdata);
+	blkcnt = BLOCK_CNT(len, desc);
+	if (blkcnt > info.size) {
+		log_debug("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_debug("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_debug("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;
+	uint mdata_parts[2];
+	struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
+
+	desc = dev_get_uclass_plat(priv->blk_dev);
+
+	ret = gpt_get_mdata_partitions(desc, mdata_parts);
+	if (ret < 0) {
+		log_debug("Error getting the FWU metadata partitions\n");
+		return -ENOENT;
+	}
+
+	/* First write the primary partition */
+	ret = gpt_write_mdata_partition(desc, mdata, mdata_parts[0]);
+	if (ret < 0) {
+		log_debug("Updating primary FWU metadata partition failed\n");
+		return ret;
+	}
+
+	/* And now the replica */
+	ret = gpt_write_mdata_partition(desc, mdata, mdata_parts[1]);
+	if (ret < 0) {
+		log_debug("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;
+	uint mdata_parts[2];
+
+	ret = gpt_get_mdata_partitions(desc, mdata_parts);
+
+	if (ret < 0) {
+		log_debug("Error getting the FWU metadata partitions\n");
+		return -ENOENT;
+	}
+
+	ret = gpt_read_mdata(desc, mdata, mdata_parts[0]);
+	if (ret < 0) {
+		log_debug("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, mdata_parts[1]);
+	if (ret < 0) {
+		log_debug("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 -EIO;
+}
+
+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;
+	uint mdata_parts[2];
+	uint valid_partitions, invalid_partitions;
+	struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
+
+	desc = dev_get_uclass_plat(priv->blk_dev);
+
+	/*
+	 * 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, mdata_parts);
+	if (ret < 0) {
+		log_debug("Error getting the FWU metadata partitions\n");
+		return -ENOENT;
+	}
+
+	ret = gpt_read_mdata(desc, &pri_mdata, mdata_parts[0]);
+	if (!ret) {
+		ret = fwu_verify_mdata(&pri_mdata, 1);
+		if (!ret)
+			valid_partitions |= PRIMARY_PART;
+	}
+
+	/* Now check the secondary partition */
+	ret = gpt_read_mdata(desc, &secondary_mdata, mdata_parts[1]);
+	if (!ret) {
+		ret = fwu_verify_mdata(&secondary_mdata, 0);
+		if (!ret)
+			valid_partitions |= SECONDARY_PART;
+	}
+
+	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_debug("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) ?
+					mdata_parts[0] : mdata_parts[1]);
+
+	if (ret < 0)
+		log_debug("Restoring %s FWU metadata partition failed\n",
+			  (invalid_partitions == PRIMARY_PART) ?
+			  "primary" : "secondary");
+
+out:
+	return ret;
+}
+
+static int fwu_gpt_mdata_check(struct udevice *dev)
+{
+	return gpt_check_mdata_validity(dev);
+}
+
+static int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata *mdata)
+{
+	struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
+
+	return gpt_get_mdata(dev_get_uclass_plat(priv->blk_dev), mdata);
+}
+
+static int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev)
+{
+	u32 phandle;
+	int ret, size;
+	struct udevice *parent;
+	const fdt32_t *phandle_p = NULL;
+
+	phandle_p = dev_read_prop(dev, "fwu-mdata-store", &size);
+	if (!phandle_p) {
+		log_debug("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;
+
+	return blk_get_from_parent(parent, mdata_dev);
+}
+
+static int fwu_mdata_gpt_blk_probe(struct udevice *dev)
+{
+	int ret;
+	struct udevice *mdata_dev = NULL;
+	struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
+
+	ret = fwu_get_mdata_device(dev, &mdata_dev);
+	if (ret)
+		return ret;
+
+	priv->blk_dev = mdata_dev;
+
+	return 0;
+}
+
+static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
+	.check_mdata = 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 a4d2d35d9a..167f91388e 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -14,6 +14,10 @@
 struct fwu_mdata;
 struct udevice;
 
+struct fwu_mdata_gpt_blk_priv {
+	struct udevice *blk_dev;
+};
+
 /**
  * @mdata_check: check the validity of the FWU metadata partitions
  * @get_mdata() - Get a FWU metadata copy
-- 
2.34.1


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

* [PATCH v11 04/15] stm32mp1: dk2: Add a node for the FWU metadata device
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (2 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 03/15] FWU: Add FWU metadata access driver for GPT partitioned block devices Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates Sughosh Ganu
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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>
Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
---
Changes since V10: None

 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.34.1


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

* [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (3 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 04/15] stm32mp1: dk2: Add a node for the FWU metadata device Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-30  5:51   ` Etienne Carriere
  2022-10-03 10:56   ` Takahiro Akashi
  2022-09-28  9:29 ` [PATCH v11 06/15] FWU: Add helper functions for accessing FWU metadata Sughosh Ganu
                   ` (10 subsequent siblings)
  15 siblings, 2 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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>
Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
Changes since V10:
* Use image_index value of 1 for the FIP image as it is now relevant

 board/st/stm32mp1/stm32mp1.c       | 18 ++++++++++++++++++
 include/configs/stm32mp15_common.h |  4 ++++
 2 files changed, 22 insertions(+)

diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index 8c162b42a5..e43dab018f 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>
@@ -87,6 +88,16 @@
 #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 */
@@ -666,6 +677,13 @@ int board_init(void)
 
 	setup_led(LEDST_ON);
 
+#if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
+	efi_guid_t image_type_guid = STM32MP_FIP_IMAGE_GUID;
+
+	guidcpy(&fw_images[0].image_type_id, &image_type_guid);
+	fw_images[0].fw_name = u"STM32MP-FIP";
+	fw_images[0].image_index = 1;
+#endif
 	return 0;
 }
 
diff --git a/include/configs/stm32mp15_common.h b/include/configs/stm32mp15_common.h
index c5412ffeb3..bb19dae945 100644
--- a/include/configs/stm32mp15_common.h
+++ b/include/configs/stm32mp15_common.h
@@ -34,6 +34,10 @@
 #define CONFIG_SERVERIP                 192.168.1.1
 #endif
 
+#define STM32MP_FIP_IMAGE_GUID \
+	EFI_GUID(0x19d5df83, 0x11b0, 0x457b, 0xbe, 0x2c, \
+		 0x75, 0x59, 0xc1, 0x31, 0x42, 0xa5)
+
 /*****************************************************************************/
 #ifdef CONFIG_DISTRO_DEFAULTS
 /*****************************************************************************/
-- 
2.34.1


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

* [PATCH v11 06/15] FWU: Add helper functions for accessing FWU metadata
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (4 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-10-03  9:51   ` Ilias Apalodimas
  2022-09-28  9:29 ` [PATCH v11 07/15] FWU: STM32MP1: Add support to read boot index from backup register Sughosh Ganu
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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 weak functions for getting the update index value and dfu
alternate number needed for FWU Multi Bank update
functionality.

The current implementation for getting the update index value is for
platforms with 2 banks. If a platform supports more than 2 banks, it
can implement it's own function. The function to get the dfu alternate
number has been added for platforms with GPT partitioned storage
devices. Platforms with other storage partition scheme need to
implement their own function.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
---
Changes since V10: None

Note: I have not changed the logic of the check in
fwu_gpt_get_alt_num(). This can be extended if and when another GPT
based device gets added to the DFU framework.

 include/fwu.h             |  29 ++++++++++
 lib/fwu_updates/fwu.c     |  27 +++++++++
 lib/fwu_updates/fwu_gpt.c | 114 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 170 insertions(+)
 create mode 100644 lib/fwu_updates/fwu_gpt.c

diff --git a/include/fwu.h b/include/fwu.h
index 167f91388e..99f43f07b0 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -212,4 +212,33 @@ 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);
 
+/**
+ * fwu_plat_get_alt_num() - Get the DFU Alt Num for the image from the platform
+ * @dev: FWU device
+ * @image_guid: Image GUID for which DFU alt number needs to be retrieved
+ * @alt_num: Pointer to the alt_num
+ *
+ * Get the DFU alt number from the platform for the image specified by the
+ * image GUID.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
+			 u8 *alt_num);
+
+/**
+ * fwu_plat_get_update_index() - Get the value of the update bank
+ * @update_idx: Bank number to which images are to be updated
+ *
+ * Get the value of the bank(partition) to which the update needs to be
+ * made.
+ *
+ * Note: This is a weak function and platforms can override this with
+ * their own implementation for selection of the update bank.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_plat_get_update_index(uint *update_idx);
 #endif /* _FWU_H_ */
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index fe8058bc37..5cf6bec6a0 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -361,3 +361,30 @@ int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank)
 	return fwu_clrset_image_accept(img_type_id, bank,
 				       IMAGE_ACCEPT_CLEAR);
 }
+
+/**
+ * fwu_plat_get_update_index() - Get the value of the update bank
+ * @update_idx: Bank number to which images are to be updated
+ *
+ * Get the value of the bank(partition) to which the update needs to be
+ * made.
+ *
+ * Note: This is a weak function and platforms can override this with
+ * their own implementation for selection of the update bank.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+__weak int fwu_plat_get_update_index(uint *update_idx)
+{
+	int ret;
+	u32 active_idx;
+
+	ret = fwu_get_active_index(&active_idx);
+	if (ret < 0)
+		return -1;
+
+	*update_idx = (active_idx + 1) % CONFIG_FWU_NUM_BANKS;
+
+	return ret;
+}
diff --git a/lib/fwu_updates/fwu_gpt.c b/lib/fwu_updates/fwu_gpt.c
new file mode 100644
index 0000000000..a1b0f3bea7
--- /dev/null
+++ b/lib/fwu_updates/fwu_gpt.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <blk.h>
+#include <dfu.h>
+#include <efi.h>
+#include <efi_loader.h>
+#include <fwu.h>
+#include <log.h>
+#include <part.h>
+
+#include <linux/errno.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 fwu_gpt_get_alt_num(struct blk_desc *desc, efi_guid_t *image_guid,
+			       u8 *alt_num, unsigned char dfu_dev)
+{
+	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)
+			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;
+}
+
+/**
+ * fwu_plat_get_alt_num() - Get the DFU alt number
+ * @dev: FWU metadata device
+ * @image_guid: GUID value of the image for which the alt num is to
+ *              be obtained
+ * @alt_num: The DFU alt number for the image that is to be updated
+ *
+ * Get the DFU alt number for the image that is to be updated. The
+ * image is identified with the image_guid parameter that is passed
+ * to the function.
+ *
+ * Note: This is a weak function and platforms can override this with
+ * their own implementation for obtaining the alt number value.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+__weak int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
+				u8 *alt_num)
+{
+	struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
+
+	return fwu_gpt_get_alt_num(dev_get_uclass_plat(priv->blk_dev),
+				   image_guid, alt_num, DFU_DEV_MMC);
+}
-- 
2.34.1


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

* [PATCH v11 07/15] FWU: STM32MP1: Add support to read boot index from backup register
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (5 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 06/15] FWU: Add helper functions for accessing FWU metadata Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 08/15] event: Add an event for main_loop Sughosh Ganu
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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>
Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
Changes since V10:
* Remove the casting of boot_idx to a u32 as suggested by Etienne

 arch/arm/mach-stm32mp/include/mach/stm32.h |  5 +++++
 board/st/stm32mp1/stm32mp1.c               | 21 +++++++++++++++++++++
 include/fwu.h                              | 12 ++++++++++++
 3 files changed, 38 insertions(+)

diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h
index c70375a723..c85ae6a34e 100644
--- a/arch/arm/mach-stm32mp/include/mach/stm32.h
+++ b/arch/arm/mach-stm32mp/include/mach/stm32.h
@@ -112,11 +112,16 @@ enum boot_device {
 #ifdef CONFIG_STM32MP15x
 #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
 #define TAMP_COPRO_STATE_CRUN		2
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index e43dab018f..43274c1ff6 100644
--- a/board/st/stm32mp1/stm32mp1.c
+++ b/board/st/stm32mp1/stm32mp1.c
@@ -957,3 +957,24 @@ 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>
+
+/**
+ * fwu_plat_get_bootidx() - Get the value of the boot index
+ * @boot_idx: Boot index value
+ *
+ * Get the value of the bank(partition) from which the platform
+ * has booted. This value is passed to U-Boot from the earlier
+ * stage bootloader which loads and boots all the relevant
+ * firmware images
+ *
+ */
+void fwu_plat_get_bootidx(uint *boot_idx)
+{
+	*boot_idx = (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 99f43f07b0..71a03cf70b 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -241,4 +241,16 @@ int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
  *
  */
 int fwu_plat_get_update_index(uint *update_idx);
+
+/**
+ * fwu_plat_get_bootidx() - Get the value of the boot index
+ * @boot_idx: Boot index value
+ *
+ * Get the value of the bank(partition) from which the platform
+ * has booted. This value is passed to U-Boot from the earlier
+ * stage bootloader which loads and boots all the relevant
+ * firmware images
+ *
+ */
+void fwu_plat_get_bootidx(uint *boot_idx);
 #endif /* _FWU_H_ */
-- 
2.34.1


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

* [PATCH v11 08/15] event: Add an event for main_loop
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (6 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 07/15] FWU: STM32MP1: Add support to read boot index from backup register Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 09/15] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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 an event type EVT_MAIN_LOOP that can be used for registering
events that need to be run after the platform has been initialised and
before the main_loop function is called.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
Changes since V10: None

 common/board_r.c | 3 +++
 common/event.c   | 3 +++
 include/event.h  | 3 +++
 3 files changed, 9 insertions(+)

diff --git a/common/board_r.c b/common/board_r.c
index 56eb60fa27..1db061e65c 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -576,6 +576,9 @@ static int run_main_loop(void)
 #ifdef CONFIG_SANDBOX
 	sandbox_main_loop_init();
 #endif
+
+	event_notify_null(EVT_MAIN_LOOP);
+
 	/* main_loop() can return to retry autoboot, if so just run it again */
 	for (;;)
 		main_loop();
diff --git a/common/event.c b/common/event.c
index 3e34550978..231b9e6ffd 100644
--- a/common/event.c
+++ b/common/event.c
@@ -38,6 +38,9 @@ const char *const type_name[] = {
 
 	/* fdt hooks */
 	"ft_fixup",
+
+	/* main loop events */
+	"main_loop",
 };
 
 _Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
diff --git a/include/event.h b/include/event.h
index e8f2f55c63..8089b464b1 100644
--- a/include/event.h
+++ b/include/event.h
@@ -34,6 +34,9 @@ enum event_t {
 	/* Device tree fixups before booting */
 	EVT_FT_FIXUP,
 
+	/* To be called once, before calling main_loop() */
+	EVT_MAIN_LOOP,
+
 	EVT_COUNT
 };
 
-- 
2.34.1


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

* [PATCH v11 09/15] FWU: Add boot time checks as highlighted by the FWU specification
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (7 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 08/15] event: Add an event for main_loop Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-10-03  9:56   ` Ilias Apalodimas
  2022-09-28  9:29 ` [PATCH v11 10/15] FWU: Add support for the FWU Multi Bank Update feature Sughosh Ganu
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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.

Call these checks through the main loop event at the time of platform
boot.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
---
Changes since V10:
* Remove the spurious newline addition in efi_setup.c
* Move the assignment of trial_state outside the if() as suggested by
  Jassi

 include/fwu.h         |  13 +++
 lib/fwu_updates/fwu.c | 193 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 204 insertions(+), 2 deletions(-)

diff --git a/include/fwu.h b/include/fwu.h
index 71a03cf70b..2effa7da38 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -253,4 +253,17 @@ int fwu_plat_get_update_index(uint *update_idx);
  *
  */
 void fwu_plat_get_bootidx(uint *boot_idx);
+
+/**
+ * fwu_update_checks_pass() - Check if FWU update can be done
+ *
+ * Check if the FWU update can be executed. The updates are
+ * allowed only when the platform is not in Trial State and
+ * the boot time checks have passed
+ *
+ * Return: 1 if OK, 0 on error
+ *
+ */
+u8 fwu_update_checks_pass(void);
+
 #endif /* _FWU_H_ */
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index 5cf6bec6a0..5cde5514d2 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -4,10 +4,19 @@
  */
 
 #include <dm.h>
+#include <efi.h>
 #include <efi_loader.h>
+#include <efi_variable.h>
+#include <event.h>
 #include <fwu.h>
 #include <fwu_mdata.h>
-#include <log.h>
+#include <malloc.h>
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+static u8 trial_state;
+static u8 boottime_check;
 
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -16,8 +25,113 @@
 #define IMAGE_ACCEPT_SET	BIT(0)
 #define IMAGE_ACCEPT_CLEAR	BIT(1)
 
-static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
+static int trial_counter_update(u16 *trial_state_ctr)
+{
+	bool delete;
+	u32 var_attr;
+	efi_status_t status;
+	efi_uintn_t var_size;
+
+	delete = !trial_state_ctr ? true : false;
+	var_size = !trial_state_ctr ? 0 : (efi_uintn_t)sizeof(*trial_state_ctr);
+	var_attr = !trial_state_ctr ? 0 : EFI_VARIABLE_NON_VOLATILE |
+		EFI_VARIABLE_BOOTSERVICE_ACCESS;
+	status = efi_set_variable_int(u"TrialStateCtr",
+				      &efi_global_variable_guid,
+				      var_attr,
+				      var_size, trial_state_ctr, false);
+
+	if ((delete && (status != EFI_NOT_FOUND &&
+			status != EFI_SUCCESS)) ||
+	    (!delete && status != EFI_SUCCESS))
+		return -1;
+
+	return 0;
+}
+
+static int in_trial_state(struct fwu_mdata *mdata)
+{
+	u32 i, active_bank;
+	struct fwu_image_entry *img_entry;
+	struct fwu_image_bank_info *img_bank_info;
+
+	active_bank = mdata->active_index;
+	img_entry = &mdata->img_entry[0];
+	for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
+		img_bank_info = &img_entry[i].img_bank_info[active_bank];
+		if (!img_bank_info->accepted) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int fwu_trial_state_check(struct udevice *dev)
+{
+	int ret;
+	efi_status_t status;
+	efi_uintn_t var_size;
+	u16 trial_state_ctr;
+	u32 var_attributes;
+	struct fwu_mdata mdata = { 0 };
+
+	ret = fwu_get_mdata(dev, &mdata);
+	if (ret)
+		return ret;
+
+	trial_state = in_trial_state(&mdata);
+	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(u"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");
+			ret = fwu_revert_boot_index();
+			if (ret) {
+				log_err("Unable to revert active_index\n");
+				goto out;
+			}
+
+			/* Delete the TrialStateCtr variable */
+			ret = trial_counter_update(NULL);
+			if (ret) {
+				log_err("Unable to delete TrialStateCtr variable\n");
+				goto out;
+			}
+		} else {
+			ret = trial_counter_update(&trial_state_ctr);
+			if (ret) {
+				log_err("Unable to increment TrialStateCtr variable\n");
+				goto out;
+			}
+		}
+	} else {
+		/* Delete the variable */
+		ret = trial_counter_update(NULL);
+		if (ret) {
+			log_err("Unable to delete TrialStateCtr variable\n");
+		}
+	}
+
+out:
+	return ret;
+}
 
+static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
 {
 	int ret;
 
@@ -27,6 +141,9 @@ static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
 		return ret;
 	}
 
+	if (!mdata)
+		return 0;
+
 	ret = fwu_get_mdata(*dev, mdata);
 	if (ret < 0)
 		log_debug("Unable to get valid FWU metadata\n");
@@ -388,3 +505,75 @@ __weak int fwu_plat_get_update_index(uint *update_idx)
 
 	return ret;
 }
+
+/**
+ * fwu_update_checks_pass() - Check if FWU update can be done
+ *
+ * Check if the FWU update can be executed. The updates are
+ * allowed only when the platform is not in Trial State and
+ * the boot time checks have passed
+ *
+ * Return: 1 if OK, 0 on error
+ *
+ */
+u8 fwu_update_checks_pass(void)
+{
+	return !trial_state && boottime_check;
+}
+
+static int fwu_boottime_checks(void *ctx, struct event *event)
+{
+	int ret;
+	struct udevice *dev;
+	u32 boot_idx, active_idx;
+
+	ret = fwu_get_dev_mdata(&dev, NULL);
+	if (ret)
+		return ret;
+
+	ret = fwu_mdata_check(dev);
+	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_set_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(dev);
+	if (!ret)
+		boottime_check = 1;
+
+	return 0;
+}
+EVENT_SPY(EVT_MAIN_LOOP, fwu_boottime_checks);
-- 
2.34.1


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

* [PATCH v11 10/15] FWU: Add support for the FWU Multi Bank Update feature
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (8 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 09/15] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 11/15] FWU: cmd: Add a command to read FWU metadata Sughosh Ganu
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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>
---
Changes since V10:
* Move the computation of the image index to the FMP set_image
  function as suggested by Takahiro
* Use true and false booleans for fw_accept_os as suggested by Jassi
* Simplify the logic in efi_capsule_update_firmware() to check for the
  empty capsules before checking for fwu_update_checks_pass() as
  suggested by Jassi
* Address a couple of nits from Jassi

 drivers/Kconfig               |   2 +
 drivers/Makefile              |   1 +
 include/fwu.h                 |  30 +++++
 lib/Kconfig                   |   6 +
 lib/Makefile                  |   1 +
 lib/efi_loader/efi_capsule.c  | 207 +++++++++++++++++++++++++++++++++-
 lib/efi_loader/efi_firmware.c |  14 +++
 lib/fwu_updates/Kconfig       |  33 ++++++
 lib/fwu_updates/Makefile      |   7 ++
 lib/fwu_updates/fwu.c         |  23 ++++
 10 files changed, 322 insertions(+), 2 deletions(-)
 create mode 100644 lib/fwu_updates/Kconfig
 create mode 100644 lib/fwu_updates/Makefile

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 8b6fead351..75ac149d31 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -44,6 +44,8 @@ source "drivers/fuzz/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 eba9940231..af7ed7bdf3 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -84,6 +84,7 @@ obj-y += cache/
 obj-$(CONFIG_CPU) += cpu/
 obj-y += crypto/
 obj-$(CONFIG_FASTBOOT) += fastboot/
+obj-$(CONFIG_FWU_MDATA) += fwu-mdata/
 obj-y += misc/
 obj-$(CONFIG_MMC) += mmc/
 obj-$(CONFIG_NVME) += nvme/
diff --git a/include/fwu.h b/include/fwu.h
index 2effa7da38..b5c59dc161 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -60,6 +60,7 @@ struct fwu_mdata_ops {
 };
 
 #define FWU_MDATA_VERSION	0x1
+#define FWU_IMAGE_ACCEPTED	0x1
 
 /*
 * GUID value defined in the FWU specification for identification
@@ -69,6 +70,24 @@ struct fwu_mdata_ops {
 	EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
 		 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
 
+/*
+* GUID value defined in the Dependable Boot specification for
+* identification of the revert capsule, used for reverting
+* any image in the updated bank.
+*/
+#define FWU_OS_REQUEST_FW_REVERT_GUID \
+	EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
+		 0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
+
+/*
+* GUID value defined in the Dependable Boot specification for
+* identification of the accept capsule, used for accepting
+* an image in the updated bank.
+*/
+#define FWU_OS_REQUEST_FW_ACCEPT_GUID \
+	EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
+		 0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
+
 /**
  * fwu_get_mdata() - Get a FWU metadata copy
  * @dev: FWU metadata device
@@ -266,4 +285,15 @@ void fwu_plat_get_bootidx(uint *boot_idx);
  */
 u8 fwu_update_checks_pass(void);
 
+/**
+ * fwu_trial_state_ctr_start() - Start the Trial State counter
+ *
+ * Start the counter to identify the platform booting in the
+ * Trial State. The counter is implemented as an EFI variable.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_trial_state_ctr_start(void);
+
 #endif /* _FWU_H_ */
diff --git a/lib/Kconfig b/lib/Kconfig
index 6121c80dc8..6abe1d0a86 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -978,3 +978,9 @@ config LMB_RESERVED_REGIONS
 	  memory blocks.
 
 endmenu
+
+menu "FWU Multi Bank Updates"
+
+source lib/fwu_updates/Kconfig
+
+endmenu
diff --git a/lib/Makefile b/lib/Makefile
index e3deb15287..f2cfd1e428 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_FIT) += libfdt/
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index a6b98f066a..23baf1c6b6 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,12 @@ 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
 
 #ifdef CONFIG_EFI_CAPSULE_ON_DISK
 /* for file system access */
@@ -388,6 +395,130 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s
 }
 #endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
 
+static __maybe_unused 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 __maybe_unused efi_status_t fwu_to_efi_error(int err)
+{
+	efi_status_t ret;
+
+	switch(err) {
+	case 0:
+		ret = EFI_SUCCESS;
+		break;
+	case -ENODEV:
+	case -ERANGE:
+	case -EIO:
+		ret = EFI_DEVICE_ERROR;
+		break;
+	case -EINVAL:
+		ret = EFI_INVALID_PARAMETER;
+		break;
+	default:
+		ret = EFI_OUT_OF_RESOURCES;
+	}
+
+	return ret;
+}
+
+static __maybe_unused 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();
+		ret = fwu_to_efi_error(status);
+		if (ret == EFI_SUCCESS)
+			log_info("Reverted the FWU active_index. Recommend rebooting the system\n");
+		else
+			log_err("Failed to revert the FWU boot index\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);
+		ret = fwu_to_efi_error(status);
+		if (ret != EFI_SUCCESS) {
+			log_err("Unable to get the active_index from the FWU metadata\n");
+			return ret;
+		}
+
+		status = fwu_accept_image(image_guid, active_idx);
+		ret = fwu_to_efi_error(status);
+		if (ret != EFI_SUCCESS)
+			log_err("Unable to set the Accept bit for the image %pUs\n",
+				image_guid);
+	}
+
+	return ret;
+}
+
+static __maybe_unused void fwu_post_update_checks(
+	struct efi_capsule_header *capsule,
+	bool *fw_accept_os, bool *capsule_update)
+{
+	if (fwu_empty_capsule(capsule))
+		*capsule_update = false;
+	else
+		if (!*fw_accept_os)
+			*fw_accept_os =
+				capsule->flags & FW_ACCEPT_OS ? true : false;
+}
+
+static __maybe_unused efi_status_t fwu_post_update_process(bool fw_accept_os)
+{
+	int status;
+	u32 update_index;
+	efi_status_t ret;
+
+	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;
+	}
+
+	/*
+	 * 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_set_active_index(update_index);
+	ret = fwu_to_efi_error(status);
+	if (ret != EFI_SUCCESS) {
+		log_err("Failed to update FWU metadata index values\n");
+	} else {
+		log_debug("Successfully updated the active_index\n");
+		ret = EFI_SUCCESS;
+		if (fw_accept_os) {
+			status = fwu_trial_state_ctr_start();
+			if (status < 0)
+				ret = EFI_DEVICE_ERROR;
+		}
+	}
+
+	return ret;
+}
 
 /**
  * efi_capsule_update_firmware - update firmware from capsule
@@ -410,7 +541,31 @@ static efi_status_t efi_capsule_update_firmware(
 	int item;
 	struct efi_firmware_management_protocol *fmp;
 	u16 *abort_reason;
+	efi_guid_t *image_type_id;
 	efi_status_t ret = EFI_SUCCESS;
+	int status;
+	u32 update_index;
+	bool fw_accept_os;
+
+	if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+		if (fwu_empty_capsule(capsule_data))
+			return fwu_empty_capsule_process(capsule_data);
+
+		if (!fwu_update_checks_pass()) {
+			log_err("FWU checks failed. Cannot start update\n");
+			return EFI_INVALID_PARAMETER;
+		}
+
+
+		/* 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;
+	}
 
 	/* sanity check */
 	if (capsule_data->header_size < sizeof(*capsule) ||
@@ -497,6 +652,34 @@ static efi_status_t efi_capsule_update_firmware(
 			efi_free_pool(abort_reason);
 			goto out;
 		}
+
+		if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+			image_type_id = &image->update_image_type_id;
+			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);
+			}
+			ret = fwu_to_efi_error(status);
+			if (ret != EFI_SUCCESS) {
+				log_err("Unable to %s the accept bit for the image %pUs\n",
+					fw_accept_os ? "clear" : "set",
+					image_type_id);
+				goto out;
+			}
+
+			log_debug("%s the accepted bit for Image %pUs\n",
+				  fw_accept_os ? "Cleared" : "Set",
+				  image_type_id);
+		}
+
 	}
 
 out:
@@ -1104,6 +1287,9 @@ efi_status_t efi_launch_capsules(void)
 	u16 **files;
 	unsigned int nfiles, index, i;
 	efi_status_t ret;
+	bool capsule_update = true;
+	bool update_status = true;
+	bool fw_accept_os = false;
 
 	if (check_run_capsules() != EFI_SUCCESS)
 		return EFI_SUCCESS;
@@ -1131,12 +1317,19 @@ 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]);
+				if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+					fwu_post_update_checks(capsule,
+							       &fw_accept_os,
+							       &capsule_update);
+				}
+			}
 
 			/* create CapsuleXXXX */
 			set_capsule_result(index, capsule, ret);
@@ -1144,6 +1337,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]);
@@ -1151,8 +1345,17 @@ 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 (capsule_update == true && update_status == true) {
+			ret = fwu_post_update_process(fw_accept_os);
+		} 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]);
 	free(files);
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index 30cafd15ca..93e2b01c07 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -10,6 +10,7 @@
 #include <charset.h>
 #include <dfu.h>
 #include <efi_loader.h>
+#include <fwu.h>
 #include <image.h>
 #include <signatures.h>
 
@@ -389,6 +390,7 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
 	efi_status_t (*progress)(efi_uintn_t completion),
 	u16 **abort_reason)
 {
+	int ret;
 	efi_status_t status;
 
 	EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
@@ -401,6 +403,18 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
 	if (status != EFI_SUCCESS)
 		return EFI_EXIT(status);
 
+	if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+		/*
+		 * Based on the value of update bank, derive the
+		 * image index value.
+		 */
+		ret = fwu_get_image_index(&image_index);
+		if (ret) {
+			log_debug("Unable to get FWU image_index\n");
+			return EFI_EXIT(EFI_DEVICE_ERROR);
+		}
+	}
+
 	if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
 			     NULL, NULL))
 		return EFI_EXIT(EFI_DEVICE_ERROR);
diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
new file mode 100644
index 0000000000..78759e6618
--- /dev/null
+++ b/lib/fwu_updates/Kconfig
@@ -0,0 +1,33 @@
+config FWU_MULTI_BANK_UPDATE
+	bool "Enable FWU Multi Bank Update Feature"
+	depends on EFI_CAPSULE_ON_DISK
+	select PARTITION_TYPE_GUID
+	select EFI_SETUP_EARLY
+	imply EFI_CAPSULE_ON_DISK_EARLY
+	select EVENT
+	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..1993088e5b
--- /dev/null
+++ b/lib/fwu_updates/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2022, Linaro Limited
+#
+
+obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o
+obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_gpt.o
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index 5cde5514d2..5c0c209e2c 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -521,7 +521,30 @@ u8 fwu_update_checks_pass(void)
 	return !trial_state && boottime_check;
 }
 
+/**
+ * fwu_trial_state_ctr_start() - Start the Trial State counter
+ *
+ * Start the counter to identify the platform booting in the
+ * Trial State. The counter is implemented as an EFI variable.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_trial_state_ctr_start(void)
+{
+	int ret;
+	u16 trial_state_ctr;
+
+	trial_state_ctr = 0;
+	ret = trial_counter_update(&trial_state_ctr);
+	if (ret)
+		log_err("Unable to initialise TrialStateCtr\n");
+
+	return ret;
+}
+
 static int fwu_boottime_checks(void *ctx, struct event *event)
+
 {
 	int ret;
 	struct udevice *dev;
-- 
2.34.1


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

* [PATCH v11 11/15] FWU: cmd: Add a command to read FWU metadata
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (9 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 10/15] FWU: Add support for the FWU Multi Bank Update feature Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 12/15] test: dm: Add test cases for FWU Metadata uclass Sughosh Ganu
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
---
Changes since V10: None

 cmd/Kconfig                 |  6 +++
 cmd/Makefile                |  1 +
 cmd/fwu_mdata.c             | 79 +++++++++++++++++++++++++++++++++++++
 doc/usage/cmd/fwu_mdata.rst | 43 ++++++++++++++++++++
 doc/usage/index.rst         |  1 +
 5 files changed, 130 insertions(+)
 create mode 100644 cmd/fwu_mdata.c
 create mode 100644 doc/usage/cmd/fwu_mdata.rst

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 0e0be94f41..af070b5459 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -161,6 +161,12 @@ 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
+	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 6e87522b62..ff6e160f4a 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..725b4c17d3
--- /dev/null
+++ b/cmd/fwu_mdata.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * 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;
+
+	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);
+
+	printf("\tImage Info\n");
+	for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; 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 < CONFIG_FWU_NUM_BANKS; j++) {
+			img_info = &img_entry->img_bank_info[j];
+			printf("Image Guid:  %pUL\n", &img_info->image_uuid);
+			printf("Image Acceptance: %s\n",
+			       img_info->accepted == 0x1 ? "yes" : "no");
+		}
+	}
+}
+
+int do_fwu_mdata_read(struct cmd_tbl *cmdtp, int flag,
+		     int argc, char * const argv[])
+{
+	struct udevice *dev;
+	int ret = CMD_RET_SUCCESS, res;
+	struct fwu_mdata mdata = { 0 };
+
+	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
+		log_err("Unable to get FWU metadata device\n");
+		return CMD_RET_FAILURE;
+	}
+
+	res = fwu_mdata_check(dev);
+	if (res < 0) {
+		log_err("FWU Metadata check failed\n");
+		ret = CMD_RET_FAILURE;
+		goto out;
+	}
+
+	res = fwu_get_mdata(dev, &mdata);
+	if (res < 0) {
+		log_err("Unable to get valid FWU metadata\n");
+		ret = CMD_RET_FAILURE;
+		goto out;
+	}
+
+	print_mdata(&mdata);
+
+out:
+	return ret;
+}
+
+U_BOOT_CMD(
+	fwu_mdata_read,	1,	1,	do_fwu_mdata_read,
+	"Read and print FWU metadata",
+	""
+);
diff --git a/doc/usage/cmd/fwu_mdata.rst b/doc/usage/cmd/fwu_mdata.rst
new file mode 100644
index 0000000000..ea3c22724a
--- /dev/null
+++ b/doc/usage/cmd/fwu_mdata.rst
@@ -0,0 +1,43 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+fwu_mdata_read command
+======================
+
+Synopsis
+--------
+
+::
+
+    fwu_mdata_read
+
+Description
+-----------
+
+The fwu_mdata_read command is used to read the FWU metadata
+structure. The command prints out information about the current active
+bank, the previous active bank, image GUIDs, image acceptance etc.
+
+The output may look like:
+
+::
+
+    => fwu_mdata_read
+            FWU Metadata
+    crc32: 0xec4fb997
+    version: 0x1
+    active_index: 0x0
+    previous_active_index: 0x1
+            Image Info
+
+    Image Type Guid: 19D5DF83-11B0-457B-BE2C-7559C13142A5
+    Location Guid: 49272BEB-8DD8-46DF-8D75-356C65EFF417
+    Image Guid:  D57428CC-BB9A-42E0-AA36-3F5A132059C7
+    Image Acceptance: yes
+    Image Guid:  2BE37D6D-8281-4938-BD7B-9A5BBF80869F
+    Image Acceptance: yes
+
+Configuration
+-------------
+
+To use the fwu_mdata_read command, CONFIG_CMD_FWU_METADATA needs to be
+enabled.
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index f1beeec59c..5b21451f6a 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -45,6 +45,7 @@ Shell commands
    cmd/fatload
    cmd/fdt
    cmd/for
+   cmd/fwu_mdata
    cmd/gpio
    cmd/load
    cmd/loadm
-- 
2.34.1


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

* [PATCH v11 12/15] test: dm: Add test cases for FWU Metadata uclass
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (10 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 11/15] FWU: cmd: Add a command to read FWU metadata Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 13/15] mkeficapsule: Add support for generating empty capsules Sughosh Ganu
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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 test cases for accessing the FWU Metadata on the sandbox
platform. The sandbox platform also uses the metadata access driver
for GPT partitioned block devices.

The FWU feature will be tested on the sandbox64 variant with a raw
capsule. Remove the FIT capsule testing from sandbox64 defconfig --
the FIT capsule test will be run on the sandbox_flattree variant.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Suggested-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
Changes since V10: None

 arch/sandbox/Kconfig                          |   6 +
 arch/sandbox/dts/test.dts                     |   7 +-
 board/sandbox/sandbox.c                       |   8 +
 configs/sandbox64_defconfig                   |   5 +-
 lib/fwu_updates/fwu.c                         |   6 +
 test/dm/Makefile                              |   1 +
 test/dm/fwu_mdata.c                           | 149 ++++++++++++++++++
 test/dm/fwu_mdata_disk_image.h                | 112 +++++++++++++
 .../test_capsule_firmware_fit.py              |   1 -
 .../test_capsule_firmware_signed_fit.py       |   1 -
 tools/Makefile                                |   2 +-
 11 files changed, 293 insertions(+), 5 deletions(-)
 create mode 100644 test/dm/fwu_mdata.c
 create mode 100644 test/dm/fwu_mdata_disk_image.h

diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 852a7c8bf2..40cdea7d46 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 2761588f0d..2cba13e98d 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -948,7 +948,7 @@
 	};
 
 	/* This is used for the fastboot tests */
-	mmc0 {
+	mmc0: mmc0 {
 		compatible = "sandbox,mmc";
 	};
 
@@ -1683,6 +1683,11 @@
 			compatible = "sandbox,regmap_test";
 		};
 	};
+
+	fwu-mdata {
+		compatible = "u-boot,fwu-mdata-gpt";
+		fwu-mdata-store = <&mmc0>;
+	};
 };
 
 #include "sandbox_pmic.dtsi"
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
index ca9a2ca5b1..c3d0c35444 100644
--- a/board/sandbox/sandbox.c
+++ b/board/sandbox/sandbox.c
@@ -164,3 +164,11 @@ int init_addr_map(void)
 
 	return 0;
 }
+
+#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
+void fwu_plat_get_bootidx(uint *boot_idx)
+{
+	/* Dummy value */
+	*boot_idx = 0;
+}
+#endif
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index 290d1506c2..8d456e33d9 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -242,9 +242,12 @@ 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_CAPSULE_FIRMWARE_RAW=y
 CONFIG_EFI_SECURE_BOOT=y
 CONFIG_TEST_FDTDEC=y
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
+CONFIG_FWU_MDATA=y
+CONFIG_FWU_MDATA_GPT_BLK=y
+CONFIG_FWU_MULTI_BANK_UPDATE=y
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index 5c0c209e2c..694cacc6b6 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -550,6 +550,12 @@ static int fwu_boottime_checks(void *ctx, struct event *event)
 	struct udevice *dev;
 	u32 boot_idx, active_idx;
 
+	/* Don't have boot time checks on sandbox */
+	if (IS_ENABLED(CONFIG_SANDBOX)) {
+		boottime_check = 1;
+		return 0;
+	}
+
 	ret = fwu_get_dev_mdata(&dev, NULL);
 	if (ret)
 		return ret;
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 7543df8823..40c2287b56 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -47,6 +47,7 @@ ifneq ($(CONFIG_EFI_PARTITION),)
 obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fastboot.o
 endif
 obj-$(CONFIG_FIRMWARE) += firmware.o
+obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata.o
 obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o
 obj-$(CONFIG_DM_I2C) += i2c.o
 obj-$(CONFIG_SOUND) += i2s.o
diff --git a/test/dm/fwu_mdata.c b/test/dm/fwu_mdata.c
new file mode 100644
index 0000000000..3401fb64d5
--- /dev/null
+++ b/test/dm/fwu_mdata.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Linaro Limited
+ * Copyright (c) 2022, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+
+#include <blk.h>
+#include <common.h>
+#include <dm.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <part.h>
+
+#include <dm/test.h>
+#include <test/ut.h>
+
+#include "fwu_mdata_disk_image.h"
+
+/* Block size of compressed disk image */
+#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
+
+static struct udevice *mmc_dev;
+static struct blk_desc *dev_desc;
+
+/* One 8 byte block of the compressed disk image */
+struct line {
+	size_t addr;
+	char *line;
+};
+
+/* Compressed disk image */
+struct compressed_disk_image {
+	size_t length;
+	struct line lines[];
+};
+
+static const struct compressed_disk_image img = FWU_MDATA_DISK_IMG;
+
+/* Decompressed disk image */
+static u8 *image;
+
+static int setup_blk_device(struct unit_test_state *uts)
+{
+	ut_assertok(uclass_get_device(UCLASS_MMC, 0, &mmc_dev));
+	ut_assertok(blk_get_device_by_str("mmc", "0", &dev_desc));
+
+	return 0;
+}
+
+static int populate_mmc_disk_image(struct unit_test_state *uts)
+{
+	u8 *buf;
+	size_t i;
+	size_t addr;
+	size_t len;
+
+	buf = malloc(img.length);
+	if (!buf)
+		return -ENOMEM;
+
+	memset(buf, 0, img.length);
+
+	for (i = 0; ; i++) {
+		if (!img.lines[i].line)
+			break;
+		addr = img.lines[i].addr;
+		len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
+		if (addr + len > img.length)
+			len = img.length - addr;
+		memcpy(buf + addr, img.lines[i].line, len);
+	}
+	image = buf;
+
+	return 0;
+}
+
+static int write_mmc_blk_device(struct unit_test_state *uts)
+{
+	lbaint_t blkcnt;
+
+	blkcnt = BLOCK_CNT(img.length, dev_desc);
+
+	ut_asserteq(blkcnt, blk_dwrite(dev_desc, 0, blkcnt, image));
+
+	return 0;
+}
+
+static int dm_test_fwu_mdata_read(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	struct fwu_mdata mdata = { 0 };
+
+	ut_assertok(uclass_first_device(UCLASS_FWU_MDATA, &dev));
+	ut_assertok(setup_blk_device(uts));
+	ut_assertok(populate_mmc_disk_image(uts));
+	ut_assertok(write_mmc_blk_device(uts));
+
+	ut_assertok(fwu_get_mdata(dev, &mdata));
+
+	ut_asserteq(mdata.version, 0x1);
+
+	return 0;
+}
+DM_TEST(dm_test_fwu_mdata_read, UT_TESTF_SCAN_FDT);
+
+static int dm_test_fwu_mdata_write(struct unit_test_state *uts)
+{
+	u32 active_idx;
+	struct udevice *dev;
+	struct fwu_mdata mdata = { 0 };
+
+	ut_assertok(setup_blk_device(uts));
+	ut_assertok(populate_mmc_disk_image(uts));
+	ut_assertok(write_mmc_blk_device(uts));
+
+	ut_assertok(uclass_first_device(UCLASS_FWU_MDATA, &dev));
+	ut_assertnonnull(dev);
+
+	ut_assertok(fwu_get_mdata(dev, &mdata));
+
+	active_idx = (mdata.active_index + 1) % CONFIG_FWU_NUM_BANKS;
+	ut_assertok(fwu_set_active_index(active_idx));
+
+	ut_assertok(fwu_get_mdata(dev, &mdata));
+	ut_asserteq(mdata.active_index, active_idx);
+
+	return 0;
+}
+DM_TEST(dm_test_fwu_mdata_write, UT_TESTF_SCAN_FDT);
+
+static int dm_test_fwu_mdata_check(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(setup_blk_device(uts));
+	ut_assertok(populate_mmc_disk_image(uts));
+	ut_assertok(write_mmc_blk_device(uts));
+
+	ut_assertok(uclass_first_device(UCLASS_FWU_MDATA, &dev));
+	ut_assertnonnull(dev);
+
+	ut_assertok(fwu_mdata_check(dev));
+
+	return 0;
+}
+DM_TEST(dm_test_fwu_mdata_check, UT_TESTF_SCAN_FDT);
diff --git a/test/dm/fwu_mdata_disk_image.h b/test/dm/fwu_mdata_disk_image.h
new file mode 100644
index 0000000000..b9803417c8
--- /dev/null
+++ b/test/dm/fwu_mdata_disk_image.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ *  Non-zero 8 byte strings of a disk image
+ *
+ *  Generated with tools/file2include
+ */
+
+#define FWU_MDATA_DISK_IMG { 0x00010000, { \
+	{0x000001c0, "\x02\x00\xee\x02\x02\x00\x01\x00"}, /* ........ */ \
+	{0x000001c8, "\x00\x00\x7f\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x000001f8, "\x00\x00\x00\x00\x00\x00\x55\xaa"}, /* ......U. */ \
+	{0x00000200, "\x45\x46\x49\x20\x50\x41\x52\x54"}, /* EFI PART */ \
+	{0x00000208, "\x00\x00\x01\x00\x5c\x00\x00\x00"}, /* ....\... */ \
+	{0x00000210, "\xa6\xf6\x92\x20\x00\x00\x00\x00"}, /* ... .... */ \
+	{0x00000218, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00000220, "\x7f\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00000228, "\x22\x00\x00\x00\x00\x00\x00\x00"}, /* "....... */ \
+	{0x00000230, "\x5e\x00\x00\x00\x00\x00\x00\x00"}, /* ^....... */ \
+	{0x00000238, "\xde\x99\xa2\x7e\x46\x34\xeb\x47"}, /* ...~F4.G */ \
+	{0x00000240, "\x87\xf6\x4f\x75\xe8\xd5\x7d\xc7"}, /* ..Ou..}. */ \
+	{0x00000248, "\x02\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00000250, "\x80\x00\x00\x00\x80\x00\x00\x00"}, /* ........ */ \
+	{0x00000258, "\x2a\x64\x03\x83\x00\x00\x00\x00"}, /* .d...... */ \
+	{0x00000400, "\xa0\x84\x7a\x8a\x87\x83\xf6\x40"}, /* ..z....@ */ \
+	{0x00000408, "\xab\x41\xa8\xb9\xa5\xa6\x0d\x23"}, /* .A.....# */ \
+	{0x00000410, "\x3d\x6c\xb9\xaa\x20\xb2\x18\x4c"}, /* =l.. ..L */ \
+	{0x00000418, "\xbc\x87\x1c\x9f\xe0\x35\x9b\x73"}, /* .....5.s */ \
+	{0x00000420, "\x22\x00\x00\x00\x00\x00\x00\x00"}, /* "....... */ \
+	{0x00000428, "\x31\x00\x00\x00\x00\x00\x00\x00"}, /* 1....... */ \
+	{0x00000438, "\x55\x00\x6e\x00\x6b\x00\x6e\x00"}, /* U.n.k.n. */ \
+	{0x00000440, "\x6f\x00\x77\x00\x6e\x00\x00\x00"}, /* o.w.n... */ \
+	{0x00000480, "\xa0\x84\x7a\x8a\x87\x83\xf6\x40"}, /* ..z....@ */ \
+	{0x00000488, "\xab\x41\xa8\xb9\xa5\xa6\x0d\x23"}, /* .A.....# */ \
+	{0x00000490, "\x57\x24\xf6\xe6\x0b\x6f\x66\x4e"}, /* W$...ofN */ \
+	{0x00000498, "\xb3\xd5\x99\x50\xa5\xc6\x4e\xc1"}, /* ...P..N. */ \
+	{0x000004a0, "\x32\x00\x00\x00\x00\x00\x00\x00"}, /* 2....... */ \
+	{0x000004a8, "\x41\x00\x00\x00\x00\x00\x00\x00"}, /* A....... */ \
+	{0x000004b8, "\x55\x00\x6e\x00\x6b\x00\x6e\x00"}, /* U.n.k.n. */ \
+	{0x000004c0, "\x6f\x00\x77\x00\x6e\x00\x00\x00"}, /* o.w.n... */ \
+	{0x00004400, "\x4e\xd5\x3f\x43\x01\x00\x00\x00"}, /* N.?C.... */ \
+	{0x00004408, "\x00\x00\x00\x00\x01\x00\x00\x00"}, /* ........ */ \
+	{0x00004410, "\x52\xcf\xd7\x09\x20\x07\x10\x47"}, /* R... ..G */ \
+	{0x00004418, "\x91\xd1\x08\x46\x9b\x7f\xe9\xc8"}, /* ...F.... */ \
+	{0x00004420, "\xeb\x2b\x27\x49\xd8\x8d\xdf\x46"}, /* .+'I...F */ \
+	{0x00004428, "\x8d\x75\x35\x6c\x65\xef\xf4\x17"}, /* .u5le... */ \
+	{0x00004430, "\x86\x7a\x05\x10\xf1\xda\x93\x4f"}, /* .z.....O */ \
+	{0x00004438, "\xba\x7f\xb1\x95\xf7\xfa\x41\x70"}, /* ......Ap */ \
+	{0x00004440, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00004448, "\x3e\xed\x62\xdb\x37\x62\xb4\x4f"}, /* >.b.7b.O */ \
+	{0x00004450, "\x80\xc4\x1b\x74\xd8\x46\xa8\xe7"}, /* ...t.F.. */ \
+	{0x00004458, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00004460, "\xf5\x21\x70\x5a\xf2\xfe\xb4\x48"}, /* .!pZ...H */ \
+	{0x00004468, "\xaa\xba\x83\x2e\x77\x74\x18\xc0"}, /* ....wt.. */ \
+	{0x00004470, "\xeb\x2b\x27\x49\xd8\x8d\xdf\x46"}, /* .+'I...F */ \
+	{0x00004478, "\x8d\x75\x35\x6c\x65\xef\xf4\x17"}, /* .u5le... */ \
+	{0x00004480, "\x3b\x0e\xd2\x0b\x9f\xab\x86\x49"}, /* ;......I */ \
+	{0x00004488, "\xb7\x90\x8d\xf3\x9c\x9c\xa3\x82"}, /* ........ */ \
+	{0x00004490, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00004498, "\x6d\xe4\x25\x0e\x15\xb6\xd3\x4c"}, /* m.%....L */ \
+	{0x000044a0, "\x94\xda\x51\x79\x8f\xb1\x9e\xb1"}, /* ..Qy.... */ \
+	{0x000044a8, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00006400, "\x4e\xd5\x3f\x43\x01\x00\x00\x00"}, /* N.?C.... */ \
+	{0x00006408, "\x00\x00\x00\x00\x01\x00\x00\x00"}, /* ........ */ \
+	{0x00006410, "\x52\xcf\xd7\x09\x20\x07\x10\x47"}, /* R... ..G */ \
+	{0x00006418, "\x91\xd1\x08\x46\x9b\x7f\xe9\xc8"}, /* ...F.... */ \
+	{0x00006420, "\xeb\x2b\x27\x49\xd8\x8d\xdf\x46"}, /* .+'I...F */ \
+	{0x00006428, "\x8d\x75\x35\x6c\x65\xef\xf4\x17"}, /* .u5le... */ \
+	{0x00006430, "\x86\x7a\x05\x10\xf1\xda\x93\x4f"}, /* .z.....O */ \
+	{0x00006438, "\xba\x7f\xb1\x95\xf7\xfa\x41\x70"}, /* ......Ap */ \
+	{0x00006440, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00006448, "\x3e\xed\x62\xdb\x37\x62\xb4\x4f"}, /* >.b.7b.O */ \
+	{0x00006450, "\x80\xc4\x1b\x74\xd8\x46\xa8\xe7"}, /* ...t.F.. */ \
+	{0x00006458, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00006460, "\xf5\x21\x70\x5a\xf2\xfe\xb4\x48"}, /* .!pZ...H */ \
+	{0x00006468, "\xaa\xba\x83\x2e\x77\x74\x18\xc0"}, /* ....wt.. */ \
+	{0x00006470, "\xeb\x2b\x27\x49\xd8\x8d\xdf\x46"}, /* .+'I...F */ \
+	{0x00006478, "\x8d\x75\x35\x6c\x65\xef\xf4\x17"}, /* .u5le... */ \
+	{0x00006480, "\x3b\x0e\xd2\x0b\x9f\xab\x86\x49"}, /* ;......I */ \
+	{0x00006488, "\xb7\x90\x8d\xf3\x9c\x9c\xa3\x82"}, /* ........ */ \
+	{0x00006490, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x00006498, "\x6d\xe4\x25\x0e\x15\xb6\xd3\x4c"}, /* m.%....L */ \
+	{0x000064a0, "\x94\xda\x51\x79\x8f\xb1\x9e\xb1"}, /* ..Qy.... */ \
+	{0x000064a8, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x0000be00, "\xa0\x84\x7a\x8a\x87\x83\xf6\x40"}, /* ..z....@ */ \
+	{0x0000be08, "\xab\x41\xa8\xb9\xa5\xa6\x0d\x23"}, /* .A.....# */ \
+	{0x0000be10, "\x3d\x6c\xb9\xaa\x20\xb2\x18\x4c"}, /* =l.. ..L */ \
+	{0x0000be18, "\xbc\x87\x1c\x9f\xe0\x35\x9b\x73"}, /* .....5.s */ \
+	{0x0000be20, "\x22\x00\x00\x00\x00\x00\x00\x00"}, /* "....... */ \
+	{0x0000be28, "\x31\x00\x00\x00\x00\x00\x00\x00"}, /* 1....... */ \
+	{0x0000be38, "\x55\x00\x6e\x00\x6b\x00\x6e\x00"}, /* U.n.k.n. */ \
+	{0x0000be40, "\x6f\x00\x77\x00\x6e\x00\x00\x00"}, /* o.w.n... */ \
+	{0x0000be80, "\xa0\x84\x7a\x8a\x87\x83\xf6\x40"}, /* ..z....@ */ \
+	{0x0000be88, "\xab\x41\xa8\xb9\xa5\xa6\x0d\x23"}, /* .A.....# */ \
+	{0x0000be90, "\x57\x24\xf6\xe6\x0b\x6f\x66\x4e"}, /* W$...ofN */ \
+	{0x0000be98, "\xb3\xd5\x99\x50\xa5\xc6\x4e\xc1"}, /* ...P..N. */ \
+	{0x0000bea0, "\x32\x00\x00\x00\x00\x00\x00\x00"}, /* 2....... */ \
+	{0x0000bea8, "\x41\x00\x00\x00\x00\x00\x00\x00"}, /* A....... */ \
+	{0x0000beb8, "\x55\x00\x6e\x00\x6b\x00\x6e\x00"}, /* U.n.k.n. */ \
+	{0x0000bec0, "\x6f\x00\x77\x00\x6e\x00\x00\x00"}, /* o.w.n... */ \
+	{0x0000fe00, "\x45\x46\x49\x20\x50\x41\x52\x54"}, /* EFI PART */ \
+	{0x0000fe08, "\x00\x00\x01\x00\x5c\x00\x00\x00"}, /* ....\... */ \
+	{0x0000fe10, "\xa2\xce\x23\xfc\x00\x00\x00\x00"}, /* ..#..... */ \
+	{0x0000fe18, "\x7f\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x0000fe20, "\x01\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \
+	{0x0000fe28, "\x22\x00\x00\x00\x00\x00\x00\x00"}, /* "....... */ \
+	{0x0000fe30, "\x5e\x00\x00\x00\x00\x00\x00\x00"}, /* ^....... */ \
+	{0x0000fe38, "\xde\x99\xa2\x7e\x46\x34\xeb\x47"}, /* ...~F4.G */ \
+	{0x0000fe40, "\x87\xf6\x4f\x75\xe8\xd5\x7d\xc7"}, /* ..Ou..}. */ \
+	{0x0000fe48, "\x5f\x00\x00\x00\x00\x00\x00\x00"}, /* _....... */ \
+	{0x0000fe50, "\x80\x00\x00\x00\x80\x00\x00\x00"}, /* ........ */ \
+	{0x0000fe58, "\x2a\x64\x03\x83\x00\x00\x00\x00"}, /* .d...... */ \
+	{0, NULL} } }
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 8f75b554ad..d28b53a1a1 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_efi_capsule/test_capsule_firmware_signed_fit.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed_fit.py
index d6ca9b1674..8c2d616fd0 100644
--- a/test/py/tests/test_efi_capsule/test_capsule_firmware_signed_fit.py
+++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed_fit.py
@@ -14,7 +14,6 @@ with signed capsule files containing FIT images
 import pytest
 from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
 
-@pytest.mark.boardspec('sandbox64')
 @pytest.mark.boardspec('sandbox_flattree')
 @pytest.mark.buildconfigspec('efi_capsule_firmware_fit')
 @pytest.mark.buildconfigspec('efi_capsule_authenticate')
diff --git a/tools/Makefile b/tools/Makefile
index 3626919633..c479d3cb4c 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -74,7 +74,7 @@ mkenvimage-objs := mkenvimage.o os_support.o lib/crc32.o
 hostprogs-y += dumpimage mkimage
 hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fit_info fit_check_sign
 
-hostprogs-$(CONFIG_CMD_BOOTEFI_SELFTEST) += file2include
+hostprogs-$(CONFIG_CMD_BOOTEFI_SELFTEST)$(CONFIG_FWU_MDATA_GPT_BLK) += file2include
 
 FIT_OBJS-y := fit_common.o fit_image.o image-host.o boot/image-fit.o
 FIT_SIG_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := image-sig-host.o boot/image-fit-sig.o
-- 
2.34.1


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

* [PATCH v11 13/15] mkeficapsule: Add support for generating empty capsules
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (11 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 12/15] test: dm: Add test cases for FWU Metadata uclass Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 14/15] mkeficapsule: Add support for setting OEM flags in capsule header Sughosh Ganu
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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>
---
Changes since V10: None

 doc/mkeficapsule.1   | 29 +++++++++----
 tools/eficapsule.h   |  8 ++++
 tools/mkeficapsule.c | 96 ++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 119 insertions(+), 14 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..25bfb39e5b 100644
--- a/tools/mkeficapsule.c
+++ b/tools/mkeficapsule.c
@@ -29,7 +29,13 @@ 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";
+
+enum {
+	CAPSULE_NORMAL_BLOB = 0,
+	CAPSULE_ACCEPT,
+	CAPSULE_REVERT,
+} capsule_type;
 
 static struct option options[] = {
 	{"guid", required_argument, NULL, 'g'},
@@ -39,6 +45,8 @@ 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},
 };
@@ -55,6 +63,8 @@ static void print_usage(void)
 		"\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, requires GUID, no image blob\n"
+		"\t-R, --fw-revert  firmware revert capsule, takes no GUID, no image blob\n"
 		"\t-h, --help                  print a help message\n",
 		tool_name);
 }
@@ -564,6 +574,49 @@ 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 = { 0 };
+	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 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) {
+		if (write_capsule_file(f, guid, sizeof(*guid),
+				       "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
@@ -592,6 +645,7 @@ int main(int argc, char **argv)
 	privkey_file = NULL;
 	cert_file = NULL;
 	dump_sig = 0;
+	capsule_type = CAPSULE_NORMAL_BLOB;
 	for (;;) {
 		c = getopt_long(argc, argv, opts_short, options, &idx);
 		if (c == -1)
@@ -639,22 +693,50 @@ int main(int argc, char **argv)
 		case 'd':
 			dump_sig = 1;
 			break;
-		case 'h':
+		case 'A':
+			if (capsule_type) {
+				fprintf(stderr,
+					"Select either of Accept or Revert capsule generation\n");
+				exit(1);
+			}
+			capsule_type = CAPSULE_ACCEPT;
+			break;
+		case 'R':
+			if (capsule_type) {
+				fprintf(stderr,
+					"Select either of Accept or Revert capsule generation\n");
+				exit(1);
+			}
+			capsule_type = CAPSULE_REVERT;
+			break;
+		default:
 			print_usage();
 			exit(EXIT_SUCCESS);
 		}
 	}
 
 	/* check necessary parameters */
-	if ((argc != optind + 2) || !guid ||
-	    ((privkey_file && !cert_file) ||
-	     (!privkey_file && cert_file))) {
+	if ((capsule_type == CAPSULE_NORMAL_BLOB &&
+	    ((argc != optind + 2) || !guid ||
+	     ((privkey_file && !cert_file) ||
+	      (!privkey_file && cert_file)))) ||
+	    (capsule_type != CAPSULE_NORMAL_BLOB &&
+	    ((argc != optind + 1) ||
+	     ((capsule_type == CAPSULE_ACCEPT) && !guid) ||
+	     ((capsule_type == 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 (capsule_type != CAPSULE_NORMAL_BLOB) {
+		if (create_empty_capsule(argv[argc - 1], guid,
+					 capsule_type == 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.34.1


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

* [PATCH v11 14/15] mkeficapsule: Add support for setting OEM flags in capsule header
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (12 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 13/15] mkeficapsule: Add support for generating empty capsules Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-28  9:29 ` [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature Sughosh Ganu
  2022-10-02 23:50 ` [PATCHv2 0/5] FWU: Add support for mtd backed feature on DeveloperBox jassisinghbrar
  15 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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 support for setting OEM flags in the capsule header. As per the
UEFI specification, bits 0-15 of the flags member of the capsule
header can be defined per capsule GUID.

The oemflags will be used for the FWU Multi Bank update feature, as
specified by the Dependable Boot specification[1]. Bit
15 of the flags member will be used to determine if the
acceptance/rejection of the updated images is to be done by the
firmware or an external component like the OS.

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

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
Changes since V10: None

 doc/mkeficapsule.1   |  4 ++++
 tools/mkeficapsule.c | 17 ++++++++++++++---
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
index 77ca061efd..6fb2dd0810 100644
--- a/doc/mkeficapsule.1
+++ b/doc/mkeficapsule.1
@@ -72,6 +72,10 @@ Generate a firmware acceptance empty capsule
 .BI "-R\fR,\fB --fw-revert "
 Generate a firmware revert empty capsule
 
+.TP
+.BI "-o\fR,\fB --capoemflag "
+Capsule OEM flag, value between 0x0000 to 0xffff
+
 .TP
 .BR -h ", " --help
 Print a help message
diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
index 25bfb39e5b..b24f873b48 100644
--- a/tools/mkeficapsule.c
+++ b/tools/mkeficapsule.c
@@ -29,7 +29,7 @@ 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:dhAR";
+static const char *opts_short = "g:i:I:v:p:c:m:o:dhAR";
 
 enum {
 	CAPSULE_NORMAL_BLOB = 0,
@@ -47,6 +47,7 @@ static struct option options[] = {
 	{"dump-sig", no_argument, NULL, 'd'},
 	{"fw-accept", no_argument, NULL, 'A'},
 	{"fw-revert", no_argument, NULL, 'R'},
+	{"capoemflag", required_argument, NULL, 'o'},
 	{"help", no_argument, NULL, 'h'},
 	{NULL, 0, NULL, 0},
 };
@@ -65,6 +66,7 @@ static void print_usage(void)
 		"\t-d, --dump_sig              dump signature (*.p7)\n"
 		"\t-A, --fw-accept  firmware accept capsule, requires GUID, no image blob\n"
 		"\t-R, --fw-revert  firmware revert capsule, takes no GUID, no image blob\n"
+		"\t-o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff\n"
 		"\t-h, --help                  print a help message\n",
 		tool_name);
 }
@@ -387,6 +389,7 @@ static void free_sig_data(struct auth_context *ctx)
  * @mcount:	Monotonic count in authentication information
  * @private_file:	Path to a private key file
  * @cert_file:	Path to a certificate file
+ * @oemflags:  Capsule OEM Flags, bits 0-15
  *
  * This function actually does the job of creating an uefi capsule file.
  * All the arguments must be supplied.
@@ -399,7 +402,8 @@ static void free_sig_data(struct auth_context *ctx)
  */
 static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
 			unsigned long index, unsigned long instance,
-			uint64_t mcount, char *privkey_file, char *cert_file)
+			uint64_t mcount, char *privkey_file, char *cert_file,
+			uint16_t oemflags)
 {
 	struct efi_capsule_header header;
 	struct efi_firmware_management_capsule_header capsule;
@@ -464,6 +468,8 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
 	header.header_size = sizeof(header);
 	/* TODO: The current implementation ignores flags */
 	header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
+	if (oemflags)
+		header.flags |= oemflags;
 	header.capsule_image_size = sizeof(header)
 					+ sizeof(capsule) + sizeof(uint64_t)
 					+ sizeof(image)
@@ -635,6 +641,7 @@ int main(int argc, char **argv)
 	unsigned char uuid_buf[16];
 	unsigned long index, instance;
 	uint64_t mcount;
+	uint16_t oemflags;
 	char *privkey_file, *cert_file;
 	int c, idx;
 
@@ -646,6 +653,7 @@ int main(int argc, char **argv)
 	cert_file = NULL;
 	dump_sig = 0;
 	capsule_type = CAPSULE_NORMAL_BLOB;
+	oemflags = 0;
 	for (;;) {
 		c = getopt_long(argc, argv, opts_short, options, &idx);
 		if (c == -1)
@@ -709,6 +717,9 @@ int main(int argc, char **argv)
 			}
 			capsule_type = CAPSULE_REVERT;
 			break;
+		case 'o':
+			oemflags = strtoul(optarg, NULL, 0);
+			break;
 		default:
 			print_usage();
 			exit(EXIT_SUCCESS);
@@ -736,7 +747,7 @@ int main(int argc, char **argv)
 		}
 	} else 	if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
 				 index, instance, mcount, privkey_file,
-				 cert_file) < 0) {
+				 cert_file, oemflags) < 0) {
 		fprintf(stderr, "Creating firmware capsule failed\n");
 		exit(EXIT_FAILURE);
 	}
-- 
2.34.1


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

* [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (13 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 14/15] mkeficapsule: Add support for setting OEM flags in capsule header Sughosh Ganu
@ 2022-09-28  9:29 ` Sughosh Ganu
  2022-09-30  6:27   ` Etienne Carriere
  2022-10-04  2:54   ` Takahiro Akashi
  2022-10-02 23:50 ` [PATCHv2 0/5] FWU: Add support for mtd backed feature on DeveloperBox jassisinghbrar
  15 siblings, 2 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-28  9: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 documentation 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>
---
Changes since V10:
* Fix review comments suggested by Etienne
* Add a paragraph in the capsule update section to highlight the
  difference in ImageIndex correlation with DFU alt num with FWU feature
  enabled

 doc/develop/uefi/fwu_updates.rst | 173 +++++++++++++++++++++++++++++++
 doc/develop/uefi/index.rst       |   1 +
 doc/develop/uefi/uefi.rst        |  10 ++
 3 files changed, 184 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..292feceb9a
--- /dev/null
+++ b/doc/develop/uefi/fwu_updates.rst
@@ -0,0 +1,173 @@
+.. 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 its 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-gpt.yaml>`__
+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_RAW=y
+
+    CONFIG_FWU_MULTI_BANK_UPDATE=y
+    CONFIG_CMD_FWU_METADATA=y
+    CONFIG_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 configuration settings 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, a GPT partitioned storage
+device is required. 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 a 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 partitions 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. An example list of images on the storage medium would be
+
+* FWU metadata 1
+* U-Boot 1
+* OP-TEE 1
+* FWU metadata 2
+* OP-TEE 2
+* U-Boot 2
+* ESP
+* rootfs
+
+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 specification 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.
+
+The task of accepting the different firmware images, post an update
+may be done by multiple, separate components in the Operating
+System. To help identify the firmware image that is being accepted,
+the accept capsule passes the image GUID of the firmware image being
+accepted. The relevant code in U-Boot then sets the Accept bit of the
+corresponding firmware image for which the accept capsule was
+found. Only when all the firmware components in a bank have been
+accepted does the platform transition from trial state to regular
+state.
+
+The revert capsule on the other hand does not pass any image GUID,
+since reverting any image of the bank has the same result of the
+platform booting from the other bank on subsequent boot.
+
+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>
+
+Some examples of using the mkeficapsule tool for generation of the
+empty capsule would be::
+
+.. code-block:: bash
+
+    $ ./tools/mkeficapsule --fw-accept --guid <image guid> \
+    <accept_capsule_name>
+    $ ./tools/mkeficapsule --fw-revert <revert_capsule_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..b5c83db65a 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
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -377,6 +379,14 @@ following command::
 
     dfu list
 
+When the FWU Multi Bank Update feature is enabled on the platform, the
+image index is used only to identify the image index with the image
+GUID. The image index would not correspond to the dfu alt number. This
+is because the FWU feature supports multiple partitions(banks) of
+updatable images, and the actual dfu alt number to which the image is
+to be written to is determined at runtime, based on the value of the
+update bank to which the image is to be written.
+
 When using the FMP for FIT images, the image index value needs to be
 set to 1.
 
-- 
2.34.1


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

* Re: [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates
  2022-09-28  9:29 ` [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates Sughosh Ganu
@ 2022-09-30  5:51   ` Etienne Carriere
  2022-10-03 10:56   ` Takahiro Akashi
  1 sibling, 0 replies; 49+ messages in thread
From: Etienne Carriere @ 2022-09-30  5:51 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 Wed, 28 Sept 2022 at 11:30, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> 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>
> Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> ---

Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org> with 1 comment:

Could the commit header line be updated? the patch no more targets
only DK2 among stm32mp1 platforms:
- stm32mp1: dk2: Add image information for capsule updates
+stm32mp1: Add image information for capsule updates

Regards,
Etienne


> Changes since V10:
> * Use image_index value of 1 for the FIP image as it is now relevant
>
>  board/st/stm32mp1/stm32mp1.c       | 18 ++++++++++++++++++
>  include/configs/stm32mp15_common.h |  4 ++++
>  2 files changed, 22 insertions(+)
>
> diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> index 8c162b42a5..e43dab018f 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>
> @@ -87,6 +88,16 @@
>  #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 */
> @@ -666,6 +677,13 @@ int board_init(void)
>
>         setup_led(LEDST_ON);
>
> +#if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
> +       efi_guid_t image_type_guid = STM32MP_FIP_IMAGE_GUID;
> +
> +       guidcpy(&fw_images[0].image_type_id, &image_type_guid);
> +       fw_images[0].fw_name = u"STM32MP-FIP";
> +       fw_images[0].image_index = 1;
> +#endif
>         return 0;
>  }
>
> diff --git a/include/configs/stm32mp15_common.h b/include/configs/stm32mp15_common.h
> index c5412ffeb3..bb19dae945 100644
> --- a/include/configs/stm32mp15_common.h
> +++ b/include/configs/stm32mp15_common.h
> @@ -34,6 +34,10 @@
>  #define CONFIG_SERVERIP                 192.168.1.1
>  #endif
>
> +#define STM32MP_FIP_IMAGE_GUID \
> +       EFI_GUID(0x19d5df83, 0x11b0, 0x457b, 0xbe, 0x2c, \
> +                0x75, 0x59, 0xc1, 0x31, 0x42, 0xa5)
> +
>  /*****************************************************************************/
>  #ifdef CONFIG_DISTRO_DEFAULTS
>  /*****************************************************************************/
> --
> 2.34.1
>

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

* Re: [PATCH v11 02/15] FWU: Add FWU metadata structure and driver for accessing metadata
  2022-09-28  9:29 ` [PATCH v11 02/15] FWU: Add FWU metadata structure and driver for accessing metadata Sughosh Ganu
@ 2022-09-30  5:54   ` Etienne Carriere
  2022-10-03  6:27     ` Sughosh Ganu
  0 siblings, 1 reply; 49+ messages in thread
From: Etienne Carriere @ 2022-09-30  5: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 Wed, 28 Sept 2022 at 11: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>
> Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
> ---
> Changes since V10:
> * s/fwu_update_active_index/fwu_set_active_index as per comment from
>   Jassi
> * Change the argument type of fwu_set_active_index() to uint from u32
>   as per comment from Jassi
> * s/mdata_check/check_mdata as per comment from Jassi
> * Fix the typo in the function comment of fwu_mdata_check()
>
>  drivers/fwu-mdata/fwu-mdata-uclass.c | 107 ++++++++
>  include/dm/uclass-id.h               |   1 +
>  include/fwu.h                        | 211 ++++++++++++++++
>  include/fwu_mdata.h                  |  67 +++++
>  lib/fwu_updates/fwu.c                | 363 +++++++++++++++++++++++++++
>  5 files changed, 749 insertions(+)
>  create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
>  create mode 100644 include/fwu.h
>  create mode 100644 include/fwu_mdata.h
>  create mode 100644 lib/fwu_updates/fwu.c
>
> diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c
> new file mode 100644
> index 0000000000..4237b89520
> --- /dev/null
> +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c
> @@ -0,0 +1,107 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#define LOG_CATEGORY UCLASS_FWU_MDATA
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <efi_loader.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <log.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <u-boot/crc.h>
> +
> +/**
> + * fwu_mdata_check() - Check if the FWU metadata is valid
> + * @dev: FWU metadata device
> + *
> + * Validate both copies of the FWU metadata. If one of the copies
> + * has gone bad, restore it from the other copy.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_mdata_check(struct udevice *dev)
> +{
> +       const struct fwu_mdata_ops *ops = device_get_ops(dev);
> +
> +       if (!ops->check_mdata) {
> +               log_debug("check_mdata() method not defined\n");
> +               return -ENOSYS;
> +       }
> +
> +       return ops->check_mdata(dev);
> +}
> +
> +/**
> + * fwu_get_mdata() - Get a FWU metadata copy
> + * @dev: FWU metadata device
> + * @mdata: Copy of the FWU metadata
> + *
> + * Get a valid copy of the FWU metadata.
> + *
> + * Note: This function is to be called first when modifying any fields
> + * in the metadata. The sequence of calls to modify any field in the
> + * metadata would  be 1) fwu_get_mdata 2) Modify metadata, followed by
> + * 3) fwu_update_mdata
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_get_mdata(struct udevice *dev, struct fwu_mdata *mdata)
> +{
> +       const struct fwu_mdata_ops *ops = device_get_ops(dev);
> +
> +       if (!ops->get_mdata) {
> +               log_debug("get_mdata() method not defined\n");
> +               return -ENOSYS;
> +       }
> +
> +       return ops->get_mdata(dev, mdata);
> +}
> +
> +/**
> + * fwu_update_mdata() - Update the FWU metadata
> + * @dev: FWU metadata device
> + * @mdata: Copy of the FWU metadata
> + *
> + * Update the FWU metadata structure by writing to the
> + * FWU metadata partitions.
> + *
> + * Note: This function is not to be called directly to update the
> + * metadata fields. The sequence of function calls should be
> + * 1) fwu_get_mdata() 2) Modify the medata fields 3) fwu_update_mdata()
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_update_mdata(struct udevice *dev, struct fwu_mdata *mdata)
> +{
> +       void *buf;
> +       const struct fwu_mdata_ops *ops = device_get_ops(dev);
> +
> +       if (!ops->update_mdata) {
> +               log_debug("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 a432e43871..598a8c10a0 100644
> --- a/include/dm/uclass-id.h
> +++ b/include/dm/uclass-id.h
> @@ -58,6 +58,7 @@ enum uclass_id {
>         UCLASS_FIRMWARE,        /* Firmware */
>         UCLASS_FUZZING_ENGINE,  /* Fuzzing engine */
>         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..a4d2d35d9a
> --- /dev/null
> +++ b/include/fwu.h
> @@ -0,0 +1,211 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * 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 {
> +       /**
> +        * check_mdata() - Check if the FWU metadata is valid
> +        * @dev:        FWU device
> +        *
> +        * Validate both copies of the FWU metadata. If one of the copies
> +        * has gone bad, restore it from the other copy.
> +        *
> +        * Return: 0 if OK, -ve on error
> +        */
> +       int (*check_mdata)(struct udevice *dev);
> +
> +       /**
> +        * get_mdata() - Get a FWU metadata copy
> +        * @dev:        FWU device
> +        * @mdata:      Pointer to FWU metadata
> +        *
> +        * Get a valid copy of the FWU metadata.
> +        *
> +        * Return: 0 if OK, -ve on error
> +        */
> +       int (*get_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
> +
> +       /**
> +        * update_mdata() - Update the FWU metadata
> +        * @dev:        FWU device
> +        * @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 (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
> +};
> +
> +#define FWU_MDATA_VERSION      0x1
> +
> +/*
> +* GUID value defined in the FWU specification for identification
> +* of the FWU metadata partition.
> +*/
> +#define FWU_MDATA_GUID \
> +       EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
> +                0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
> +
> +/**
> + * fwu_get_mdata() - Get a FWU metadata copy
> + * @dev: FWU metadata device
> + * @mdata: Copy of the FWU metadata
> + *
> + * Get a valid copy of the FWU metadata.
> + *
> + * Note: This function is to be called first when modifying any fields
> + * in the metadata. The sequence of calls to modify any field in the
> + * metadata would  be 1) fwu_get_mdata 2) Modify metadata, followed by
> + * 3) fwu_update_mdata
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_get_mdata(struct udevice *dev, struct fwu_mdata *mdata);
> +
> +/**
> + * fwu_update_mdata() - Update the FWU metadata
> + * @dev: FWU metadata device
> + * @mdata: Copy of the FWU metadata
> + *
> + * Update the FWU metadata structure by writing to the
> + * FWU metadata partitions.
> + *
> + * Note: This function is not to be called directly to update the
> + * metadata fields. The sequence of function calls should be
> + * 1) fwu_get_mdata() 2) Modify the medata fields 3) fwu_update_mdata()
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_update_mdata(struct udevice *dev, struct fwu_mdata *mdata);
> +
> +/**
> + * fwu_get_active_index() - Get active_index from the FWU metadata
> + * @active_idxp: 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(uint *active_idxp);
> +
> +/**
> + * fwu_set_active_index() - Set active_index in the FWU metadata
> + * @active_idx: active_index value to be set
> + *
> + * Update the active_index field in the FWU metadata
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_set_active_index(uint active_idx);
> +
> +/**
> + * fwu_get_image_index() - Get the Image Index to be used for capsule update
> + * @image_index: The Image Index for the image
> + *
> + * The FWU multi bank update feature computes the value of image_index at
> + * runtime, based on the bank to which the image needs to be written to.
> + * Derive the image_index value for the image.
> + *
> + * Currently, the capsule update driver uses the DFU framework for
> + * the updates. This function gets the DFU alt number which is to
> + * be used as the Image Index
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_get_image_index(u8 *image_index);
> +
> +/**
> + * fwu_mdata_check() - Check if the FWU metadata is valid
> + * @dev: FWU metadata device
> + *
> + * Validate both copies of the FWU metadata. If one of the copies
> + * has gone bad, restore it from the other copy.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_mdata_check(struct udevice *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);
> +
> +/**
> + * 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);
> +
> +/**
> + * 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);
> +
> +/**
> + * 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);
> +
> +#endif /* _FWU_H_ */
> diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h
> new file mode 100644
> index 0000000000..8fda4f4ac2
> --- /dev/null
> +++ b/include/fwu_mdata.h
> @@ -0,0 +1,67 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * 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;
> +};
> +
> +/**
> + * 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];
> +};
> +
> +/**
> + * 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];
> +};
> +
> +#endif /* _FWU_MDATA_H_ */
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> new file mode 100644
> index 0000000000..fe8058bc37
> --- /dev/null
> +++ b/lib/fwu_updates/fwu.c
> @@ -0,0 +1,363 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <dm.h>
> +#include <efi_loader.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <log.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)

Nitpicking: i think an enumerated type would be better here.
(not a strong opinion)

> +
> +static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
> +

Remove this empty line.

> +{
> +       int ret;
> +
> +       ret = uclass_first_device(UCLASS_FWU_MDATA, dev);
> +       if (ret) {
> +               log_debug("Cannot find fwu device\n");
> +               return ret;
> +       }

`uclass_first_device()` returns 0 when node is not found but no issue
reported while parsing the FDT (learned by experience :(. In that
case, *dev is set to NULL and next instruction segfaults.
Proposal:

     ret = uclass_first_device(UCLASS_FWU_MDATA, dev);
-    if (ret) {
+    if (ret || !*dev) {
         log_debug("Cannot find fwu device\n");
+        if (!ret)
+            ret = -ENOENT;
         return ret;
     }



> +
> +       ret = fwu_get_mdata(*dev, mdata);
> +       if (ret < 0)
> +               log_debug("Unable to get valid FWU metadata\n");
> +
> +       return ret;
> +}
> +
> +static int fwu_get_image_type_id(u8 *image_index, efi_guid_t *image_type_id)
> +{
> +       u8 index;
> +       int i;
> +       struct efi_fw_image *image;
> +
> +       index = *image_index;
> +       image = update_info.images;
> +       for (i = 0; i < num_image_type_guids; i++) {
> +               if (index == image[i].image_index) {
> +                       guidcpy(image_type_id, &image[i].image_type_id);
> +                       return 0;
> +               }
> +       }
> +
> +       return -ENOENT;
> +}
> +
> +/**
> + * 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_debug("crc32 check failed for %s FWU metadata partition\n",
> +                         pri_part ? "primary" : "secondary");
> +               return -EINVAL;
> +       }
> +
> +       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(uint *active_idx)
> +{
> +       int ret;
> +       struct udevice *dev;
> +       struct fwu_mdata mdata = { 0 };
> +
> +       ret = fwu_get_dev_mdata(&dev, &mdata);
> +       if (ret)
> +               return ret;
> +
> +       /*
> +        * Found the FWU metadata partition, now read the active_index
> +        * value
> +        */
> +       *active_idx = mdata.active_index;
> +       if (*active_idx >= CONFIG_FWU_NUM_BANKS) {
> +               log_debug("Active index value read is incorrect\n");
> +               ret = -EINVAL;
> +       }
> +
> +       return ret;
> +}
> +
> +/**
> + * fwu_set_active_index() - Set active_index in the FWU metadata
> + * @active_idx: active_index value to be set
> + *
> + * Update the active_index field in the FWU metadata
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_set_active_index(uint active_idx)
> +{
> +       int ret;
> +       struct udevice *dev;
> +       struct fwu_mdata mdata = { 0 };
> +
> +       if (active_idx >= CONFIG_FWU_NUM_BANKS) {
> +               log_debug("Invalid active index value\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = fwu_get_dev_mdata(&dev, &mdata);
> +       if (ret)
> +               return ret;
> +
> +       /*
> +        * 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(dev, &mdata);
> +       if (ret < 0) {

Function description says it returns 0 on success so prefer here 'if (ret)'.

> +               log_debug("Failed to update FWU metadata partitions\n");
> +               ret = -EIO;
> +       }
> +
> +       return ret;
> +}
> +
> +/**
> + * fwu_get_image_index() - Get the Image Index to be used for capsule update
> + * @image_index: The Image Index for the image
> + *
> + * The FWU multi bank update feature computes the value of image_index at
> + * runtime, based on the bank to which the image needs to be written to.
> + * Derive the image_index value for the image.
> + *
> + * Currently, the capsule update driver uses the DFU framework for
> + * the updates. This function gets the DFU alt number which is to
> + * be used as the Image Index
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_get_image_index(u8 *image_index)
> +{
> +       int ret, i;
> +       u8 alt_num;
> +       u32 update_bank;
> +       efi_guid_t *image_guid, image_type_id;
> +       struct udevice *dev;
> +       struct fwu_mdata mdata = { 0 };
> +       struct fwu_image_entry *img_entry;
> +       struct fwu_image_bank_info *img_bank_info;
> +
> +       ret = fwu_get_dev_mdata(&dev, &mdata);
> +       if (ret)
> +               return ret;
> +
> +       ret = fwu_plat_get_update_index(&update_bank);
> +       if (ret) {
> +               log_debug("Failed to get the FWU update bank\n");
> +               goto out;
> +       }
> +
> +       ret = fwu_get_image_type_id(image_index, &image_type_id);
> +       if (ret) {
> +               log_debug("Unable to get image_type_id for image_index %u\n",
> +                         *image_index);
> +               goto out;
> +       }
> +
> +       ret = -EINVAL;
> +       /*
> +        * 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, image_guid, &alt_num);
> +                       if (ret) {
> +                               log_debug("alt_num not found for partition with GUID %pUs\n",
> +                                         image_guid);
> +                       } else {
> +                               log_debug("alt_num %d for partition %pUs\n",
> +                                         alt_num, image_guid);
> +                               *image_index = alt_num + 1;
> +                       }
> +
> +                       goto out;
> +               }
> +       }
> +
> +       log_debug("Partition with the image type %pUs not found\n",
> +                 &image_type_id);
> +
> +out:
> +       return ret;
> +}
> +
> +/**
> + * 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 udevice *dev;
> +       struct fwu_mdata mdata = { 0 };
> +
> +       ret = fwu_get_dev_mdata(&dev, &mdata);
> +       if (ret)
> +               return ret;
> +
> +       /*
> +        * 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(dev, &mdata);
> +       if (ret < 0) {

Same comment here: error case should be trapped with 'if (ret)'.

br,
etienne

> +               log_debug("Failed to update FWU metadata partitions\n");
> +               ret = -EIO;
> +       }
> +
> +       return ret;
> +}
> +
> +/**
> + * fwu_clrset_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_clrset_image_accept(efi_guid_t *img_type_id, u32 bank, u8 action)
> +{
> +       int ret, i;
> +       struct udevice *dev;
> +       struct fwu_mdata mdata = { 0 };
> +       struct fwu_image_entry *img_entry;
> +       struct fwu_image_bank_info *img_bank_info;
> +
> +       ret = fwu_get_dev_mdata(&dev, &mdata);
> +       if (ret)
> +               return ret;
> +
> +       img_entry = &mdata.img_entry[0];
> +       for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; 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(dev, &mdata);
> +                       goto out;
> +               }
> +       }
> +
> +       /* Image not found */
> +       ret = -ENOENT;
> +
> +out:
> +       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_clrset_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_clrset_image_accept(img_type_id, bank,
> +                                      IMAGE_ACCEPT_CLEAR);
> +}
> --
> 2.34.1
>

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

* Re: [PATCH v11 03/15] FWU: Add FWU metadata access driver for GPT partitioned block devices
  2022-09-28  9:29 ` [PATCH v11 03/15] FWU: Add FWU metadata access driver for GPT partitioned block devices Sughosh Ganu
@ 2022-09-30  6:10   ` Etienne Carriere
  0 siblings, 0 replies; 49+ messages in thread
From: Etienne Carriere @ 2022-09-30  6:10 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,

My R-b tag still applies, with the 2 below comments addressed or not.

Br,
etienne

On Wed, 28 Sept 2022 at 11: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 formatted with GPT based partition scheme.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
> ---
> Changes since V10:
> * Use array for storing the metadata partition numbers as suggested by
>   Ilias
> * Skip a couple of goto's in gpt_check_mdata_validity() as suggested
>   by Ilias
> * Have the FWU_MDATA_GPT_BLK config symbol depend on FWU_MDATA and BLK
> * Remove the comment in fwu_gpt_mdata_check() as it is already
>   mentioned in the corresponding API comment
>
>  drivers/fwu-mdata/Kconfig   |  16 ++
>  drivers/fwu-mdata/Makefile  |   8 +
>  drivers/fwu-mdata/gpt_blk.c | 356 ++++++++++++++++++++++++++++++++++++
>  include/fwu.h               |   4 +
>  4 files changed, 384 insertions(+)
>  create mode 100644 drivers/fwu-mdata/Kconfig
>  create mode 100644 drivers/fwu-mdata/Makefile
>  create mode 100644 drivers/fwu-mdata/gpt_blk.c
>
> diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
> new file mode 100644
> index 0000000000..36c4479a59
> --- /dev/null
> +++ b/drivers/fwu-mdata/Kconfig
> @@ -0,0 +1,16 @@
> +config 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.
> +
> +config FWU_MDATA_GPT_BLK
> +       bool "FWU Metadata access for GPT partitioned Block devices"
> +       select PARTITION_TYPE_GUID
> +       select PARTITION_UUIDS
> +       depends on FWU_MDATA && BLK && 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
> new file mode 100644
> index 0000000000..3fee64c10c
> --- /dev/null
> +++ b/drivers/fwu-mdata/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (c) 2022, Linaro Limited
> +#
> +
> +
> +obj-$(CONFIG_FWU_MDATA) += fwu-mdata-uclass.o
> +obj-$(CONFIG_FWU_MDATA_GPT_BLK) += gpt_blk.o
> diff --git a/drivers/fwu-mdata/gpt_blk.c b/drivers/fwu-mdata/gpt_blk.c
> new file mode 100644
> index 0000000000..d20bb19d52
> --- /dev/null
> +++ b/drivers/fwu-mdata/gpt_blk.c
> @@ -0,0 +1,356 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#define LOG_CATEGORY UCLASS_FWU_MDATA
> +
> +#include <blk.h>
> +#include <dm.h>
> +#include <efi_loader.h>
> +#include <fwu.h>
> +#include <fwu_mdata.h>
> +#include <log.h>
> +#include <memalign.h>
> +#include <part.h>
> +#include <part_efi.h>
> +
> +#include <dm/device-internal.h>
> +#include <linux/errno.h>
> +#include <linux/types.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,
> +                                   uint *mdata_parts)

Maybe nitpicking but I think this should better explicit declare a 2
cell array argument:
static int gpt_get_mdata_partitions(struct blk_desc *desc, uint mdata_parts[2])

> +{
> +       int i, ret;
> +       u32 nparts;
> +       efi_guid_t part_type_guid;
> +       struct disk_partition info;
> +       const efi_guid_t fwu_mdata_guid = FWU_MDATA_GUID;
> +
> +       nparts = 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 (nparts < 2 && !guidcmp(&fwu_mdata_guid, &part_type_guid)) {
> +                       mdata_parts[nparts] = i;
> +                       ++nparts;
> +               }
> +       }
> +
> +       if (nparts != 2) {
> +               log_debug("Expect two copies of the FWU metadata instead of %d\n",
> +                         nparts);
> +               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_debug("Unable to get the partition info for the FWU metadata part %d\n",
> +                         part_num);
> +               return -ENOENT;
> +       }
> +
> +       /* 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 -ENOENT;
> +}
> +
> +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 -ENOENT;
> +       }
> +
> +       len = sizeof(*mdata);
> +       blkcnt = BLOCK_CNT(len, desc);
> +       if (blkcnt > info.size) {
> +               log_debug("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_debug("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_debug("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;
> +       uint mdata_parts[2];
> +       struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
> +
> +       desc = dev_get_uclass_plat(priv->blk_dev);
> +
> +       ret = gpt_get_mdata_partitions(desc, mdata_parts);
> +       if (ret < 0) {
> +               log_debug("Error getting the FWU metadata partitions\n");
> +               return -ENOENT;
> +       }
> +
> +       /* First write the primary partition */
> +       ret = gpt_write_mdata_partition(desc, mdata, mdata_parts[0]);
> +       if (ret < 0) {
> +               log_debug("Updating primary FWU metadata partition failed\n");
> +               return ret;
> +       }
> +
> +       /* And now the replica */
> +       ret = gpt_write_mdata_partition(desc, mdata, mdata_parts[1]);
> +       if (ret < 0) {
> +               log_debug("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;
> +       uint mdata_parts[2];
> +
> +       ret = gpt_get_mdata_partitions(desc, mdata_parts);
> +
> +       if (ret < 0) {
> +               log_debug("Error getting the FWU metadata partitions\n");
> +               return -ENOENT;
> +       }
> +
> +       ret = gpt_read_mdata(desc, mdata, mdata_parts[0]);
> +       if (ret < 0) {
> +               log_debug("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, mdata_parts[1]);
> +       if (ret < 0) {
> +               log_debug("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 -EIO;
> +}
> +
> +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;
> +       uint mdata_parts[2];
> +       uint valid_partitions, invalid_partitions;
> +       struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
> +
> +       desc = dev_get_uclass_plat(priv->blk_dev);
> +
> +       /*
> +        * 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, mdata_parts);
> +       if (ret < 0) {
> +               log_debug("Error getting the FWU metadata partitions\n");
> +               return -ENOENT;
> +       }
> +
> +       ret = gpt_read_mdata(desc, &pri_mdata, mdata_parts[0]);
> +       if (!ret) {
> +               ret = fwu_verify_mdata(&pri_mdata, 1);
> +               if (!ret)
> +                       valid_partitions |= PRIMARY_PART;
> +       }
> +
> +       /* Now check the secondary partition */
> +       ret = gpt_read_mdata(desc, &secondary_mdata, mdata_parts[1]);
> +       if (!ret) {
> +               ret = fwu_verify_mdata(&secondary_mdata, 0);
> +               if (!ret)
> +                       valid_partitions |= SECONDARY_PART;
> +       }
> +
> +       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_debug("Both FWU metadata copies are valid but do not match. Please check!\n");
> +               }
> +               goto out;
> +       }
> +
> +       ret = -1;
> +       if (!(valid_partitions & BOTH_PARTS))
> +               goto out;

The 3 above preload of @ret are a bit misplaced (yet no functional
issue) i think.
Better a classic way:

       if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) {
-               ret = -1;
                (...)
                if (!memcmp(&pri_mdata, &secondary_mdata,
                            sizeof(struct fwu_mdata))) {
                        ret = 0;
                } else {
                        log_debug("Both FWU metadata copies are valid
but do not match. Please check!\n");
+                       ret = -1;
                }
                goto out;
        }

-       ret = -1;
        if (!(valid_partitions & BOTH_PARTS)) {
+              ret = -1;
               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) ?
> +                                       mdata_parts[0] : mdata_parts[1]);
> +
> +       if (ret < 0)
> +               log_debug("Restoring %s FWU metadata partition failed\n",
> +                         (invalid_partitions == PRIMARY_PART) ?
> +                         "primary" : "secondary");
> +
> +out:
> +       return ret;
> +}
> +
> +static int fwu_gpt_mdata_check(struct udevice *dev)
> +{
> +       return gpt_check_mdata_validity(dev);
> +}
> +
> +static int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata *mdata)
> +{
> +       struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
> +
> +       return gpt_get_mdata(dev_get_uclass_plat(priv->blk_dev), mdata);
> +}
> +
> +static int fwu_get_mdata_device(struct udevice *dev, struct udevice **mdata_dev)
> +{
> +       u32 phandle;
> +       int ret, size;
> +       struct udevice *parent;
> +       const fdt32_t *phandle_p = NULL;
> +
> +       phandle_p = dev_read_prop(dev, "fwu-mdata-store", &size);
> +       if (!phandle_p) {
> +               log_debug("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;
> +
> +       return blk_get_from_parent(parent, mdata_dev);
> +}
> +
> +static int fwu_mdata_gpt_blk_probe(struct udevice *dev)
> +{
> +       int ret;
> +       struct udevice *mdata_dev = NULL;
> +       struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
> +
> +       ret = fwu_get_mdata_device(dev, &mdata_dev);
> +       if (ret)
> +               return ret;
> +
> +       priv->blk_dev = mdata_dev;
> +
> +       return 0;
> +}
> +
> +static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
> +       .check_mdata = 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 a4d2d35d9a..167f91388e 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -14,6 +14,10 @@
>  struct fwu_mdata;
>  struct udevice;
>
> +struct fwu_mdata_gpt_blk_priv {
> +       struct udevice *blk_dev;
> +};
> +
>  /**
>   * @mdata_check: check the validity of the FWU metadata partitions
>   * @get_mdata() - Get a FWU metadata copy
> --
> 2.34.1
>

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

* Re: [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature
  2022-09-28  9:29 ` [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature Sughosh Ganu
@ 2022-09-30  6:27   ` Etienne Carriere
  2022-09-30  8:23     ` Sughosh Ganu
  2022-10-04  2:54   ` Takahiro Akashi
  1 sibling, 1 reply; 49+ messages in thread
From: Etienne Carriere @ 2022-09-30  6:27 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,

2 comments on the documentation. Otherwise it looks all good to me.

Best regards,
Etienne

On Wed, 28 Sept 2022 at 11:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
>
> Add documentation 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>
> ---
> Changes since V10:
> * Fix review comments suggested by Etienne
> * Add a paragraph in the capsule update section to highlight the
>   difference in ImageIndex correlation with DFU alt num with FWU feature
>   enabled
>
>  doc/develop/uefi/fwu_updates.rst | 173 +++++++++++++++++++++++++++++++
>  doc/develop/uefi/index.rst       |   1 +
>  doc/develop/uefi/uefi.rst        |  10 ++
>  3 files changed, 184 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..292feceb9a
> --- /dev/null
> +++ b/doc/develop/uefi/fwu_updates.rst
> @@ -0,0 +1,173 @@
> +.. 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 its 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-gpt.yaml>`__
> +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_RAW=y
> +
> +    CONFIG_FWU_MULTI_BANK_UPDATE=y
> +    CONFIG_CMD_FWU_METADATA=y

Actually the command is optional. Even without cmd support, capsules
can be consumed from CAPSULE_ON_DISK_EARLY.
Is it worth mentioning here?

> +    CONFIG_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 configuration settings 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, a GPT partitioned storage
> +device is required. 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 a 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 partitions 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. An example list of images on the storage medium would be
> +
> +* FWU metadata 1
> +* U-Boot 1
> +* OP-TEE 1
> +* FWU metadata 2
> +* OP-TEE 2
> +* U-Boot 2
> +* ESP
> +* rootfs

Here or below, maybe mention FWU metadata1/2 and ESP (at least) expect
dedicated partition type guid and reference the 2 U-Boot macros
FWU_MDATA_GUID and PARTITION_SYSTEM_GUID.


> +
> +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 specification 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.
> +
> +The task of accepting the different firmware images, post an update
> +may be done by multiple, separate components in the Operating
> +System. To help identify the firmware image that is being accepted,
> +the accept capsule passes the image GUID of the firmware image being
> +accepted. The relevant code in U-Boot then sets the Accept bit of the
> +corresponding firmware image for which the accept capsule was
> +found. Only when all the firmware components in a bank have been
> +accepted does the platform transition from trial state to regular
> +state.
> +
> +The revert capsule on the other hand does not pass any image GUID,
> +since reverting any image of the bank has the same result of the
> +platform booting from the other bank on subsequent boot.
> +
> +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>
> +
> +Some examples of using the mkeficapsule tool for generation of the
> +empty capsule would be::
> +
> +.. code-block:: bash
> +
> +    $ ./tools/mkeficapsule --fw-accept --guid <image guid> \
> +    <accept_capsule_name>
> +    $ ./tools/mkeficapsule --fw-revert <revert_capsule_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..b5c83db65a 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
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> @@ -377,6 +379,14 @@ following command::
>
>      dfu list
>
> +When the FWU Multi Bank Update feature is enabled on the platform, the
> +image index is used only to identify the image index with the image
> +GUID. The image index would not correspond to the dfu alt number. This
> +is because the FWU feature supports multiple partitions(banks) of
> +updatable images, and the actual dfu alt number to which the image is
> +to be written to is determined at runtime, based on the value of the
> +update bank to which the image is to be written.
> +
>  When using the FMP for FIT images, the image index value needs to be
>  set to 1.
>
> --
> 2.34.1
>

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

* Re: [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature
  2022-09-30  6:27   ` Etienne Carriere
@ 2022-09-30  8:23     ` Sughosh Ganu
  0 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-09-30  8:23 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 Fri, 30 Sept 2022 at 11:57, Etienne Carriere
<etienne.carriere@linaro.org> wrote:
>
> Hello Sughosh,
>
> 2 comments on the documentation. Otherwise it looks all good to me.
>
> Best regards,
> Etienne
>
> On Wed, 28 Sept 2022 at 11:31, Sughosh Ganu <sughosh.ganu@linaro.org> wrote:
> >
> > Add documentation 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>
> > ---
> > Changes since V10:
> > * Fix review comments suggested by Etienne
> > * Add a paragraph in the capsule update section to highlight the
> >   difference in ImageIndex correlation with DFU alt num with FWU feature
> >   enabled
> >
> >  doc/develop/uefi/fwu_updates.rst | 173 +++++++++++++++++++++++++++++++
> >  doc/develop/uefi/index.rst       |   1 +
> >  doc/develop/uefi/uefi.rst        |  10 ++
> >  3 files changed, 184 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..292feceb9a
> > --- /dev/null
> > +++ b/doc/develop/uefi/fwu_updates.rst
> > @@ -0,0 +1,173 @@
> > +.. 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 its 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-gpt.yaml>`__
> > +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_RAW=y
> > +
> > +    CONFIG_FWU_MULTI_BANK_UPDATE=y
> > +    CONFIG_CMD_FWU_METADATA=y
>
> Actually the command is optional. Even without cmd support, capsules
> can be consumed from CAPSULE_ON_DISK_EARLY.
> Is it worth mentioning here?

Yes, the command is more useful from getting the understanding of
which bank is currently active and if the images are accepted or not.
I can put a separate statement saying that the command can be used to
get the metadata information.

>
> > +    CONFIG_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 configuration settings 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, a GPT partitioned storage
> > +device is required. 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 a 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 partitions 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. An example list of images on the storage medium would be
> > +
> > +* FWU metadata 1
> > +* U-Boot 1
> > +* OP-TEE 1
> > +* FWU metadata 2
> > +* OP-TEE 2
> > +* U-Boot 2
> > +* ESP
> > +* rootfs
>
> Here or below, maybe mention FWU metadata1/2 and ESP (at least) expect
> dedicated partition type guid and reference the 2 U-Boot macros
> FWU_MDATA_GUID and PARTITION_SYSTEM_GUID.

I have mentioned the FWU metadata GUIDs below. Is this not good enough?

"Similarly, the FWU specification defines the GUID value to be used
for the metadata partitions. This would be the PartitionTypeGUID for
the metadata partitions."

Maybe similarly I can mention that the ESP GUID can be obtained from
the UEFI specification.

-sughosh

>
>
> > +
> > +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 specification 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.
> > +
> > +The task of accepting the different firmware images, post an update
> > +may be done by multiple, separate components in the Operating
> > +System. To help identify the firmware image that is being accepted,
> > +the accept capsule passes the image GUID of the firmware image being
> > +accepted. The relevant code in U-Boot then sets the Accept bit of the
> > +corresponding firmware image for which the accept capsule was
> > +found. Only when all the firmware components in a bank have been
> > +accepted does the platform transition from trial state to regular
> > +state.
> > +
> > +The revert capsule on the other hand does not pass any image GUID,
> > +since reverting any image of the bank has the same result of the
> > +platform booting from the other bank on subsequent boot.
> > +
> > +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>
> > +
> > +Some examples of using the mkeficapsule tool for generation of the
> > +empty capsule would be::
> > +
> > +.. code-block:: bash
> > +
> > +    $ ./tools/mkeficapsule --fw-accept --guid <image guid> \
> > +    <accept_capsule_name>
> > +    $ ./tools/mkeficapsule --fw-revert <revert_capsule_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..b5c83db65a 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
> >  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >
> > @@ -377,6 +379,14 @@ following command::
> >
> >      dfu list
> >
> > +When the FWU Multi Bank Update feature is enabled on the platform, the
> > +image index is used only to identify the image index with the image
> > +GUID. The image index would not correspond to the dfu alt number. This
> > +is because the FWU feature supports multiple partitions(banks) of
> > +updatable images, and the actual dfu alt number to which the image is
> > +to be written to is determined at runtime, based on the value of the
> > +update bank to which the image is to be written.
> > +
> >  When using the FMP for FIT images, the image index value needs to be
> >  set to 1.
> >
> > --
> > 2.34.1
> >

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

* [PATCHv2 0/5] FWU: Add support for mtd backed feature on DeveloperBox
  2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
                   ` (14 preceding siblings ...)
  2022-09-28  9:29 ` [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature Sughosh Ganu
@ 2022-10-02 23:50 ` jassisinghbrar
  2022-10-02 23:51   ` [PATCHv2 1/5] FWU: Add FWU metadata access driver for MTD storage regions jassisinghbrar
                     ` (4 more replies)
  15 siblings, 5 replies; 49+ messages in thread
From: jassisinghbrar @ 2022-10-02 23:50 UTC (permalink / raw)
  To: u-boot
  Cc: xypron.glpk, ilias.apalodimas, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Jassi Brar

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

Introduce support for mtd backed storage for FWU feature and enable it on
Synquacer platform based DeveloperBox.

The patchset has been rebased on latest(v11) submission of FWU Multi Bank Update
feature by Sughosh[1].

[1] https://lore.kernel.org/u-boot/20220928092956.2535777-1-sughosh.ganu@linaro.org/

Masami Hiramatsu (3):
  dt: fwu: developerbox: enable fwu banks and mdata regions
  fwu: DeveloperBox: add support for FWU
  tools: Add mkfwumdata tool for FWU metadata image

Sughosh Ganu (2):
  FWU: Add FWU metadata access driver for MTD storage regions
  FWU: mtd: Add helper functions for accessing FWU metadata

 .../synquacer-sc2a11-developerbox-u-boot.dtsi |  22 +-
 board/socionext/developerbox/Makefile         |   1 +
 board/socionext/developerbox/developerbox.c   |   8 +
 board/socionext/developerbox/fwu_plat.c       |  68 ++++
 configs/synquacer_developerbox_defconfig      |  13 +-
 doc/board/socionext/developerbox.rst          |  96 ++++++
 drivers/fwu-mdata/Kconfig                     |  17 +-
 drivers/fwu-mdata/Makefile                    |   1 +
 drivers/fwu-mdata/raw_mtd.c                   | 305 +++++++++++++++++
 include/configs/synquacer.h                   |  10 +
 include/fwu.h                                 |  27 ++
 lib/fwu_updates/Makefile                      |   1 +
 lib/fwu_updates/fwu_mtd.c                     | 178 ++++++++++
 tools/Kconfig                                 |   9 +
 tools/Makefile                                |   4 +
 tools/mkfwumdata.c                            | 323 ++++++++++++++++++
 16 files changed, 1079 insertions(+), 4 deletions(-)
 create mode 100644 board/socionext/developerbox/fwu_plat.c
 create mode 100644 drivers/fwu-mdata/raw_mtd.c
 create mode 100644 lib/fwu_updates/fwu_mtd.c
 create mode 100644 tools/mkfwumdata.c

-- 
2.25.1


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

* [PATCHv2 1/5] FWU: Add FWU metadata access driver for MTD storage regions
  2022-10-02 23:50 ` [PATCHv2 0/5] FWU: Add support for mtd backed feature on DeveloperBox jassisinghbrar
@ 2022-10-02 23:51   ` jassisinghbrar
  2022-10-14  7:07     ` Ilias Apalodimas
  2022-10-02 23:51   ` [PATCHv2 2/5] FWU: mtd: Add helper functions for accessing FWU metadata jassisinghbrar
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 49+ messages in thread
From: jassisinghbrar @ 2022-10-02 23:51 UTC (permalink / raw)
  To: u-boot
  Cc: xypron.glpk, ilias.apalodimas, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Sughosh Ganu, Jassi Brar

From: Sughosh Ganu <sughosh.ganu@linaro.org>

In the FWU Multi Bank Update feature, the information about the
updatable images is stored as part of the metadata, on a separate
region. Add a driver for reading from and writing to the metadata
when the updatable images and the metadata are stored on a raw
MTD region.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
---
 drivers/fwu-mdata/Kconfig   |  17 +-
 drivers/fwu-mdata/Makefile  |   1 +
 drivers/fwu-mdata/raw_mtd.c | 305 ++++++++++++++++++++++++++++++++++++
 3 files changed, 322 insertions(+), 1 deletion(-)
 create mode 100644 drivers/fwu-mdata/raw_mtd.c

diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig
index 36c4479a59..841c6f5b2d 100644
--- a/drivers/fwu-mdata/Kconfig
+++ b/drivers/fwu-mdata/Kconfig
@@ -6,11 +6,26 @@ config FWU_MDATA
 	  FWU Metadata partitions reside on the same storage device
 	  which contains the other FWU updatable firmware images.
 
+choice
+	prompt "Storage Layout Scheme"
+	depends on FWU_MDATA
+	default FWU_MDATA_GPT_BLK
+
 config FWU_MDATA_GPT_BLK
-	bool "FWU Metadata access for GPT partitioned Block devices"
+	bool "GPT Partitioned Block devices"
 	select PARTITION_TYPE_GUID
 	select PARTITION_UUIDS
 	depends on FWU_MDATA && BLK && EFI_PARTITION
 	help
 	  Enable support for accessing FWU Metadata on GPT partitioned
 	  block devices.
+
+config FWU_MDATA_MTD
+	bool "Raw MTD devices"
+	depends on MTD
+	help
+	  Enable support for accessing FWU Metadata on non-partitioned
+	  (or non-GPT partitioned, e.g. partition nodes in devicetree)
+	  MTD devices.
+
+endchoice
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile
index 3fee64c10c..06c49747ba 100644
--- a/drivers/fwu-mdata/Makefile
+++ b/drivers/fwu-mdata/Makefile
@@ -6,3 +6,4 @@
 
 obj-$(CONFIG_FWU_MDATA) += fwu-mdata-uclass.o
 obj-$(CONFIG_FWU_MDATA_GPT_BLK) += gpt_blk.o
+obj-$(CONFIG_FWU_MDATA_MTD) += raw_mtd.o
diff --git a/drivers/fwu-mdata/raw_mtd.c b/drivers/fwu-mdata/raw_mtd.c
new file mode 100644
index 0000000000..ff2064b442
--- /dev/null
+++ b/drivers/fwu-mdata/raw_mtd.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#define LOG_CATEGORY UCLASS_FWU_MDATA
+
+#include <efi_loader.h>
+#include <fwu.h>
+#include <fwu_mdata.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>
+
+/* Internal helper structure to move data around */
+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,
+};
+
+#define FWU_MDATA_PRIMARY	true
+#define FWU_MDATA_SECONDARY	false
+
+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)) {
+		log_err("Offset unaligned with a block (0x%x)\n", mtd->erasesize);
+		return -EINVAL;
+	}
+
+	lock_offs = offs;
+	/* This will expand erase size to align with the block size */
+	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 = {};
+
+		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;
+	}
+
+	/* 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;
+	}
+	memset(buf, 0xff, len);
+
+	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:
+	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;
+
+	ret = mtd_io_data(mtd, offs, size, mdata, FWU_MTD_READ);
+	if (ret >= 0)
+		ret = fwu_verify_mdata(mdata, primary);
+
+	return ret;
+}
+
+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)
+{
+	int ret;
+
+	ret = fwu_mtd_load_mdata(mtd_priv->mtd, mdata,
+							 mtd_priv->pri_offset, FWU_MDATA_PRIMARY);
+	if (!ret)
+		return 0;
+
+	log_debug("Failed to load primary mdata. Trying secondary...\n");
+
+	ret = fwu_mtd_load_mdata(mtd_priv->mtd, mdata,
+							 mtd_priv->sec_offset, FWU_MDATA_SECONDARY);
+	if (ret) {
+		log_debug("Failed to load secondary mdata.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+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;
+
+	/* First write the primary mdata */
+	ret = fwu_mtd_save_primary_mdata(mtd_priv, mdata);
+	if (ret < 0) {
+		log_debug("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_debug("Failed to update the secondary mdata.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fwu_mtd_check_mdata(struct udevice *dev)
+{
+	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
+	struct fwu_mdata primary, secondary;
+	bool pri = false, sec = false;
+	int ret;
+
+	ret = fwu_mtd_load_mdata(mtd_priv->mtd, &primary,
+							 mtd_priv->pri_offset, FWU_MDATA_PRIMARY);
+	if (ret < 0)
+		log_debug("Failed to read the primary mdata: %d\n", ret);
+	else
+		pri = true;
+
+	ret = fwu_mtd_load_mdata(mtd_priv->mtd, &secondary,
+							 mtd_priv->sec_offset, FWU_MDATA_SECONDARY);
+	if (ret < 0)
+		log_debug("Failed to read the secondary mdata: %d\n", ret);
+	else
+		sec = true;
+
+	if (pri && sec) {
+		if (memcmp(&primary, &secondary, sizeof(struct fwu_mdata))) {
+			log_debug("The primary and the secondary mdata are different\n");
+			ret = -1;
+		}
+	} else if (pri) {
+		ret = fwu_mtd_save_secondary_mdata(mtd_priv, &primary);
+		if (ret < 0)
+			log_debug("Restoring secondary mdata partition failed\n");
+	} else if (sec) {
+		ret = fwu_mtd_save_primary_mdata(mtd_priv, &secondary);
+		if (ret < 0)
+			log_debug("Restoring primary mdata partition failed\n");
+	}
+
+	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 meta data store not defined in device-tree\n");
+		return -ENOENT;
+	}
+
+	phandle = fdt32_to_cpu(*phandle_p);
+
+	ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
+									  &mtd_dev);
+	if (ret) {
+		log_err("FWU: failed to get mtd device\n");
+		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_check_mdata(dev);
+}
+
+static struct fwu_mdata_ops fwu_mtd_ops = {
+	.check_mdata = fwu_mtd_check_mdata,
+	.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] 49+ messages in thread

* [PATCHv2 2/5] FWU: mtd: Add helper functions for accessing FWU metadata
  2022-10-02 23:50 ` [PATCHv2 0/5] FWU: Add support for mtd backed feature on DeveloperBox jassisinghbrar
  2022-10-02 23:51   ` [PATCHv2 1/5] FWU: Add FWU metadata access driver for MTD storage regions jassisinghbrar
@ 2022-10-02 23:51   ` jassisinghbrar
  2022-10-14  7:10     ` Ilias Apalodimas
  2022-10-02 23:51   ` [PATCHv2 3/5] dt: fwu: developerbox: enable fwu banks and mdata regions jassisinghbrar
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 49+ messages in thread
From: jassisinghbrar @ 2022-10-02 23:51 UTC (permalink / raw)
  To: u-boot
  Cc: xypron.glpk, ilias.apalodimas, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Sughosh Ganu, Jassi Brar

From: Sughosh Ganu <sughosh.ganu@linaro.org>

Add helper functions needed for accessing the FWU metadata which
contains information on the updatable images.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
---
 include/fwu.h             |  27 ++++++
 lib/fwu_updates/Makefile  |   1 +
 lib/fwu_updates/fwu_mtd.c | 178 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 206 insertions(+)
 create mode 100644 lib/fwu_updates/fwu_mtd.c

diff --git a/include/fwu.h b/include/fwu.h
index b5c59dc161..48c83f7618 100644
--- a/include/fwu.h
+++ b/include/fwu.h
@@ -8,6 +8,7 @@
 
 #include <blk.h>
 #include <efi.h>
+#include <mtd.h>
 
 #include <linux/types.h>
 
@@ -296,4 +297,30 @@ u8 fwu_update_checks_pass(void);
  */
 int fwu_trial_state_ctr_start(void);
 
+/**
+ * fwu_gen_alt_info_from_mtd() - Parse dfu_alt_info from metadata in mtd
+ * @buf: Buffer into which the dfu_alt_info is filled
+ * @len: Maximum charaters that can be written in buf
+ * @mtd: Pointer to underlying MTD device
+ *
+ * Parse dfu_alt_info from metadata in mtd. Used for setting the env.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd);
+
+/**
+ * fwu_mtd_get_alt_num() - Mapping of fwu_plat_get_alt_num for MTD device
+ * @image_guid: Image GUID for which DFU alt number needs to be retrieved
+ * @alt_num: Pointer to the alt_num
+ * @mtd_dev: Name of mtd device instance
+ *
+ * To map fwu_plat_get_alt_num onto mtd based metadata implementation.
+ *
+ * Return: 0 if OK, -ve on error
+ *
+ */
+int fwu_mtd_get_alt_num(efi_guid_t *image_id, u8 *alt_num, const char *mtd_dev);
+
 #endif /* _FWU_H_ */
diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile
index 1993088e5b..c9e3c06b48 100644
--- a/lib/fwu_updates/Makefile
+++ b/lib/fwu_updates/Makefile
@@ -5,3 +5,4 @@
 
 obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o
 obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_gpt.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..6acf91320d
--- /dev/null
+++ b/lib/fwu_updates/fwu_mtd.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <dm.h>
+#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_mtd_get_alt_num(efi_guid_t *image_id, u8 *alt_num,
+			const char *mtd_dev)
+{
+	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, 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);
+
+		/* Only MTD RAW access */
+		if (!dfu || dfu->dev_type != DFU_DEV_MTD ||
+			dfu->layout != DFU_RAW_ADDR ||
+			dfu->data.mtd.start != offset ||
+			dfu->data.mtd.size != size)
+			continue;
+
+		*alt_num = dfu->alt;
+		ret = 0;
+		break;
+	}
+
+	dfu_free_entities();
+
+	return ret;
+}
+
+static int gen_image_alt_info(char *buf, size_t len, int sidx,
+		       struct fwu_image_entry *img, struct mtd_info *mtd)
+{
+	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),
+					  "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("Got 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) {
+		log_err("%s:%d Run out of buffer\n", __func__, __LINE__);
+		return -E2BIG;
+	}
+
+	/*
+	 * List 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_err("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) {
+			log_err("%s:%d Run out of buffer\n", __func__, __LINE__);
+			return -E2BIG;
+		}
+	}
+
+	if (i == CONFIG_FWU_NUM_BANKS)
+		return 0;
+
+	return -ENOENT;
+}
+
+int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
+{
+	struct fwu_mdata mdata = { 0 };
+	struct udevice *dev = NULL;
+	int i, l, ret;
+
+	if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
+		log_err("Unable to get FWU metadata device\n");
+		return -ENODEV;
+	}
+
+	ret = fwu_get_mdata(dev, &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;
+	}
+
+	return ret;
+}
-- 
2.25.1


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

* [PATCHv2 3/5] dt: fwu: developerbox: enable fwu banks and mdata regions
  2022-10-02 23:50 ` [PATCHv2 0/5] FWU: Add support for mtd backed feature on DeveloperBox jassisinghbrar
  2022-10-02 23:51   ` [PATCHv2 1/5] FWU: Add FWU metadata access driver for MTD storage regions jassisinghbrar
  2022-10-02 23:51   ` [PATCHv2 2/5] FWU: mtd: Add helper functions for accessing FWU metadata jassisinghbrar
@ 2022-10-02 23:51   ` jassisinghbrar
  2022-10-14  7:33     ` Ilias Apalodimas
  2022-10-02 23:52   ` [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU jassisinghbrar
  2022-10-02 23:52   ` [PATCHv2 5/5] tools: Add mkfwumdata tool for FWU metadata image jassisinghbrar
  4 siblings, 1 reply; 49+ messages in thread
From: jassisinghbrar @ 2022-10-02 23:51 UTC (permalink / raw)
  To: u-boot
  Cc: xypron.glpk, ilias.apalodimas, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Masami Hiramatsu, Jassi Brar

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

Specify Bank-0/1 and fwu metadata mtd regions.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
---
 .../synquacer-sc2a11-developerbox-u-boot.dtsi | 22 ++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
index 7a56116d6f..62eee0aaf0 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";
@@ -36,6 +36,7 @@
 				compatible = "fixed-partitions";
 				#address-cells = <1>;
 				#size-cells = <1>;
+				uuid = "17e86d77-41f9-4fd7-87ec-a55df9842de5";
 
 				partition@0 {
 					label = "BootStrap-BL1";
@@ -79,6 +80,19 @@
 					label = "Ex-OPTEE";
 					reg = <0x500000 0x200000>;
 				};
+
+				/* FWU Multi bank update partitions */
+				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";
+				};
 			};
 		};
 	};
@@ -104,6 +118,12 @@
 		optee {
 			status = "okay";
 		};
+
+		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] 49+ messages in thread

* [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU
  2022-10-02 23:50 ` [PATCHv2 0/5] FWU: Add support for mtd backed feature on DeveloperBox jassisinghbrar
                     ` (2 preceding siblings ...)
  2022-10-02 23:51   ` [PATCHv2 3/5] dt: fwu: developerbox: enable fwu banks and mdata regions jassisinghbrar
@ 2022-10-02 23:52   ` jassisinghbrar
  2022-10-03 11:04     ` AKASHI Takahiro
  2022-10-02 23:52   ` [PATCHv2 5/5] tools: Add mkfwumdata tool for FWU metadata image jassisinghbrar
  4 siblings, 1 reply; 49+ messages in thread
From: jassisinghbrar @ 2022-10-02 23:52 UTC (permalink / raw)
  To: u-boot
  Cc: xypron.glpk, ilias.apalodimas, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Masami Hiramatsu, Jassi Brar

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

Add code to support FWU_MULTI_BANK_UPDATE.
The platform does not have gpt-partition storage for
Banks and MetaData, rather it used SPI-NOR backed
mtd regions for the purpose.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
---
 board/socionext/developerbox/Makefile       |  1 +
 board/socionext/developerbox/developerbox.c |  8 ++
 board/socionext/developerbox/fwu_plat.c     | 68 +++++++++++++++
 configs/synquacer_developerbox_defconfig    | 13 ++-
 doc/board/socionext/developerbox.rst        | 96 +++++++++++++++++++++
 include/configs/synquacer.h                 | 10 +++
 6 files changed, 194 insertions(+), 2 deletions(-)
 create mode 100644 board/socionext/developerbox/fwu_plat.c

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/developerbox.c b/board/socionext/developerbox/developerbox.c
index f5a5fe0121..a0db26eaf3 100644
--- a/board/socionext/developerbox/developerbox.c
+++ b/board/socionext/developerbox/developerbox.c
@@ -20,6 +20,13 @@
 
 #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
 struct efi_fw_image fw_images[] = {
+#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
+	{
+		.image_type_id = DEVELOPERBOX_FIP_IMAGE_GUID,
+		.fw_name = u"DEVELOPERBOX-FIP",
+		.image_index = 1,
+	},
+#else
 	{
 		.image_type_id = DEVELOPERBOX_UBOOT_IMAGE_GUID,
 		.fw_name = u"DEVELOPERBOX-UBOOT",
@@ -35,6 +42,7 @@ struct efi_fw_image fw_images[] = {
 		.fw_name = u"DEVELOPERBOX-OPTEE",
 		.image_index = 3,
 	},
+#endif
 };
 
 struct efi_capsule_update_info update_info = {
diff --git a/board/socionext/developerbox/fwu_plat.c b/board/socionext/developerbox/fwu_plat.c
new file mode 100644
index 0000000000..f333cd4027
--- /dev/null
+++ b/board/socionext/developerbox/fwu_plat.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, 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 <mtd.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <uuid.h>
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <u-boot/crc.h>
+
+#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;
+
+	ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN);
+	memset(buf, 0, sizeof(buf));
+
+	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);
+}
+
+int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
+			 efi_guid_t *image_id, u8 *alt_num)
+{
+	return fwu_mtd_get_alt_num(image_id, alt_num, "nor1");
+}
+
+void fwu_plat_get_bootidx(uint *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;
+}
diff --git a/configs/synquacer_developerbox_defconfig b/configs/synquacer_developerbox_defconfig
index c0b784b072..b1085a388e 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"
@@ -96,3 +97,11 @@ 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=y
+CONFIG_FWU_MDATA_MTD=y
+CONFIG_FWU_NUM_BANKS=2
+CONFIG_FWU_NUM_IMAGES_PER_BANK=1
+CONFIG_CMD_FWU_METADATA=y
+CONFIG_TOOLS_MKFWUMDATA=y
diff --git a/doc/board/socionext/developerbox.rst b/doc/board/socionext/developerbox.rst
index 2d943c23be..be872aa79d 100644
--- a/doc/board/socionext/developerbox.rst
+++ b/doc/board/socionext/developerbox.rst
@@ -85,3 +85,99 @@ 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=y
+ CONFIG_FWU_MDATA_MTD=y
+ CONFIG_FWU_NUM_BANKS=2
+ CONFIG_FWU_NUM_IMAGES_PER_BANK=1
+ CONFIG_CMD_FWU_METADATA=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.
+
+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.::
+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.)
diff --git a/include/configs/synquacer.h b/include/configs/synquacer.h
index 63d897d090..c798a23bed 100644
--- a/include/configs/synquacer.h
+++ b/include/configs/synquacer.h
@@ -41,19 +41,29 @@
 
 /* Since U-Boot 64bit PCIe support is limited, disable 64bit MMIO support */
 
+#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
+#define DEFAULT_DFU_ALT_INFO
+#else
 #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"
+#endif
 
 /* GUIDs for capsule updatable firmware images */
 #define DEVELOPERBOX_UBOOT_IMAGE_GUID \
 	EFI_GUID(0x53a92e83, 0x4ef4, 0x473a, 0x8b, 0x0d, \
 		 0xb5, 0xd8, 0xc7, 0xb2, 0xd6, 0x00)
 
+#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
+#define DEVELOPERBOX_FIP_IMAGE_GUID \
+	EFI_GUID(0x7d6dc310, 0x52ca, 0x43b8, 0xb7, 0xb9, \
+		 0xf9, 0xd6, 0xc5, 0x01, 0xd1, 0x08)
+#else
 #define DEVELOPERBOX_FIP_IMAGE_GUID \
 	EFI_GUID(0x880866e9, 0x84ba, 0x4793, 0xa9, 0x08, \
 		 0x33, 0xe0, 0xb9, 0x16, 0xf3, 0x98)
+#endif
 
 #define DEVELOPERBOX_OPTEE_IMAGE_GUID \
 	EFI_GUID(0xc1b629f1, 0xce0e, 0x4894, 0x82, 0xbf, \
-- 
2.25.1


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

* [PATCHv2 5/5] tools: Add mkfwumdata tool for FWU metadata image
  2022-10-02 23:50 ` [PATCHv2 0/5] FWU: Add support for mtd backed feature on DeveloperBox jassisinghbrar
                     ` (3 preceding siblings ...)
  2022-10-02 23:52   ` [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU jassisinghbrar
@ 2022-10-02 23:52   ` jassisinghbrar
  4 siblings, 0 replies; 49+ messages in thread
From: jassisinghbrar @ 2022-10-02 23:52 UTC (permalink / raw)
  To: u-boot
  Cc: xypron.glpk, ilias.apalodimas, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Masami Hiramatsu, Sughosh Ganu,
	Jassi Brar

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

Add 'mkfwumdata' tool to generate FWU metadata image for the meta-data
partition to be used in A/B Update imeplementation.

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

diff --git a/tools/Kconfig b/tools/Kconfig
index 539708f277..6e23f44d55 100644
--- a/tools/Kconfig
+++ b/tools/Kconfig
@@ -157,4 +157,13 @@ config LUT_SEQUENCE
 	help
 	  Look Up Table Sequence
 
+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 c479d3cb4c..2fe2910fa4 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -254,6 +254,10 @@ HOSTLDLIBS_mkeficapsule += \
 	$(shell pkg-config --libs uuid 2> /dev/null || echo "-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..35ee540cde
--- /dev/null
+++ b/tools/mkfwumdata.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <errno.h>
+#include <getopt.h>
+#include <limits.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:p: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'},
+	{"previous-bank", required_argument, NULL, 'p'},
+	{"help", no_argument, NULL, 'h'},
+	{NULL, 0, NULL, 0},
+};
+
+static void print_usage(void)
+{
+	fprintf(stderr, "Usage: mkfwumdata [options] <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-p, --previous-bank  <num>  Previous 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>,<images uuid list>\n"
+		"\t    images uuid list syntax:\n"
+		"\t\t    img_uuid_00,img_uuid_01...img_uuid_0b,\n"
+		"\t\t    img_uuid_10,img_uuid_11...img_uuid_1b,\n"
+		"\t\t    ...,\n"
+		"\t\t    img_uuid_i0,img_uuid_i1...img_uuid_ib,\n"
+		"\t\t    where 'b' and 'i' are number of banks and numbder of images in a bank respectively.\n"
+	       );
+}
+
+static int active_bank = 0;
+static int previous_bank = INT_MAX; /* unset */
+static bool __use_guid = false;
+
+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 = calloc(1, 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 = calloc(1, mobj->size);
+	if (!mobj->mdata) {
+		free(mobj);
+		return NULL;
+	}
+
+	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 = previous_bank;
+
+	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)
+		goto done_make;
+
+	file = fopen(output, "w");
+	if (!file) {
+		ret = -errno;
+		goto done_make;
+	}
+
+	ret = fwrite(mobj->mdata, mobj->size, 1, file);
+	if (ret != mobj->size)
+		ret = -errno;
+	else
+		ret = 0;
+
+	fclose(file);
+
+done_make:
+	free(mobj->mdata);
+	free(mobj);
+
+	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 'p':
+			previous_bank = strtoul(optarg, NULL, 0);
+			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;
+	}
+
+	if (previous_bank == INT_MAX) {
+		/* set to the earlier bank in round-robin scheme */
+		previous_bank = active_bank > 0 ? active_bank - 1 : banks - 1;
+	}
+
+	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] 49+ messages in thread

* Re: [PATCH v11 02/15] FWU: Add FWU metadata structure and driver for accessing metadata
  2022-09-30  5:54   ` Etienne Carriere
@ 2022-10-03  6:27     ` Sughosh Ganu
  0 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-10-03  6:27 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 Fri, 30 Sept 2022 at 11:24, Etienne Carriere
<etienne.carriere@linaro.org> wrote:
>
> Hello Sughosh,
>
> On Wed, 28 Sept 2022 at 11: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>
> > Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> > Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
> > ---
> > Changes since V10:
> > * s/fwu_update_active_index/fwu_set_active_index as per comment from
> >   Jassi
> > * Change the argument type of fwu_set_active_index() to uint from u32
> >   as per comment from Jassi
> > * s/mdata_check/check_mdata as per comment from Jassi
> > * Fix the typo in the function comment of fwu_mdata_check()
> >
> >  drivers/fwu-mdata/fwu-mdata-uclass.c | 107 ++++++++
> >  include/dm/uclass-id.h               |   1 +
> >  include/fwu.h                        | 211 ++++++++++++++++
> >  include/fwu_mdata.h                  |  67 +++++
> >  lib/fwu_updates/fwu.c                | 363 +++++++++++++++++++++++++++
> >  5 files changed, 749 insertions(+)
> >  create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c
> >  create mode 100644 include/fwu.h
> >  create mode 100644 include/fwu_mdata.h
> >  create mode 100644 lib/fwu_updates/fwu.c

<snip>

> > diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> > new file mode 100644
> > index 0000000000..fe8058bc37
> > --- /dev/null
> > +++ b/lib/fwu_updates/fwu.c
> > @@ -0,0 +1,363 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Copyright (c) 2022, Linaro Limited
> > + */
> > +
> > +#include <dm.h>
> > +#include <efi_loader.h>
> > +#include <fwu.h>
> > +#include <fwu_mdata.h>
> > +#include <log.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)
>
> Nitpicking: i think an enumerated type would be better here.
> (not a strong opinion)

Okay

>
> > +
> > +static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
> > +
>
> Remove this empty line.

Will do

>
> > +{
> > +       int ret;
> > +
> > +       ret = uclass_first_device(UCLASS_FWU_MDATA, dev);
> > +       if (ret) {
> > +               log_debug("Cannot find fwu device\n");
> > +               return ret;
> > +       }
>
> `uclass_first_device()` returns 0 when node is not found but no issue
> reported while parsing the FDT (learned by experience :(. In that
> case, *dev is set to NULL and next instruction segfaults.
> Proposal:
>
>      ret = uclass_first_device(UCLASS_FWU_MDATA, dev);
> -    if (ret) {
> +    if (ret || !*dev) {
>          log_debug("Cannot find fwu device\n");
> +        if (!ret)
> +            ret = -ENOENT;
>          return ret;
>      }

I think I can instead use uclass_first_device_err(). I think that is
doing what you are proposing above.

>
>
>
> > +
> > +       ret = fwu_get_mdata(*dev, mdata);
> > +       if (ret < 0)
> > +               log_debug("Unable to get valid FWU metadata\n");
> > +
> > +       return ret;
> > +}
> > +
> > +static int fwu_get_image_type_id(u8 *image_index, efi_guid_t *image_type_id)
> > +{
> > +       u8 index;
> > +       int i;
> > +       struct efi_fw_image *image;
> > +
> > +       index = *image_index;
> > +       image = update_info.images;
> > +       for (i = 0; i < num_image_type_guids; i++) {
> > +               if (index == image[i].image_index) {
> > +                       guidcpy(image_type_id, &image[i].image_type_id);
> > +                       return 0;
> > +               }
> > +       }
> > +
> > +       return -ENOENT;
> > +}
> > +
> > +/**
> > + * 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_debug("crc32 check failed for %s FWU metadata partition\n",
> > +                         pri_part ? "primary" : "secondary");
> > +               return -EINVAL;
> > +       }
> > +
> > +       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(uint *active_idx)
> > +{
> > +       int ret;
> > +       struct udevice *dev;
> > +       struct fwu_mdata mdata = { 0 };
> > +
> > +       ret = fwu_get_dev_mdata(&dev, &mdata);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /*
> > +        * Found the FWU metadata partition, now read the active_index
> > +        * value
> > +        */
> > +       *active_idx = mdata.active_index;
> > +       if (*active_idx >= CONFIG_FWU_NUM_BANKS) {
> > +               log_debug("Active index value read is incorrect\n");
> > +               ret = -EINVAL;
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> > +/**
> > + * fwu_set_active_index() - Set active_index in the FWU metadata
> > + * @active_idx: active_index value to be set
> > + *
> > + * Update the active_index field in the FWU metadata
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_set_active_index(uint active_idx)
> > +{
> > +       int ret;
> > +       struct udevice *dev;
> > +       struct fwu_mdata mdata = { 0 };
> > +
> > +       if (active_idx >= CONFIG_FWU_NUM_BANKS) {
> > +               log_debug("Invalid active index value\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       ret = fwu_get_dev_mdata(&dev, &mdata);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /*
> > +        * 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(dev, &mdata);
> > +       if (ret < 0) {
>
> Function description says it returns 0 on success so prefer here 'if (ret)'.

Okay

>
> > +               log_debug("Failed to update FWU metadata partitions\n");
> > +               ret = -EIO;
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> > +/**
> > + * fwu_get_image_index() - Get the Image Index to be used for capsule update
> > + * @image_index: The Image Index for the image
> > + *
> > + * The FWU multi bank update feature computes the value of image_index at
> > + * runtime, based on the bank to which the image needs to be written to.
> > + * Derive the image_index value for the image.
> > + *
> > + * Currently, the capsule update driver uses the DFU framework for
> > + * the updates. This function gets the DFU alt number which is to
> > + * be used as the Image Index
> > + *
> > + * Return: 0 if OK, -ve on error
> > + *
> > + */
> > +int fwu_get_image_index(u8 *image_index)
> > +{
> > +       int ret, i;
> > +       u8 alt_num;
> > +       u32 update_bank;
> > +       efi_guid_t *image_guid, image_type_id;
> > +       struct udevice *dev;
> > +       struct fwu_mdata mdata = { 0 };
> > +       struct fwu_image_entry *img_entry;
> > +       struct fwu_image_bank_info *img_bank_info;
> > +
> > +       ret = fwu_get_dev_mdata(&dev, &mdata);
> > +       if (ret)
> > +               return ret;
> > +
> > +       ret = fwu_plat_get_update_index(&update_bank);
> > +       if (ret) {
> > +               log_debug("Failed to get the FWU update bank\n");
> > +               goto out;
> > +       }
> > +
> > +       ret = fwu_get_image_type_id(image_index, &image_type_id);
> > +       if (ret) {
> > +               log_debug("Unable to get image_type_id for image_index %u\n",
> > +                         *image_index);
> > +               goto out;
> > +       }
> > +
> > +       ret = -EINVAL;
> > +       /*
> > +        * 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, image_guid, &alt_num);
> > +                       if (ret) {
> > +                               log_debug("alt_num not found for partition with GUID %pUs\n",
> > +                                         image_guid);
> > +                       } else {
> > +                               log_debug("alt_num %d for partition %pUs\n",
> > +                                         alt_num, image_guid);
> > +                               *image_index = alt_num + 1;
> > +                       }
> > +
> > +                       goto out;
> > +               }
> > +       }
> > +
> > +       log_debug("Partition with the image type %pUs not found\n",
> > +                 &image_type_id);
> > +
> > +out:
> > +       return ret;
> > +}
> > +
> > +/**
> > + * 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 udevice *dev;
> > +       struct fwu_mdata mdata = { 0 };
> > +
> > +       ret = fwu_get_dev_mdata(&dev, &mdata);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /*
> > +        * 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(dev, &mdata);
> > +       if (ret < 0) {
>
> Same comment here: error case should be trapped with 'if (ret)'.

Okay

-sughosh

>
> br,
> etienne
>
> > +               log_debug("Failed to update FWU metadata partitions\n");
> > +               ret = -EIO;
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> > +/**
> > + * fwu_clrset_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_clrset_image_accept(efi_guid_t *img_type_id, u32 bank, u8 action)
> > +{
> > +       int ret, i;
> > +       struct udevice *dev;
> > +       struct fwu_mdata mdata = { 0 };
> > +       struct fwu_image_entry *img_entry;
> > +       struct fwu_image_bank_info *img_bank_info;
> > +
> > +       ret = fwu_get_dev_mdata(&dev, &mdata);
> > +       if (ret)
> > +               return ret;
> > +
> > +       img_entry = &mdata.img_entry[0];
> > +       for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; 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(dev, &mdata);
> > +                       goto out;
> > +               }
> > +       }
> > +
> > +       /* Image not found */
> > +       ret = -ENOENT;
> > +
> > +out:
> > +       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_clrset_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_clrset_image_accept(img_type_id, bank,
> > +                                      IMAGE_ACCEPT_CLEAR);
> > +}
> > --
> > 2.34.1
> >

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

* Re: [PATCH v11 06/15] FWU: Add helper functions for accessing FWU metadata
  2022-09-28  9:29 ` [PATCH v11 06/15] FWU: Add helper functions for accessing FWU metadata Sughosh Ganu
@ 2022-10-03  9:51   ` Ilias Apalodimas
  0 siblings, 0 replies; 49+ messages in thread
From: Ilias Apalodimas @ 2022-10-03  9:51 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 Wed, Sep 28, 2022 at 02:59:47PM +0530, Sughosh Ganu wrote:
> Add weak functions for getting the update index value and dfu
> alternate number needed for FWU Multi Bank update
> functionality.
> 
> The current implementation for getting the update index value is for
> platforms with 2 banks. If a platform supports more than 2 banks, it
> can implement it's own function. The function to get the dfu alternate
> number has been added for platforms with GPT partitioned storage
> devices. Platforms with other storage partition scheme need to
> implement their own function.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
> ---
> Changes since V10: None
> 
> Note: I have not changed the logic of the check in
> fwu_gpt_get_alt_num(). This can be extended if and when another GPT
> based device gets added to the DFU framework.
> 
>  include/fwu.h             |  29 ++++++++++
>  lib/fwu_updates/fwu.c     |  27 +++++++++
>  lib/fwu_updates/fwu_gpt.c | 114 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 170 insertions(+)
>  create mode 100644 lib/fwu_updates/fwu_gpt.c
> 
> diff --git a/include/fwu.h b/include/fwu.h
> index 167f91388e..99f43f07b0 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -212,4 +212,33 @@ 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);
>  
> +/**
> + * fwu_plat_get_alt_num() - Get the DFU Alt Num for the image from the platform
> + * @dev: FWU device
> + * @image_guid: Image GUID for which DFU alt number needs to be retrieved
> + * @alt_num: Pointer to the alt_num
> + *
> + * Get the DFU alt number from the platform for the image specified by the
> + * image GUID.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
> +			 u8 *alt_num);
> +
> +/**
> + * fwu_plat_get_update_index() - Get the value of the update bank
> + * @update_idx: Bank number to which images are to be updated
> + *
> + * Get the value of the bank(partition) to which the update needs to be
> + * made.
> + *
> + * Note: This is a weak function and platforms can override this with
> + * their own implementation for selection of the update bank.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int fwu_plat_get_update_index(uint *update_idx);
>  #endif /* _FWU_H_ */
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> index fe8058bc37..5cf6bec6a0 100644
> --- a/lib/fwu_updates/fwu.c
> +++ b/lib/fwu_updates/fwu.c
> @@ -361,3 +361,30 @@ int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank)
>  	return fwu_clrset_image_accept(img_type_id, bank,
>  				       IMAGE_ACCEPT_CLEAR);
>  }
> +
> +/**
> + * fwu_plat_get_update_index() - Get the value of the update bank
> + * @update_idx: Bank number to which images are to be updated
> + *
> + * Get the value of the bank(partition) to which the update needs to be
> + * made.
> + *
> + * Note: This is a weak function and platforms can override this with
> + * their own implementation for selection of the update bank.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +__weak int fwu_plat_get_update_index(uint *update_idx)
> +{
> +	int ret;
> +	u32 active_idx;
> +
> +	ret = fwu_get_active_index(&active_idx);
> +	if (ret < 0)
> +		return -1;
> +
> +	*update_idx = (active_idx + 1) % CONFIG_FWU_NUM_BANKS;
> +
> +	return ret;
> +}
> diff --git a/lib/fwu_updates/fwu_gpt.c b/lib/fwu_updates/fwu_gpt.c
> new file mode 100644
> index 0000000000..a1b0f3bea7
> --- /dev/null
> +++ b/lib/fwu_updates/fwu_gpt.c
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2022, Linaro Limited
> + */
> +
> +#include <blk.h>
> +#include <dfu.h>
> +#include <efi.h>
> +#include <efi_loader.h>
> +#include <fwu.h>
> +#include <log.h>
> +#include <part.h>
> +
> +#include <linux/errno.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 fwu_gpt_get_alt_num(struct blk_desc *desc, efi_guid_t *image_guid,
> +			       u8 *alt_num, unsigned char dfu_dev)
> +{
> +	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++;

Why do we have to do this?  Can't we just call dfu_get_entity() on a
for(;;) loop and break out if the result is NULL?

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

I still this needs to go into a different function.  Maybe in one with 
switch/cases where you only check DFU_DEV_MMC for now and return -ENOTSUPP
for other device types

> +	}
> +
> +	dfu_free_entities();
> +
> +	return ret;
> +}
> +
> +/**
> + * fwu_plat_get_alt_num() - Get the DFU alt number
> + * @dev: FWU metadata device
> + * @image_guid: GUID value of the image for which the alt num is to
> + *              be obtained
> + * @alt_num: The DFU alt number for the image that is to be updated
> + *
> + * Get the DFU alt number for the image that is to be updated. The
> + * image is identified with the image_guid parameter that is passed
> + * to the function.
> + *
> + * Note: This is a weak function and platforms can override this with
> + * their own implementation for obtaining the alt number value.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +__weak int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_guid,
> +				u8 *alt_num)
> +{
> +	struct fwu_mdata_gpt_blk_priv *priv = dev_get_priv(dev);
> +
> +	return fwu_gpt_get_alt_num(dev_get_uclass_plat(priv->blk_dev),
> +				   image_guid, alt_num, DFU_DEV_MMC);
> +}
> -- 
> 2.34.1
> 

Cheers
/Ilias

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

* Re: [PATCH v11 09/15] FWU: Add boot time checks as highlighted by the FWU specification
  2022-09-28  9:29 ` [PATCH v11 09/15] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
@ 2022-10-03  9:56   ` Ilias Apalodimas
  2022-10-03 10:31     ` Sughosh Ganu
  0 siblings, 1 reply; 49+ messages in thread
From: Ilias Apalodimas @ 2022-10-03  9:56 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 Wed, Sep 28, 2022 at 02:59:50PM +0530, 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.
> 
> Call these checks through the main loop event at the time of platform
> boot.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
> ---
> Changes since V10:
> * Remove the spurious newline addition in efi_setup.c
> * Move the assignment of trial_state outside the if() as suggested by
>   Jassi
> 
>  include/fwu.h         |  13 +++
>  lib/fwu_updates/fwu.c | 193 +++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 204 insertions(+), 2 deletions(-)
> 
> diff --git a/include/fwu.h b/include/fwu.h
> index 71a03cf70b..2effa7da38 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -253,4 +253,17 @@ int fwu_plat_get_update_index(uint *update_idx);
>   *
>   */
>  void fwu_plat_get_bootidx(uint *boot_idx);
> +
> +/**
> + * fwu_update_checks_pass() - Check if FWU update can be done
> + *
> + * Check if the FWU update can be executed. The updates are
> + * allowed only when the platform is not in Trial State and
> + * the boot time checks have passed
> + *
> + * Return: 1 if OK, 0 on error
> + *
> + */
> +u8 fwu_update_checks_pass(void);
> +
>  #endif /* _FWU_H_ */
> diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> index 5cf6bec6a0..5cde5514d2 100644
> --- a/lib/fwu_updates/fwu.c
> +++ b/lib/fwu_updates/fwu.c
> @@ -4,10 +4,19 @@
>   */
>  
>  #include <dm.h>
> +#include <efi.h>
>  #include <efi_loader.h>
> +#include <efi_variable.h>
> +#include <event.h>
>  #include <fwu.h>
>  #include <fwu_mdata.h>
> -#include <log.h>
> +#include <malloc.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
> +static u8 trial_state;
> +static u8 boottime_check;
>  
>  #include <linux/errno.h>
>  #include <linux/types.h>
> @@ -16,8 +25,113 @@
>  #define IMAGE_ACCEPT_SET	BIT(0)
>  #define IMAGE_ACCEPT_CLEAR	BIT(1)
>  
> -static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
> +static int trial_counter_update(u16 *trial_state_ctr)
> +{
> +	bool delete;
> +	u32 var_attr;
> +	efi_status_t status;
> +	efi_uintn_t var_size;
> +
> +	delete = !trial_state_ctr ? true : false;
> +	var_size = !trial_state_ctr ? 0 : (efi_uintn_t)sizeof(*trial_state_ctr);
> +	var_attr = !trial_state_ctr ? 0 : EFI_VARIABLE_NON_VOLATILE |
> +		EFI_VARIABLE_BOOTSERVICE_ACCESS;
> +	status = efi_set_variable_int(u"TrialStateCtr",
> +				      &efi_global_variable_guid,
> +				      var_attr,
> +				      var_size, trial_state_ctr, false);
> +
> +	if ((delete && (status != EFI_NOT_FOUND &&

Is there a legitimate case where we need to delete the variable while it's not there? 
Wouldn't that be some kind of failure we shouldn't hide?

> +			status != EFI_SUCCESS)) ||
> +	    (!delete && status != EFI_SUCCESS))
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static int in_trial_state(struct fwu_mdata *mdata)
> +{
> +	u32 i, active_bank;
> +	struct fwu_image_entry *img_entry;
> +	struct fwu_image_bank_info *img_bank_info;
> +
> +	active_bank = mdata->active_index;
> +	img_entry = &mdata->img_entry[0];
> +	for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
> +		img_bank_info = &img_entry[i].img_bank_info[active_bank];
> +		if (!img_bank_info->accepted) {
> +			return 1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int fwu_trial_state_check(struct udevice *dev)
> +{
> +	int ret;
> +	efi_status_t status;
> +	efi_uintn_t var_size;
> +	u16 trial_state_ctr;
> +	u32 var_attributes;
> +	struct fwu_mdata mdata = { 0 };
> +
> +	ret = fwu_get_mdata(dev, &mdata);
> +	if (ret)
> +		return ret;
> +
> +	trial_state = in_trial_state(&mdata);
> +	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(u"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");
> +			ret = fwu_revert_boot_index();
> +			if (ret) {
> +				log_err("Unable to revert active_index\n");
> +				goto out;
> +			}
> +
> +			/* Delete the TrialStateCtr variable */
> +			ret = trial_counter_update(NULL);
> +			if (ret) {
> +				log_err("Unable to delete TrialStateCtr variable\n");
> +				goto out;
> +			}
> +		} else {
> +			ret = trial_counter_update(&trial_state_ctr);
> +			if (ret) {
> +				log_err("Unable to increment TrialStateCtr variable\n");
> +				goto out;
> +			}
> +		}
> +	} else {
> +		/* Delete the variable */
> +		ret = trial_counter_update(NULL);
> +		if (ret) {
> +			log_err("Unable to delete TrialStateCtr variable\n");
> +		}
> +	}
> +
> +out:
> +	return ret;
> +}
>  
> +static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
>  {
>  	int ret;
>  
> @@ -27,6 +141,9 @@ static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
>  		return ret;
>  	}
>  
> +	if (!mdata)
> +		return 0;
> +

Doesn't this belong to the patch that introduced the function?

>  	ret = fwu_get_mdata(*dev, mdata);
>  	if (ret < 0)
>  		log_debug("Unable to get valid FWU metadata\n");
> @@ -388,3 +505,75 @@ __weak int fwu_plat_get_update_index(uint *update_idx)
>  
>  	return ret;
>  }
> +
> +/**
> + * fwu_update_checks_pass() - Check if FWU update can be done
> + *
> + * Check if the FWU update can be executed. The updates are
> + * allowed only when the platform is not in Trial State and
> + * the boot time checks have passed
> + *
> + * Return: 1 if OK, 0 on error
> + *
> + */
> +u8 fwu_update_checks_pass(void)
> +{
> +	return !trial_state && boottime_check;
> +}
> +
> +static int fwu_boottime_checks(void *ctx, struct event *event)

I think this should be declared as bool 

> +{
> +	int ret;
> +	struct udevice *dev;
> +	u32 boot_idx, active_idx;
> +
> +	ret = fwu_get_dev_mdata(&dev, NULL);
> +	if (ret)
> +		return ret;
> +
> +	ret = fwu_mdata_check(dev);
> +	if (ret) {
> +		return 0;
> +	}

You don't need {}

> +
> +	/*
> +	 * 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_set_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(dev);
> +	if (!ret)
> +		boottime_check = 1;
> +
> +	return 0;
> +}
> +EVENT_SPY(EVT_MAIN_LOOP, fwu_boottime_checks);
> -- 
> 2.34.1
> 


Cheers
/Ilias

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

* Re: [PATCH v11 09/15] FWU: Add boot time checks as highlighted by the FWU specification
  2022-10-03  9:56   ` Ilias Apalodimas
@ 2022-10-03 10:31     ` Sughosh Ganu
  0 siblings, 0 replies; 49+ messages in thread
From: Sughosh Ganu @ 2022-10-03 10:31 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 Mon, 3 Oct 2022 at 15:26, Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>
> On Wed, Sep 28, 2022 at 02:59:50PM +0530, 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.
> >
> > Call these checks through the main loop event at the time of platform
> > boot.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
> > ---
> > Changes since V10:
> > * Remove the spurious newline addition in efi_setup.c
> > * Move the assignment of trial_state outside the if() as suggested by
> >   Jassi
> >
> >  include/fwu.h         |  13 +++
> >  lib/fwu_updates/fwu.c | 193 +++++++++++++++++++++++++++++++++++++++++-
> >  2 files changed, 204 insertions(+), 2 deletions(-)
> >
> > diff --git a/include/fwu.h b/include/fwu.h
> > index 71a03cf70b..2effa7da38 100644
> > --- a/include/fwu.h
> > +++ b/include/fwu.h
> > @@ -253,4 +253,17 @@ int fwu_plat_get_update_index(uint *update_idx);
> >   *
> >   */
> >  void fwu_plat_get_bootidx(uint *boot_idx);
> > +
> > +/**
> > + * fwu_update_checks_pass() - Check if FWU update can be done
> > + *
> > + * Check if the FWU update can be executed. The updates are
> > + * allowed only when the platform is not in Trial State and
> > + * the boot time checks have passed
> > + *
> > + * Return: 1 if OK, 0 on error
> > + *
> > + */
> > +u8 fwu_update_checks_pass(void);
> > +
> >  #endif /* _FWU_H_ */
> > diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
> > index 5cf6bec6a0..5cde5514d2 100644
> > --- a/lib/fwu_updates/fwu.c
> > +++ b/lib/fwu_updates/fwu.c
> > @@ -4,10 +4,19 @@
> >   */
> >
> >  #include <dm.h>
> > +#include <efi.h>
> >  #include <efi_loader.h>
> > +#include <efi_variable.h>
> > +#include <event.h>
> >  #include <fwu.h>
> >  #include <fwu_mdata.h>
> > -#include <log.h>
> > +#include <malloc.h>
> > +
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +
> > +static u8 trial_state;
> > +static u8 boottime_check;
> >
> >  #include <linux/errno.h>
> >  #include <linux/types.h>
> > @@ -16,8 +25,113 @@
> >  #define IMAGE_ACCEPT_SET     BIT(0)
> >  #define IMAGE_ACCEPT_CLEAR   BIT(1)
> >
> > -static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
> > +static int trial_counter_update(u16 *trial_state_ctr)
> > +{
> > +     bool delete;
> > +     u32 var_attr;
> > +     efi_status_t status;
> > +     efi_uintn_t var_size;
> > +
> > +     delete = !trial_state_ctr ? true : false;
> > +     var_size = !trial_state_ctr ? 0 : (efi_uintn_t)sizeof(*trial_state_ctr);
> > +     var_attr = !trial_state_ctr ? 0 : EFI_VARIABLE_NON_VOLATILE |
> > +             EFI_VARIABLE_BOOTSERVICE_ACCESS;
> > +     status = efi_set_variable_int(u"TrialStateCtr",
> > +                                   &efi_global_variable_guid,
> > +                                   var_attr,
> > +                                   var_size, trial_state_ctr, false);
> > +
> > +     if ((delete && (status != EFI_NOT_FOUND &&
>
> Is there a legitimate case where we need to delete the variable while it's not there?
> Wouldn't that be some kind of failure we shouldn't hide?

The variable will be found the first time the platform transitions
from Trial State to regular state. However, on subsequent boots, the
variable would no longer be present, and the efi_set_variable_int()
would return EFI_NOT_FOUND. That would not be an error scenario and
hence the check.

>
> > +                     status != EFI_SUCCESS)) ||
> > +         (!delete && status != EFI_SUCCESS))
> > +             return -1;
> > +
> > +     return 0;
> > +}
> > +
> > +static int in_trial_state(struct fwu_mdata *mdata)
> > +{
> > +     u32 i, active_bank;
> > +     struct fwu_image_entry *img_entry;
> > +     struct fwu_image_bank_info *img_bank_info;
> > +
> > +     active_bank = mdata->active_index;
> > +     img_entry = &mdata->img_entry[0];
> > +     for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
> > +             img_bank_info = &img_entry[i].img_bank_info[active_bank];
> > +             if (!img_bank_info->accepted) {
> > +                     return 1;
> > +             }
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int fwu_trial_state_check(struct udevice *dev)
> > +{
> > +     int ret;
> > +     efi_status_t status;
> > +     efi_uintn_t var_size;
> > +     u16 trial_state_ctr;
> > +     u32 var_attributes;
> > +     struct fwu_mdata mdata = { 0 };
> > +
> > +     ret = fwu_get_mdata(dev, &mdata);
> > +     if (ret)
> > +             return ret;
> > +
> > +     trial_state = in_trial_state(&mdata);
> > +     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(u"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");
> > +                     ret = fwu_revert_boot_index();
> > +                     if (ret) {
> > +                             log_err("Unable to revert active_index\n");
> > +                             goto out;
> > +                     }
> > +
> > +                     /* Delete the TrialStateCtr variable */
> > +                     ret = trial_counter_update(NULL);
> > +                     if (ret) {
> > +                             log_err("Unable to delete TrialStateCtr variable\n");
> > +                             goto out;
> > +                     }
> > +             } else {
> > +                     ret = trial_counter_update(&trial_state_ctr);
> > +                     if (ret) {
> > +                             log_err("Unable to increment TrialStateCtr variable\n");
> > +                             goto out;
> > +                     }
> > +             }
> > +     } else {
> > +             /* Delete the variable */
> > +             ret = trial_counter_update(NULL);
> > +             if (ret) {
> > +                     log_err("Unable to delete TrialStateCtr variable\n");
> > +             }
> > +     }
> > +
> > +out:
> > +     return ret;
> > +}
> >
> > +static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
> >  {
> >       int ret;
> >
> > @@ -27,6 +141,9 @@ static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
> >               return ret;
> >       }
> >
> > +     if (!mdata)
> > +             return 0;
> > +
>
> Doesn't this belong to the patch that introduced the function?

I thought of putting it along with a call to the fwu_get_dev_mdata()
function with mdata set to NULL.

>
> >       ret = fwu_get_mdata(*dev, mdata);
> >       if (ret < 0)
> >               log_debug("Unable to get valid FWU metadata\n");
> > @@ -388,3 +505,75 @@ __weak int fwu_plat_get_update_index(uint *update_idx)
> >
> >       return ret;
> >  }
> > +
> > +/**
> > + * fwu_update_checks_pass() - Check if FWU update can be done
> > + *
> > + * Check if the FWU update can be executed. The updates are
> > + * allowed only when the platform is not in Trial State and
> > + * the boot time checks have passed
> > + *
> > + * Return: 1 if OK, 0 on error
> > + *
> > + */
> > +u8 fwu_update_checks_pass(void)
> > +{
> > +     return !trial_state && boottime_check;
> > +}
> > +
> > +static int fwu_boottime_checks(void *ctx, struct event *event)
>
> I think this should be declared as bool

This being an event handler, is following the signature of event_handler_t.

>
> > +{
> > +     int ret;
> > +     struct udevice *dev;
> > +     u32 boot_idx, active_idx;
> > +
> > +     ret = fwu_get_dev_mdata(&dev, NULL);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = fwu_mdata_check(dev);
> > +     if (ret) {
> > +             return 0;
> > +     }
>
> You don't need {}

Will remove

-sughosh

>
> > +
> > +     /*
> > +      * 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_set_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(dev);
> > +     if (!ret)
> > +             boottime_check = 1;
> > +
> > +     return 0;
> > +}
> > +EVENT_SPY(EVT_MAIN_LOOP, fwu_boottime_checks);
> > --
> > 2.34.1
> >
>
>
> Cheers
> /Ilias

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

* Re: [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates
  2022-09-28  9:29 ` [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates Sughosh Ganu
  2022-09-30  5:51   ` Etienne Carriere
@ 2022-10-03 10:56   ` Takahiro Akashi
  2022-10-03 11:10     ` Sughosh Ganu
  1 sibling, 1 reply; 49+ messages in thread
From: Takahiro Akashi @ 2022-10-03 10:56 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

Hi Sughosh,

On Wed, Sep 28, 2022 at 02:59:46PM +0530, Sughosh Ganu wrote:
> 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>
> Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> ---
> Changes since V10:
> * Use image_index value of 1 for the FIP image as it is now relevant
> 
>  board/st/stm32mp1/stm32mp1.c       | 18 ++++++++++++++++++
>  include/configs/stm32mp15_common.h |  4 ++++
>  2 files changed, 22 insertions(+)
> 
> diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> index 8c162b42a5..e43dab018f 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>
> @@ -87,6 +88,16 @@
>  #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);

The definition of num_image_type_guids is always the same
across boards. Why do we need it for every platform?
I believe that we can remove it. Anyhow it's not documented
in doc/develop/uefi/uefi.rst.

> +#endif /* EFI_HAVE_CAPSULE_SUPPORT */
> +
>  int board_early_init_f(void)
>  {
>  	/* nothing to do, only used in SPL */
> @@ -666,6 +677,13 @@ int board_init(void)
>  
>  	setup_led(LEDST_ON);
>  
> +#if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
> +	efi_guid_t image_type_guid = STM32MP_FIP_IMAGE_GUID;
> +
> +	guidcpy(&fw_images[0].image_type_id, &image_type_guid);
> +	fw_images[0].fw_name = u"STM32MP-FIP";
> +	fw_images[0].image_index = 1;

Then, we should describe that image_index must be 1 to num_image_type_guids
(or strictly, number of descriptors returned by GetImageInfo()) in
the document above.
(I hope that you add a sanity checker against it as well.)

-Takahiro Akashi

> +#endif
>  	return 0;
>  }
>  
> diff --git a/include/configs/stm32mp15_common.h b/include/configs/stm32mp15_common.h
> index c5412ffeb3..bb19dae945 100644
> --- a/include/configs/stm32mp15_common.h
> +++ b/include/configs/stm32mp15_common.h
> @@ -34,6 +34,10 @@
>  #define CONFIG_SERVERIP                 192.168.1.1
>  #endif
>  
> +#define STM32MP_FIP_IMAGE_GUID \
> +	EFI_GUID(0x19d5df83, 0x11b0, 0x457b, 0xbe, 0x2c, \
> +		 0x75, 0x59, 0xc1, 0x31, 0x42, 0xa5)
> +
>  /*****************************************************************************/
>  #ifdef CONFIG_DISTRO_DEFAULTS
>  /*****************************************************************************/
> -- 
> 2.34.1
> 

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

* Re: [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU
  2022-10-02 23:52   ` [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU jassisinghbrar
@ 2022-10-03 11:04     ` AKASHI Takahiro
  2022-10-03 13:40       ` Jassi Brar
  0 siblings, 1 reply; 49+ messages in thread
From: AKASHI Takahiro @ 2022-10-03 11:04 UTC (permalink / raw)
  To: jassisinghbrar
  Cc: u-boot, xypron.glpk, ilias.apalodimas, sjg, trini,
	etienne.carriere, monstr, Masami Hiramatsu, Jassi Brar

Hi Jassi,

On Sun, Oct 02, 2022 at 06:52:14PM -0500, jassisinghbrar@gmail.com wrote:
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> 
> Add code to support FWU_MULTI_BANK_UPDATE.
> The platform does not have gpt-partition storage for
> Banks and MetaData, rather it used SPI-NOR backed
> mtd regions for the purpose.
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
> ---
>  board/socionext/developerbox/Makefile       |  1 +
>  board/socionext/developerbox/developerbox.c |  8 ++
>  board/socionext/developerbox/fwu_plat.c     | 68 +++++++++++++++
>  configs/synquacer_developerbox_defconfig    | 13 ++-
>  doc/board/socionext/developerbox.rst        | 96 +++++++++++++++++++++
>  include/configs/synquacer.h                 | 10 +++
>  6 files changed, 194 insertions(+), 2 deletions(-)
>  create mode 100644 board/socionext/developerbox/fwu_plat.c
> 
> 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/developerbox.c b/board/socionext/developerbox/developerbox.c
> index f5a5fe0121..a0db26eaf3 100644
> --- a/board/socionext/developerbox/developerbox.c
> +++ b/board/socionext/developerbox/developerbox.c
> @@ -20,6 +20,13 @@
>  
>  #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
>  struct efi_fw_image fw_images[] = {
> +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> +	{
> +		.image_type_id = DEVELOPERBOX_FIP_IMAGE_GUID,
> +		.fw_name = u"DEVELOPERBOX-FIP",
> +		.image_index = 1,
> +	},
> +#else

From curiosity, why do you want to use different capsule formats
for multi-bank update and normal case?

-Takahiro Akashi

>  	{
>  		.image_type_id = DEVELOPERBOX_UBOOT_IMAGE_GUID,
>  		.fw_name = u"DEVELOPERBOX-UBOOT",
> @@ -35,6 +42,7 @@ struct efi_fw_image fw_images[] = {
>  		.fw_name = u"DEVELOPERBOX-OPTEE",
>  		.image_index = 3,
>  	},
> +#endif
>  };
>  
>  struct efi_capsule_update_info update_info = {
> diff --git a/board/socionext/developerbox/fwu_plat.c b/board/socionext/developerbox/fwu_plat.c
> new file mode 100644
> index 0000000000..f333cd4027
> --- /dev/null
> +++ b/board/socionext/developerbox/fwu_plat.c
> @@ -0,0 +1,68 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2022, 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 <mtd.h>
> +#include <spi.h>
> +#include <spi_flash.h>
> +#include <uuid.h>
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <u-boot/crc.h>
> +
> +#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;
> +
> +	ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN);
> +	memset(buf, 0, sizeof(buf));
> +
> +	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);
> +}
> +
> +int fwu_plat_get_alt_num(struct udevice __always_unused *dev,
> +			 efi_guid_t *image_id, u8 *alt_num)
> +{
> +	return fwu_mtd_get_alt_num(image_id, alt_num, "nor1");
> +}
> +
> +void fwu_plat_get_bootidx(uint *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;
> +}
> diff --git a/configs/synquacer_developerbox_defconfig b/configs/synquacer_developerbox_defconfig
> index c0b784b072..b1085a388e 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"
> @@ -96,3 +97,11 @@ 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=y
> +CONFIG_FWU_MDATA_MTD=y
> +CONFIG_FWU_NUM_BANKS=2
> +CONFIG_FWU_NUM_IMAGES_PER_BANK=1
> +CONFIG_CMD_FWU_METADATA=y
> +CONFIG_TOOLS_MKFWUMDATA=y
> diff --git a/doc/board/socionext/developerbox.rst b/doc/board/socionext/developerbox.rst
> index 2d943c23be..be872aa79d 100644
> --- a/doc/board/socionext/developerbox.rst
> +++ b/doc/board/socionext/developerbox.rst
> @@ -85,3 +85,99 @@ 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=y
> + CONFIG_FWU_MDATA_MTD=y
> + CONFIG_FWU_NUM_BANKS=2
> + CONFIG_FWU_NUM_IMAGES_PER_BANK=1
> + CONFIG_CMD_FWU_METADATA=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.
> +
> +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.::
> +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.)
> diff --git a/include/configs/synquacer.h b/include/configs/synquacer.h
> index 63d897d090..c798a23bed 100644
> --- a/include/configs/synquacer.h
> +++ b/include/configs/synquacer.h
> @@ -41,19 +41,29 @@
>  
>  /* Since U-Boot 64bit PCIe support is limited, disable 64bit MMIO support */
>  
> +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
> +#define DEFAULT_DFU_ALT_INFO
> +#else
>  #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"
> +#endif
>  
>  /* GUIDs for capsule updatable firmware images */
>  #define DEVELOPERBOX_UBOOT_IMAGE_GUID \
>  	EFI_GUID(0x53a92e83, 0x4ef4, 0x473a, 0x8b, 0x0d, \
>  		 0xb5, 0xd8, 0xc7, 0xb2, 0xd6, 0x00)
>  
> +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
> +#define DEVELOPERBOX_FIP_IMAGE_GUID \
> +	EFI_GUID(0x7d6dc310, 0x52ca, 0x43b8, 0xb7, 0xb9, \
> +		 0xf9, 0xd6, 0xc5, 0x01, 0xd1, 0x08)
> +#else
>  #define DEVELOPERBOX_FIP_IMAGE_GUID \
>  	EFI_GUID(0x880866e9, 0x84ba, 0x4793, 0xa9, 0x08, \
>  		 0x33, 0xe0, 0xb9, 0x16, 0xf3, 0x98)
> +#endif
>  
>  #define DEVELOPERBOX_OPTEE_IMAGE_GUID \
>  	EFI_GUID(0xc1b629f1, 0xce0e, 0x4894, 0x82, 0xbf, \
> -- 
> 2.25.1
> 

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

* Re: [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates
  2022-10-03 10:56   ` Takahiro Akashi
@ 2022-10-03 11:10     ` Sughosh Ganu
  2022-10-04  3:04       ` Takahiro Akashi
  0 siblings, 1 reply; 49+ messages in thread
From: Sughosh Ganu @ 2022-10-03 11: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

hi Takahiro,

On Mon, 3 Oct 2022 at 16:27, Takahiro Akashi <takahiro.akashi@linaro.org> wrote:
>
> Hi Sughosh,
>
> On Wed, Sep 28, 2022 at 02:59:46PM +0530, Sughosh Ganu wrote:
> > 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>
> > Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> > Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> > ---
> > Changes since V10:
> > * Use image_index value of 1 for the FIP image as it is now relevant
> >
> >  board/st/stm32mp1/stm32mp1.c       | 18 ++++++++++++++++++
> >  include/configs/stm32mp15_common.h |  4 ++++
> >  2 files changed, 22 insertions(+)
> >
> > diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> > index 8c162b42a5..e43dab018f 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>
> > @@ -87,6 +88,16 @@
> >  #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);
>
> The definition of num_image_type_guids is always the same
> across boards. Why do we need it for every platform?

Yes, but that is because at present every platform is declaring the
same variable name(fw_images) for the struct efi_fw_image. That is not
mandatory, and a subsequent addition can declare a variable with a
different name. But in case there is consensus on using a fixed
variable name for the structure, I can make the change that you are
suggesting subsequently. I will work on it if needed after the FWU
patches upstreaming work is done.


> I believe that we can remove it. Anyhow it's not documented
> in doc/develop/uefi/uefi.rst.
>
> > +#endif /* EFI_HAVE_CAPSULE_SUPPORT */
> > +
> >  int board_early_init_f(void)
> >  {
> >       /* nothing to do, only used in SPL */
> > @@ -666,6 +677,13 @@ int board_init(void)
> >
> >       setup_led(LEDST_ON);
> >
> > +#if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
> > +     efi_guid_t image_type_guid = STM32MP_FIP_IMAGE_GUID;
> > +
> > +     guidcpy(&fw_images[0].image_type_id, &image_type_guid);
> > +     fw_images[0].fw_name = u"STM32MP-FIP";
> > +     fw_images[0].image_index = 1;
>
> Then, we should describe that image_index must be 1 to num_image_type_guids
> (or strictly, number of descriptors returned by GetImageInfo()) in
> the document above.

Okay

> (I hope that you add a sanity checker against it as well.)

Yes, in the efi_fmp_find(), there is a check for the index value
passed through the capsule against the value returned by the
GetImageInfo().

-sughosh

>
> -Takahiro Akashi
>
> > +#endif
> >       return 0;
> >  }
> >
> > diff --git a/include/configs/stm32mp15_common.h b/include/configs/stm32mp15_common.h
> > index c5412ffeb3..bb19dae945 100644
> > --- a/include/configs/stm32mp15_common.h
> > +++ b/include/configs/stm32mp15_common.h
> > @@ -34,6 +34,10 @@
> >  #define CONFIG_SERVERIP                 192.168.1.1
> >  #endif
> >
> > +#define STM32MP_FIP_IMAGE_GUID \
> > +     EFI_GUID(0x19d5df83, 0x11b0, 0x457b, 0xbe, 0x2c, \
> > +              0x75, 0x59, 0xc1, 0x31, 0x42, 0xa5)
> > +
> >  /*****************************************************************************/
> >  #ifdef CONFIG_DISTRO_DEFAULTS
> >  /*****************************************************************************/
> > --
> > 2.34.1
> >

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

* Re: [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU
  2022-10-03 11:04     ` AKASHI Takahiro
@ 2022-10-03 13:40       ` Jassi Brar
  2022-10-03 13:51         ` Ilias Apalodimas
  0 siblings, 1 reply; 49+ messages in thread
From: Jassi Brar @ 2022-10-03 13:40 UTC (permalink / raw)
  To: AKASHI Takahiro, jassisinghbrar, u-boot, xypron.glpk,
	ilias.apalodimas, sjg, trini, etienne.carriere, monstr,
	Masami Hiramatsu, Jassi Brar

On Mon, Oct 3, 2022 at 6:04 AM AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:

> > diff --git a/board/socionext/developerbox/developerbox.c b/board/socionext/developerbox/developerbox.c
> > index f5a5fe0121..a0db26eaf3 100644
> > --- a/board/socionext/developerbox/developerbox.c
> > +++ b/board/socionext/developerbox/developerbox.c
> > @@ -20,6 +20,13 @@
> >
> >  #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
> >  struct efi_fw_image fw_images[] = {
> > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > +     {
> > +             .image_type_id = DEVELOPERBOX_FIP_IMAGE_GUID,
> > +             .fw_name = u"DEVELOPERBOX-FIP",
> > +             .image_index = 1,
> > +     },
> > +#else
>
> From curiosity, why do you want to use different capsule formats
> for multi-bank update and normal case?
>
normal/legacy layout has one image for each component - uboot, tfa and
optee, whereas the new layout contains everything in one fip image.
So I thought it would be better to make the image_index consistent by
making the fip's as 1.

cheers.

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

* Re: [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU
  2022-10-03 13:40       ` Jassi Brar
@ 2022-10-03 13:51         ` Ilias Apalodimas
  2022-10-04  1:06           ` AKASHI Takahiro
  0 siblings, 1 reply; 49+ messages in thread
From: Ilias Apalodimas @ 2022-10-03 13:51 UTC (permalink / raw)
  To: Jassi Brar
  Cc: AKASHI Takahiro, u-boot, xypron.glpk, sjg, trini,
	etienne.carriere, monstr, Masami Hiramatsu, Jassi Brar

Hi Jassi,

On Mon, 3 Oct 2022 at 16:40, Jassi Brar <jassisinghbrar@gmail.com> wrote:
>
> On Mon, Oct 3, 2022 at 6:04 AM AKASHI Takahiro
> <takahiro.akashi@linaro.org> wrote:
>
> > > diff --git a/board/socionext/developerbox/developerbox.c b/board/socionext/developerbox/developerbox.c
> > > index f5a5fe0121..a0db26eaf3 100644
> > > --- a/board/socionext/developerbox/developerbox.c
> > > +++ b/board/socionext/developerbox/developerbox.c
> > > @@ -20,6 +20,13 @@
> > >
> > >  #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
> > >  struct efi_fw_image fw_images[] = {
> > > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > > +     {
> > > +             .image_type_id = DEVELOPERBOX_FIP_IMAGE_GUID,
> > > +             .fw_name = u"DEVELOPERBOX-FIP",
> > > +             .image_index = 1,
> > > +     },
> > > +#else
> >
> > From curiosity, why do you want to use different capsule formats
> > for multi-bank update and normal case?
> >
> normal/legacy layout has one image for each component - uboot, tfa and
> optee, whereas the new layout contains everything in one fip image.
> So I thought it would be better to make the image_index consistent by
> making the fip's as 1.

FWIW this does make a lot of sense.  Since the SCP firmware is not
included in the capsule and that SCP firmware is needed to transition
from old -> new layout, I think we are better off having those in
different GUIDs.  On top of that those GUIDs can be used in LVFS if we
ever decide to upload firmwares there.

Not having discrete GUIDs means there's a chance to brick the board on
old -> new update,  unless the SCP is explicitly updated.

Cheers
/Ilias
>
> cheers.

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

* Re: [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU
  2022-10-03 13:51         ` Ilias Apalodimas
@ 2022-10-04  1:06           ` AKASHI Takahiro
  2022-10-04  2:00             ` Jassi Brar
  0 siblings, 1 reply; 49+ messages in thread
From: AKASHI Takahiro @ 2022-10-04  1:06 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: Jassi Brar, u-boot, xypron.glpk, sjg, trini, etienne.carriere,
	monstr, Jassi Brar

On Mon, Oct 03, 2022 at 04:51:32PM +0300, Ilias Apalodimas wrote:
> Hi Jassi,
> 
> On Mon, 3 Oct 2022 at 16:40, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> >
> > On Mon, Oct 3, 2022 at 6:04 AM AKASHI Takahiro
> > <takahiro.akashi@linaro.org> wrote:
> >
> > > > diff --git a/board/socionext/developerbox/developerbox.c b/board/socionext/developerbox/developerbox.c
> > > > index f5a5fe0121..a0db26eaf3 100644
> > > > --- a/board/socionext/developerbox/developerbox.c
> > > > +++ b/board/socionext/developerbox/developerbox.c
> > > > @@ -20,6 +20,13 @@
> > > >
> > > >  #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
> > > >  struct efi_fw_image fw_images[] = {
> > > > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > > > +     {
> > > > +             .image_type_id = DEVELOPERBOX_FIP_IMAGE_GUID,
> > > > +             .fw_name = u"DEVELOPERBOX-FIP",
> > > > +             .image_index = 1,
> > > > +     },
> > > > +#else
> > >
> > > From curiosity, why do you want to use different capsule formats
> > > for multi-bank update and normal case?
> > >
> > normal/legacy layout has one image for each component - uboot, tfa and
> > optee, whereas the new layout contains everything in one fip image.

Yes, that is exactly what I understand here.

> > So I thought it would be better to make the image_index consistent by
> > making the fip's as 1.
> 
> FWIW this does make a lot of sense.  Since the SCP firmware is not
> included in the capsule and that SCP firmware is needed to transition
> from old -> new layout, I think we are better off having those in
> different GUIDs.  On top of that those GUIDs can be used in LVFS if we
> ever decide to upload firmwares there.
> 
> Not having discrete GUIDs means there's a chance to brick the board on
> old -> new update,  unless the SCP is explicitly updated.

SCP? I don't care.
My question is why you use a single capsule (FIP) in A/B update while you use
three separate capsule files in normal case.

-Takahiro Akashi

> Cheers
> /Ilias
> >
> > cheers.

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

* Re: [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU
  2022-10-04  1:06           ` AKASHI Takahiro
@ 2022-10-04  2:00             ` Jassi Brar
  2022-10-04  2:44               ` AKASHI Takahiro
  0 siblings, 1 reply; 49+ messages in thread
From: Jassi Brar @ 2022-10-04  2:00 UTC (permalink / raw)
  To: AKASHI Takahiro, Ilias Apalodimas, Jassi Brar, u-boot,
	xypron.glpk, sjg, trini, etienne.carriere, monstr, Jassi Brar

On Mon, Oct 3, 2022 at 8:06 PM AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:
>
> On Mon, Oct 03, 2022 at 04:51:32PM +0300, Ilias Apalodimas wrote:
> > Hi Jassi,
> >
> > On Mon, 3 Oct 2022 at 16:40, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> > >
> > > On Mon, Oct 3, 2022 at 6:04 AM AKASHI Takahiro
> > > <takahiro.akashi@linaro.org> wrote:
> > >
> > > > > diff --git a/board/socionext/developerbox/developerbox.c b/board/socionext/developerbox/developerbox.c
> > > > > index f5a5fe0121..a0db26eaf3 100644
> > > > > --- a/board/socionext/developerbox/developerbox.c
> > > > > +++ b/board/socionext/developerbox/developerbox.c
> > > > > @@ -20,6 +20,13 @@
> > > > >
> > > > >  #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
> > > > >  struct efi_fw_image fw_images[] = {
> > > > > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > > > > +     {
> > > > > +             .image_type_id = DEVELOPERBOX_FIP_IMAGE_GUID,
> > > > > +             .fw_name = u"DEVELOPERBOX-FIP",
> > > > > +             .image_index = 1,
> > > > > +     },
> > > > > +#else
> > > >
> > > > From curiosity, why do you want to use different capsule formats
> > > > for multi-bank update and normal case?
> > > >
> > > normal/legacy layout has one image for each component - uboot, tfa and
> > > optee, whereas the new layout contains everything in one fip image.
>
> Yes, that is exactly what I understand here.
>
> > > So I thought it would be better to make the image_index consistent by
> > > making the fip's as 1.
> >
> > FWIW this does make a lot of sense.  Since the SCP firmware is not
> > included in the capsule and that SCP firmware is needed to transition
> > from old -> new layout, I think we are better off having those in
> > different GUIDs.  On top of that those GUIDs can be used in LVFS if we
> > ever decide to upload firmwares there.
> >
> > Not having discrete GUIDs means there's a chance to brick the board on
> > old -> new update,  unless the SCP is explicitly updated.
>
> SCP? I don't care.
> My question is why you use a single capsule (FIP) in A/B update while you use
> three separate capsule files in normal case.
>
We think it is cleaner to not tie up boot binaries at fixed offsets in
storage, so all CA53 boot assets are now in one parseable FIP image.
Secondly, and personally, I think there is no real usecase of more
than one image per bank - that will be too fragile and complicated to
manage.

cheers.

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

* Re: [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU
  2022-10-04  2:00             ` Jassi Brar
@ 2022-10-04  2:44               ` AKASHI Takahiro
  2022-10-04  2:53                 ` Jassi Brar
  0 siblings, 1 reply; 49+ messages in thread
From: AKASHI Takahiro @ 2022-10-04  2:44 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Ilias Apalodimas, u-boot, xypron.glpk, sjg, trini,
	etienne.carriere, monstr, Jassi Brar

On Mon, Oct 03, 2022 at 09:00:35PM -0500, Jassi Brar wrote:
> On Mon, Oct 3, 2022 at 8:06 PM AKASHI Takahiro
> <takahiro.akashi@linaro.org> wrote:
> >
> > On Mon, Oct 03, 2022 at 04:51:32PM +0300, Ilias Apalodimas wrote:
> > > Hi Jassi,
> > >
> > > On Mon, 3 Oct 2022 at 16:40, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> > > >
> > > > On Mon, Oct 3, 2022 at 6:04 AM AKASHI Takahiro
> > > > <takahiro.akashi@linaro.org> wrote:
> > > >
> > > > > > diff --git a/board/socionext/developerbox/developerbox.c b/board/socionext/developerbox/developerbox.c
> > > > > > index f5a5fe0121..a0db26eaf3 100644
> > > > > > --- a/board/socionext/developerbox/developerbox.c
> > > > > > +++ b/board/socionext/developerbox/developerbox.c
> > > > > > @@ -20,6 +20,13 @@
> > > > > >
> > > > > >  #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
> > > > > >  struct efi_fw_image fw_images[] = {
> > > > > > +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE)
> > > > > > +     {
> > > > > > +             .image_type_id = DEVELOPERBOX_FIP_IMAGE_GUID,
> > > > > > +             .fw_name = u"DEVELOPERBOX-FIP",
> > > > > > +             .image_index = 1,
> > > > > > +     },
> > > > > > +#else
> > > > >
> > > > > From curiosity, why do you want to use different capsule formats
> > > > > for multi-bank update and normal case?
> > > > >
> > > > normal/legacy layout has one image for each component - uboot, tfa and
> > > > optee, whereas the new layout contains everything in one fip image.
> >
> > Yes, that is exactly what I understand here.
> >
> > > > So I thought it would be better to make the image_index consistent by
> > > > making the fip's as 1.
> > >
> > > FWIW this does make a lot of sense.  Since the SCP firmware is not
> > > included in the capsule and that SCP firmware is needed to transition
> > > from old -> new layout, I think we are better off having those in
> > > different GUIDs.  On top of that those GUIDs can be used in LVFS if we
> > > ever decide to upload firmwares there.
> > >
> > > Not having discrete GUIDs means there's a chance to brick the board on
> > > old -> new update,  unless the SCP is explicitly updated.
> >
> > SCP? I don't care.
> > My question is why you use a single capsule (FIP) in A/B update while you use
> > three separate capsule files in normal case.
> >
> We think it is cleaner to not tie up boot binaries at fixed offsets in
> storage, so all CA53 boot assets are now in one parseable FIP image.
> Secondly, and personally, I think there is no real usecase of more
> than one image per bank - that will be too fragile and complicated to
> manage.

If so, my point is why not use a single capsule in normal case (a single bank
in another word) as well?

-Takahiro Akashi

> cheers.

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

* Re: [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU
  2022-10-04  2:44               ` AKASHI Takahiro
@ 2022-10-04  2:53                 ` Jassi Brar
  0 siblings, 0 replies; 49+ messages in thread
From: Jassi Brar @ 2022-10-04  2:53 UTC (permalink / raw)
  To: AKASHI Takahiro, Jassi Brar, Ilias Apalodimas, u-boot,
	xypron.glpk, sjg, trini, etienne.carriere, monstr, Jassi Brar

On Mon, Oct 3, 2022 at 9:44 PM AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:
> On Mon, Oct 03, 2022 at 09:00:35PM -0500, Jassi Brar wrote:

> > > My question is why you use a single capsule (FIP) in A/B update while you use
> > > three separate capsule files in normal case.
> > >
> > We think it is cleaner to not tie up boot binaries at fixed offsets in
> > storage, so all CA53 boot assets are now in one parseable FIP image.
> > Secondly, and personally, I think there is no real usecase of more
> > than one image per bank - that will be too fragile and complicated to
> > manage.
>
> If so, my point is why not use a single capsule in normal case (a single bank
> in another word) as well?
>
for historical/legacy reasons.

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

* Re: [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature
  2022-09-28  9:29 ` [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature Sughosh Ganu
  2022-09-30  6:27   ` Etienne Carriere
@ 2022-10-04  2:54   ` Takahiro Akashi
  2022-10-04  6:40     ` Sughosh Ganu
  1 sibling, 1 reply; 49+ messages in thread
From: Takahiro Akashi @ 2022-10-04  2:54 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, Sep 28, 2022 at 02:59:56PM +0530, Sughosh Ganu wrote:
> Add documentation 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>
> ---
> Changes since V10:
> * Fix review comments suggested by Etienne
> * Add a paragraph in the capsule update section to highlight the
>   difference in ImageIndex correlation with DFU alt num with FWU feature
>   enabled
> 
>  doc/develop/uefi/fwu_updates.rst | 173 +++++++++++++++++++++++++++++++
>  doc/develop/uefi/index.rst       |   1 +
>  doc/develop/uefi/uefi.rst        |  10 ++
>  3 files changed, 184 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..292feceb9a
> --- /dev/null
> +++ b/doc/develop/uefi/fwu_updates.rst
> @@ -0,0 +1,173 @@
> +.. 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 its 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-gpt.yaml>`__
> +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_RAW=y
> +
> +    CONFIG_FWU_MULTI_BANK_UPDATE=y
> +    CONFIG_CMD_FWU_METADATA=y
> +    CONFIG_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 configuration settings 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, a GPT partitioned storage
> +device is required. 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 a 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 partitions 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. An example list of images on the storage medium would be
> +
> +* FWU metadata 1
> +* U-Boot 1
> +* OP-TEE 1
> +* FWU metadata 2
> +* OP-TEE 2
> +* U-Boot 2
> +* ESP
> +* rootfs
> +
> +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.

Well, what is not clear to me here is:
- who is responsible to set up FWU metadata and when
- how FWU metadata is related to fw_images and update_info
  which are used in normal case, which is mentioned in develop/uefi/uefi.rst

I know the whole text here is dedicated to A/B update, but I think
it would also be helpful to have a single document which covers both cases
for developers to understand how differently FWU is configured for those cases.

-Takahiro Akashi

> +
> +Similarly, the FWU specification 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.
> +
> +The task of accepting the different firmware images, post an update
> +may be done by multiple, separate components in the Operating
> +System. To help identify the firmware image that is being accepted,
> +the accept capsule passes the image GUID of the firmware image being
> +accepted. The relevant code in U-Boot then sets the Accept bit of the
> +corresponding firmware image for which the accept capsule was
> +found. Only when all the firmware components in a bank have been
> +accepted does the platform transition from trial state to regular
> +state.
> +
> +The revert capsule on the other hand does not pass any image GUID,
> +since reverting any image of the bank has the same result of the
> +platform booting from the other bank on subsequent boot.
> +
> +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>
> +
> +Some examples of using the mkeficapsule tool for generation of the
> +empty capsule would be::
> +
> +.. code-block:: bash
> +
> +    $ ./tools/mkeficapsule --fw-accept --guid <image guid> \
> +    <accept_capsule_name>
> +    $ ./tools/mkeficapsule --fw-revert <revert_capsule_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..b5c83db65a 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
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>  
> @@ -377,6 +379,14 @@ following command::
>  
>      dfu list
>  
> +When the FWU Multi Bank Update feature is enabled on the platform, the
> +image index is used only to identify the image index with the image
> +GUID. The image index would not correspond to the dfu alt number. This
> +is because the FWU feature supports multiple partitions(banks) of
> +updatable images, and the actual dfu alt number to which the image is
> +to be written to is determined at runtime, based on the value of the
> +update bank to which the image is to be written.
> +
>  When using the FMP for FIT images, the image index value needs to be
>  set to 1.
>  
> -- 
> 2.34.1
> 

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

* Re: [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates
  2022-10-03 11:10     ` Sughosh Ganu
@ 2022-10-04  3:04       ` Takahiro Akashi
  0 siblings, 0 replies; 49+ messages in thread
From: Takahiro Akashi @ 2022-10-04  3:04 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 Mon, Oct 03, 2022 at 04:40:04PM +0530, Sughosh Ganu wrote:
> hi Takahiro,
> 
> On Mon, 3 Oct 2022 at 16:27, Takahiro Akashi <takahiro.akashi@linaro.org> wrote:
> >
> > Hi Sughosh,
> >
> > On Wed, Sep 28, 2022 at 02:59:46PM +0530, Sughosh Ganu wrote:
> > > 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>
> > > Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> > > Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> > > ---
> > > Changes since V10:
> > > * Use image_index value of 1 for the FIP image as it is now relevant
> > >
> > >  board/st/stm32mp1/stm32mp1.c       | 18 ++++++++++++++++++
> > >  include/configs/stm32mp15_common.h |  4 ++++
> > >  2 files changed, 22 insertions(+)
> > >
> > > diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
> > > index 8c162b42a5..e43dab018f 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>
> > > @@ -87,6 +88,16 @@
> > >  #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);
> >
> > The definition of num_image_type_guids is always the same
> > across boards. Why do we need it for every platform?
> 
> Yes, but that is because at present every platform is declaring the
> same variable name(fw_images) for the struct efi_fw_image.

That's because fw_images is hard-coded in efi_firmware.c by your change.

> That is not mandatory,

In this sense, it is mandatory unless you want to write a new FMP driver
from the scratch.

> and a subsequent addition can declare a variable with a
> different name. But in case there is consensus on using a fixed
> variable name for the structure, I can make the change that you are
> suggesting subsequently. I will work on it if needed after the FWU
> patches upstreaming work is done.
> 
> 
> > I believe that we can remove it. Anyhow it's not documented
> > in doc/develop/uefi/uefi.rst.
> >
> > > +#endif /* EFI_HAVE_CAPSULE_SUPPORT */
> > > +
> > >  int board_early_init_f(void)
> > >  {
> > >       /* nothing to do, only used in SPL */
> > > @@ -666,6 +677,13 @@ int board_init(void)
> > >
> > >       setup_led(LEDST_ON);
> > >
> > > +#if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
> > > +     efi_guid_t image_type_guid = STM32MP_FIP_IMAGE_GUID;
> > > +
> > > +     guidcpy(&fw_images[0].image_type_id, &image_type_guid);
> > > +     fw_images[0].fw_name = u"STM32MP-FIP";
> > > +     fw_images[0].image_index = 1;
> >
> > Then, we should describe that image_index must be 1 to num_image_type_guids
> > (or strictly, number of descriptors returned by GetImageInfo()) in
> > the document above.
> 
> Okay
> 
> > (I hope that you add a sanity checker against it as well.)
> 
> Yes, in the efi_fmp_find(), there is a check for the index value
> passed through the capsule against the value returned by the
> GetImageInfo().

I meant that the check takes place at some time in initialization,
but yes, efi_fmp_find() works as a safe guard.

-Takahiro Akashi

> -sughosh
> 
> >
> > -Takahiro Akashi
> >
> > > +#endif
> > >       return 0;
> > >  }
> > >
> > > diff --git a/include/configs/stm32mp15_common.h b/include/configs/stm32mp15_common.h
> > > index c5412ffeb3..bb19dae945 100644
> > > --- a/include/configs/stm32mp15_common.h
> > > +++ b/include/configs/stm32mp15_common.h
> > > @@ -34,6 +34,10 @@
> > >  #define CONFIG_SERVERIP                 192.168.1.1
> > >  #endif
> > >
> > > +#define STM32MP_FIP_IMAGE_GUID \
> > > +     EFI_GUID(0x19d5df83, 0x11b0, 0x457b, 0xbe, 0x2c, \
> > > +              0x75, 0x59, 0xc1, 0x31, 0x42, 0xa5)
> > > +
> > >  /*****************************************************************************/
> > >  #ifdef CONFIG_DISTRO_DEFAULTS
> > >  /*****************************************************************************/
> > > --
> > > 2.34.1
> > >

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

* Re: [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature
  2022-10-04  2:54   ` Takahiro Akashi
@ 2022-10-04  6:40     ` Sughosh Ganu
  2022-10-04  7:09       ` Takahiro Akashi
  0 siblings, 1 reply; 49+ messages in thread
From: Sughosh Ganu @ 2022-10-04  6:40 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

hi Takahiro,

On Tue, 4 Oct 2022 at 08:24, Takahiro Akashi <takahiro.akashi@linaro.org> wrote:
>
> Sughosh,
>
> On Wed, Sep 28, 2022 at 02:59:56PM +0530, Sughosh Ganu wrote:
> > Add documentation 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>
> > ---
> > Changes since V10:
> > * Fix review comments suggested by Etienne
> > * Add a paragraph in the capsule update section to highlight the
> >   difference in ImageIndex correlation with DFU alt num with FWU feature
> >   enabled
> >
> >  doc/develop/uefi/fwu_updates.rst | 173 +++++++++++++++++++++++++++++++
> >  doc/develop/uefi/index.rst       |   1 +
> >  doc/develop/uefi/uefi.rst        |  10 ++
> >  3 files changed, 184 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..292feceb9a
> > --- /dev/null
> > +++ b/doc/develop/uefi/fwu_updates.rst
> > @@ -0,0 +1,173 @@
> > +.. 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 its 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-gpt.yaml>`__
> > +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_RAW=y
> > +
> > +    CONFIG_FWU_MULTI_BANK_UPDATE=y
> > +    CONFIG_CMD_FWU_METADATA=y
> > +    CONFIG_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 configuration settings 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, a GPT partitioned storage
> > +device is required. 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 a 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 partitions 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. An example list of images on the storage medium would be
> > +
> > +* FWU metadata 1
> > +* U-Boot 1
> > +* OP-TEE 1
> > +* FWU metadata 2
> > +* OP-TEE 2
> > +* U-Boot 2
> > +* ESP
> > +* rootfs
> > +
> > +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.
>
> Well, what is not clear to me here is:
> - who is responsible to set up FWU metadata and when

Initially, when the board is being provisioned, the metadata is
supposed to be installed on two separate partitions. This is described
under "Setting up the device for GPT partitioned storage".

> - how FWU metadata is related to fw_images and update_info
>   which are used in normal case, which is mentioned in develop/uefi/uefi.rst

The entire update process is the same as the UEFI capsule update. This
is being highlighted in the first paragraph under "Performing the
Update". I have also added a paragraph under "Performing the update"
which specifies how the image index value used with the FWU feature
enabled is different from the normal capsule update.

>
> I know the whole text here is dedicated to A/B update, but I think
> it would also be helpful to have a single document which covers both cases
> for developers to understand how differently FWU is configured for those cases.

I would think that it would be more clear to have a separate document
for the FWU updates. In any case, the fwu_updates.rst is under the
same directory as the uefi.rst which explains the normal capsule
update functionality. There would also be addition of the section for
the FWU updates on platforms using MTD based devices. So I think it
would be better to keep the documents separate. Even if we move the
content in fwu_updates.rst under uefi.rst, the actual update process
would still be explained by the section under
'uefi_capsule_update_ref'. Do you see difficulty in understanding the
FWU update feature being kept in a separate file?

-sughosh

>
> -Takahiro Akashi
>
> > +
> > +Similarly, the FWU specification 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.
> > +
> > +The task of accepting the different firmware images, post an update
> > +may be done by multiple, separate components in the Operating
> > +System. To help identify the firmware image that is being accepted,
> > +the accept capsule passes the image GUID of the firmware image being
> > +accepted. The relevant code in U-Boot then sets the Accept bit of the
> > +corresponding firmware image for which the accept capsule was
> > +found. Only when all the firmware components in a bank have been
> > +accepted does the platform transition from trial state to regular
> > +state.
> > +
> > +The revert capsule on the other hand does not pass any image GUID,
> > +since reverting any image of the bank has the same result of the
> > +platform booting from the other bank on subsequent boot.
> > +
> > +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>
> > +
> > +Some examples of using the mkeficapsule tool for generation of the
> > +empty capsule would be::
> > +
> > +.. code-block:: bash
> > +
> > +    $ ./tools/mkeficapsule --fw-accept --guid <image guid> \
> > +    <accept_capsule_name>
> > +    $ ./tools/mkeficapsule --fw-revert <revert_capsule_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..b5c83db65a 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
> >  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >
> > @@ -377,6 +379,14 @@ following command::
> >
> >      dfu list
> >
> > +When the FWU Multi Bank Update feature is enabled on the platform, the
> > +image index is used only to identify the image index with the image
> > +GUID. The image index would not correspond to the dfu alt number. This
> > +is because the FWU feature supports multiple partitions(banks) of
> > +updatable images, and the actual dfu alt number to which the image is
> > +to be written to is determined at runtime, based on the value of the
> > +update bank to which the image is to be written.
> > +
> >  When using the FMP for FIT images, the image index value needs to be
> >  set to 1.
> >
> > --
> > 2.34.1
> >

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

* Re: [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature
  2022-10-04  6:40     ` Sughosh Ganu
@ 2022-10-04  7:09       ` Takahiro Akashi
  2022-10-04  7:46         ` Ilias Apalodimas
  0 siblings, 1 reply; 49+ messages in thread
From: Takahiro Akashi @ 2022-10-04  7:09 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 Tue, Oct 04, 2022 at 12:10:27PM +0530, Sughosh Ganu wrote:
> hi Takahiro,
> 
> On Tue, 4 Oct 2022 at 08:24, Takahiro Akashi <takahiro.akashi@linaro.org> wrote:
> >
> > Sughosh,
> >
> > On Wed, Sep 28, 2022 at 02:59:56PM +0530, Sughosh Ganu wrote:
> > > Add documentation 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>
> > > ---
> > > Changes since V10:
> > > * Fix review comments suggested by Etienne
> > > * Add a paragraph in the capsule update section to highlight the
> > >   difference in ImageIndex correlation with DFU alt num with FWU feature
> > >   enabled
> > >
> > >  doc/develop/uefi/fwu_updates.rst | 173 +++++++++++++++++++++++++++++++
> > >  doc/develop/uefi/index.rst       |   1 +
> > >  doc/develop/uefi/uefi.rst        |  10 ++
> > >  3 files changed, 184 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..292feceb9a
> > > --- /dev/null
> > > +++ b/doc/develop/uefi/fwu_updates.rst
> > > @@ -0,0 +1,173 @@
> > > +.. 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 its 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-gpt.yaml>`__
> > > +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_RAW=y
> > > +
> > > +    CONFIG_FWU_MULTI_BANK_UPDATE=y
> > > +    CONFIG_CMD_FWU_METADATA=y
> > > +    CONFIG_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 configuration settings 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, a GPT partitioned storage
> > > +device is required. 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 a 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 partitions 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. An example list of images on the storage medium would be
> > > +
> > > +* FWU metadata 1
> > > +* U-Boot 1
> > > +* OP-TEE 1
> > > +* FWU metadata 2
> > > +* OP-TEE 2
> > > +* U-Boot 2
> > > +* ESP
> > > +* rootfs
> > > +
> > > +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.
> >
> > Well, what is not clear to me here is:
> > - who is responsible to set up FWU metadata and when
> 
> Initially, when the board is being provisioned, the metadata is
> supposed to be installed on two separate partitions. This is described
> under "Setting up the device for GPT partitioned storage".
> 
> > - how FWU metadata is related to fw_images and update_info
> >   which are used in normal case, which is mentioned in develop/uefi/uefi.rst
> 
> The entire update process is the same as the UEFI capsule update. This
> is being highlighted in the first paragraph under "Performing the
> Update".

I think of developers.

For instance, as I mentioned above, image_type_uuid/image_index in FWU metadata
must match with the ones in fw_images.
And how about update_info, especially dfu_string? This field won't be used
in A/B update IIUC.
There are a couple of points that developers should be aware.
That is why I suggested the whole explanation is in one place.

> I have also added a paragraph under "Performing the update"
> which specifies how the image index value used with the FWU feature
> enabled is different from the normal capsule update.
> 
> >
> > I know the whole text here is dedicated to A/B update, but I think
> > it would also be helpful to have a single document which covers both cases
> > for developers to understand how differently FWU is configured for those cases.
> 
> I would think that it would be more clear to have a separate document
> for the FWU updates. In any case, the fwu_updates.rst is under the
> same directory as the uefi.rst which explains the normal capsule
> update functionality. There would also be addition of the section for
> the FWU updates on platforms using MTD based devices. So I think it
> would be better to keep the documents separate. Even if we move the
> content in fwu_updates.rst under uefi.rst, the actual update process
> would still be explained by the section under
> 'uefi_capsule_update_ref'. Do you see difficulty in understanding the
> FWU update feature being kept in a separate file?

Yes.

I don't care whether the text is contained in a physically-single document,
but do expect that the normal case and A/B update are described (in different
sections) under the logically-same chapter for better understanding of differences.

-Takahiro Akashi


> -sughosh
> 
> >
> > -Takahiro Akashi
> >
> > > +
> > > +Similarly, the FWU specification 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.
> > > +
> > > +The task of accepting the different firmware images, post an update
> > > +may be done by multiple, separate components in the Operating
> > > +System. To help identify the firmware image that is being accepted,
> > > +the accept capsule passes the image GUID of the firmware image being
> > > +accepted. The relevant code in U-Boot then sets the Accept bit of the
> > > +corresponding firmware image for which the accept capsule was
> > > +found. Only when all the firmware components in a bank have been
> > > +accepted does the platform transition from trial state to regular
> > > +state.
> > > +
> > > +The revert capsule on the other hand does not pass any image GUID,
> > > +since reverting any image of the bank has the same result of the
> > > +platform booting from the other bank on subsequent boot.
> > > +
> > > +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>
> > > +
> > > +Some examples of using the mkeficapsule tool for generation of the
> > > +empty capsule would be::
> > > +
> > > +.. code-block:: bash
> > > +
> > > +    $ ./tools/mkeficapsule --fw-accept --guid <image guid> \
> > > +    <accept_capsule_name>
> > > +    $ ./tools/mkeficapsule --fw-revert <revert_capsule_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..b5c83db65a 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
> > >  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > >
> > > @@ -377,6 +379,14 @@ following command::
> > >
> > >      dfu list
> > >
> > > +When the FWU Multi Bank Update feature is enabled on the platform, the
> > > +image index is used only to identify the image index with the image
> > > +GUID. The image index would not correspond to the dfu alt number. This
> > > +is because the FWU feature supports multiple partitions(banks) of
> > > +updatable images, and the actual dfu alt number to which the image is
> > > +to be written to is determined at runtime, based on the value of the
> > > +update bank to which the image is to be written.
> > > +
> > >  When using the FMP for FIT images, the image index value needs to be
> > >  set to 1.
> > >
> > > --
> > > 2.34.1
> > >

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

* Re: [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature
  2022-10-04  7:09       ` Takahiro Akashi
@ 2022-10-04  7:46         ` Ilias Apalodimas
  0 siblings, 0 replies; 49+ messages in thread
From: Ilias Apalodimas @ 2022-10-04  7:46 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

Akashi-san


> > > > +
> > > > +* FWU metadata 1
> > > > +* U-Boot 1
> > > > +* OP-TEE 1
> > > > +* FWU metadata 2
> > > > +* OP-TEE 2
> > > > +* U-Boot 2
> > > > +* ESP
> > > > +* rootfs
> > > > +
> > > > +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.
> > >
> > > Well, what is not clear to me here is:
> > > - who is responsible to set up FWU metadata and when
> >
> > Initially, when the board is being provisioned, the metadata is
> > supposed to be installed on two separate partitions. This is described
> > under "Setting up the device for GPT partitioned storage".
> >
> > > - how FWU metadata is related to fw_images and update_info
> > >   which are used in normal case, which is mentioned in develop/uefi/uefi.rst
> >
> > The entire update process is the same as the UEFI capsule update. This
> > is being highlighted in the first paragraph under "Performing the
> > Update".
>
> I think of developers.
>
> For instance, as I mentioned above, image_type_uuid/image_index in FWU metadata
> must match with the ones in fw_images.
> And how about update_info, especially dfu_string? This field won't be used
> in A/B update IIUC.
> There are a couple of points that developers should be aware.
> That is why I suggested the whole explanation is in one place.
>
> > I have also added a paragraph under "Performing the update"
> > which specifies how the image index value used with the FWU feature
> > enabled is different from the normal capsule update.
> >
> > >
> > > I know the whole text here is dedicated to A/B update, but I think
> > > it would also be helpful to have a single document which covers both cases
> > > for developers to understand how differently FWU is configured for those cases.
> >
> > I would think that it would be more clear to have a separate document
> > for the FWU updates. In any case, the fwu_updates.rst is under the
> > same directory as the uefi.rst which explains the normal capsule
> > update functionality. There would also be addition of the section for
> > the FWU updates on platforms using MTD based devices. So I think it
> > would be better to keep the documents separate. Even if we move the
> > content in fwu_updates.rst under uefi.rst, the actual update process
> > would still be explained by the section under
> > 'uefi_capsule_update_ref'. Do you see difficulty in understanding the
> > FWU update feature being kept in a separate file?
>
> Yes.
>
> I don't care whether the text is contained in a physically-single document,
> but do expect that the normal case and A/B update are described (in different
> sections) under the logically-same chapter for better understanding of differences.

That would make the document quite big though wouldn't it?  Wouldn't
it be a bit more readable to add a link in the capsule update
documentation pointing to the FWU functionality? IOW add a paragraph
in capsule updates describing the basics and then have a link the the
existing FWU documentation.

Regards
/Ilias

> -Takahiro Akashi
>
>
> > -sughosh
> >
> > >
> > > -Takahiro Akashi
> > >
> > > > +
> > > > +Similarly, the FWU specification 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.
> > > > +
> > > > +The task of accepting the different firmware images, post an update
> > > > +may be done by multiple, separate components in the Operating
> > > > +System. To help identify the firmware image that is being accepted,
> > > > +the accept capsule passes the image GUID of the firmware image being
> > > > +accepted. The relevant code in U-Boot then sets the Accept bit of the
> > > > +corresponding firmware image for which the accept capsule was
> > > > +found. Only when all the firmware components in a bank have been
> > > > +accepted does the platform transition from trial state to regular
> > > > +state.
> > > > +
> > > > +The revert capsule on the other hand does not pass any image GUID,
> > > > +since reverting any image of the bank has the same result of the
> > > > +platform booting from the other bank on subsequent boot.
> > > > +
> > > > +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>
> > > > +
> > > > +Some examples of using the mkeficapsule tool for generation of the
> > > > +empty capsule would be::
> > > > +
> > > > +.. code-block:: bash
> > > > +
> > > > +    $ ./tools/mkeficapsule --fw-accept --guid <image guid> \
> > > > +    <accept_capsule_name>
> > > > +    $ ./tools/mkeficapsule --fw-revert <revert_capsule_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..b5c83db65a 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
> > > >  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > > >
> > > > @@ -377,6 +379,14 @@ following command::
> > > >
> > > >      dfu list
> > > >
> > > > +When the FWU Multi Bank Update feature is enabled on the platform, the
> > > > +image index is used only to identify the image index with the image
> > > > +GUID. The image index would not correspond to the dfu alt number. This
> > > > +is because the FWU feature supports multiple partitions(banks) of
> > > > +updatable images, and the actual dfu alt number to which the image is
> > > > +to be written to is determined at runtime, based on the value of the
> > > > +update bank to which the image is to be written.
> > > > +
> > > >  When using the FMP for FIT images, the image index value needs to be
> > > >  set to 1.
> > > >
> > > > --
> > > > 2.34.1
> > > >

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

* Re: [PATCHv2 1/5] FWU: Add FWU metadata access driver for MTD storage regions
  2022-10-02 23:51   ` [PATCHv2 1/5] FWU: Add FWU metadata access driver for MTD storage regions jassisinghbrar
@ 2022-10-14  7:07     ` Ilias Apalodimas
  2022-10-31 23:37       ` Jassi Brar
  0 siblings, 1 reply; 49+ messages in thread
From: Ilias Apalodimas @ 2022-10-14  7:07 UTC (permalink / raw)
  To: jassisinghbrar
  Cc: u-boot, xypron.glpk, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Sughosh Ganu, Jassi Brar

Hi Jassi,

Thanks for the patches and apologies for the late reply

On Sun, Oct 02, 2022 at 06:51:32PM -0500, jassisinghbrar@gmail.com wrote:
> From: Sughosh Ganu <sughosh.ganu@linaro.org>
> 
> In the FWU Multi Bank Update feature, the information about the
> updatable images is stored as part of the metadata, on a separate
> region. Add a driver for reading from and writing to the metadata
> when the updatable images and the metadata are stored on a raw
> MTD region.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
> ---
>  drivers/fwu-mdata/Kconfig   |  17 +-
>  drivers/fwu-mdata/Makefile  |   1 +

[...]

> +
> +/* Internal helper structure to move data around */
> +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,
> +};
> +
> +#define FWU_MDATA_PRIMARY	true
> +#define FWU_MDATA_SECONDARY	false
> +
> +static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
> +{
> +	return !do_div(size, mtd->erasesize);
> +}
> +

Can we please add some sphinx style documentation overall ?

> +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)) {
> +		log_err("Offset unaligned with a block (0x%x)\n", mtd->erasesize);
> +		return -EINVAL;
> +	}
> +
> +	lock_offs = offs;
> +	/* This will expand erase size to align with the block size */
> +	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 = {};
> +
> +		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;
> +	}
> +
> +	/* 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;
> +	}
> +	memset(buf, 0xff, len);
> +
> +	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:
> +	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;
> +
> +	ret = mtd_io_data(mtd, offs, size, mdata, FWU_MTD_READ);
> +	if (ret >= 0)
> +		ret = fwu_verify_mdata(mdata, primary);
> +
> +	return ret;
> +}
> +
> +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)
> +{
> +	int ret;
> +
> +	ret = fwu_mtd_load_mdata(mtd_priv->mtd, mdata,
> +							 mtd_priv->pri_offset, FWU_MDATA_PRIMARY);
> +	if (!ret)
> +		return 0;
> +
> +	log_debug("Failed to load primary mdata. Trying secondary...\n");
> +
> +	ret = fwu_mtd_load_mdata(mtd_priv->mtd, mdata,
> +							 mtd_priv->sec_offset, FWU_MDATA_SECONDARY);
> +	if (ret) {
> +		log_debug("Failed to load secondary mdata.\n");
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +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;
> +
> +	/* First write the primary mdata */
> +	ret = fwu_mtd_save_primary_mdata(mtd_priv, mdata);
> +	if (ret < 0) {
> +		log_debug("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_debug("Failed to update the secondary mdata.\n");
> +		return ret;
> +	}

Looking at Sughosh patches as well, we can probably abstract this even more with
either ptrs or just including the device type in the function arguments,
since all update mdata functions are calling xxx_save_primary_mdata() ->
xxx_ave_secondary_mdata().  But I am fine as-is for now.  We can clean that
up once the patches get in 

> +
> +	return 0;
> +}
> +
> +static int fwu_mtd_check_mdata(struct udevice *dev)
> +{
> +	struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> +	struct fwu_mdata primary, secondary;
> +	bool pri = false, sec = false;
> +	int ret;
> +
> +	ret = fwu_mtd_load_mdata(mtd_priv->mtd, &primary,
> +							 mtd_priv->pri_offset, FWU_MDATA_PRIMARY);
> +	if (ret < 0)
> +		log_debug("Failed to read the primary mdata: %d\n", ret);
> +	else
> +		pri = true;
> +
> +	ret = fwu_mtd_load_mdata(mtd_priv->mtd, &secondary,
> +							 mtd_priv->sec_offset, FWU_MDATA_SECONDARY);
> +	if (ret < 0)
> +		log_debug("Failed to read the secondary mdata: %d\n", ret);
> +	else
> +		sec = true;
> +
> +	if (pri && sec) {
> +		if (memcmp(&primary, &secondary, sizeof(struct fwu_mdata))) {
> +			log_debug("The primary and the secondary mdata are different\n");
> +			ret = -1;
> +		}
> +	} else if (pri) {
> +		ret = fwu_mtd_save_secondary_mdata(mtd_priv, &primary);
> +		if (ret < 0)
> +			log_debug("Restoring secondary mdata partition failed\n");
> +	} else if (sec) {
> +		ret = fwu_mtd_save_primary_mdata(mtd_priv, &secondary);
> +		if (ret < 0)
> +			log_debug("Restoring primary mdata partition failed\n");
> +	}

Same on this one.  The requirements here are 
- Read our metadata
- Compare the 2 partitions

The only thing that's 'hardware' specific here is reading the metadata.  We
should at least unify the comparing part and restoration in case of
failures, no ?

> +
> +	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
> + */
 

Thanks
/Ilias

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

* Re: [PATCHv2 2/5] FWU: mtd: Add helper functions for accessing FWU metadata
  2022-10-02 23:51   ` [PATCHv2 2/5] FWU: mtd: Add helper functions for accessing FWU metadata jassisinghbrar
@ 2022-10-14  7:10     ` Ilias Apalodimas
  0 siblings, 0 replies; 49+ messages in thread
From: Ilias Apalodimas @ 2022-10-14  7:10 UTC (permalink / raw)
  To: jassisinghbrar
  Cc: u-boot, xypron.glpk, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Sughosh Ganu, Jassi Brar

Hi Sughosh, Jassi
On Sun, Oct 02, 2022 at 06:51:45PM -0500, jassisinghbrar@gmail.com wrote:
> From: Sughosh Ganu <sughosh.ganu@linaro.org>
> 
> Add helper functions needed for accessing the FWU metadata which
> contains information on the updatable images.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
> ---
>  include/fwu.h             |  27 ++++++
>  lib/fwu_updates/Makefile  |   1 +
>  lib/fwu_updates/fwu_mtd.c | 178 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 206 insertions(+)
>  create mode 100644 lib/fwu_updates/fwu_mtd.c
> 
> diff --git a/include/fwu.h b/include/fwu.h
> index b5c59dc161..48c83f7618 100644
> --- a/include/fwu.h
> +++ b/include/fwu.h
> @@ -8,6 +8,7 @@
>  
>  #include <blk.h>
>  #include <efi.h>
> +#include <mtd.h>
>  
>  #include <linux/types.h>
>  
> @@ -296,4 +297,30 @@ u8 fwu_update_checks_pass(void);
>   */
>  int fwu_trial_state_ctr_start(void);
>  
> +/**

[..]

> +#include <dm/ofnode.h>
> +
> +int fwu_mtd_get_alt_num(efi_guid_t *image_id, u8 *alt_num,
> +			const char *mtd_dev)
> +{
> +	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, 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++;

Sughosh we need to update this and follow similar logic to the GPT patches,
where nalt goes away and this is converted to a while (true) loop 
> +
> +	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);
> +
> +		/* Only MTD RAW access */
> +		if (!dfu || dfu->dev_type != DFU_DEV_MTD ||
> +			dfu->layout != DFU_RAW_ADDR ||
> +			dfu->data.mtd.start != offset ||
> +			dfu->data.mtd.size != size)
> +			continue;

This needs to be rebased as well and that code needs to be added in that
new function you created

> +
> +		*alt_num = dfu->alt;
> +		ret = 0;
> +		break;
> +	}
> +
> +	dfu_free_entities();
> +
> +	return ret;
> +}
> +
> +static int gen_image_alt_info(char *buf, size_t len, int sidx,
> +		       struct fwu_image_entry *img, struct mtd_info *mtd)
> +{
> +	int i;
> +	const char *suuid;
 
[...]

Thanks
/Ilias

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

* Re: [PATCHv2 3/5] dt: fwu: developerbox: enable fwu banks and mdata regions
  2022-10-02 23:51   ` [PATCHv2 3/5] dt: fwu: developerbox: enable fwu banks and mdata regions jassisinghbrar
@ 2022-10-14  7:33     ` Ilias Apalodimas
  0 siblings, 0 replies; 49+ messages in thread
From: Ilias Apalodimas @ 2022-10-14  7:33 UTC (permalink / raw)
  To: jassisinghbrar
  Cc: u-boot, xypron.glpk, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Masami Hiramatsu, Jassi Brar

On Sun, Oct 02, 2022 at 06:51:58PM -0500, jassisinghbrar@gmail.com wrote:
> From: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> 
> Specify Bank-0/1 and fwu metadata mtd regions.
> 
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu@linaro.org>
> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
> ---
>  .../synquacer-sc2a11-developerbox-u-boot.dtsi | 22 ++++++++++++++++++-
>  1 file changed, 21 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi b/arch/arm/dts/synquacer-sc2a11-developerbox-u-boot.dtsi
> index 7a56116d6f..62eee0aaf0 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";
> @@ -36,6 +36,7 @@
>  				compatible = "fixed-partitions";
>  				#address-cells = <1>;
>  				#size-cells = <1>;
> +				uuid = "17e86d77-41f9-4fd7-87ec-a55df9842de5";
>  
>  				partition@0 {
>  					label = "BootStrap-BL1";
> @@ -79,6 +80,19 @@
>  					label = "Ex-OPTEE";
>  					reg = <0x500000 0x200000>;
>  				};
> +
> +				/* FWU Multi bank update partitions */
> +				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";
> +				};
>  			};
>  		};
>  	};
> @@ -104,6 +118,12 @@
>  		optee {
>  			status = "okay";
>  		};
> +
> +		fwu-mdata {
> +			compatible = "u-boot,fwu-mdata-mtd";
> +			fwu-mdata-store = <&spi_flash>;
> +			mdata-offsets = <0x500000 0x530000>;
> +		};
>  	};
>  };
>  
> -- 
> 2.25.1
> 

Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>


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

* Re: [PATCHv2 1/5] FWU: Add FWU metadata access driver for MTD storage regions
  2022-10-14  7:07     ` Ilias Apalodimas
@ 2022-10-31 23:37       ` Jassi Brar
  0 siblings, 0 replies; 49+ messages in thread
From: Jassi Brar @ 2022-10-31 23:37 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: u-boot, xypron.glpk, takahiro.akashi, sjg, trini,
	etienne.carriere, monstr, Sughosh Ganu, Jassi Brar

On Fri, Oct 14, 2022 at 2:07 AM Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>
> On Sun, Oct 02, 2022 at 06:51:32PM -0500, jassisinghbrar@gmail.com wrote:
> > +
> > +static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
> > +{
> > +     return !do_div(size, mtd->erasesize);
> > +}
> > +
>
> Can we please add some sphinx style documentation overall ?
>
I can but I thought that is for public api and not static helper functions?


> > +
> > +static int fwu_mtd_check_mdata(struct udevice *dev)
> > +{
> > +     struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev);
> > +     struct fwu_mdata primary, secondary;
> > +     bool pri = false, sec = false;
> > +     int ret;
> > +
> > +     ret = fwu_mtd_load_mdata(mtd_priv->mtd, &primary,
> > +                                                      mtd_priv->pri_offset, FWU_MDATA_PRIMARY);
> > +     if (ret < 0)
> > +             log_debug("Failed to read the primary mdata: %d\n", ret);
> > +     else
> > +             pri = true;
> > +
> > +     ret = fwu_mtd_load_mdata(mtd_priv->mtd, &secondary,
> > +                                                      mtd_priv->sec_offset, FWU_MDATA_SECONDARY);
> > +     if (ret < 0)
> > +             log_debug("Failed to read the secondary mdata: %d\n", ret);
> > +     else
> > +             sec = true;
> > +
> > +     if (pri && sec) {
> > +             if (memcmp(&primary, &secondary, sizeof(struct fwu_mdata))) {
> > +                     log_debug("The primary and the secondary mdata are different\n");
> > +                     ret = -1;
> > +             }
> > +     } else if (pri) {
> > +             ret = fwu_mtd_save_secondary_mdata(mtd_priv, &primary);
> > +             if (ret < 0)
> > +                     log_debug("Restoring secondary mdata partition failed\n");
> > +     } else if (sec) {
> > +             ret = fwu_mtd_save_primary_mdata(mtd_priv, &secondary);
> > +             if (ret < 0)
> > +                     log_debug("Restoring primary mdata partition failed\n");
> > +     }
>
> Same on this one.  The requirements here are
> - Read our metadata
> - Compare the 2 partitions
>
> The only thing that's 'hardware' specific here is reading the metadata.  We
> should at least unify the comparing part and restoration in case of
> failures, no ?
>
Yes.  Since redundant copy of meta-data is a requirement of the spec,
we should maintain that in the fwu core code.
Maybe something like adding 'bool primary' argument to get_mdata() and
update_mdata()

thanks

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

end of thread, other threads:[~2022-10-31 23:38 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-28  9:29 [PATCH v11 00/15] FWU: Add FWU Multi Bank Update feature support Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 01/15] dt/bindings: Add bindings for GPT based FWU Metadata storage device Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 02/15] FWU: Add FWU metadata structure and driver for accessing metadata Sughosh Ganu
2022-09-30  5:54   ` Etienne Carriere
2022-10-03  6:27     ` Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 03/15] FWU: Add FWU metadata access driver for GPT partitioned block devices Sughosh Ganu
2022-09-30  6:10   ` Etienne Carriere
2022-09-28  9:29 ` [PATCH v11 04/15] stm32mp1: dk2: Add a node for the FWU metadata device Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 05/15] stm32mp1: dk2: Add image information for capsule updates Sughosh Ganu
2022-09-30  5:51   ` Etienne Carriere
2022-10-03 10:56   ` Takahiro Akashi
2022-10-03 11:10     ` Sughosh Ganu
2022-10-04  3:04       ` Takahiro Akashi
2022-09-28  9:29 ` [PATCH v11 06/15] FWU: Add helper functions for accessing FWU metadata Sughosh Ganu
2022-10-03  9:51   ` Ilias Apalodimas
2022-09-28  9:29 ` [PATCH v11 07/15] FWU: STM32MP1: Add support to read boot index from backup register Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 08/15] event: Add an event for main_loop Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 09/15] FWU: Add boot time checks as highlighted by the FWU specification Sughosh Ganu
2022-10-03  9:56   ` Ilias Apalodimas
2022-10-03 10:31     ` Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 10/15] FWU: Add support for the FWU Multi Bank Update feature Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 11/15] FWU: cmd: Add a command to read FWU metadata Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 12/15] test: dm: Add test cases for FWU Metadata uclass Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 13/15] mkeficapsule: Add support for generating empty capsules Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 14/15] mkeficapsule: Add support for setting OEM flags in capsule header Sughosh Ganu
2022-09-28  9:29 ` [PATCH v11 15/15] FWU: doc: Add documentation for the FWU feature Sughosh Ganu
2022-09-30  6:27   ` Etienne Carriere
2022-09-30  8:23     ` Sughosh Ganu
2022-10-04  2:54   ` Takahiro Akashi
2022-10-04  6:40     ` Sughosh Ganu
2022-10-04  7:09       ` Takahiro Akashi
2022-10-04  7:46         ` Ilias Apalodimas
2022-10-02 23:50 ` [PATCHv2 0/5] FWU: Add support for mtd backed feature on DeveloperBox jassisinghbrar
2022-10-02 23:51   ` [PATCHv2 1/5] FWU: Add FWU metadata access driver for MTD storage regions jassisinghbrar
2022-10-14  7:07     ` Ilias Apalodimas
2022-10-31 23:37       ` Jassi Brar
2022-10-02 23:51   ` [PATCHv2 2/5] FWU: mtd: Add helper functions for accessing FWU metadata jassisinghbrar
2022-10-14  7:10     ` Ilias Apalodimas
2022-10-02 23:51   ` [PATCHv2 3/5] dt: fwu: developerbox: enable fwu banks and mdata regions jassisinghbrar
2022-10-14  7:33     ` Ilias Apalodimas
2022-10-02 23:52   ` [PATCHv2 4/5] fwu: DeveloperBox: add support for FWU jassisinghbrar
2022-10-03 11:04     ` AKASHI Takahiro
2022-10-03 13:40       ` Jassi Brar
2022-10-03 13:51         ` Ilias Apalodimas
2022-10-04  1:06           ` AKASHI Takahiro
2022-10-04  2:00             ` Jassi Brar
2022-10-04  2:44               ` AKASHI Takahiro
2022-10-04  2:53                 ` Jassi Brar
2022-10-02 23:52   ` [PATCHv2 5/5] tools: Add mkfwumdata tool for FWU metadata image jassisinghbrar

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.