[PATCH v4 00/11] FWU: Add support for FWU Multi Bank Update feature

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 board which boots a FIP image from a uSD card partitioned with the GPT partioning scheme. This also requires changes in the previous stage of bootloader, which parses the metadata and selects the bank to boot the image(s) from. Support is 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's integration branch[3].
These patches are based on top of the series from Takahiro to add Authentication support to mkeficapsule utility[4] and a couple of other patches[5][6]
TODO's ------ * Add a unit test case for the newly added FWU_MDATA uclass. Some involved effort is needed on this since the host device interface on sandbox cannot be used with the UT framework. * Add test case for the feature with the python test suite, along the lines of capsule update testing.
[1] - https://developer.arm.com/documentation/den0118/a [2] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e... [3] - https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/log/?h=integrati... [4] - https://patchwork.ozlabs.org/project/uboot/list/?series=281549 [5] - https://patchwork.ozlabs.org/project/uboot/patch/164388019634.446835.1827148... [6] - https://patchwork.ozlabs.org/project/uboot/patch/20220129192108.6618-1-sugho...
Changes since V3: * Move the FWU metadata access to driver model * Get the storage device containing the metadata from a device tree property instead of a platform helper function * Move the metadata access driver for GPT partitioned block devices under drivers/fwu-mdata/ directory, complying with driver model. * Move functionality to get the active index under the common function instead of the GPT block device specific driver. * Remove function for getting the storage device containing the metadata as the information is now obtained from the device tree. * Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs * Define the function fill_image_type_guid_array for the ST DK2 board for GPT partitioned devices. * Change the TrialStateCtr efi variable attribute to remove the runtime attribute * Rebase the change on top of the patch from Masami to call efi_capsule_update_firmware directly. * Put the FWU related checks which were earlier in efi_update_capsule function to separate functions fwu_empty_capsule and fwu_empty_capsule_process. * Use the device model api uclass_get_device to probe and get the FWU Metadata device. * Add related documentation for empty capsules in the mkeficapsule man page. * Add separate usage for empty capsules, with corresponding valid options. * Use ternary operators where possible. * Put a exclusivity check for the empty capsule options.
Sughosh Ganu (11): FWU: Add FWU metadata structure and driver for accessing metadata FWU: Add FWU metadata access driver for GPT partitioned block devices FWU: stm32mp1: Add helper functions for accessing FWU metadata FWU: STM32MP1: Add support to read boot index from backup register EFI: FMP: Add provision to update image's ImageTypeId in image descriptor stm32mp1: Populate ImageTypeId values in EFI_FIRMWARE_IMAGE_DESCRIPTOR array FWU: Add boot time checks as highlighted by the FWU specification FWU: Add support for FWU Multi Bank Update feature FWU: cmd: Add a command to read FWU metadata mkeficapsule: Add support for generating empty capsules FWU: doc: Add documentation for the FWU feature
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + board/st/stm32mp1/stm32mp1.c | 178 +++++++ cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/fwu_mdata.c | 74 +++ common/board_r.c | 6 + doc/develop/uefi/fwu_updates.rst | 142 +++++ doc/develop/uefi/index.rst | 1 + doc/develop/uefi/uefi.rst | 2 + .../firmware/fwu-mdata.txt | 18 + doc/mkeficapsule.1 | 23 +- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 16 + drivers/fwu-mdata/Makefile | 7 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 +++++++++++++++ drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 501 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/efi_loader.h | 2 + include/fwu.h | 70 +++ include/fwu_mdata.h | 67 +++ lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 221 +++++++- lib/efi_loader/efi_firmware.c | 71 ++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 ++ lib/fwu_updates/Makefile | 6 + lib/fwu_updates/fwu.c | 204 +++++++ tools/eficapsule.h | 8 + tools/mkeficapsule.c | 131 ++++- 31 files changed, 2208 insertions(+), 34 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.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c create mode 100644 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

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

Hi Sughosh,
Thanks for updating the series. I have some comment on this patch.
2022年2月8日(火) 3:21 Sughosh Ganu sughosh.ganu@linaro.org: [snip]
+/**
- fwu_get_active_index() - Get active_index from the FWU metadata
- @active_idx: active_index value to be read
- Read the active_index field from the FWU metadata and place it in
- the variable pointed to be the function argument.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
Again, as we discussed previous series, please don't return unused allocated memory if the function returns an error. That is something like putting a burden on the callers. They always needs to initialize the pointer before call and free it even if the function is failed.
}
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
*active_idx = mdata->active_index;
if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value read is incorrect\n");
ret = -EINVAL;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_update_active_index() - Update active_index from the FWU metadata
- @active_idx: active_index value to be updated
- Update the active_index field in the FWU metadata
- Return: 0 if OK, -ve on error
- */
+int fwu_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata = NULL;
if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value to be updated is incorrect\n");
return -1;
}
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
mdata->previous_active_index = mdata->active_index;
mdata->active_index = active_idx;
/*
* 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));
I would like to suggest moving this crc32 calculation in the fwu_update_mdata(). If the crc32 is for detecting a broken metadata on the "storage media", I think it should be calculated in the fwu_update_mdata() to simplify the code and avoid unexpected bugs from mistakes. If the crc32 is calculated right before updating metadata, we can ensure that the crc32 is always sane except for someone breaking it on the storage media.
Thank you,

hi Masami,
On Tue, 8 Feb 2022 at 15:04, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
Thanks for updating the series. I have some comment on this patch.
2022年2月8日(火) 3:21 Sughosh Ganu sughosh.ganu@linaro.org: [snip]
+/**
- fwu_get_active_index() - Get active_index from the FWU metadata
- @active_idx: active_index value to be read
- Read the active_index field from the FWU metadata and place it in
- the variable pointed to be the function argument.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
Again, as we discussed previous series, please don't return unused allocated memory if the function returns an error. That is something like putting a burden on the callers. They always needs to initialize the pointer before call and free it even if the function is failed.
I would like to keep the convention consistent. The function that declares the pointer will also be responsible for free'ing it up. I find the alternative to be more confusing, where in some instances the callee frees up the memory, while in some cases it is the caller that frees it up. If there is no stated convention in u-boot which forbids this style of memory handling, I would like to keep this as is. I would say that this makes the implementation easier for the callee, since it is the responsibility of the caller to free up the memory.
}
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
*active_idx = mdata->active_index;
if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value read is incorrect\n");
ret = -EINVAL;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_update_active_index() - Update active_index from the FWU metadata
- @active_idx: active_index value to be updated
- Update the active_index field in the FWU metadata
- Return: 0 if OK, -ve on error
- */
+int fwu_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata = NULL;
if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value to be updated is incorrect\n");
return -1;
}
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
mdata->previous_active_index = mdata->active_index;
mdata->active_index = active_idx;
/*
* 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));
I would like to suggest moving this crc32 calculation in the fwu_update_mdata(). If the crc32 is for detecting a broken metadata on the "storage media", I think it should be calculated in the fwu_update_mdata() to simplify the code and avoid unexpected bugs from mistakes. If the crc32 is calculated right before updating metadata, we can ensure that the crc32 is always sane except for someone breaking it on the storage media.
Makes sense. I will make the change as you are suggesting. Thanks.
-sughosh
Thank you,
-- Masami Hiramatsu

Hi Sughosh,
2022年2月8日(火) 19:24 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Tue, 8 Feb 2022 at 15:04, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
Thanks for updating the series. I have some comment on this patch.
2022年2月8日(火) 3:21 Sughosh Ganu sughosh.ganu@linaro.org: [snip]
+/**
- fwu_get_active_index() - Get active_index from the FWU metadata
- @active_idx: active_index value to be read
- Read the active_index field from the FWU metadata and place it in
- the variable pointed to be the function argument.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
Again, as we discussed previous series, please don't return unused allocated memory if the function returns an error. That is something like putting a burden on the callers. They always needs to initialize the pointer before call and free it even if the function is failed.
I would like to keep the convention consistent. The function that declares the pointer will also be responsible for free'ing it up. I find the alternative to be more confusing, where in some instances the callee frees up the memory, while in some cases it is the caller that frees it up. If there is no stated convention in u-boot which forbids this style of memory handling, I would like to keep this as is. I would say that this makes the implementation easier for the callee, since it is the responsibility of the caller to free up the memory.
Hmm, ... I'm not convinced yet. Please give me the last chance to argue. I think the pointer is the pointer, that is not the resource itself.
Please see `man asprintf` for example. Usually, if the function, which allocates any resource including memory, returns an error, the resource pointer is undefined. Of course, there is no need to unallocate the memory for undefined address. That is I think the standard way to handle the resource allocation.
And actually, the callee implementation isn't simplified. In my case, it forces me to re-initialize the pointer to NULL if an error occurs. additional 1-line is needed :-) (maybe I need more comment lines to explain why this NULL setting is required)
BTW, I attached a patch to change this code. You can see the gpt_get_mdata() is refined into 2 gpt_get_mdata_part() and many gotos are removed. This shows how both of callee and caller can be simplified with the convention which I suggested.
Thank you,

po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Move the FWU metadata access to driver model
- Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
In 0/11 you are describing GPT partitions but I don't think this binding is generic enough to describe other cases. It is saying device but not where exactly it is. I didn't read the whole series yet but arm spec recommends GPT but dt binding should be generic enough to describe also other cases. We are saving this structure to qspi for example but current binding can't be used for it.
+Example :
fwu-mdata {
compatible = "u-boot,fwu-mdata";
fwu-mdata-store = <&sdmmc1>;
};
I don't think this is aligned with getting these u-boot nodes to any standard locations. Simon had that discussion with Rob some time ago. Was there any outcome from this discussion where u-boot nodes should go?
Thanks, Michal

On Tue, 8 Feb 2022 at 16:26, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Move the FWU metadata access to driver model
- Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
In 0/11 you are describing GPT partitions but I don't think this binding is generic enough to describe other cases. It is saying device but not where exactly it is. I didn't read the whole series yet but arm spec recommends GPT but dt binding should be generic enough to describe also other cases. We are saving this structure to qspi for example but current binding can't be used for it.
I would wait to see Masami's implementation of this feature. If I am not wrong, his platform too is enabling this feature with a spi as the storage device. Maybe we can instead put a list of <device partition> tuples which can then list the device and partition number of the metadata partitions.
-sughosh
+Example :
fwu-mdata {
compatible = "u-boot,fwu-mdata";
fwu-mdata-store = <&sdmmc1>;
};
I don't think this is aligned with getting these u-boot nodes to any standard locations. Simon had that discussion with Rob some time ago. Was there any outcome from this discussion where u-boot nodes should go?
Thanks, Michal

On 2/8/22 12:35, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 16:26, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
Move the FWU metadata access to driver model
Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
In 0/11 you are describing GPT partitions but I don't think this binding is generic enough to describe other cases. It is saying device but not where exactly it is. I didn't read the whole series yet but arm spec recommends GPT but dt binding should be generic enough to describe also other cases. We are saving this structure to qspi for example but current binding can't be used for it.
I would wait to see Masami's implementation of this feature. If I am not wrong, his platform too is enabling this feature with a spi as the storage device. Maybe we can instead put a list of <device partition> tuples which can then list the device and partition number of the metadata partitions.
I think you should list all possible devices which can be used to have generic description for it. It is sort of the same list of devices which could be used for storing u-boot internal variables. That's why the same description can be used for it too.
Thanks, Michal

2022年2月8日(火) 20:35 Sughosh Ganu sughosh.ganu@linaro.org:
On Tue, 8 Feb 2022 at 16:26, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Move the FWU metadata access to driver model
- Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
In 0/11 you are describing GPT partitions but I don't think this binding is generic enough to describe other cases. It is saying device but not where exactly it is. I didn't read the whole series yet but arm spec recommends GPT but dt binding should be generic enough to describe also other cases. We are saving this structure to qspi for example but current binding can't be used for it.
I would wait to see Masami's implementation of this feature. If I am not wrong, his platform too is enabling this feature with a spi as the storage device. Maybe we can instead put a list of <device partition> tuples which can then list the device and partition number of the metadata partitions.
Yes, I would like to define new compatible for sf backend, e.g. "u-boot,fwu-mdata-sf". It will have the fwu-mdata-store to point the SPI flash device, and will have a list of offset information for the metadata.
Thank you,
-sughosh
+Example :
fwu-mdata {
compatible = "u-boot,fwu-mdata";
fwu-mdata-store = <&sdmmc1>;
};
I don't think this is aligned with getting these u-boot nodes to any standard locations. Simon had that discussion with Rob some time ago. Was there any outcome from this discussion where u-boot nodes should go?
Thanks, Michal
-- Masami Hiramatsu

On 2/8/22 14:36, Masami Hiramatsu wrote:
2022年2月8日(火) 20:35 Sughosh Ganu sughosh.ganu@linaro.org:
On Tue, 8 Feb 2022 at 16:26, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
Move the FWU metadata access to driver model
Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
In 0/11 you are describing GPT partitions but I don't think this binding is generic enough to describe other cases. It is saying device but not where exactly it is. I didn't read the whole series yet but arm spec recommends GPT but dt binding should be generic enough to describe also other cases. We are saving this structure to qspi for example but current binding can't be used for it.
I would wait to see Masami's implementation of this feature. If I am not wrong, his platform too is enabling this feature with a spi as the storage device. Maybe we can instead put a list of <device partition> tuples which can then list the device and partition number of the metadata partitions.
Yes, I would like to define new compatible for sf backend, e.g. "u-boot,fwu-mdata-sf".
backend is fine. What does this compatible string have to do with it? I didn't see any fwu-mdata-gpt in this series.
It will have the fwu-mdata-store to point the SPI flash device, and will have a list of offset information for the metadata.
Can you describe it?
Something like for raw accesses? fwu-mdta-store = <&qspi 0 XXXX>;
Thanks, Michal

2022年2月8日(火) 22:45 Michal Simek michal.simek@xilinx.com:
On 2/8/22 14:36, Masami Hiramatsu wrote:
2022年2月8日(火) 20:35 Sughosh Ganu sughosh.ganu@linaro.org:
On Tue, 8 Feb 2022 at 16:26, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
Move the FWU metadata access to driver model
Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
In 0/11 you are describing GPT partitions but I don't think this binding is generic enough to describe other cases. It is saying device but not where exactly it is. I didn't read the whole series yet but arm spec recommends GPT but dt binding should be generic enough to describe also other cases. We are saving this structure to qspi for example but current binding can't be used for it.
I would wait to see Masami's implementation of this feature. If I am not wrong, his platform too is enabling this feature with a spi as the storage device. Maybe we can instead put a list of <device partition> tuples which can then list the device and partition number of the metadata partitions.
Yes, I would like to define new compatible for sf backend, e.g. "u-boot,fwu-mdata-sf".
backend is fine. What does this compatible string have to do with it? I didn't see any fwu-mdata-gpt in this series.
Sughosh made it "fwu-mdata" but I think it should be "fwu-mdata-gpt" if the required parameters are different.
It will have the fwu-mdata-store to point the SPI flash device, and will have a list of offset information for the metadata.
Can you describe it?
Something like for raw accesses? fwu-mdta-store = <&qspi 0 XXXX>;
I'm still not sure what is the best way. What I thought was,
fwu-mdata-store = <&spi-flash>; fwu-mdata-offsets = <500000, 520000>;
Thanks,
Thanks, Michal

On 2/8/22 15:14, Masami Hiramatsu wrote:
2022年2月8日(火) 22:45 Michal Simek michal.simek@xilinx.com:
On 2/8/22 14:36, Masami Hiramatsu wrote:
2022年2月8日(火) 20:35 Sughosh Ganu sughosh.ganu@linaro.org:
On Tue, 8 Feb 2022 at 16:26, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
Move the FWU metadata access to driver model
Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
In 0/11 you are describing GPT partitions but I don't think this binding is generic enough to describe other cases. It is saying device but not where exactly it is. I didn't read the whole series yet but arm spec recommends GPT but dt binding should be generic enough to describe also other cases. We are saving this structure to qspi for example but current binding can't be used for it.
I would wait to see Masami's implementation of this feature. If I am not wrong, his platform too is enabling this feature with a spi as the storage device. Maybe we can instead put a list of <device partition> tuples which can then list the device and partition number of the metadata partitions.
Yes, I would like to define new compatible for sf backend, e.g. "u-boot,fwu-mdata-sf".
backend is fine. What does this compatible string have to do with it? I didn't see any fwu-mdata-gpt in this series.
Sughosh made it "fwu-mdata" but I think it should be "fwu-mdata-gpt" if the required parameters are different.
It will have the fwu-mdata-store to point the SPI flash device, and will have a list of offset information for the metadata.
Can you describe it?
Something like for raw accesses? fwu-mdta-store = <&qspi 0 XXXX>;
I'm still not sure what is the best way. What I thought was,
fwu-mdata-store = <&spi-flash>; fwu-mdata-offsets = <500000, 520000>;
as I said. Before this is applied I think we should work on generic proposal how to describe it. Because the same way can be used for u-boot variables and maybe others. Definitely I would prefer to ask Rob for helping with this and get this to yaml to be able to use the whole infrastructure to check it.
Thanks, Michal

Hi Michal,
2022年2月8日(火) 23:27 Michal Simek michal.simek@xilinx.com:
On 2/8/22 15:14, Masami Hiramatsu wrote:
2022年2月8日(火) 22:45 Michal Simek michal.simek@xilinx.com:
On 2/8/22 14:36, Masami Hiramatsu wrote:
2022年2月8日(火) 20:35 Sughosh Ganu sughosh.ganu@linaro.org:
On Tue, 8 Feb 2022 at 16:26, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal: > > 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. > > A device tree node fwu-mdata has been added, which is used for > pointing to the storage device which contains the FWU metadata. The > fwu-mdata node is u-boot specific, and can be added the platform's > u-boot dtsi file. > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > --- > > Changes since V3: > * Move the FWU metadata access to driver model > * Get the storage device containing the metadata from a device tree > property instead of a platform helper function > > arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + > .../firmware/fwu-mdata.txt | 18 + > drivers/Kconfig | 2 + > drivers/Makefile | 1 + > drivers/fwu-mdata/Kconfig | 7 + > drivers/fwu-mdata/Makefile | 6 + > drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ > include/dm/uclass-id.h | 1 + > include/fwu.h | 51 ++ > include/fwu_mdata.h | 67 +++ > 10 files changed, 594 insertions(+) > create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt > create mode 100644 drivers/fwu-mdata/Kconfig > create mode 100644 drivers/fwu-mdata/Makefile > create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c > create mode 100644 include/fwu.h > create mode 100644 include/fwu_mdata.h > > diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi > index 06ef3a4095..3bec6107f7 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"; > + fwu-mdata-store = <&sdmmc1>; > + }; > +}; > diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt > new file mode 100644 > index 0000000000..c766b595ef > --- /dev/null > +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt > @@ -0,0 +1,18 @@ > +FWU Metadata Access Devicetree Binding > + > +The FWU Multi Bank Update feature uses a metadata structure, stored on > +a separate partition for keeping information on the set of updatable > +images. The device tree node provides information on the storage > +device that contains the FWU metadata. > + > +Required properties : > + > +- compatible : "u-boot,fwu-mdata"; > +- fwu-mdata-store : should point to the storage device which contains > + the FWU metadata partition.
In 0/11 you are describing GPT partitions but I don't think this binding is generic enough to describe other cases. It is saying device but not where exactly it is. I didn't read the whole series yet but arm spec recommends GPT but dt binding should be generic enough to describe also other cases. We are saving this structure to qspi for example but current binding can't be used for it.
I would wait to see Masami's implementation of this feature. If I am not wrong, his platform too is enabling this feature with a spi as the storage device. Maybe we can instead put a list of <device partition> tuples which can then list the device and partition number of the metadata partitions.
Yes, I would like to define new compatible for sf backend, e.g. "u-boot,fwu-mdata-sf".
backend is fine. What does this compatible string have to do with it? I didn't see any fwu-mdata-gpt in this series.
Sughosh made it "fwu-mdata" but I think it should be "fwu-mdata-gpt" if the required parameters are different.
It will have the fwu-mdata-store to point the SPI flash device, and will have a list of offset information for the metadata.
Can you describe it?
Something like for raw accesses? fwu-mdta-store = <&qspi 0 XXXX>;
I'm still not sure what is the best way. What I thought was,
fwu-mdata-store = <&spi-flash>; fwu-mdata-offsets = <500000, 520000>;
as I said. Before this is applied I think we should work on generic proposal how to describe it. Because the same way can be used for u-boot variables and maybe others.
Agreed. This also reminds me the dfu_alt_info. Currently the dfu_alt_info is passed via u-boot variables, but this should be a (important) part of firmware information. I think it should be defined in the devicetree too. (actually, stm32 builds dfu_alt_info from the device information already)
Definitely I would prefer to ask Rob for helping with this and get this to yaml to be able to use the whole infrastructure to check it.
Yeah, and at first we should define what information should be in the devicetree.
Thank you,
Thanks, Michal

Hi,
On 2/9/22 00:39, Masami Hiramatsu wrote:
Hi Michal,
2022年2月8日(火) 23:27 Michal Simek michal.simek@xilinx.com:
On 2/8/22 15:14, Masami Hiramatsu wrote:
2022年2月8日(火) 22:45 Michal Simek michal.simek@xilinx.com:
On 2/8/22 14:36, Masami Hiramatsu wrote:
2022年2月8日(火) 20:35 Sughosh Ganu sughosh.ganu@linaro.org:
On Tue, 8 Feb 2022 at 16:26, Michal Simek monstr@monstr.eu wrote: > > po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal: >> >> 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. >> >> A device tree node fwu-mdata has been added, which is used for >> pointing to the storage device which contains the FWU metadata. The >> fwu-mdata node is u-boot specific, and can be added the platform's >> u-boot dtsi file. >> >> Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org >> --- >> >> Changes since V3: >> * Move the FWU metadata access to driver model >> * Get the storage device containing the metadata from a device tree >> property instead of a platform helper function >> >> arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + >> .../firmware/fwu-mdata.txt | 18 + >> drivers/Kconfig | 2 + >> drivers/Makefile | 1 + >> drivers/fwu-mdata/Kconfig | 7 + >> drivers/fwu-mdata/Makefile | 6 + >> drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ >> include/dm/uclass-id.h | 1 + >> include/fwu.h | 51 ++ >> include/fwu_mdata.h | 67 +++ >> 10 files changed, 594 insertions(+) >> create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt >> create mode 100644 drivers/fwu-mdata/Kconfig >> create mode 100644 drivers/fwu-mdata/Makefile >> create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c >> create mode 100644 include/fwu.h >> create mode 100644 include/fwu_mdata.h >> >> diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi >> index 06ef3a4095..3bec6107f7 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"; >> + fwu-mdata-store = <&sdmmc1>; >> + }; >> +}; >> diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt >> new file mode 100644 >> index 0000000000..c766b595ef >> --- /dev/null >> +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt >> @@ -0,0 +1,18 @@ >> +FWU Metadata Access Devicetree Binding >> + >> +The FWU Multi Bank Update feature uses a metadata structure, stored on >> +a separate partition for keeping information on the set of updatable >> +images. The device tree node provides information on the storage >> +device that contains the FWU metadata. >> + >> +Required properties : >> + >> +- compatible : "u-boot,fwu-mdata"; >> +- fwu-mdata-store : should point to the storage device which contains >> + the FWU metadata partition. > > In 0/11 you are describing GPT partitions but I don't think this > binding is generic enough to describe > other cases. It is saying device but not where exactly it is. > I didn't read the whole series yet but arm spec recommends GPT but dt > binding should be generic enough to describe > also other cases. > We are saving this structure to qspi for example but current binding > can't be used for it.
I would wait to see Masami's implementation of this feature. If I am not wrong, his platform too is enabling this feature with a spi as the storage device. Maybe we can instead put a list of <device partition> tuples which can then list the device and partition number of the metadata partitions.
Yes, I would like to define new compatible for sf backend, e.g. "u-boot,fwu-mdata-sf".
backend is fine. What does this compatible string have to do with it? I didn't see any fwu-mdata-gpt in this series.
Sughosh made it "fwu-mdata" but I think it should be "fwu-mdata-gpt" if the required parameters are different.
It will have the fwu-mdata-store to point the SPI flash device, and will have a list of offset information for the metadata.
Can you describe it?
Something like for raw accesses? fwu-mdta-store = <&qspi 0 XXXX>;
I'm still not sure what is the best way. What I thought was,
fwu-mdata-store = <&spi-flash>; fwu-mdata-offsets = <500000, 520000>;
as I said. Before this is applied I think we should work on generic proposal how to describe it. Because the same way can be used for u-boot variables and maybe others.
Agreed. This also reminds me the dfu_alt_info. Currently the dfu_alt_info is passed via u-boot variables, but this should be a (important) part of firmware information. I think it should be defined in the devicetree too. (actually, stm32 builds dfu_alt_info from the device information already)
yes that capsule update via dfu_alt_info and upgrading all that structure should be also the part of it. I am not saying in this series. On the top of this one should be fine but it should be clear how this is supposed to work.
Definitely I would prefer to ask Rob for helping with this and get this to yaml to be able to use the whole infrastructure to check it.
Yeah, and at first we should define what information should be in the devicetree.
yes.
Thanks, Michal

po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Move the FWU metadata access to driver model
- Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
+Example :
fwu-mdata {
compatible = "u-boot,fwu-mdata";
fwu-mdata-store = <&sdmmc1>;
};
diff --git a/drivers/Kconfig b/drivers/Kconfig index b26ca8cf70..adc6079ecf 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/fwu-mdata/Kconfig"
source "drivers/gpio/Kconfig"
source "drivers/hwspinlock/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 4e7cf28440..56f0f04874 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -81,6 +81,7 @@ obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ obj-$(CONFIG_FASTBOOT) += fastboot/ +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/ obj-y += misc/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_NVME) += nvme/ diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig new file mode 100644 index 0000000000..d6a21c8e19 --- /dev/null +++ b/drivers/fwu-mdata/Kconfig @@ -0,0 +1,7 @@ +config DM_FWU_MDATA
bool "Driver support for accessing FWU Metadata"
depends on DM
help
Enable support for accessing FWU Metadata partitions. The
FWU Metadata partitions reside on the same storage device
which contains the other FWU updatable firmware images.
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile new file mode 100644 index 0000000000..7fec7171f4 --- /dev/null +++ b/drivers/fwu-mdata/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2022, Linaro Limited +#
+obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c new file mode 100644 index 0000000000..64b3051ecf --- /dev/null +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#include <common.h> +#include <dm.h> +#include <efi_loader.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <log.h> +#include <malloc.h>
+#include <linux/errno.h> +#include <linux/types.h> +#include <u-boot/crc.h>
+#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR BIT(1)
+static int fwu_get_dev_ops(struct udevice **dev,
const struct fwu_mdata_ops **ops)
+{
int ret;
ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev);
if (ret) {
log_debug("Cannot find fwu device\n");
return ret;
}
if ((*ops = device_get_ops(*dev)) == NULL) {
log_debug("Cannot get fwu device ops\n");
return -ENOSYS;
}
return 0;
+}
+/**
- fwu_verify_mdata() - Verify the FWU metadata
- @mdata: FWU metadata structure
- @pri_part: FWU metadata partition is primary or secondary
- Verify the FWU metadata by computing the CRC32 for the metadata
- structure and comparing it against the CRC32 value stored as part
- of the structure.
- Return: 0 if OK, -ve on error
- */
+int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part) +{
u32 calc_crc32;
void *buf;
buf = &mdata->version;
calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
if (calc_crc32 != mdata->crc32) {
log_err("crc32 check failed for %s FWU metadata partition\n",
pri_part ? "primary" : "secondary");
return -1;
}
return 0;
+}
+/**
- fwu_get_active_index() - Get active_index from the FWU metadata
- @active_idx: active_index value to be read
- Read the active_index field from the FWU metadata and place it in
- the variable pointed to be the function argument.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
*active_idx = mdata->active_index;
if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value read is incorrect\n");
ret = -EINVAL;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_update_active_index() - Update active_index from the FWU metadata
- @active_idx: active_index value to be updated
- Update the active_index field in the FWU metadata
- Return: 0 if OK, -ve on error
- */
+int fwu_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata = NULL;
if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value to be updated is incorrect\n");
return -1;
}
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
mdata->previous_active_index = mdata->active_index;
mdata->active_index = active_idx;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update
- @image_type_id: image guid as passed in the capsule
- @update_bank: Bank to which the update is to be made
- @alt_num: The alt_num for the image
- Based on the guid value passed in the capsule, along with the bank to which the
- image needs to be updated, get the dfu alt number which will be used for the
- capsule update
- Return: 0 if OK, -ve on error
- */
+int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num)
+{
int ret;
const struct fwu_mdata_ops *ops = NULL;
struct udevice *dev = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_image_alt_num) {
log_err("get_image_alt_num() method not defined\n");
return -ENOSYS;
}
return ops->get_image_alt_num(dev, image_type_id,
update_bank, alt_num);
+}
+/**
- fwu_mdata_check() - Check if the FWU metadata is valid
- Validate both copies of the FWU metadata. If one of the copies
- has gone bad, restore it from the other bad copy.
- Return: 0 if OK, -ve on error
- */
+int fwu_mdata_check(void) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->mdata_check) {
log_err("mdata_check() method not defined\n");
return -ENOSYS;
}
return ops->mdata_check(dev);
+}
+/**
- fwu_revert_boot_index() - Revert the active index in the FWU metadata
- Revert the active_index value in the FWU metadata, by swapping the values
- of active_index and previous_active_index in both copies of the
- FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_revert_boot_index(void) +{
int ret;
void *buf;
u32 cur_active_index;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Swap the active index and previous_active_index fields
* in the FWU metadata
*/
cur_active_index = mdata->active_index;
mdata->active_index = mdata->previous_active_index;
mdata->previous_active_index = cur_active_index;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
set or cleared
- @bank: Bank of which the image's Accept bit is to be set or cleared
- @action: Action which specifies whether image's Accept bit is to be set or
cleared
- Set/Clear the accepted bit for the image specified by the img_guid parameter.
- This indicates acceptance or rejection of image for subsequent boots by some
- governing component like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+static int fwu_set_clear_image_accept(efi_guid_t *img_type_id,
u32 bank, u8 action)
+{
void *buf;
int ret, i;
u32 nimages;
struct fwu_mdata *mdata = NULL;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
img_entry = &mdata->img_entry[0];
for (i = 0; i < nimages; i++) {
if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
img_bank_info = &img_entry[i].img_bank_info[bank];
if (action == IMAGE_ACCEPT_SET)
img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
else
img_bank_info->accepted = 0;
buf = &mdata->version;
mdata->crc32 = crc32(0, buf, sizeof(*mdata) -
sizeof(u32));
ret = fwu_update_mdata(mdata);
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+/**
- fwu_accept_image() - Set the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be set
- Set the accepted bit for the image specified by the img_guid parameter. This
- indicates acceptance of image for subsequent boots by some governing component
- like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+int fwu_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_SET);
+}
+/**
- fwu_clear_accept_image() - Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be cleared
- Clear the accepted bit for the image type specified by the img_type_id parameter.
- This function is called after the image has been updated. The accepted bit is
- cleared to be set subsequently after passing the image acceptance criteria, by
- either the OS(or firmware)
- Return: 0 if OK, -ve on error
- */
+int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_CLEAR);
+}
+/**
- fwu_get_mdata() - Get a FWU metadata copy
- @mdata: Copy of the FWU metadata
- Get a valid copy of the FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_mdata(struct fwu_mdata **mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
return ops->get_mdata(dev, mdata);
+}
+/**
- fwu_update_mdata() - Update the FWU metadata
- @mdata: Copy of the FWU metadata
- Update the FWU metadata structure by writing to the
- FWU metadata partitions.
- Return: 0 if OK, -ve on error
- */
+int fwu_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->update_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
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 0e26e1d138..d0ab1c9235 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -54,6 +54,7 @@ enum uclass_id { UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
UCLASS_FWU_MDATA, /* FWU Metadata Access */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ UCLASS_HASH, /* Hash device */ UCLASS_HWSPINLOCK, /* Hardware semaphores */
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..5a99c579fc --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <blk.h> +#include <efi.h>
+#include <linux/types.h>
+struct fwu_mdata; +struct udevice;
+/**
- @get_image_alt_num: get the alt number to be used for the image
- @mdata_check: check the validity of the FWU metadata partitions
- @get_mdata() - Get a FWU metadata copy
- @update_mdata() - Update the FWU metadata copy
- */
+struct fwu_mdata_ops {
int (*get_image_alt_num)(struct udevice *dev, efi_guid_t image_type_id,
u32 update_bank, int *alt_num);
int (*mdata_check)(struct udevice *dev);
int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata);
int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
+};
+#define FWU_MDATA_VERSION 0x1
+#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+int fwu_get_mdata(struct fwu_mdata **mdata); +int fwu_update_mdata(struct fwu_mdata *mdata); +int fwu_get_active_index(u32 *active_idx); +int fwu_update_active_index(u32 active_idx); +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num);
+int fwu_mdata_check(void); +int fwu_revert_boot_index(void); +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank);
+#endif /* _FWU_H_ */ diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h new file mode 100644 index 0000000000..701efbba03 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h>
+/**
- struct fwu_image_bank_info - firmware image information
- @image_uuid: Guid value of the image in this bank
- @accepted: Acceptance status of the image
- @reserved: Reserved
- The structure contains image specific fields which are
- used to identify the image and to specify the image's
- acceptance status
- */
+struct fwu_image_bank_info {
efi_guid_t image_uuid;
uint32_t accepted;
uint32_t reserved;
+} __attribute__((__packed__));
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+} __attribute__((__packed__));
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for performing
- multi bank updates on the platform. This contains info on the bank being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
uint32_t crc32;
uint32_t version;
uint32_t active_index;
uint32_t previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+} __attribute__((__packed__));
+#endif /* _FWU_MDATA_H_ */
2.17.1
One more thing. run kernel-doc to validate your description. [u-boot](eeee)$ ./scripts/kernel-doc -v -man drivers/fwu-mdata/fwu-mdata-uclass.c 1>/dev/null drivers/fwu-mdata/fwu-mdata-uclass.c:41: info: Scanning doc for fwu_verify_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:70: info: Scanning doc for fwu_get_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:107: info: Scanning doc for fwu_update_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:164: info: Scanning doc for fwu_get_image_alt_num drivers/fwu-mdata/fwu-mdata-uclass.c:197: info: Scanning doc for fwu_mdata_check drivers/fwu-mdata/fwu-mdata-uclass.c:202: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:224: info: Scanning doc for fwu_revert_boot_index drivers/fwu-mdata/fwu-mdata-uclass.c:230: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:279: info: Scanning doc for fwu_set_clear_image_accept drivers/fwu-mdata/fwu-mdata-uclass.c:338: info: Scanning doc for fwu_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:357: info: Scanning doc for fwu_clear_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:377: info: Scanning doc for fwu_get_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:404: info: Scanning doc for fwu_update_mdata 2 warnings
when I run buildman over this series it is visible that it is not bisectable at all. CONFIG_FWU_NUM_BANKS is defined in this patch but the symbol is added much later. Please make sure every single patch is bisectable.
And also I would separate dt binding, board dt update from actual feature.
Thanks, Michal

On Tue, 8 Feb 2022 at 17:01, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Move the FWU metadata access to driver model
- Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
+Example :
fwu-mdata {
compatible = "u-boot,fwu-mdata";
fwu-mdata-store = <&sdmmc1>;
};
diff --git a/drivers/Kconfig b/drivers/Kconfig index b26ca8cf70..adc6079ecf 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/fwu-mdata/Kconfig"
source "drivers/gpio/Kconfig"
source "drivers/hwspinlock/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 4e7cf28440..56f0f04874 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -81,6 +81,7 @@ obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ obj-$(CONFIG_FASTBOOT) += fastboot/ +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/ obj-y += misc/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_NVME) += nvme/ diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig new file mode 100644 index 0000000000..d6a21c8e19 --- /dev/null +++ b/drivers/fwu-mdata/Kconfig @@ -0,0 +1,7 @@ +config DM_FWU_MDATA
bool "Driver support for accessing FWU Metadata"
depends on DM
help
Enable support for accessing FWU Metadata partitions. The
FWU Metadata partitions reside on the same storage device
which contains the other FWU updatable firmware images.
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile new file mode 100644 index 0000000000..7fec7171f4 --- /dev/null +++ b/drivers/fwu-mdata/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2022, Linaro Limited +#
+obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c new file mode 100644 index 0000000000..64b3051ecf --- /dev/null +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#include <common.h> +#include <dm.h> +#include <efi_loader.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <log.h> +#include <malloc.h>
+#include <linux/errno.h> +#include <linux/types.h> +#include <u-boot/crc.h>
+#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR BIT(1)
+static int fwu_get_dev_ops(struct udevice **dev,
const struct fwu_mdata_ops **ops)
+{
int ret;
ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev);
if (ret) {
log_debug("Cannot find fwu device\n");
return ret;
}
if ((*ops = device_get_ops(*dev)) == NULL) {
log_debug("Cannot get fwu device ops\n");
return -ENOSYS;
}
return 0;
+}
+/**
- fwu_verify_mdata() - Verify the FWU metadata
- @mdata: FWU metadata structure
- @pri_part: FWU metadata partition is primary or secondary
- Verify the FWU metadata by computing the CRC32 for the metadata
- structure and comparing it against the CRC32 value stored as part
- of the structure.
- Return: 0 if OK, -ve on error
- */
+int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part) +{
u32 calc_crc32;
void *buf;
buf = &mdata->version;
calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
if (calc_crc32 != mdata->crc32) {
log_err("crc32 check failed for %s FWU metadata partition\n",
pri_part ? "primary" : "secondary");
return -1;
}
return 0;
+}
+/**
- fwu_get_active_index() - Get active_index from the FWU metadata
- @active_idx: active_index value to be read
- Read the active_index field from the FWU metadata and place it in
- the variable pointed to be the function argument.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
*active_idx = mdata->active_index;
if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value read is incorrect\n");
ret = -EINVAL;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_update_active_index() - Update active_index from the FWU metadata
- @active_idx: active_index value to be updated
- Update the active_index field in the FWU metadata
- Return: 0 if OK, -ve on error
- */
+int fwu_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata = NULL;
if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value to be updated is incorrect\n");
return -1;
}
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
mdata->previous_active_index = mdata->active_index;
mdata->active_index = active_idx;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update
- @image_type_id: image guid as passed in the capsule
- @update_bank: Bank to which the update is to be made
- @alt_num: The alt_num for the image
- Based on the guid value passed in the capsule, along with the bank to which the
- image needs to be updated, get the dfu alt number which will be used for the
- capsule update
- Return: 0 if OK, -ve on error
- */
+int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num)
+{
int ret;
const struct fwu_mdata_ops *ops = NULL;
struct udevice *dev = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_image_alt_num) {
log_err("get_image_alt_num() method not defined\n");
return -ENOSYS;
}
return ops->get_image_alt_num(dev, image_type_id,
update_bank, alt_num);
+}
+/**
- fwu_mdata_check() - Check if the FWU metadata is valid
- Validate both copies of the FWU metadata. If one of the copies
- has gone bad, restore it from the other bad copy.
- Return: 0 if OK, -ve on error
- */
+int fwu_mdata_check(void) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->mdata_check) {
log_err("mdata_check() method not defined\n");
return -ENOSYS;
}
return ops->mdata_check(dev);
+}
+/**
- fwu_revert_boot_index() - Revert the active index in the FWU metadata
- Revert the active_index value in the FWU metadata, by swapping the values
- of active_index and previous_active_index in both copies of the
- FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_revert_boot_index(void) +{
int ret;
void *buf;
u32 cur_active_index;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Swap the active index and previous_active_index fields
* in the FWU metadata
*/
cur_active_index = mdata->active_index;
mdata->active_index = mdata->previous_active_index;
mdata->previous_active_index = cur_active_index;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
set or cleared
- @bank: Bank of which the image's Accept bit is to be set or cleared
- @action: Action which specifies whether image's Accept bit is to be set or
cleared
- Set/Clear the accepted bit for the image specified by the img_guid parameter.
- This indicates acceptance or rejection of image for subsequent boots by some
- governing component like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+static int fwu_set_clear_image_accept(efi_guid_t *img_type_id,
u32 bank, u8 action)
+{
void *buf;
int ret, i;
u32 nimages;
struct fwu_mdata *mdata = NULL;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
img_entry = &mdata->img_entry[0];
for (i = 0; i < nimages; i++) {
if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
img_bank_info = &img_entry[i].img_bank_info[bank];
if (action == IMAGE_ACCEPT_SET)
img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
else
img_bank_info->accepted = 0;
buf = &mdata->version;
mdata->crc32 = crc32(0, buf, sizeof(*mdata) -
sizeof(u32));
ret = fwu_update_mdata(mdata);
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+/**
- fwu_accept_image() - Set the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be set
- Set the accepted bit for the image specified by the img_guid parameter. This
- indicates acceptance of image for subsequent boots by some governing component
- like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+int fwu_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_SET);
+}
+/**
- fwu_clear_accept_image() - Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be cleared
- Clear the accepted bit for the image type specified by the img_type_id parameter.
- This function is called after the image has been updated. The accepted bit is
- cleared to be set subsequently after passing the image acceptance criteria, by
- either the OS(or firmware)
- Return: 0 if OK, -ve on error
- */
+int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_CLEAR);
+}
+/**
- fwu_get_mdata() - Get a FWU metadata copy
- @mdata: Copy of the FWU metadata
- Get a valid copy of the FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_mdata(struct fwu_mdata **mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
return ops->get_mdata(dev, mdata);
+}
+/**
- fwu_update_mdata() - Update the FWU metadata
- @mdata: Copy of the FWU metadata
- Update the FWU metadata structure by writing to the
- FWU metadata partitions.
- Return: 0 if OK, -ve on error
- */
+int fwu_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->update_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
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 0e26e1d138..d0ab1c9235 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -54,6 +54,7 @@ enum uclass_id { UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
UCLASS_FWU_MDATA, /* FWU Metadata Access */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ UCLASS_HASH, /* Hash device */ UCLASS_HWSPINLOCK, /* Hardware semaphores */
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..5a99c579fc --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <blk.h> +#include <efi.h>
+#include <linux/types.h>
+struct fwu_mdata; +struct udevice;
+/**
- @get_image_alt_num: get the alt number to be used for the image
- @mdata_check: check the validity of the FWU metadata partitions
- @get_mdata() - Get a FWU metadata copy
- @update_mdata() - Update the FWU metadata copy
- */
+struct fwu_mdata_ops {
int (*get_image_alt_num)(struct udevice *dev, efi_guid_t image_type_id,
u32 update_bank, int *alt_num);
int (*mdata_check)(struct udevice *dev);
int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata);
int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
+};
+#define FWU_MDATA_VERSION 0x1
+#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+int fwu_get_mdata(struct fwu_mdata **mdata); +int fwu_update_mdata(struct fwu_mdata *mdata); +int fwu_get_active_index(u32 *active_idx); +int fwu_update_active_index(u32 active_idx); +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num);
+int fwu_mdata_check(void); +int fwu_revert_boot_index(void); +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank);
+#endif /* _FWU_H_ */ diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h new file mode 100644 index 0000000000..701efbba03 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h>
+/**
- struct fwu_image_bank_info - firmware image information
- @image_uuid: Guid value of the image in this bank
- @accepted: Acceptance status of the image
- @reserved: Reserved
- The structure contains image specific fields which are
- used to identify the image and to specify the image's
- acceptance status
- */
+struct fwu_image_bank_info {
efi_guid_t image_uuid;
uint32_t accepted;
uint32_t reserved;
+} __attribute__((__packed__));
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+} __attribute__((__packed__));
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for performing
- multi bank updates on the platform. This contains info on the bank being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
uint32_t crc32;
uint32_t version;
uint32_t active_index;
uint32_t previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+} __attribute__((__packed__));
+#endif /* _FWU_MDATA_H_ */
2.17.1
One more thing. run kernel-doc to validate your description. [u-boot](eeee)$ ./scripts/kernel-doc -v -man drivers/fwu-mdata/fwu-mdata-uclass.c 1>/dev/null drivers/fwu-mdata/fwu-mdata-uclass.c:41: info: Scanning doc for fwu_verify_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:70: info: Scanning doc for fwu_get_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:107: info: Scanning doc for fwu_update_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:164: info: Scanning doc for fwu_get_image_alt_num drivers/fwu-mdata/fwu-mdata-uclass.c:197: info: Scanning doc for fwu_mdata_check drivers/fwu-mdata/fwu-mdata-uclass.c:202: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:224: info: Scanning doc for fwu_revert_boot_index drivers/fwu-mdata/fwu-mdata-uclass.c:230: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:279: info: Scanning doc for fwu_set_clear_image_accept drivers/fwu-mdata/fwu-mdata-uclass.c:338: info: Scanning doc for fwu_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:357: info: Scanning doc for fwu_clear_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:377: info: Scanning doc for fwu_get_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:404: info: Scanning doc for fwu_update_mdata 2 warnings
when I run buildman over this series it is visible that it is not bisectable at all. CONFIG_FWU_NUM_BANKS is defined in this patch but the symbol is added much later. Please make sure every single patch is bisectable.
But how is this driver getting built in the first place -- the driver is not enabling the config symbol which would result in the code getting built. The idea is to add support for the driver and the feature, and enable the functionality in the final patch. I have added each patch separately and built for the qemu arm64 platform without any issues.
And also I would separate dt binding, board dt update from actual feature.
Okay.
-sughosh
Thanks, Michal
-- Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91 w: www.monstr.eu p: +42-0-721842854 Maintainer of Linux kernel - Xilinx Microblaze Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs

On 2/8/22 12:38, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:01, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
Move the FWU metadata access to driver model
Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
+Example :
fwu-mdata {
compatible = "u-boot,fwu-mdata";
fwu-mdata-store = <&sdmmc1>;
};
diff --git a/drivers/Kconfig b/drivers/Kconfig index b26ca8cf70..adc6079ecf 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/fwu-mdata/Kconfig"
source "drivers/gpio/Kconfig"
source "drivers/hwspinlock/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile index 4e7cf28440..56f0f04874 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -81,6 +81,7 @@ obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ obj-$(CONFIG_FASTBOOT) += fastboot/ +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/ obj-y += misc/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_NVME) += nvme/ diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig new file mode 100644 index 0000000000..d6a21c8e19 --- /dev/null +++ b/drivers/fwu-mdata/Kconfig @@ -0,0 +1,7 @@ +config DM_FWU_MDATA
bool "Driver support for accessing FWU Metadata"
depends on DM
help
Enable support for accessing FWU Metadata partitions. The
FWU Metadata partitions reside on the same storage device
which contains the other FWU updatable firmware images.
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile new file mode 100644 index 0000000000..7fec7171f4 --- /dev/null +++ b/drivers/fwu-mdata/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2022, Linaro Limited +#
+obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c new file mode 100644 index 0000000000..64b3051ecf --- /dev/null +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#include <common.h> +#include <dm.h> +#include <efi_loader.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <log.h> +#include <malloc.h>
+#include <linux/errno.h> +#include <linux/types.h> +#include <u-boot/crc.h>
+#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR BIT(1)
+static int fwu_get_dev_ops(struct udevice **dev,
const struct fwu_mdata_ops **ops)
+{
int ret;
ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev);
if (ret) {
log_debug("Cannot find fwu device\n");
return ret;
}
if ((*ops = device_get_ops(*dev)) == NULL) {
log_debug("Cannot get fwu device ops\n");
return -ENOSYS;
}
return 0;
+}
+/**
- fwu_verify_mdata() - Verify the FWU metadata
- @mdata: FWU metadata structure
- @pri_part: FWU metadata partition is primary or secondary
- Verify the FWU metadata by computing the CRC32 for the metadata
- structure and comparing it against the CRC32 value stored as part
- of the structure.
- Return: 0 if OK, -ve on error
- */
+int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part) +{
u32 calc_crc32;
void *buf;
buf = &mdata->version;
calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
if (calc_crc32 != mdata->crc32) {
log_err("crc32 check failed for %s FWU metadata partition\n",
pri_part ? "primary" : "secondary");
return -1;
}
return 0;
+}
+/**
- fwu_get_active_index() - Get active_index from the FWU metadata
- @active_idx: active_index value to be read
- Read the active_index field from the FWU metadata and place it in
- the variable pointed to be the function argument.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
*active_idx = mdata->active_index;
if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value read is incorrect\n");
ret = -EINVAL;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_update_active_index() - Update active_index from the FWU metadata
- @active_idx: active_index value to be updated
- Update the active_index field in the FWU metadata
- Return: 0 if OK, -ve on error
- */
+int fwu_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata = NULL;
if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value to be updated is incorrect\n");
return -1;
}
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
mdata->previous_active_index = mdata->active_index;
mdata->active_index = active_idx;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update
- @image_type_id: image guid as passed in the capsule
- @update_bank: Bank to which the update is to be made
- @alt_num: The alt_num for the image
- Based on the guid value passed in the capsule, along with the bank to which the
- image needs to be updated, get the dfu alt number which will be used for the
- capsule update
- Return: 0 if OK, -ve on error
- */
+int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num)
+{
int ret;
const struct fwu_mdata_ops *ops = NULL;
struct udevice *dev = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_image_alt_num) {
log_err("get_image_alt_num() method not defined\n");
return -ENOSYS;
}
return ops->get_image_alt_num(dev, image_type_id,
update_bank, alt_num);
+}
+/**
- fwu_mdata_check() - Check if the FWU metadata is valid
- Validate both copies of the FWU metadata. If one of the copies
- has gone bad, restore it from the other bad copy.
- Return: 0 if OK, -ve on error
- */
+int fwu_mdata_check(void) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->mdata_check) {
log_err("mdata_check() method not defined\n");
return -ENOSYS;
}
return ops->mdata_check(dev);
+}
+/**
- fwu_revert_boot_index() - Revert the active index in the FWU metadata
- Revert the active_index value in the FWU metadata, by swapping the values
- of active_index and previous_active_index in both copies of the
- FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_revert_boot_index(void) +{
int ret;
void *buf;
u32 cur_active_index;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Swap the active index and previous_active_index fields
* in the FWU metadata
*/
cur_active_index = mdata->active_index;
mdata->active_index = mdata->previous_active_index;
mdata->previous_active_index = cur_active_index;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
set or cleared
- @bank: Bank of which the image's Accept bit is to be set or cleared
- @action: Action which specifies whether image's Accept bit is to be set or
cleared
- Set/Clear the accepted bit for the image specified by the img_guid parameter.
- This indicates acceptance or rejection of image for subsequent boots by some
- governing component like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+static int fwu_set_clear_image_accept(efi_guid_t *img_type_id,
u32 bank, u8 action)
+{
void *buf;
int ret, i;
u32 nimages;
struct fwu_mdata *mdata = NULL;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
img_entry = &mdata->img_entry[0];
for (i = 0; i < nimages; i++) {
if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
img_bank_info = &img_entry[i].img_bank_info[bank];
if (action == IMAGE_ACCEPT_SET)
img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
else
img_bank_info->accepted = 0;
buf = &mdata->version;
mdata->crc32 = crc32(0, buf, sizeof(*mdata) -
sizeof(u32));
ret = fwu_update_mdata(mdata);
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+/**
- fwu_accept_image() - Set the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be set
- Set the accepted bit for the image specified by the img_guid parameter. This
- indicates acceptance of image for subsequent boots by some governing component
- like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+int fwu_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_SET);
+}
+/**
- fwu_clear_accept_image() - Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be cleared
- Clear the accepted bit for the image type specified by the img_type_id parameter.
- This function is called after the image has been updated. The accepted bit is
- cleared to be set subsequently after passing the image acceptance criteria, by
- either the OS(or firmware)
- Return: 0 if OK, -ve on error
- */
+int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_CLEAR);
+}
+/**
- fwu_get_mdata() - Get a FWU metadata copy
- @mdata: Copy of the FWU metadata
- Get a valid copy of the FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_mdata(struct fwu_mdata **mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
return ops->get_mdata(dev, mdata);
+}
+/**
- fwu_update_mdata() - Update the FWU metadata
- @mdata: Copy of the FWU metadata
- Update the FWU metadata structure by writing to the
- FWU metadata partitions.
- Return: 0 if OK, -ve on error
- */
+int fwu_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->update_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
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 0e26e1d138..d0ab1c9235 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -54,6 +54,7 @@ enum uclass_id { UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
UCLASS_FWU_MDATA, /* FWU Metadata Access */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ UCLASS_HASH, /* Hash device */ UCLASS_HWSPINLOCK, /* Hardware semaphores */
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..5a99c579fc --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <blk.h> +#include <efi.h>
+#include <linux/types.h>
+struct fwu_mdata; +struct udevice;
+/**
- @get_image_alt_num: get the alt number to be used for the image
- @mdata_check: check the validity of the FWU metadata partitions
- @get_mdata() - Get a FWU metadata copy
- @update_mdata() - Update the FWU metadata copy
- */
+struct fwu_mdata_ops {
int (*get_image_alt_num)(struct udevice *dev, efi_guid_t image_type_id,
u32 update_bank, int *alt_num);
int (*mdata_check)(struct udevice *dev);
int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata);
int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
+};
+#define FWU_MDATA_VERSION 0x1
+#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+int fwu_get_mdata(struct fwu_mdata **mdata); +int fwu_update_mdata(struct fwu_mdata *mdata); +int fwu_get_active_index(u32 *active_idx); +int fwu_update_active_index(u32 active_idx); +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num);
+int fwu_mdata_check(void); +int fwu_revert_boot_index(void); +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank);
+#endif /* _FWU_H_ */ diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h new file mode 100644 index 0000000000..701efbba03 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h>
+/**
- struct fwu_image_bank_info - firmware image information
- @image_uuid: Guid value of the image in this bank
- @accepted: Acceptance status of the image
- @reserved: Reserved
- The structure contains image specific fields which are
- used to identify the image and to specify the image's
- acceptance status
- */
+struct fwu_image_bank_info {
efi_guid_t image_uuid;
uint32_t accepted;
uint32_t reserved;
+} __attribute__((__packed__));
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+} __attribute__((__packed__));
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for performing
- multi bank updates on the platform. This contains info on the bank being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
uint32_t crc32;
uint32_t version;
uint32_t active_index;
uint32_t previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+} __attribute__((__packed__));
+#endif /* _FWU_MDATA_H_ */
2.17.1
One more thing. run kernel-doc to validate your description. [u-boot](eeee)$ ./scripts/kernel-doc -v -man drivers/fwu-mdata/fwu-mdata-uclass.c 1>/dev/null drivers/fwu-mdata/fwu-mdata-uclass.c:41: info: Scanning doc for fwu_verify_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:70: info: Scanning doc for fwu_get_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:107: info: Scanning doc for fwu_update_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:164: info: Scanning doc for fwu_get_image_alt_num drivers/fwu-mdata/fwu-mdata-uclass.c:197: info: Scanning doc for fwu_mdata_check drivers/fwu-mdata/fwu-mdata-uclass.c:202: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:224: info: Scanning doc for fwu_revert_boot_index drivers/fwu-mdata/fwu-mdata-uclass.c:230: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:279: info: Scanning doc for fwu_set_clear_image_accept drivers/fwu-mdata/fwu-mdata-uclass.c:338: info: Scanning doc for fwu_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:357: info: Scanning doc for fwu_clear_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:377: info: Scanning doc for fwu_get_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:404: info: Scanning doc for fwu_update_mdata 2 warnings
when I run buildman over this series it is visible that it is not bisectable at all. CONFIG_FWU_NUM_BANKS is defined in this patch but the symbol is added much later. Please make sure every single patch is bisectable.
But how is this driver getting built in the first place -- the driver is not enabling the config symbol which would result in the code getting built. The idea is to add support for the driver and the feature, and enable the functionality in the final patch. I have added each patch separately and built for the qemu arm64 platform without any issues.
first of all I wasn't able to apply all patches because this series is not there. https://patchwork.ozlabs.org/project/uboot/list/?series=281549 (better would be to use links to lore which are much easier to download)
That's why 2 patches weren't applied.
And I just enabled configs which land in the tree for zynqmp virt and rebase this patch to be the first one. That's why all the time all existing Kconfigs were enabled when buildman build them. It is not that far from using the same defconfig with bisicting tree. You can definitely avoid it in your series.
Thanks, Michal

On Tue, 8 Feb 2022 at 17:15, Michal Simek michal.simek@xilinx.com wrote:
On 2/8/22 12:38, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:01, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
Move the FWU metadata access to driver model
Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
+Example :
fwu-mdata {
compatible = "u-boot,fwu-mdata";
fwu-mdata-store = <&sdmmc1>;
};
diff --git a/drivers/Kconfig b/drivers/Kconfig index b26ca8cf70..adc6079ecf 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/fwu-mdata/Kconfig"
source "drivers/gpio/Kconfig"
source "drivers/hwspinlock/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile index 4e7cf28440..56f0f04874 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -81,6 +81,7 @@ obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ obj-$(CONFIG_FASTBOOT) += fastboot/ +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/ obj-y += misc/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_NVME) += nvme/ diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig new file mode 100644 index 0000000000..d6a21c8e19 --- /dev/null +++ b/drivers/fwu-mdata/Kconfig @@ -0,0 +1,7 @@ +config DM_FWU_MDATA
bool "Driver support for accessing FWU Metadata"
depends on DM
help
Enable support for accessing FWU Metadata partitions. The
FWU Metadata partitions reside on the same storage device
which contains the other FWU updatable firmware images.
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile new file mode 100644 index 0000000000..7fec7171f4 --- /dev/null +++ b/drivers/fwu-mdata/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2022, Linaro Limited +#
+obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c new file mode 100644 index 0000000000..64b3051ecf --- /dev/null +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#include <common.h> +#include <dm.h> +#include <efi_loader.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <log.h> +#include <malloc.h>
+#include <linux/errno.h> +#include <linux/types.h> +#include <u-boot/crc.h>
+#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR BIT(1)
+static int fwu_get_dev_ops(struct udevice **dev,
const struct fwu_mdata_ops **ops)
+{
int ret;
ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev);
if (ret) {
log_debug("Cannot find fwu device\n");
return ret;
}
if ((*ops = device_get_ops(*dev)) == NULL) {
log_debug("Cannot get fwu device ops\n");
return -ENOSYS;
}
return 0;
+}
+/**
- fwu_verify_mdata() - Verify the FWU metadata
- @mdata: FWU metadata structure
- @pri_part: FWU metadata partition is primary or secondary
- Verify the FWU metadata by computing the CRC32 for the metadata
- structure and comparing it against the CRC32 value stored as part
- of the structure.
- Return: 0 if OK, -ve on error
- */
+int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part) +{
u32 calc_crc32;
void *buf;
buf = &mdata->version;
calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
if (calc_crc32 != mdata->crc32) {
log_err("crc32 check failed for %s FWU metadata partition\n",
pri_part ? "primary" : "secondary");
return -1;
}
return 0;
+}
+/**
- fwu_get_active_index() - Get active_index from the FWU metadata
- @active_idx: active_index value to be read
- Read the active_index field from the FWU metadata and place it in
- the variable pointed to be the function argument.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
*active_idx = mdata->active_index;
if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value read is incorrect\n");
ret = -EINVAL;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_update_active_index() - Update active_index from the FWU metadata
- @active_idx: active_index value to be updated
- Update the active_index field in the FWU metadata
- Return: 0 if OK, -ve on error
- */
+int fwu_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata = NULL;
if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value to be updated is incorrect\n");
return -1;
}
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
mdata->previous_active_index = mdata->active_index;
mdata->active_index = active_idx;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update
- @image_type_id: image guid as passed in the capsule
- @update_bank: Bank to which the update is to be made
- @alt_num: The alt_num for the image
- Based on the guid value passed in the capsule, along with the bank to which the
- image needs to be updated, get the dfu alt number which will be used for the
- capsule update
- Return: 0 if OK, -ve on error
- */
+int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num)
+{
int ret;
const struct fwu_mdata_ops *ops = NULL;
struct udevice *dev = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_image_alt_num) {
log_err("get_image_alt_num() method not defined\n");
return -ENOSYS;
}
return ops->get_image_alt_num(dev, image_type_id,
update_bank, alt_num);
+}
+/**
- fwu_mdata_check() - Check if the FWU metadata is valid
- Validate both copies of the FWU metadata. If one of the copies
- has gone bad, restore it from the other bad copy.
- Return: 0 if OK, -ve on error
- */
+int fwu_mdata_check(void) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->mdata_check) {
log_err("mdata_check() method not defined\n");
return -ENOSYS;
}
return ops->mdata_check(dev);
+}
+/**
- fwu_revert_boot_index() - Revert the active index in the FWU metadata
- Revert the active_index value in the FWU metadata, by swapping the values
- of active_index and previous_active_index in both copies of the
- FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_revert_boot_index(void) +{
int ret;
void *buf;
u32 cur_active_index;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Swap the active index and previous_active_index fields
* in the FWU metadata
*/
cur_active_index = mdata->active_index;
mdata->active_index = mdata->previous_active_index;
mdata->previous_active_index = cur_active_index;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
set or cleared
- @bank: Bank of which the image's Accept bit is to be set or cleared
- @action: Action which specifies whether image's Accept bit is to be set or
cleared
- Set/Clear the accepted bit for the image specified by the img_guid parameter.
- This indicates acceptance or rejection of image for subsequent boots by some
- governing component like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+static int fwu_set_clear_image_accept(efi_guid_t *img_type_id,
u32 bank, u8 action)
+{
void *buf;
int ret, i;
u32 nimages;
struct fwu_mdata *mdata = NULL;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
img_entry = &mdata->img_entry[0];
for (i = 0; i < nimages; i++) {
if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
img_bank_info = &img_entry[i].img_bank_info[bank];
if (action == IMAGE_ACCEPT_SET)
img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
else
img_bank_info->accepted = 0;
buf = &mdata->version;
mdata->crc32 = crc32(0, buf, sizeof(*mdata) -
sizeof(u32));
ret = fwu_update_mdata(mdata);
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+/**
- fwu_accept_image() - Set the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be set
- Set the accepted bit for the image specified by the img_guid parameter. This
- indicates acceptance of image for subsequent boots by some governing component
- like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+int fwu_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_SET);
+}
+/**
- fwu_clear_accept_image() - Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be cleared
- Clear the accepted bit for the image type specified by the img_type_id parameter.
- This function is called after the image has been updated. The accepted bit is
- cleared to be set subsequently after passing the image acceptance criteria, by
- either the OS(or firmware)
- Return: 0 if OK, -ve on error
- */
+int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_CLEAR);
+}
+/**
- fwu_get_mdata() - Get a FWU metadata copy
- @mdata: Copy of the FWU metadata
- Get a valid copy of the FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_mdata(struct fwu_mdata **mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
return ops->get_mdata(dev, mdata);
+}
+/**
- fwu_update_mdata() - Update the FWU metadata
- @mdata: Copy of the FWU metadata
- Update the FWU metadata structure by writing to the
- FWU metadata partitions.
- Return: 0 if OK, -ve on error
- */
+int fwu_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->update_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
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 0e26e1d138..d0ab1c9235 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -54,6 +54,7 @@ enum uclass_id { UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
UCLASS_FWU_MDATA, /* FWU Metadata Access */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ UCLASS_HASH, /* Hash device */ UCLASS_HWSPINLOCK, /* Hardware semaphores */
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..5a99c579fc --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <blk.h> +#include <efi.h>
+#include <linux/types.h>
+struct fwu_mdata; +struct udevice;
+/**
- @get_image_alt_num: get the alt number to be used for the image
- @mdata_check: check the validity of the FWU metadata partitions
- @get_mdata() - Get a FWU metadata copy
- @update_mdata() - Update the FWU metadata copy
- */
+struct fwu_mdata_ops {
int (*get_image_alt_num)(struct udevice *dev, efi_guid_t image_type_id,
u32 update_bank, int *alt_num);
int (*mdata_check)(struct udevice *dev);
int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata);
int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
+};
+#define FWU_MDATA_VERSION 0x1
+#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+int fwu_get_mdata(struct fwu_mdata **mdata); +int fwu_update_mdata(struct fwu_mdata *mdata); +int fwu_get_active_index(u32 *active_idx); +int fwu_update_active_index(u32 active_idx); +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num);
+int fwu_mdata_check(void); +int fwu_revert_boot_index(void); +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank);
+#endif /* _FWU_H_ */ diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h new file mode 100644 index 0000000000..701efbba03 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h>
+/**
- struct fwu_image_bank_info - firmware image information
- @image_uuid: Guid value of the image in this bank
- @accepted: Acceptance status of the image
- @reserved: Reserved
- The structure contains image specific fields which are
- used to identify the image and to specify the image's
- acceptance status
- */
+struct fwu_image_bank_info {
efi_guid_t image_uuid;
uint32_t accepted;
uint32_t reserved;
+} __attribute__((__packed__));
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+} __attribute__((__packed__));
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for performing
- multi bank updates on the platform. This contains info on the bank being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
uint32_t crc32;
uint32_t version;
uint32_t active_index;
uint32_t previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+} __attribute__((__packed__));
+#endif /* _FWU_MDATA_H_ */
2.17.1
One more thing. run kernel-doc to validate your description. [u-boot](eeee)$ ./scripts/kernel-doc -v -man drivers/fwu-mdata/fwu-mdata-uclass.c 1>/dev/null drivers/fwu-mdata/fwu-mdata-uclass.c:41: info: Scanning doc for fwu_verify_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:70: info: Scanning doc for fwu_get_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:107: info: Scanning doc for fwu_update_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:164: info: Scanning doc for fwu_get_image_alt_num drivers/fwu-mdata/fwu-mdata-uclass.c:197: info: Scanning doc for fwu_mdata_check drivers/fwu-mdata/fwu-mdata-uclass.c:202: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:224: info: Scanning doc for fwu_revert_boot_index drivers/fwu-mdata/fwu-mdata-uclass.c:230: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:279: info: Scanning doc for fwu_set_clear_image_accept drivers/fwu-mdata/fwu-mdata-uclass.c:338: info: Scanning doc for fwu_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:357: info: Scanning doc for fwu_clear_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:377: info: Scanning doc for fwu_get_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:404: info: Scanning doc for fwu_update_mdata 2 warnings
when I run buildman over this series it is visible that it is not bisectable at all. CONFIG_FWU_NUM_BANKS is defined in this patch but the symbol is added much later. Please make sure every single patch is bisectable.
But how is this driver getting built in the first place -- the driver is not enabling the config symbol which would result in the code getting built. The idea is to add support for the driver and the feature, and enable the functionality in the final patch. I have added each patch separately and built for the qemu arm64 platform without any issues.
first of all I wasn't able to apply all patches because this series is not there. https://patchwork.ozlabs.org/project/uboot/list/?series=281549 (better would be to use links to lore which are much easier to download)
You can download the mkeficapsule series from linaro's patchwork[1].
That's why 2 patches weren't applied.
And I just enabled configs which land in the tree for zynqmp virt and rebase this patch to be the first one. That's why all the time all existing Kconfigs were enabled when buildman build them.
Okay my understanding of a patch being bisectable was if the build does not break after applying a patch. Please note that on top of my series, you will need to define CONFIG_FWU_NUM_BANKS and CONFIG_FWU_NUM_IMAGES_PER_BANK. I did not define that on purpose since each platform would have it's own specific values.
-sughosh
[1] - https://patches.linaro.org/project/u-boot/list/?series=166236
It is not that far from using the same defconfig with bisicting tree. You can definitely avoid it in your series.
Thanks, Michal

On 2/8/22 12:54, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:15, Michal Simek michal.simek@xilinx.com wrote:
On 2/8/22 12:38, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:01, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
Move the FWU metadata access to driver model
Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
+Example :
fwu-mdata {
compatible = "u-boot,fwu-mdata";
fwu-mdata-store = <&sdmmc1>;
};
diff --git a/drivers/Kconfig b/drivers/Kconfig index b26ca8cf70..adc6079ecf 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/fwu-mdata/Kconfig"
source "drivers/gpio/Kconfig"
source "drivers/hwspinlock/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile index 4e7cf28440..56f0f04874 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -81,6 +81,7 @@ obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ obj-$(CONFIG_FASTBOOT) += fastboot/ +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/ obj-y += misc/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_NVME) += nvme/ diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig new file mode 100644 index 0000000000..d6a21c8e19 --- /dev/null +++ b/drivers/fwu-mdata/Kconfig @@ -0,0 +1,7 @@ +config DM_FWU_MDATA
bool "Driver support for accessing FWU Metadata"
depends on DM
help
Enable support for accessing FWU Metadata partitions. The
FWU Metadata partitions reside on the same storage device
which contains the other FWU updatable firmware images.
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile new file mode 100644 index 0000000000..7fec7171f4 --- /dev/null +++ b/drivers/fwu-mdata/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2022, Linaro Limited +#
+obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c new file mode 100644 index 0000000000..64b3051ecf --- /dev/null +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#include <common.h> +#include <dm.h> +#include <efi_loader.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <log.h> +#include <malloc.h>
+#include <linux/errno.h> +#include <linux/types.h> +#include <u-boot/crc.h>
+#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR BIT(1)
+static int fwu_get_dev_ops(struct udevice **dev,
const struct fwu_mdata_ops **ops)
+{
int ret;
ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev);
if (ret) {
log_debug("Cannot find fwu device\n");
return ret;
}
if ((*ops = device_get_ops(*dev)) == NULL) {
log_debug("Cannot get fwu device ops\n");
return -ENOSYS;
}
return 0;
+}
+/**
- fwu_verify_mdata() - Verify the FWU metadata
- @mdata: FWU metadata structure
- @pri_part: FWU metadata partition is primary or secondary
- Verify the FWU metadata by computing the CRC32 for the metadata
- structure and comparing it against the CRC32 value stored as part
- of the structure.
- Return: 0 if OK, -ve on error
- */
+int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part) +{
u32 calc_crc32;
void *buf;
buf = &mdata->version;
calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
if (calc_crc32 != mdata->crc32) {
log_err("crc32 check failed for %s FWU metadata partition\n",
pri_part ? "primary" : "secondary");
return -1;
}
return 0;
+}
+/**
- fwu_get_active_index() - Get active_index from the FWU metadata
- @active_idx: active_index value to be read
- Read the active_index field from the FWU metadata and place it in
- the variable pointed to be the function argument.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
*active_idx = mdata->active_index;
if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value read is incorrect\n");
ret = -EINVAL;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_update_active_index() - Update active_index from the FWU metadata
- @active_idx: active_index value to be updated
- Update the active_index field in the FWU metadata
- Return: 0 if OK, -ve on error
- */
+int fwu_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata = NULL;
if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value to be updated is incorrect\n");
return -1;
}
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
mdata->previous_active_index = mdata->active_index;
mdata->active_index = active_idx;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update
- @image_type_id: image guid as passed in the capsule
- @update_bank: Bank to which the update is to be made
- @alt_num: The alt_num for the image
- Based on the guid value passed in the capsule, along with the bank to which the
- image needs to be updated, get the dfu alt number which will be used for the
- capsule update
- Return: 0 if OK, -ve on error
- */
+int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num)
+{
int ret;
const struct fwu_mdata_ops *ops = NULL;
struct udevice *dev = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_image_alt_num) {
log_err("get_image_alt_num() method not defined\n");
return -ENOSYS;
}
return ops->get_image_alt_num(dev, image_type_id,
update_bank, alt_num);
+}
+/**
- fwu_mdata_check() - Check if the FWU metadata is valid
- Validate both copies of the FWU metadata. If one of the copies
- has gone bad, restore it from the other bad copy.
- Return: 0 if OK, -ve on error
- */
+int fwu_mdata_check(void) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->mdata_check) {
log_err("mdata_check() method not defined\n");
return -ENOSYS;
}
return ops->mdata_check(dev);
+}
+/**
- fwu_revert_boot_index() - Revert the active index in the FWU metadata
- Revert the active_index value in the FWU metadata, by swapping the values
- of active_index and previous_active_index in both copies of the
- FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_revert_boot_index(void) +{
int ret;
void *buf;
u32 cur_active_index;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Swap the active index and previous_active_index fields
* in the FWU metadata
*/
cur_active_index = mdata->active_index;
mdata->active_index = mdata->previous_active_index;
mdata->previous_active_index = cur_active_index;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
set or cleared
- @bank: Bank of which the image's Accept bit is to be set or cleared
- @action: Action which specifies whether image's Accept bit is to be set or
cleared
- Set/Clear the accepted bit for the image specified by the img_guid parameter.
- This indicates acceptance or rejection of image for subsequent boots by some
- governing component like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+static int fwu_set_clear_image_accept(efi_guid_t *img_type_id,
u32 bank, u8 action)
+{
void *buf;
int ret, i;
u32 nimages;
struct fwu_mdata *mdata = NULL;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
img_entry = &mdata->img_entry[0];
for (i = 0; i < nimages; i++) {
if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
img_bank_info = &img_entry[i].img_bank_info[bank];
if (action == IMAGE_ACCEPT_SET)
img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
else
img_bank_info->accepted = 0;
buf = &mdata->version;
mdata->crc32 = crc32(0, buf, sizeof(*mdata) -
sizeof(u32));
ret = fwu_update_mdata(mdata);
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+/**
- fwu_accept_image() - Set the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be set
- Set the accepted bit for the image specified by the img_guid parameter. This
- indicates acceptance of image for subsequent boots by some governing component
- like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+int fwu_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_SET);
+}
+/**
- fwu_clear_accept_image() - Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be cleared
- Clear the accepted bit for the image type specified by the img_type_id parameter.
- This function is called after the image has been updated. The accepted bit is
- cleared to be set subsequently after passing the image acceptance criteria, by
- either the OS(or firmware)
- Return: 0 if OK, -ve on error
- */
+int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_CLEAR);
+}
+/**
- fwu_get_mdata() - Get a FWU metadata copy
- @mdata: Copy of the FWU metadata
- Get a valid copy of the FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_mdata(struct fwu_mdata **mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
return ops->get_mdata(dev, mdata);
+}
+/**
- fwu_update_mdata() - Update the FWU metadata
- @mdata: Copy of the FWU metadata
- Update the FWU metadata structure by writing to the
- FWU metadata partitions.
- Return: 0 if OK, -ve on error
- */
+int fwu_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->update_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
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 0e26e1d138..d0ab1c9235 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -54,6 +54,7 @@ enum uclass_id { UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
UCLASS_FWU_MDATA, /* FWU Metadata Access */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ UCLASS_HASH, /* Hash device */ UCLASS_HWSPINLOCK, /* Hardware semaphores */
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..5a99c579fc --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <blk.h> +#include <efi.h>
+#include <linux/types.h>
+struct fwu_mdata; +struct udevice;
+/**
- @get_image_alt_num: get the alt number to be used for the image
- @mdata_check: check the validity of the FWU metadata partitions
- @get_mdata() - Get a FWU metadata copy
- @update_mdata() - Update the FWU metadata copy
- */
+struct fwu_mdata_ops {
int (*get_image_alt_num)(struct udevice *dev, efi_guid_t image_type_id,
u32 update_bank, int *alt_num);
int (*mdata_check)(struct udevice *dev);
int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata);
int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
+};
+#define FWU_MDATA_VERSION 0x1
+#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+int fwu_get_mdata(struct fwu_mdata **mdata); +int fwu_update_mdata(struct fwu_mdata *mdata); +int fwu_get_active_index(u32 *active_idx); +int fwu_update_active_index(u32 active_idx); +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num);
+int fwu_mdata_check(void); +int fwu_revert_boot_index(void); +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank);
+#endif /* _FWU_H_ */ diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h new file mode 100644 index 0000000000..701efbba03 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h>
+/**
- struct fwu_image_bank_info - firmware image information
- @image_uuid: Guid value of the image in this bank
- @accepted: Acceptance status of the image
- @reserved: Reserved
- The structure contains image specific fields which are
- used to identify the image and to specify the image's
- acceptance status
- */
+struct fwu_image_bank_info {
efi_guid_t image_uuid;
uint32_t accepted;
uint32_t reserved;
+} __attribute__((__packed__));
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+} __attribute__((__packed__));
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for performing
- multi bank updates on the platform. This contains info on the bank being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
uint32_t crc32;
uint32_t version;
uint32_t active_index;
uint32_t previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+} __attribute__((__packed__));
+#endif /* _FWU_MDATA_H_ */
2.17.1
One more thing. run kernel-doc to validate your description. [u-boot](eeee)$ ./scripts/kernel-doc -v -man drivers/fwu-mdata/fwu-mdata-uclass.c 1>/dev/null drivers/fwu-mdata/fwu-mdata-uclass.c:41: info: Scanning doc for fwu_verify_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:70: info: Scanning doc for fwu_get_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:107: info: Scanning doc for fwu_update_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:164: info: Scanning doc for fwu_get_image_alt_num drivers/fwu-mdata/fwu-mdata-uclass.c:197: info: Scanning doc for fwu_mdata_check drivers/fwu-mdata/fwu-mdata-uclass.c:202: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:224: info: Scanning doc for fwu_revert_boot_index drivers/fwu-mdata/fwu-mdata-uclass.c:230: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:279: info: Scanning doc for fwu_set_clear_image_accept drivers/fwu-mdata/fwu-mdata-uclass.c:338: info: Scanning doc for fwu_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:357: info: Scanning doc for fwu_clear_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:377: info: Scanning doc for fwu_get_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:404: info: Scanning doc for fwu_update_mdata 2 warnings
when I run buildman over this series it is visible that it is not bisectable at all. CONFIG_FWU_NUM_BANKS is defined in this patch but the symbol is added much later. Please make sure every single patch is bisectable.
But how is this driver getting built in the first place -- the driver is not enabling the config symbol which would result in the code getting built. The idea is to add support for the driver and the feature, and enable the functionality in the final patch. I have added each patch separately and built for the qemu arm64 platform without any issues.
first of all I wasn't able to apply all patches because this series is not there. https://patchwork.ozlabs.org/project/uboot/list/?series=281549 (better would be to use links to lore which are much easier to download)
You can download the mkeficapsule series from linaro's patchwork[1].
you depend on 3 series. Much easier is to create a branch and push it somewhere.
That's why 2 patches weren't applied.
And I just enabled configs which land in the tree for zynqmp virt and rebase this patch to be the first one. That's why all the time all existing Kconfigs were enabled when buildman build them.
Okay my understanding of a patch being bisectable was if the build does not break after applying a patch. Please note that on top of my series, you will need to define CONFIG_FWU_NUM_BANKS and CONFIG_FWU_NUM_IMAGES_PER_BANK. I did not define that on purpose since each platform would have it's own specific values.
Even if this is true you can't use in any patch a macro/value which is not defined and it is not clear what it is. I apply patch 1 and review patch 1 and not looking at patch 8 to get what that values are for.
Define them as reasonable default for common case or your usecase. Platform can set them up when they adopt this approach and they are not happy with your defaults.
Thanks, Michal

On Tue, 8 Feb 2022 at 17:29, Michal Simek michal.simek@xilinx.com wrote:
On 2/8/22 12:54, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:15, Michal Simek michal.simek@xilinx.com wrote:
On 2/8/22 12:38, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:01, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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.
A device tree node fwu-mdata has been added, which is used for pointing to the storage device which contains the FWU metadata. The fwu-mdata node is u-boot specific, and can be added the platform's u-boot dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
Move the FWU metadata access to driver model
Get the storage device containing the metadata from a device tree property instead of a platform helper function
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + .../firmware/fwu-mdata.txt | 18 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 7 + drivers/fwu-mdata/Makefile | 6 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fwu.h | 51 ++ include/fwu_mdata.h | 67 +++ 10 files changed, 594 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h
diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi index 06ef3a4095..3bec6107f7 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";
fwu-mdata-store = <&sdmmc1>;
};
+}; diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt new file mode 100644 index 0000000000..c766b595ef --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt @@ -0,0 +1,18 @@ +FWU Metadata Access Devicetree Binding
+The FWU Multi Bank Update feature uses a metadata structure, stored on +a separate partition for keeping information on the set of updatable +images. The device tree node provides information on the storage +device that contains the FWU metadata.
+Required properties :
+- compatible : "u-boot,fwu-mdata"; +- fwu-mdata-store : should point to the storage device which contains
the FWU metadata partition.
+Example :
fwu-mdata {
compatible = "u-boot,fwu-mdata";
fwu-mdata-store = <&sdmmc1>;
};
diff --git a/drivers/Kconfig b/drivers/Kconfig index b26ca8cf70..adc6079ecf 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/fwu-mdata/Kconfig"
source "drivers/gpio/Kconfig"
source "drivers/hwspinlock/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile index 4e7cf28440..56f0f04874 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -81,6 +81,7 @@ obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ obj-$(CONFIG_FASTBOOT) += fastboot/ +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/ obj-y += misc/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_NVME) += nvme/ diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig new file mode 100644 index 0000000000..d6a21c8e19 --- /dev/null +++ b/drivers/fwu-mdata/Kconfig @@ -0,0 +1,7 @@ +config DM_FWU_MDATA
bool "Driver support for accessing FWU Metadata"
depends on DM
help
Enable support for accessing FWU Metadata partitions. The
FWU Metadata partitions reside on the same storage device
which contains the other FWU updatable firmware images.
diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile new file mode 100644 index 0000000000..7fec7171f4 --- /dev/null +++ b/drivers/fwu-mdata/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2022, Linaro Limited +#
+obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c new file mode 100644 index 0000000000..64b3051ecf --- /dev/null +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#include <common.h> +#include <dm.h> +#include <efi_loader.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <log.h> +#include <malloc.h>
+#include <linux/errno.h> +#include <linux/types.h> +#include <u-boot/crc.h>
+#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR BIT(1)
+static int fwu_get_dev_ops(struct udevice **dev,
const struct fwu_mdata_ops **ops)
+{
int ret;
ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev);
if (ret) {
log_debug("Cannot find fwu device\n");
return ret;
}
if ((*ops = device_get_ops(*dev)) == NULL) {
log_debug("Cannot get fwu device ops\n");
return -ENOSYS;
}
return 0;
+}
+/**
- fwu_verify_mdata() - Verify the FWU metadata
- @mdata: FWU metadata structure
- @pri_part: FWU metadata partition is primary or secondary
- Verify the FWU metadata by computing the CRC32 for the metadata
- structure and comparing it against the CRC32 value stored as part
- of the structure.
- Return: 0 if OK, -ve on error
- */
+int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part) +{
u32 calc_crc32;
void *buf;
buf = &mdata->version;
calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
if (calc_crc32 != mdata->crc32) {
log_err("crc32 check failed for %s FWU metadata partition\n",
pri_part ? "primary" : "secondary");
return -1;
}
return 0;
+}
+/**
- fwu_get_active_index() - Get active_index from the FWU metadata
- @active_idx: active_index value to be read
- Read the active_index field from the FWU metadata and place it in
- the variable pointed to be the function argument.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
*active_idx = mdata->active_index;
if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value read is incorrect\n");
ret = -EINVAL;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_update_active_index() - Update active_index from the FWU metadata
- @active_idx: active_index value to be updated
- Update the active_index field in the FWU metadata
- Return: 0 if OK, -ve on error
- */
+int fwu_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata = NULL;
if (active_idx > CONFIG_FWU_NUM_BANKS - 1) {
log_err("Active index value to be updated is incorrect\n");
return -1;
}
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
mdata->previous_active_index = mdata->active_index;
mdata->active_index = active_idx;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update
- @image_type_id: image guid as passed in the capsule
- @update_bank: Bank to which the update is to be made
- @alt_num: The alt_num for the image
- Based on the guid value passed in the capsule, along with the bank to which the
- image needs to be updated, get the dfu alt number which will be used for the
- capsule update
- Return: 0 if OK, -ve on error
- */
+int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num)
+{
int ret;
const struct fwu_mdata_ops *ops = NULL;
struct udevice *dev = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_image_alt_num) {
log_err("get_image_alt_num() method not defined\n");
return -ENOSYS;
}
return ops->get_image_alt_num(dev, image_type_id,
update_bank, alt_num);
+}
+/**
- fwu_mdata_check() - Check if the FWU metadata is valid
- Validate both copies of the FWU metadata. If one of the copies
- has gone bad, restore it from the other bad copy.
- Return: 0 if OK, -ve on error
- */
+int fwu_mdata_check(void) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->mdata_check) {
log_err("mdata_check() method not defined\n");
return -ENOSYS;
}
return ops->mdata_check(dev);
+}
+/**
- fwu_revert_boot_index() - Revert the active index in the FWU metadata
- Revert the active_index value in the FWU metadata, by swapping the values
- of active_index and previous_active_index in both copies of the
- FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_revert_boot_index(void) +{
int ret;
void *buf;
u32 cur_active_index;
struct fwu_mdata *mdata = NULL;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
/*
* Swap the active index and previous_active_index fields
* in the FWU metadata
*/
cur_active_index = mdata->active_index;
mdata->active_index = mdata->previous_active_index;
mdata->previous_active_index = cur_active_index;
/*
* 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));
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
ret = fwu_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+/**
- fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
set or cleared
- @bank: Bank of which the image's Accept bit is to be set or cleared
- @action: Action which specifies whether image's Accept bit is to be set or
cleared
- Set/Clear the accepted bit for the image specified by the img_guid parameter.
- This indicates acceptance or rejection of image for subsequent boots by some
- governing component like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+static int fwu_set_clear_image_accept(efi_guid_t *img_type_id,
u32 bank, u8 action)
+{
void *buf;
int ret, i;
u32 nimages;
struct fwu_mdata *mdata = NULL;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
ret = fwu_get_mdata(&mdata);
if (ret < 0) {
log_err("Unable to get valid FWU metadata\n");
goto out;
}
nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
img_entry = &mdata->img_entry[0];
for (i = 0; i < nimages; i++) {
if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
img_bank_info = &img_entry[i].img_bank_info[bank];
if (action == IMAGE_ACCEPT_SET)
img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
else
img_bank_info->accepted = 0;
buf = &mdata->version;
mdata->crc32 = crc32(0, buf, sizeof(*mdata) -
sizeof(u32));
ret = fwu_update_mdata(mdata);
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+/**
- fwu_accept_image() - Set the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be set
- Set the accepted bit for the image specified by the img_guid parameter. This
- indicates acceptance of image for subsequent boots by some governing component
- like OS(or firmware).
- Return: 0 if OK, -ve on error
- */
+int fwu_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_SET);
+}
+/**
- fwu_clear_accept_image() - Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be cleared
- Clear the accepted bit for the image type specified by the img_type_id parameter.
- This function is called after the image has been updated. The accepted bit is
- cleared to be set subsequently after passing the image acceptance criteria, by
- either the OS(or firmware)
- Return: 0 if OK, -ve on error
- */
+int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_CLEAR);
+}
+/**
- fwu_get_mdata() - Get a FWU metadata copy
- @mdata: Copy of the FWU metadata
- Get a valid copy of the FWU metadata.
- Return: 0 if OK, -ve on error
- */
+int fwu_get_mdata(struct fwu_mdata **mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->get_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
return ops->get_mdata(dev, mdata);
+}
+/**
- fwu_update_mdata() - Update the FWU metadata
- @mdata: Copy of the FWU metadata
- Update the FWU metadata structure by writing to the
- FWU metadata partitions.
- Return: 0 if OK, -ve on error
- */
+int fwu_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct udevice *dev = NULL;
const struct fwu_mdata_ops *ops = NULL;
ret = fwu_get_dev_ops(&dev, &ops);
if (ret)
return ret;
if (!ops->update_mdata) {
log_err("get_mdata() method not defined\n");
return -ENOSYS;
}
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 0e26e1d138..d0ab1c9235 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -54,6 +54,7 @@ enum uclass_id { UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
UCLASS_FWU_MDATA, /* FWU Metadata Access */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ UCLASS_HASH, /* Hash device */ UCLASS_HWSPINLOCK, /* Hardware semaphores */
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..5a99c579fc --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <blk.h> +#include <efi.h>
+#include <linux/types.h>
+struct fwu_mdata; +struct udevice;
+/**
- @get_image_alt_num: get the alt number to be used for the image
- @mdata_check: check the validity of the FWU metadata partitions
- @get_mdata() - Get a FWU metadata copy
- @update_mdata() - Update the FWU metadata copy
- */
+struct fwu_mdata_ops {
int (*get_image_alt_num)(struct udevice *dev, efi_guid_t image_type_id,
u32 update_bank, int *alt_num);
int (*mdata_check)(struct udevice *dev);
int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata);
int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata);
+};
+#define FWU_MDATA_VERSION 0x1
+#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+int fwu_get_mdata(struct fwu_mdata **mdata); +int fwu_update_mdata(struct fwu_mdata *mdata); +int fwu_get_active_index(u32 *active_idx); +int fwu_update_active_index(u32 active_idx); +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank,
int *alt_num);
+int fwu_mdata_check(void); +int fwu_revert_boot_index(void); +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank);
+#endif /* _FWU_H_ */ diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h new file mode 100644 index 0000000000..701efbba03 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2022, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h>
+/**
- struct fwu_image_bank_info - firmware image information
- @image_uuid: Guid value of the image in this bank
- @accepted: Acceptance status of the image
- @reserved: Reserved
- The structure contains image specific fields which are
- used to identify the image and to specify the image's
- acceptance status
- */
+struct fwu_image_bank_info {
efi_guid_t image_uuid;
uint32_t accepted;
uint32_t reserved;
+} __attribute__((__packed__));
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+} __attribute__((__packed__));
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for performing
- multi bank updates on the platform. This contains info on the bank being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
uint32_t crc32;
uint32_t version;
uint32_t active_index;
uint32_t previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+} __attribute__((__packed__));
+#endif /* _FWU_MDATA_H_ */
2.17.1
One more thing. run kernel-doc to validate your description. [u-boot](eeee)$ ./scripts/kernel-doc -v -man drivers/fwu-mdata/fwu-mdata-uclass.c 1>/dev/null drivers/fwu-mdata/fwu-mdata-uclass.c:41: info: Scanning doc for fwu_verify_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:70: info: Scanning doc for fwu_get_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:107: info: Scanning doc for fwu_update_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:164: info: Scanning doc for fwu_get_image_alt_num drivers/fwu-mdata/fwu-mdata-uclass.c:197: info: Scanning doc for fwu_mdata_check drivers/fwu-mdata/fwu-mdata-uclass.c:202: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:224: info: Scanning doc for fwu_revert_boot_index drivers/fwu-mdata/fwu-mdata-uclass.c:230: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:279: info: Scanning doc for fwu_set_clear_image_accept drivers/fwu-mdata/fwu-mdata-uclass.c:338: info: Scanning doc for fwu_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:357: info: Scanning doc for fwu_clear_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:377: info: Scanning doc for fwu_get_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:404: info: Scanning doc for fwu_update_mdata 2 warnings
when I run buildman over this series it is visible that it is not bisectable at all. CONFIG_FWU_NUM_BANKS is defined in this patch but the symbol is added much later. Please make sure every single patch is bisectable.
But how is this driver getting built in the first place -- the driver is not enabling the config symbol which would result in the code getting built. The idea is to add support for the driver and the feature, and enable the functionality in the final patch. I have added each patch separately and built for the qemu arm64 platform without any issues.
first of all I wasn't able to apply all patches because this series is not there. https://patchwork.ozlabs.org/project/uboot/list/?series=281549 (better would be to use links to lore which are much easier to download)
You can download the mkeficapsule series from linaro's patchwork[1].
you depend on 3 series. Much easier is to create a branch and push it somewhere.
That's why 2 patches weren't applied.
And I just enabled configs which land in the tree for zynqmp virt and rebase this patch to be the first one. That's why all the time all existing Kconfigs were enabled when buildman build them.
Okay my understanding of a patch being bisectable was if the build does not break after applying a patch. Please note that on top of my series, you will need to define CONFIG_FWU_NUM_BANKS and CONFIG_FWU_NUM_IMAGES_PER_BANK. I did not define that on purpose since each platform would have it's own specific values.
Even if this is true you can't use in any patch a macro/value which is not defined and it is not clear what it is. I apply patch 1 and review patch 1 and not looking at patch 8 to get what that values are for.
My point was that I have not defined these values at all. These will have to be defined on a per platform level. But if you insist, I will define default values, but in my opinion it is better to get a build failure and then set correct values, rather than the build going through with some values which are incorrect for the platform.
If you apply the patches as they are, they should not result in any build failures.
-sughosh
Define them as reasonable default for common case or your usecase. Platform can set them up when they adopt this approach and they are not happy with your defaults.
Thanks, Michal

On 2/8/22 13:07, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:29, Michal Simek michal.simek@xilinx.com wrote:
On 2/8/22 12:54, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:15, Michal Simek michal.simek@xilinx.com wrote:
On 2/8/22 12:38, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:01, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal: > > 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. > > A device tree node fwu-mdata has been added, which is used for > pointing to the storage device which contains the FWU metadata. The > fwu-mdata node is u-boot specific, and can be added the platform's > u-boot dtsi file. > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > --- > > Changes since V3: > * Move the FWU metadata access to driver model > * Get the storage device containing the metadata from a device tree > property instead of a platform helper function > > arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + > .../firmware/fwu-mdata.txt | 18 + > drivers/Kconfig | 2 + > drivers/Makefile | 1 + > drivers/fwu-mdata/Kconfig | 7 + > drivers/fwu-mdata/Makefile | 6 + > drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ > include/dm/uclass-id.h | 1 + > include/fwu.h | 51 ++ > include/fwu_mdata.h | 67 +++ > 10 files changed, 594 insertions(+) > create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt > create mode 100644 drivers/fwu-mdata/Kconfig > create mode 100644 drivers/fwu-mdata/Makefile > create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c > create mode 100644 include/fwu.h > create mode 100644 include/fwu_mdata.h > > diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi > index 06ef3a4095..3bec6107f7 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"; > + fwu-mdata-store = <&sdmmc1>; > + }; > +}; > diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt > new file mode 100644 > index 0000000000..c766b595ef > --- /dev/null > +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt > @@ -0,0 +1,18 @@ > +FWU Metadata Access Devicetree Binding > + > +The FWU Multi Bank Update feature uses a metadata structure, stored on > +a separate partition for keeping information on the set of updatable > +images. The device tree node provides information on the storage > +device that contains the FWU metadata. > + > +Required properties : > + > +- compatible : "u-boot,fwu-mdata"; > +- fwu-mdata-store : should point to the storage device which contains > + the FWU metadata partition. > + > +Example : > + fwu-mdata { > + compatible = "u-boot,fwu-mdata"; > + fwu-mdata-store = <&sdmmc1>; > + }; > diff --git a/drivers/Kconfig b/drivers/Kconfig > index b26ca8cf70..adc6079ecf 100644 > --- a/drivers/Kconfig > +++ b/drivers/Kconfig > @@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig" > > source "drivers/fpga/Kconfig" > > +source "drivers/fwu-mdata/Kconfig" > + > source "drivers/gpio/Kconfig" > > source "drivers/hwspinlock/Kconfig" > diff --git a/drivers/Makefile b/drivers/Makefile > index 4e7cf28440..56f0f04874 100644 > --- a/drivers/Makefile > +++ b/drivers/Makefile > @@ -81,6 +81,7 @@ obj-y += cache/ > obj-$(CONFIG_CPU) += cpu/ > obj-y += crypto/ > obj-$(CONFIG_FASTBOOT) += fastboot/ > +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/ > obj-y += misc/ > obj-$(CONFIG_MMC) += mmc/ > obj-$(CONFIG_NVME) += nvme/ > diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig > new file mode 100644 > index 0000000000..d6a21c8e19 > --- /dev/null > +++ b/drivers/fwu-mdata/Kconfig > @@ -0,0 +1,7 @@ > +config DM_FWU_MDATA > + bool "Driver support for accessing FWU Metadata" > + depends on DM > + help > + Enable support for accessing FWU Metadata partitions. The > + FWU Metadata partitions reside on the same storage device > + which contains the other FWU updatable firmware images. > diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile > new file mode 100644 > index 0000000000..7fec7171f4 > --- /dev/null > +++ b/drivers/fwu-mdata/Makefile > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: GPL-2.0+ > +# > +# Copyright (c) 2022, Linaro Limited > +# > + > +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o > diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c > new file mode 100644 > index 0000000000..64b3051ecf > --- /dev/null > +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c > @@ -0,0 +1,434 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (c) 2022, Linaro Limited > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <efi_loader.h> > +#include <fwu.h> > +#include <fwu_mdata.h> > +#include <log.h> > +#include <malloc.h> > + > +#include <linux/errno.h> > +#include <linux/types.h> > +#include <u-boot/crc.h> > + > +#define IMAGE_ACCEPT_SET BIT(0) > +#define IMAGE_ACCEPT_CLEAR BIT(1) > + > +static int fwu_get_dev_ops(struct udevice **dev, > + const struct fwu_mdata_ops **ops) > +{ > + int ret; > + > + ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev); > + if (ret) { > + log_debug("Cannot find fwu device\n"); > + return ret; > + } > + > + if ((*ops = device_get_ops(*dev)) == NULL) { > + log_debug("Cannot get fwu device ops\n"); > + return -ENOSYS; > + } > + > + return 0; > +} > + > +/** > + * fwu_verify_mdata() - Verify the FWU metadata > + * @mdata: FWU metadata structure > + * @pri_part: FWU metadata partition is primary or secondary > + * > + * Verify the FWU metadata by computing the CRC32 for the metadata > + * structure and comparing it against the CRC32 value stored as part > + * of the structure. > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part) > +{ > + u32 calc_crc32; > + void *buf; > + > + buf = &mdata->version; > + calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); > + > + if (calc_crc32 != mdata->crc32) { > + log_err("crc32 check failed for %s FWU metadata partition\n", > + pri_part ? "primary" : "secondary"); > + return -1; > + } > + > + return 0; > +} > + > +/** > + * fwu_get_active_index() - Get active_index from the FWU metadata > + * @active_idx: active_index value to be read > + * > + * Read the active_index field from the FWU metadata and place it in > + * the variable pointed to be the function argument. > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_get_active_index(u32 *active_idx) > +{ > + int ret; > + struct fwu_mdata *mdata = NULL; > + > + ret = fwu_get_mdata(&mdata); > + if (ret < 0) { > + log_err("Unable to get valid FWU metadata\n"); > + goto out; > + } > + > + /* > + * Found the FWU metadata partition, now read the active_index > + * value > + */ > + *active_idx = mdata->active_index; > + if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) { > + log_err("Active index value read is incorrect\n"); > + ret = -EINVAL; > + } > + > +out: > + free(mdata); > + > + return ret; > +} > + > +/** > + * fwu_update_active_index() - Update active_index from the FWU metadata > + * @active_idx: active_index value to be updated > + * > + * Update the active_index field in the FWU metadata > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_update_active_index(u32 active_idx) > +{ > + int ret; > + void *buf; > + struct fwu_mdata *mdata = NULL; > + > + if (active_idx > CONFIG_FWU_NUM_BANKS - 1) { > + log_err("Active index value to be updated is incorrect\n"); > + return -1; > + } > + > + ret = fwu_get_mdata(&mdata); > + if (ret < 0) { > + log_err("Unable to get valid FWU metadata\n"); > + goto out; > + } > + > + /* > + * Update the active index and previous_active_index fields > + * in the FWU metadata > + */ > + mdata->previous_active_index = mdata->active_index; > + mdata->active_index = active_idx; > + > + /* > + * 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)); > + > + /* > + * Now write this updated FWU metadata to both the > + * FWU metadata partitions > + */ > + ret = fwu_update_mdata(mdata); > + if (ret < 0) { > + log_err("Failed to update FWU metadata partitions\n"); > + ret = -EIO; > + } > + > +out: > + free(mdata); > + > + return ret; > +} > + > +/** > + * fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update > + * @image_type_id: image guid as passed in the capsule > + * @update_bank: Bank to which the update is to be made > + * @alt_num: The alt_num for the image > + * > + * Based on the guid value passed in the capsule, along with the bank to which the > + * image needs to be updated, get the dfu alt number which will be used for the > + * capsule update > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, > + int *alt_num) > +{ > + int ret; > + const struct fwu_mdata_ops *ops = NULL; > + struct udevice *dev = NULL; > + > + ret = fwu_get_dev_ops(&dev, &ops); > + if (ret) > + return ret; > + > + if (!ops->get_image_alt_num) { > + log_err("get_image_alt_num() method not defined\n"); > + return -ENOSYS; > + } > + > + return ops->get_image_alt_num(dev, image_type_id, > + update_bank, alt_num); > +} > + > +/** > + * fwu_mdata_check() - Check if the FWU metadata is valid > + * > + * Validate both copies of the FWU metadata. If one of the copies > + * has gone bad, restore it from the other bad copy. > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_mdata_check(void) > +{ > + int ret; > + struct udevice *dev = NULL; > + const struct fwu_mdata_ops *ops = NULL; > + > + ret = fwu_get_dev_ops(&dev, &ops); > + if (ret) > + return ret; > + > + if (!ops->mdata_check) { > + log_err("mdata_check() method not defined\n"); > + return -ENOSYS; > + } > + > + return ops->mdata_check(dev); > +} > + > +/** > + * fwu_revert_boot_index() - Revert the active index in the FWU metadata > + * > + * Revert the active_index value in the FWU metadata, by swapping the values > + * of active_index and previous_active_index in both copies of the > + * FWU metadata. > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_revert_boot_index(void) > +{ > + int ret; > + void *buf; > + u32 cur_active_index; > + struct fwu_mdata *mdata = NULL; > + > + ret = fwu_get_mdata(&mdata); > + if (ret < 0) { > + log_err("Unable to get valid FWU metadata\n"); > + goto out; > + } > + > + /* > + * Swap the active index and previous_active_index fields > + * in the FWU metadata > + */ > + cur_active_index = mdata->active_index; > + mdata->active_index = mdata->previous_active_index; > + mdata->previous_active_index = cur_active_index; > + > + /* > + * 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)); > + > + /* > + * Now write this updated FWU metadata to both the > + * FWU metadata partitions > + */ > + ret = fwu_update_mdata(mdata); > + if (ret < 0) { > + log_err("Failed to update FWU metadata partitions\n"); > + ret = -EIO; > + } > + > +out: > + free(mdata); > + > + return ret; > +} > + > +/** > + * fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image > + * @img_type_id: Guid of the image type for which the accepted bit is to be > + * set or cleared > + * @bank: Bank of which the image's Accept bit is to be set or cleared > + * @action: Action which specifies whether image's Accept bit is to be set or > + * cleared > + * > + * Set/Clear the accepted bit for the image specified by the img_guid parameter. > + * This indicates acceptance or rejection of image for subsequent boots by some > + * governing component like OS(or firmware). > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +static int fwu_set_clear_image_accept(efi_guid_t *img_type_id, > + u32 bank, u8 action) > +{ > + void *buf; > + int ret, i; > + u32 nimages; > + struct fwu_mdata *mdata = NULL; > + struct fwu_image_entry *img_entry; > + struct fwu_image_bank_info *img_bank_info; > + > + ret = fwu_get_mdata(&mdata); > + if (ret < 0) { > + log_err("Unable to get valid FWU metadata\n"); > + goto out; > + } > + > + nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK; > + img_entry = &mdata->img_entry[0]; > + for (i = 0; i < nimages; i++) { > + if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) { > + img_bank_info = &img_entry[i].img_bank_info[bank]; > + if (action == IMAGE_ACCEPT_SET) > + img_bank_info->accepted |= FWU_IMAGE_ACCEPTED; > + else > + img_bank_info->accepted = 0; > + > + buf = &mdata->version; > + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - > + sizeof(u32)); > + > + ret = fwu_update_mdata(mdata); > + goto out; > + } > + } > + > + /* Image not found */ > + ret = -EINVAL; > + > +out: > + free(mdata); > + > + return ret; > +} > + > +/** > + * fwu_accept_image() - Set the Acceptance bit for the image > + * @img_type_id: Guid of the image type for which the accepted bit is to be > + * cleared > + * @bank: Bank of which the image's Accept bit is to be set > + * > + * Set the accepted bit for the image specified by the img_guid parameter. This > + * indicates acceptance of image for subsequent boots by some governing component > + * like OS(or firmware). > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank) > +{ > + return fwu_set_clear_image_accept(img_type_id, bank, > + IMAGE_ACCEPT_SET); > +} > + > +/** > + * fwu_clear_accept_image() - Clear the Acceptance bit for the image > + * @img_type_id: Guid of the image type for which the accepted bit is to be > + * cleared > + * @bank: Bank of which the image's Accept bit is to be cleared > + * > + * Clear the accepted bit for the image type specified by the img_type_id parameter. > + * This function is called after the image has been updated. The accepted bit is > + * cleared to be set subsequently after passing the image acceptance criteria, by > + * either the OS(or firmware) > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) > +{ > + return fwu_set_clear_image_accept(img_type_id, bank, > + IMAGE_ACCEPT_CLEAR); > +} > + > +/** > + * fwu_get_mdata() - Get a FWU metadata copy > + * @mdata: Copy of the FWU metadata > + * > + * Get a valid copy of the FWU metadata. > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_get_mdata(struct fwu_mdata **mdata) > +{ > + int ret; > + struct udevice *dev = NULL; > + const struct fwu_mdata_ops *ops = NULL; > + > + ret = fwu_get_dev_ops(&dev, &ops); > + if (ret) > + return ret; > + > + if (!ops->get_mdata) { > + log_err("get_mdata() method not defined\n"); > + return -ENOSYS; > + } > + > + return ops->get_mdata(dev, mdata); > +} > + > +/** > + * fwu_update_mdata() - Update the FWU metadata > + * @mdata: Copy of the FWU metadata > + * > + * Update the FWU metadata structure by writing to the > + * FWU metadata partitions. > + * > + * Return: 0 if OK, -ve on error > + * > + */ > +int fwu_update_mdata(struct fwu_mdata *mdata) > +{ > + int ret; > + struct udevice *dev = NULL; > + const struct fwu_mdata_ops *ops = NULL; > + > + ret = fwu_get_dev_ops(&dev, &ops); > + if (ret) > + return ret; > + > + if (!ops->update_mdata) { > + log_err("get_mdata() method not defined\n"); > + return -ENOSYS; > + } > + > + 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 0e26e1d138..d0ab1c9235 100644 > --- a/include/dm/uclass-id.h > +++ b/include/dm/uclass-id.h > @@ -54,6 +54,7 @@ enum uclass_id { > UCLASS_ETH_PHY, /* Ethernet PHY device */ > UCLASS_FIRMWARE, /* Firmware */ > UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */ > + UCLASS_FWU_MDATA, /* FWU Metadata Access */ > UCLASS_GPIO, /* Bank of general-purpose I/O pins */ > UCLASS_HASH, /* Hash device */ > UCLASS_HWSPINLOCK, /* Hardware semaphores */ > diff --git a/include/fwu.h b/include/fwu.h > new file mode 100644 > index 0000000000..5a99c579fc > --- /dev/null > +++ b/include/fwu.h > @@ -0,0 +1,51 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Copyright (c) 2022, Linaro Limited > + */ > + > +#if !defined _FWU_H_ > +#define _FWU_H_ > + > +#include <blk.h> > +#include <efi.h> > + > +#include <linux/types.h> > + > +struct fwu_mdata; > +struct udevice; > + > +/** > + * @get_image_alt_num: get the alt number to be used for the image > + * @mdata_check: check the validity of the FWU metadata partitions > + * @get_mdata() - Get a FWU metadata copy > + * @update_mdata() - Update the FWU metadata copy > + */ > +struct fwu_mdata_ops { > + int (*get_image_alt_num)(struct udevice *dev, efi_guid_t image_type_id, > + u32 update_bank, int *alt_num); > + > + int (*mdata_check)(struct udevice *dev); > + > + int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata); > + > + int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata); > +}; > + > +#define FWU_MDATA_VERSION 0x1 > + > +#define FWU_MDATA_GUID \ > + EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ > + 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23) > + > +int fwu_get_mdata(struct fwu_mdata **mdata); > +int fwu_update_mdata(struct fwu_mdata *mdata); > +int fwu_get_active_index(u32 *active_idx); > +int fwu_update_active_index(u32 active_idx); > +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, > + int *alt_num); > +int fwu_mdata_check(void); > +int fwu_revert_boot_index(void); > +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); > +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank); > + > +#endif /* _FWU_H_ */ > diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h > new file mode 100644 > index 0000000000..701efbba03 > --- /dev/null > +++ b/include/fwu_mdata.h > @@ -0,0 +1,67 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Copyright (c) 2022, Linaro Limited > + */ > + > +#if !defined _FWU_MDATA_H_ > +#define _FWU_MDATA_H_ > + > +#include <efi.h> > + > +/** > + * struct fwu_image_bank_info - firmware image information > + * @image_uuid: Guid value of the image in this bank > + * @accepted: Acceptance status of the image > + * @reserved: Reserved > + * > + * The structure contains image specific fields which are > + * used to identify the image and to specify the image's > + * acceptance status > + */ > +struct fwu_image_bank_info { > + efi_guid_t image_uuid; > + uint32_t accepted; > + uint32_t reserved; > +} __attribute__((__packed__)); > + > +/** > + * struct fwu_image_entry - information for a particular type of image > + * @image_type_uuid: Guid value for identifying the image type > + * @location_uuid: Guid of the storage volume where the image is located > + * @img_bank_info: Array containing properties of images > + * > + * This structure contains information on various types of updatable > + * firmware images. Each image type then contains an array of image > + * information per bank. > + */ > +struct fwu_image_entry { > + efi_guid_t image_type_uuid; > + efi_guid_t location_uuid; > + struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS]; > +} __attribute__((__packed__)); > + > +/** > + * struct fwu_mdata - FWU metadata structure for multi-bank updates > + * @crc32: crc32 value for the FWU metadata > + * @version: FWU metadata version > + * @active_index: Index of the bank currently used for booting images > + * @previous_active_inde: Index of the bank used before the current bank > + * being used for booting > + * @img_entry: Array of information on various firmware images that can > + * be updated > + * > + * This structure is used to store all the needed information for performing > + * multi bank updates on the platform. This contains info on the bank being > + * used to boot along with the information needed for identification of > + * individual images > + */ > +struct fwu_mdata { > + uint32_t crc32; > + uint32_t version; > + uint32_t active_index; > + uint32_t previous_active_index; > + > + struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK]; > +} __attribute__((__packed__)); > + > +#endif /* _FWU_MDATA_H_ */ > -- > 2.17.1 >
One more thing. run kernel-doc to validate your description. [u-boot](eeee)$ ./scripts/kernel-doc -v -man drivers/fwu-mdata/fwu-mdata-uclass.c 1>/dev/null drivers/fwu-mdata/fwu-mdata-uclass.c:41: info: Scanning doc for fwu_verify_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:70: info: Scanning doc for fwu_get_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:107: info: Scanning doc for fwu_update_active_index drivers/fwu-mdata/fwu-mdata-uclass.c:164: info: Scanning doc for fwu_get_image_alt_num drivers/fwu-mdata/fwu-mdata-uclass.c:197: info: Scanning doc for fwu_mdata_check drivers/fwu-mdata/fwu-mdata-uclass.c:202: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:224: info: Scanning doc for fwu_revert_boot_index drivers/fwu-mdata/fwu-mdata-uclass.c:230: warning: contents before sections drivers/fwu-mdata/fwu-mdata-uclass.c:279: info: Scanning doc for fwu_set_clear_image_accept drivers/fwu-mdata/fwu-mdata-uclass.c:338: info: Scanning doc for fwu_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:357: info: Scanning doc for fwu_clear_accept_image drivers/fwu-mdata/fwu-mdata-uclass.c:377: info: Scanning doc for fwu_get_mdata drivers/fwu-mdata/fwu-mdata-uclass.c:404: info: Scanning doc for fwu_update_mdata 2 warnings
when I run buildman over this series it is visible that it is not bisectable at all. CONFIG_FWU_NUM_BANKS is defined in this patch but the symbol is added much later. Please make sure every single patch is bisectable.
But how is this driver getting built in the first place -- the driver is not enabling the config symbol which would result in the code getting built. The idea is to add support for the driver and the feature, and enable the functionality in the final patch. I have added each patch separately and built for the qemu arm64 platform without any issues.
first of all I wasn't able to apply all patches because this series is not there. https://patchwork.ozlabs.org/project/uboot/list/?series=281549 (better would be to use links to lore which are much easier to download)
You can download the mkeficapsule series from linaro's patchwork[1].
you depend on 3 series. Much easier is to create a branch and push it somewhere.
That's why 2 patches weren't applied.
And I just enabled configs which land in the tree for zynqmp virt and rebase this patch to be the first one. That's why all the time all existing Kconfigs were enabled when buildman build them.
Okay my understanding of a patch being bisectable was if the build does not break after applying a patch. Please note that on top of my series, you will need to define CONFIG_FWU_NUM_BANKS and CONFIG_FWU_NUM_IMAGES_PER_BANK. I did not define that on purpose since each platform would have it's own specific values.
Even if this is true you can't use in any patch a macro/value which is not defined and it is not clear what it is. I apply patch 1 and review patch 1 and not looking at patch 8 to get what that values are for.
My point was that I have not defined these values at all. These will have to be defined on a per platform level. But if you insist, I will define default values, but in my opinion it is better to get a build failure and then set correct values, rather than the build going through with some values which are incorrect for the platform.
If you apply the patches as they are, they should not result in any build failures.
This code should be enabled for at least one platform. It means I expect you define that values at least for one platform which you use for testing. I don't agree that it is better to get build error. Feature will be disabled by default for other platforms and when developer enables it should check all these settings before enablement happens.
Thanks, Michal

On Tue, 8 Feb 2022 at 17:44, Michal Simek michal.simek@xilinx.com wrote:
On 2/8/22 13:07, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:29, Michal Simek michal.simek@xilinx.com wrote:
On 2/8/22 12:54, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:15, Michal Simek michal.simek@xilinx.com wrote:
On 2/8/22 12:38, Sughosh Ganu wrote:
On Tue, 8 Feb 2022 at 17:01, Michal Simek monstr@monstr.eu wrote: > > po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal: >> >> 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. >> >> A device tree node fwu-mdata has been added, which is used for >> pointing to the storage device which contains the FWU metadata. The >> fwu-mdata node is u-boot specific, and can be added the platform's >> u-boot dtsi file. >> >> Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org >> --- >> >> Changes since V3: >> * Move the FWU metadata access to driver model >> * Get the storage device containing the metadata from a device tree >> property instead of a platform helper function >> >> arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + >> .../firmware/fwu-mdata.txt | 18 + >> drivers/Kconfig | 2 + >> drivers/Makefile | 1 + >> drivers/fwu-mdata/Kconfig | 7 + >> drivers/fwu-mdata/Makefile | 6 + >> drivers/fwu-mdata/fwu-mdata-uclass.c | 434 ++++++++++++++++++ >> include/dm/uclass-id.h | 1 + >> include/fwu.h | 51 ++ >> include/fwu_mdata.h | 67 +++ >> 10 files changed, 594 insertions(+) >> create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata.txt >> create mode 100644 drivers/fwu-mdata/Kconfig >> create mode 100644 drivers/fwu-mdata/Makefile >> create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c >> create mode 100644 include/fwu.h >> create mode 100644 include/fwu_mdata.h >> >> diff --git a/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi b/arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi >> index 06ef3a4095..3bec6107f7 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"; >> + fwu-mdata-store = <&sdmmc1>; >> + }; >> +}; >> diff --git a/doc/device-tree-bindings/firmware/fwu-mdata.txt b/doc/device-tree-bindings/firmware/fwu-mdata.txt >> new file mode 100644 >> index 0000000000..c766b595ef >> --- /dev/null >> +++ b/doc/device-tree-bindings/firmware/fwu-mdata.txt >> @@ -0,0 +1,18 @@ >> +FWU Metadata Access Devicetree Binding >> + >> +The FWU Multi Bank Update feature uses a metadata structure, stored on >> +a separate partition for keeping information on the set of updatable >> +images. The device tree node provides information on the storage >> +device that contains the FWU metadata. >> + >> +Required properties : >> + >> +- compatible : "u-boot,fwu-mdata"; >> +- fwu-mdata-store : should point to the storage device which contains >> + the FWU metadata partition. >> + >> +Example : >> + fwu-mdata { >> + compatible = "u-boot,fwu-mdata"; >> + fwu-mdata-store = <&sdmmc1>; >> + }; >> diff --git a/drivers/Kconfig b/drivers/Kconfig >> index b26ca8cf70..adc6079ecf 100644 >> --- a/drivers/Kconfig >> +++ b/drivers/Kconfig >> @@ -42,6 +42,8 @@ source "drivers/firmware/Kconfig" >> >> source "drivers/fpga/Kconfig" >> >> +source "drivers/fwu-mdata/Kconfig" >> + >> source "drivers/gpio/Kconfig" >> >> source "drivers/hwspinlock/Kconfig" >> diff --git a/drivers/Makefile b/drivers/Makefile >> index 4e7cf28440..56f0f04874 100644 >> --- a/drivers/Makefile >> +++ b/drivers/Makefile >> @@ -81,6 +81,7 @@ obj-y += cache/ >> obj-$(CONFIG_CPU) += cpu/ >> obj-y += crypto/ >> obj-$(CONFIG_FASTBOOT) += fastboot/ >> +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata/ >> obj-y += misc/ >> obj-$(CONFIG_MMC) += mmc/ >> obj-$(CONFIG_NVME) += nvme/ >> diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig >> new file mode 100644 >> index 0000000000..d6a21c8e19 >> --- /dev/null >> +++ b/drivers/fwu-mdata/Kconfig >> @@ -0,0 +1,7 @@ >> +config DM_FWU_MDATA >> + bool "Driver support for accessing FWU Metadata" >> + depends on DM >> + help >> + Enable support for accessing FWU Metadata partitions. The >> + FWU Metadata partitions reside on the same storage device >> + which contains the other FWU updatable firmware images. >> diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile >> new file mode 100644 >> index 0000000000..7fec7171f4 >> --- /dev/null >> +++ b/drivers/fwu-mdata/Makefile >> @@ -0,0 +1,6 @@ >> +# SPDX-License-Identifier: GPL-2.0+ >> +# >> +# Copyright (c) 2022, Linaro Limited >> +# >> + >> +obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o >> diff --git a/drivers/fwu-mdata/fwu-mdata-uclass.c b/drivers/fwu-mdata/fwu-mdata-uclass.c >> new file mode 100644 >> index 0000000000..64b3051ecf >> --- /dev/null >> +++ b/drivers/fwu-mdata/fwu-mdata-uclass.c >> @@ -0,0 +1,434 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Copyright (c) 2022, Linaro Limited >> + */ >> + >> +#include <common.h> >> +#include <dm.h> >> +#include <efi_loader.h> >> +#include <fwu.h> >> +#include <fwu_mdata.h> >> +#include <log.h> >> +#include <malloc.h> >> + >> +#include <linux/errno.h> >> +#include <linux/types.h> >> +#include <u-boot/crc.h> >> + >> +#define IMAGE_ACCEPT_SET BIT(0) >> +#define IMAGE_ACCEPT_CLEAR BIT(1) >> + >> +static int fwu_get_dev_ops(struct udevice **dev, >> + const struct fwu_mdata_ops **ops) >> +{ >> + int ret; >> + >> + ret = uclass_get_device(UCLASS_FWU_MDATA, 0, dev); >> + if (ret) { >> + log_debug("Cannot find fwu device\n"); >> + return ret; >> + } >> + >> + if ((*ops = device_get_ops(*dev)) == NULL) { >> + log_debug("Cannot get fwu device ops\n"); >> + return -ENOSYS; >> + } >> + >> + return 0; >> +} >> + >> +/** >> + * fwu_verify_mdata() - Verify the FWU metadata >> + * @mdata: FWU metadata structure >> + * @pri_part: FWU metadata partition is primary or secondary >> + * >> + * Verify the FWU metadata by computing the CRC32 for the metadata >> + * structure and comparing it against the CRC32 value stored as part >> + * of the structure. >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part) >> +{ >> + u32 calc_crc32; >> + void *buf; >> + >> + buf = &mdata->version; >> + calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); >> + >> + if (calc_crc32 != mdata->crc32) { >> + log_err("crc32 check failed for %s FWU metadata partition\n", >> + pri_part ? "primary" : "secondary"); >> + return -1; >> + } >> + >> + return 0; >> +} >> + >> +/** >> + * fwu_get_active_index() - Get active_index from the FWU metadata >> + * @active_idx: active_index value to be read >> + * >> + * Read the active_index field from the FWU metadata and place it in >> + * the variable pointed to be the function argument. >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_get_active_index(u32 *active_idx) >> +{ >> + int ret; >> + struct fwu_mdata *mdata = NULL; >> + >> + ret = fwu_get_mdata(&mdata); >> + if (ret < 0) { >> + log_err("Unable to get valid FWU metadata\n"); >> + goto out; >> + } >> + >> + /* >> + * Found the FWU metadata partition, now read the active_index >> + * value >> + */ >> + *active_idx = mdata->active_index; >> + if (*active_idx > CONFIG_FWU_NUM_BANKS - 1) { >> + log_err("Active index value read is incorrect\n"); >> + ret = -EINVAL; >> + } >> + >> +out: >> + free(mdata); >> + >> + return ret; >> +} >> + >> +/** >> + * fwu_update_active_index() - Update active_index from the FWU metadata >> + * @active_idx: active_index value to be updated >> + * >> + * Update the active_index field in the FWU metadata >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_update_active_index(u32 active_idx) >> +{ >> + int ret; >> + void *buf; >> + struct fwu_mdata *mdata = NULL; >> + >> + if (active_idx > CONFIG_FWU_NUM_BANKS - 1) { >> + log_err("Active index value to be updated is incorrect\n"); >> + return -1; >> + } >> + >> + ret = fwu_get_mdata(&mdata); >> + if (ret < 0) { >> + log_err("Unable to get valid FWU metadata\n"); >> + goto out; >> + } >> + >> + /* >> + * Update the active index and previous_active_index fields >> + * in the FWU metadata >> + */ >> + mdata->previous_active_index = mdata->active_index; >> + mdata->active_index = active_idx; >> + >> + /* >> + * 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)); >> + >> + /* >> + * Now write this updated FWU metadata to both the >> + * FWU metadata partitions >> + */ >> + ret = fwu_update_mdata(mdata); >> + if (ret < 0) { >> + log_err("Failed to update FWU metadata partitions\n"); >> + ret = -EIO; >> + } >> + >> +out: >> + free(mdata); >> + >> + return ret; >> +} >> + >> +/** >> + * fwu_get_image_alt_num() - Get the dfu alt number to be used for capsule update >> + * @image_type_id: image guid as passed in the capsule >> + * @update_bank: Bank to which the update is to be made >> + * @alt_num: The alt_num for the image >> + * >> + * Based on the guid value passed in the capsule, along with the bank to which the >> + * image needs to be updated, get the dfu alt number which will be used for the >> + * capsule update >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, >> + int *alt_num) >> +{ >> + int ret; >> + const struct fwu_mdata_ops *ops = NULL; >> + struct udevice *dev = NULL; >> + >> + ret = fwu_get_dev_ops(&dev, &ops); >> + if (ret) >> + return ret; >> + >> + if (!ops->get_image_alt_num) { >> + log_err("get_image_alt_num() method not defined\n"); >> + return -ENOSYS; >> + } >> + >> + return ops->get_image_alt_num(dev, image_type_id, >> + update_bank, alt_num); >> +} >> + >> +/** >> + * fwu_mdata_check() - Check if the FWU metadata is valid >> + * >> + * Validate both copies of the FWU metadata. If one of the copies >> + * has gone bad, restore it from the other bad copy. >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_mdata_check(void) >> +{ >> + int ret; >> + struct udevice *dev = NULL; >> + const struct fwu_mdata_ops *ops = NULL; >> + >> + ret = fwu_get_dev_ops(&dev, &ops); >> + if (ret) >> + return ret; >> + >> + if (!ops->mdata_check) { >> + log_err("mdata_check() method not defined\n"); >> + return -ENOSYS; >> + } >> + >> + return ops->mdata_check(dev); >> +} >> + >> +/** >> + * fwu_revert_boot_index() - Revert the active index in the FWU metadata >> + * >> + * Revert the active_index value in the FWU metadata, by swapping the values >> + * of active_index and previous_active_index in both copies of the >> + * FWU metadata. >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_revert_boot_index(void) >> +{ >> + int ret; >> + void *buf; >> + u32 cur_active_index; >> + struct fwu_mdata *mdata = NULL; >> + >> + ret = fwu_get_mdata(&mdata); >> + if (ret < 0) { >> + log_err("Unable to get valid FWU metadata\n"); >> + goto out; >> + } >> + >> + /* >> + * Swap the active index and previous_active_index fields >> + * in the FWU metadata >> + */ >> + cur_active_index = mdata->active_index; >> + mdata->active_index = mdata->previous_active_index; >> + mdata->previous_active_index = cur_active_index; >> + >> + /* >> + * 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)); >> + >> + /* >> + * Now write this updated FWU metadata to both the >> + * FWU metadata partitions >> + */ >> + ret = fwu_update_mdata(mdata); >> + if (ret < 0) { >> + log_err("Failed to update FWU metadata partitions\n"); >> + ret = -EIO; >> + } >> + >> +out: >> + free(mdata); >> + >> + return ret; >> +} >> + >> +/** >> + * fwu_set_clear_image_accept() - Set or Clear the Acceptance bit for the image >> + * @img_type_id: Guid of the image type for which the accepted bit is to be >> + * set or cleared >> + * @bank: Bank of which the image's Accept bit is to be set or cleared >> + * @action: Action which specifies whether image's Accept bit is to be set or >> + * cleared >> + * >> + * Set/Clear the accepted bit for the image specified by the img_guid parameter. >> + * This indicates acceptance or rejection of image for subsequent boots by some >> + * governing component like OS(or firmware). >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +static int fwu_set_clear_image_accept(efi_guid_t *img_type_id, >> + u32 bank, u8 action) >> +{ >> + void *buf; >> + int ret, i; >> + u32 nimages; >> + struct fwu_mdata *mdata = NULL; >> + struct fwu_image_entry *img_entry; >> + struct fwu_image_bank_info *img_bank_info; >> + >> + ret = fwu_get_mdata(&mdata); >> + if (ret < 0) { >> + log_err("Unable to get valid FWU metadata\n"); >> + goto out; >> + } >> + >> + nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK; >> + img_entry = &mdata->img_entry[0]; >> + for (i = 0; i < nimages; i++) { >> + if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) { >> + img_bank_info = &img_entry[i].img_bank_info[bank]; >> + if (action == IMAGE_ACCEPT_SET) >> + img_bank_info->accepted |= FWU_IMAGE_ACCEPTED; >> + else >> + img_bank_info->accepted = 0; >> + >> + buf = &mdata->version; >> + mdata->crc32 = crc32(0, buf, sizeof(*mdata) - >> + sizeof(u32)); >> + >> + ret = fwu_update_mdata(mdata); >> + goto out; >> + } >> + } >> + >> + /* Image not found */ >> + ret = -EINVAL; >> + >> +out: >> + free(mdata); >> + >> + return ret; >> +} >> + >> +/** >> + * fwu_accept_image() - Set the Acceptance bit for the image >> + * @img_type_id: Guid of the image type for which the accepted bit is to be >> + * cleared >> + * @bank: Bank of which the image's Accept bit is to be set >> + * >> + * Set the accepted bit for the image specified by the img_guid parameter. This >> + * indicates acceptance of image for subsequent boots by some governing component >> + * like OS(or firmware). >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank) >> +{ >> + return fwu_set_clear_image_accept(img_type_id, bank, >> + IMAGE_ACCEPT_SET); >> +} >> + >> +/** >> + * fwu_clear_accept_image() - Clear the Acceptance bit for the image >> + * @img_type_id: Guid of the image type for which the accepted bit is to be >> + * cleared >> + * @bank: Bank of which the image's Accept bit is to be cleared >> + * >> + * Clear the accepted bit for the image type specified by the img_type_id parameter. >> + * This function is called after the image has been updated. The accepted bit is >> + * cleared to be set subsequently after passing the image acceptance criteria, by >> + * either the OS(or firmware) >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) >> +{ >> + return fwu_set_clear_image_accept(img_type_id, bank, >> + IMAGE_ACCEPT_CLEAR); >> +} >> + >> +/** >> + * fwu_get_mdata() - Get a FWU metadata copy >> + * @mdata: Copy of the FWU metadata >> + * >> + * Get a valid copy of the FWU metadata. >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_get_mdata(struct fwu_mdata **mdata) >> +{ >> + int ret; >> + struct udevice *dev = NULL; >> + const struct fwu_mdata_ops *ops = NULL; >> + >> + ret = fwu_get_dev_ops(&dev, &ops); >> + if (ret) >> + return ret; >> + >> + if (!ops->get_mdata) { >> + log_err("get_mdata() method not defined\n"); >> + return -ENOSYS; >> + } >> + >> + return ops->get_mdata(dev, mdata); >> +} >> + >> +/** >> + * fwu_update_mdata() - Update the FWU metadata >> + * @mdata: Copy of the FWU metadata >> + * >> + * Update the FWU metadata structure by writing to the >> + * FWU metadata partitions. >> + * >> + * Return: 0 if OK, -ve on error >> + * >> + */ >> +int fwu_update_mdata(struct fwu_mdata *mdata) >> +{ >> + int ret; >> + struct udevice *dev = NULL; >> + const struct fwu_mdata_ops *ops = NULL; >> + >> + ret = fwu_get_dev_ops(&dev, &ops); >> + if (ret) >> + return ret; >> + >> + if (!ops->update_mdata) { >> + log_err("get_mdata() method not defined\n"); >> + return -ENOSYS; >> + } >> + >> + 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 0e26e1d138..d0ab1c9235 100644 >> --- a/include/dm/uclass-id.h >> +++ b/include/dm/uclass-id.h >> @@ -54,6 +54,7 @@ enum uclass_id { >> UCLASS_ETH_PHY, /* Ethernet PHY device */ >> UCLASS_FIRMWARE, /* Firmware */ >> UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */ >> + UCLASS_FWU_MDATA, /* FWU Metadata Access */ >> UCLASS_GPIO, /* Bank of general-purpose I/O pins */ >> UCLASS_HASH, /* Hash device */ >> UCLASS_HWSPINLOCK, /* Hardware semaphores */ >> diff --git a/include/fwu.h b/include/fwu.h >> new file mode 100644 >> index 0000000000..5a99c579fc >> --- /dev/null >> +++ b/include/fwu.h >> @@ -0,0 +1,51 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright (c) 2022, Linaro Limited >> + */ >> + >> +#if !defined _FWU_H_ >> +#define _FWU_H_ >> + >> +#include <blk.h> >> +#include <efi.h> >> + >> +#include <linux/types.h> >> + >> +struct fwu_mdata; >> +struct udevice; >> + >> +/** >> + * @get_image_alt_num: get the alt number to be used for the image >> + * @mdata_check: check the validity of the FWU metadata partitions >> + * @get_mdata() - Get a FWU metadata copy >> + * @update_mdata() - Update the FWU metadata copy >> + */ >> +struct fwu_mdata_ops { >> + int (*get_image_alt_num)(struct udevice *dev, efi_guid_t image_type_id, >> + u32 update_bank, int *alt_num); >> + >> + int (*mdata_check)(struct udevice *dev); >> + >> + int (*get_mdata)(struct udevice *dev, struct fwu_mdata **mdata); >> + >> + int (*update_mdata)(struct udevice *dev, struct fwu_mdata *mdata); >> +}; >> + >> +#define FWU_MDATA_VERSION 0x1 >> + >> +#define FWU_MDATA_GUID \ >> + EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ >> + 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23) >> + >> +int fwu_get_mdata(struct fwu_mdata **mdata); >> +int fwu_update_mdata(struct fwu_mdata *mdata); >> +int fwu_get_active_index(u32 *active_idx); >> +int fwu_update_active_index(u32 active_idx); >> +int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, >> + int *alt_num); >> +int fwu_mdata_check(void); >> +int fwu_revert_boot_index(void); >> +int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); >> +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank); >> + >> +#endif /* _FWU_H_ */ >> diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h >> new file mode 100644 >> index 0000000000..701efbba03 >> --- /dev/null >> +++ b/include/fwu_mdata.h >> @@ -0,0 +1,67 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright (c) 2022, Linaro Limited >> + */ >> + >> +#if !defined _FWU_MDATA_H_ >> +#define _FWU_MDATA_H_ >> + >> +#include <efi.h> >> + >> +/** >> + * struct fwu_image_bank_info - firmware image information >> + * @image_uuid: Guid value of the image in this bank >> + * @accepted: Acceptance status of the image >> + * @reserved: Reserved >> + * >> + * The structure contains image specific fields which are >> + * used to identify the image and to specify the image's >> + * acceptance status >> + */ >> +struct fwu_image_bank_info { >> + efi_guid_t image_uuid; >> + uint32_t accepted; >> + uint32_t reserved; >> +} __attribute__((__packed__)); >> + >> +/** >> + * struct fwu_image_entry - information for a particular type of image >> + * @image_type_uuid: Guid value for identifying the image type >> + * @location_uuid: Guid of the storage volume where the image is located >> + * @img_bank_info: Array containing properties of images >> + * >> + * This structure contains information on various types of updatable >> + * firmware images. Each image type then contains an array of image >> + * information per bank. >> + */ >> +struct fwu_image_entry { >> + efi_guid_t image_type_uuid; >> + efi_guid_t location_uuid; >> + struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS]; >> +} __attribute__((__packed__)); >> + >> +/** >> + * struct fwu_mdata - FWU metadata structure for multi-bank updates >> + * @crc32: crc32 value for the FWU metadata >> + * @version: FWU metadata version >> + * @active_index: Index of the bank currently used for booting images >> + * @previous_active_inde: Index of the bank used before the current bank >> + * being used for booting >> + * @img_entry: Array of information on various firmware images that can >> + * be updated >> + * >> + * This structure is used to store all the needed information for performing >> + * multi bank updates on the platform. This contains info on the bank being >> + * used to boot along with the information needed for identification of >> + * individual images >> + */ >> +struct fwu_mdata { >> + uint32_t crc32; >> + uint32_t version; >> + uint32_t active_index; >> + uint32_t previous_active_index; >> + >> + struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK]; >> +} __attribute__((__packed__)); >> + >> +#endif /* _FWU_MDATA_H_ */ >> -- >> 2.17.1 >> > > One more thing. run kernel-doc to validate your description. > [u-boot](eeee)$ ./scripts/kernel-doc -v -man > drivers/fwu-mdata/fwu-mdata-uclass.c 1>/dev/null > drivers/fwu-mdata/fwu-mdata-uclass.c:41: info: Scanning doc for fwu_verify_mdata > drivers/fwu-mdata/fwu-mdata-uclass.c:70: info: Scanning doc for > fwu_get_active_index > drivers/fwu-mdata/fwu-mdata-uclass.c:107: info: Scanning doc for > fwu_update_active_index > drivers/fwu-mdata/fwu-mdata-uclass.c:164: info: Scanning doc for > fwu_get_image_alt_num > drivers/fwu-mdata/fwu-mdata-uclass.c:197: info: Scanning doc for fwu_mdata_check > drivers/fwu-mdata/fwu-mdata-uclass.c:202: warning: contents before sections > drivers/fwu-mdata/fwu-mdata-uclass.c:224: info: Scanning doc for > fwu_revert_boot_index > drivers/fwu-mdata/fwu-mdata-uclass.c:230: warning: contents before sections > drivers/fwu-mdata/fwu-mdata-uclass.c:279: info: Scanning doc for > fwu_set_clear_image_accept > drivers/fwu-mdata/fwu-mdata-uclass.c:338: info: Scanning doc for > fwu_accept_image > drivers/fwu-mdata/fwu-mdata-uclass.c:357: info: Scanning doc for > fwu_clear_accept_image > drivers/fwu-mdata/fwu-mdata-uclass.c:377: info: Scanning doc for fwu_get_mdata > drivers/fwu-mdata/fwu-mdata-uclass.c:404: info: Scanning doc for > fwu_update_mdata > 2 warnings > > when I run buildman over this series it is visible that it is not > bisectable at all. > CONFIG_FWU_NUM_BANKS is defined in this patch but the symbol is added > much later. > Please make sure every single patch is bisectable.
But how is this driver getting built in the first place -- the driver is not enabling the config symbol which would result in the code getting built. The idea is to add support for the driver and the feature, and enable the functionality in the final patch. I have added each patch separately and built for the qemu arm64 platform without any issues.
first of all I wasn't able to apply all patches because this series is not there. https://patchwork.ozlabs.org/project/uboot/list/?series=281549 (better would be to use links to lore which are much easier to download)
You can download the mkeficapsule series from linaro's patchwork[1].
you depend on 3 series. Much easier is to create a branch and push it somewhere.
That's why 2 patches weren't applied.
And I just enabled configs which land in the tree for zynqmp virt and rebase this patch to be the first one. That's why all the time all existing Kconfigs were enabled when buildman build them.
Okay my understanding of a patch being bisectable was if the build does not break after applying a patch. Please note that on top of my series, you will need to define CONFIG_FWU_NUM_BANKS and CONFIG_FWU_NUM_IMAGES_PER_BANK. I did not define that on purpose since each platform would have it's own specific values.
Even if this is true you can't use in any patch a macro/value which is not defined and it is not clear what it is. I apply patch 1 and review patch 1 and not looking at patch 8 to get what that values are for.
My point was that I have not defined these values at all. These will have to be defined on a per platform level. But if you insist, I will define default values, but in my opinion it is better to get a build failure and then set correct values, rather than the build going through with some values which are incorrect for the platform.
If you apply the patches as they are, they should not result in any build failures.
This code should be enabled for at least one platform. It means I expect you define that values at least for one platform which you use for testing. I don't agree that it is better to get build error. Feature will be disabled by default for other platforms and when developer enables it should check all these settings before enablement happens.
I will leave this to the ST maintainers on whether they want me to define some default values. If they do, I will add a patch doing so.
-sughosh
Thanks, Michal

In the FWU Multi Bank Update feature, the information about the updatable images is stored as part of the metadata, on a separate partition. Add a driver for reading from and writing to the metadata when the updatable images and the metadata are stored on a block device which is formated with GPT based partition scheme.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org ---
Changes since V3: * Move the metadata access driver for GPT partitioned block devices under drivers/fwu-mdata/ directory, complying with driver model. * Move functionality to get the active index under the common function instead of the GPT block device specific driver.
drivers/fwu-mdata/Kconfig | 9 + drivers/fwu-mdata/Makefile | 1 + drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 501 ++++++++++++++++++++++++++ include/fwu.h | 2 + 4 files changed, 513 insertions(+) create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c
diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig index d6a21c8e19..d5edef19d6 100644 --- a/drivers/fwu-mdata/Kconfig +++ b/drivers/fwu-mdata/Kconfig @@ -5,3 +5,12 @@ config DM_FWU_MDATA Enable support for accessing FWU Metadata partitions. The FWU Metadata partitions reside on the same storage device which contains the other FWU updatable firmware images. + +config FWU_MDATA_GPT_BLK + bool "FWU Metadata access for GPT partitioned Block devices" + select PARTITION_TYPE_GUID + select PARTITION_UUIDS + depends on DM && HAVE_BLOCK_DEVICE && EFI_PARTITION + help + Enable support for accessing FWU Metadata on GPT partitioned + block devices. diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile index 7fec7171f4..12a5b4fe04 100644 --- a/drivers/fwu-mdata/Makefile +++ b/drivers/fwu-mdata/Makefile @@ -4,3 +4,4 @@ #
obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o +obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o diff --git a/drivers/fwu-mdata/fwu_mdata_gpt_blk.c b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c new file mode 100644 index 0000000000..b3e0fcafb2 --- /dev/null +++ b/drivers/fwu-mdata/fwu_mdata_gpt_blk.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2022, Linaro Limited + */ + +#include <blk.h> +#include <dm.h> +#include <efi_loader.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <log.h> +#include <malloc.h> +#include <memalign.h> +#include <part.h> +#include <part_efi.h> + +#include <dm/device-internal.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <u-boot/crc.h> + +#define PRIMARY_PART BIT(0) +#define SECONDARY_PART BIT(1) +#define BOTH_PARTS (PRIMARY_PART | SECONDARY_PART) + +#define MDATA_READ BIT(0) +#define MDATA_WRITE BIT(1) + +static int gpt_get_mdata_partitions(struct blk_desc *desc, + u16 *primary_mpart, + u16 *secondary_mpart) +{ + int i, ret; + u32 mdata_parts; + efi_guid_t part_type_guid; + struct disk_partition info; + const efi_guid_t fwu_mdata_guid = FWU_MDATA_GUID; + + mdata_parts = 0; + for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) { + if (part_get_info(desc, i, &info)) + continue; + uuid_str_to_bin(info.type_guid, part_type_guid.b, + UUID_STR_FORMAT_GUID); + + if (!guidcmp(&fwu_mdata_guid, &part_type_guid)) { + ++mdata_parts; + if (!*primary_mpart) + *primary_mpart = i; + else + *secondary_mpart = i; + } + } + + if (mdata_parts != 2) { + log_err("Expect two copies of the FWU metadata instead of %d\n", + mdata_parts); + ret = -EINVAL; + } else { + ret = 0; + } + + return ret; +} + +static int gpt_get_mdata_disk_part(struct blk_desc *desc, + struct disk_partition *info, + u32 part_num) +{ + int ret; + char *mdata_guid_str = "8a7a84a0-8387-40f6-ab41-a8b9a5a60d23"; + + ret = part_get_info(desc, part_num, info); + if (ret < 0) { + log_err("Unable to get the partition info for the FWU metadata part %d", + part_num); + return -1; + } + + /* Check that it is indeed the FWU metadata partition */ + if (!strncmp(info->type_guid, mdata_guid_str, UUID_STR_LEN)) { + /* Found the FWU metadata partition */ + return 0; + } + + return -1; +} + +static int gpt_read_write_mdata(struct blk_desc *desc, + struct fwu_mdata *mdata, + u8 access, u32 part_num) +{ + int ret; + u32 len, blk_start, blkcnt; + struct disk_partition info; + + ALLOC_CACHE_ALIGN_BUFFER_PAD(struct fwu_mdata, mdata_aligned, 1, + desc->blksz); + + ret = gpt_get_mdata_disk_part(desc, &info, part_num); + if (ret < 0) { + printf("Unable to get the FWU metadata partition\n"); + return -ENODEV; + } + + len = sizeof(*mdata); + blkcnt = BLOCK_CNT(len, desc); + if (blkcnt > info.size) { + log_err("Block count exceeds FWU metadata partition size\n"); + return -ERANGE; + } + + blk_start = info.start; + if (access == MDATA_READ) { + if (blk_dread(desc, blk_start, blkcnt, mdata_aligned) != blkcnt) { + log_err("Error reading FWU metadata from the device\n"); + return -EIO; + } + memcpy(mdata, mdata_aligned, sizeof(struct fwu_mdata)); + } else { + if (blk_dwrite(desc, blk_start, blkcnt, mdata) != blkcnt) { + log_err("Error writing FWU metadata to the device\n"); + return -EIO; + } + } + + return 0; +} + +static int gpt_read_mdata(struct blk_desc *desc, + struct fwu_mdata *mdata, u32 part_num) +{ + return gpt_read_write_mdata(desc, mdata, MDATA_READ, part_num); +} + +static int gpt_write_mdata_partition(struct blk_desc *desc, + struct fwu_mdata *mdata, + u32 part_num) +{ + return gpt_read_write_mdata(desc, mdata, MDATA_WRITE, part_num); +} + +static int fwu_gpt_update_mdata(struct udevice * dev, struct fwu_mdata *mdata) +{ + int ret; + struct blk_desc *desc; + u16 primary_mpart = 0, secondary_mpart = 0; + + desc = dev_get_uclass_plat(dev_get_priv(dev)); + if (!desc) { + log_err("Block device not found\n"); + return -ENODEV; + } + + ret = gpt_get_mdata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the FWU metadata partitions\n"); + return -ENODEV; + } + + /* First write the primary partition*/ + ret = gpt_write_mdata_partition(desc, mdata, primary_mpart); + if (ret < 0) { + log_err("Updating primary FWU metadata partition failed\n"); + return ret; + } + + /* And now the replica */ + ret = gpt_write_mdata_partition(desc, mdata, secondary_mpart); + if (ret < 0) { + log_err("Updating secondary FWU metadata partition failed\n"); + return ret; + } + + return 0; +} + +static int gpt_get_mdata(struct blk_desc *desc, struct fwu_mdata **mdata) +{ + int ret; + u16 primary_mpart = 0, secondary_mpart = 0; + + ret = gpt_get_mdata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the FWU metadata partitions\n"); + return -ENODEV; + } + + *mdata = malloc(sizeof(struct fwu_mdata)); + if (!*mdata) { + log_err("Unable to allocate memory for reading FWU metadata\n"); + return -ENOMEM; + } + + ret = gpt_read_mdata(desc, *mdata, primary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + return -EIO; + } + + ret = fwu_verify_mdata(*mdata, 1); + if (!ret) + return 0; + + /* + * Verification of the primary FWU metadata copy failed. + * Try to read the replica. + */ + memset(*mdata, 0, sizeof(struct fwu_mdata)); + ret = gpt_read_mdata(desc, *mdata, secondary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + return -EIO; + } + + ret = fwu_verify_mdata(*mdata, 0); + if (!ret) + return 0; + + /* Both the FWU metadata copies are corrupted. */ + return -1; +} + +static int gpt_check_mdata_validity(struct udevice *dev) +{ + int ret; + struct blk_desc *desc; + struct fwu_mdata pri_mdata; + struct fwu_mdata secondary_mdata; + u16 primary_mpart = 0, secondary_mpart = 0; + u16 valid_partitions, invalid_partitions; + + desc = dev_get_uclass_plat(dev_get_priv(dev)); + if (!desc) { + log_err("Block device not found\n"); + return -ENODEV; + } + + /* + * Two FWU metadata partitions are expected. + * If we don't have two, user needs to create + * them first + */ + valid_partitions = 0; + ret = gpt_get_mdata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the FWU metadata partitions\n"); + return -ENODEV; + } + + ret = gpt_read_mdata(desc, &pri_mdata, primary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + goto secondary_read; + } + + ret = fwu_verify_mdata(&pri_mdata, 1); + if (!ret) + valid_partitions |= PRIMARY_PART; + +secondary_read: + /* Now check the secondary partition */ + ret = gpt_read_mdata(desc, &secondary_mdata, secondary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + goto mdata_restore; + } + + ret = fwu_verify_mdata(&secondary_mdata, 0); + if (!ret) + valid_partitions |= SECONDARY_PART; + +mdata_restore: + if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) { + ret = -1; + /* + * Before returning, check that both the + * FWU metadata copies are the same. If not, + * the FWU metadata copies need to be + * re-populated. + */ + if (!memcmp(&pri_mdata, &secondary_mdata, + sizeof(struct fwu_mdata))) { + ret = 0; + } else { + log_err("Both FWU metadata copies are valid but do not match. Please check!\n"); + } + goto out; + } + + ret = -1; + if (!(valid_partitions & BOTH_PARTS)) + goto out; + + invalid_partitions = valid_partitions ^ BOTH_PARTS; + ret = gpt_write_mdata_partition(desc, + (invalid_partitions == PRIMARY_PART) ? + &secondary_mdata : &pri_mdata, + (invalid_partitions == PRIMARY_PART) ? + primary_mpart : secondary_mpart); + + if (ret < 0) + log_err("Restoring %s FWU metadata partition failed\n", + (invalid_partitions == PRIMARY_PART) ? + "primary" : "secondary"); + +out: + return ret; +} + +static int gpt_get_image_alt_num(struct udevice *dev, struct blk_desc *desc, + efi_guid_t image_type_id, u32 update_bank, + int *alt_no) +{ + int ret, i; + u32 part; + struct fwu_mdata *mdata = NULL; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_bank_info; + struct disk_partition info; + efi_guid_t unique_part_guid; + efi_guid_t image_guid = NULL_GUID; + + ret = gpt_get_mdata(desc, &mdata); + if (ret < 0) { + log_err("Unable to read valid FWU metadata\n"); + goto out; + } + + /* + * The FWU metadata has been read. Now get the image_uuid for the + * image with the update_bank. + */ + for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) { + if (!guidcmp(&image_type_id, + &mdata->img_entry[i].image_type_uuid)) { + img_entry = &mdata->img_entry[i]; + img_bank_info = &img_entry->img_bank_info[update_bank]; + guidcpy(&image_guid, &img_bank_info->image_uuid); + break; + } + } + + /* + * Now read the GPT Partition Table Entries to find a matching + * partition with UniquePartitionGuid value. We need to iterate + * through all the GPT partitions since they might be in any + * order + */ + 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)) { + /* Found the partition */ + part = i; + *alt_no = fwu_plat_get_alt_num(dev_get_priv(dev), &part); + if (*alt_no != -1) + log_info("alt_num %d for partition %pUl\n", + *alt_no, &image_guid); + ret = 0; + break; + } + } + + if (*alt_no == -1) { + log_err("alt_num not found for partition with GUID %pUl\n", + &image_guid); + ret = -EINVAL; + } + + if (i == MAX_SEARCH_PARTITIONS) { + log_err("Partition with the image guid not found\n"); + ret = -EINVAL; + } + +out: + free(mdata); + + return ret; +} + +int fwu_gpt_get_image_alt_num(struct udevice *dev, efi_guid_t image_type_id, + u32 update_bank, int *alt_no) +{ + struct blk_desc *desc; + + desc = dev_get_uclass_plat(dev_get_priv(dev)); + if (!desc) { + log_err("Block device not found\n"); + return -ENODEV; + } + + return gpt_get_image_alt_num(dev, desc, image_type_id, update_bank, + alt_no); +} + +int fwu_gpt_mdata_check(struct udevice *dev) +{ + /* + * Check if both the copies of the FWU metadata are + * valid. If one has gone bad, restore it from the + * other good copy. + */ + return gpt_check_mdata_validity(dev); +} + +int fwu_gpt_get_mdata(struct udevice *dev, struct fwu_mdata **mdata) +{ + struct blk_desc *desc; + + desc = dev_get_uclass_plat(dev_get_priv(dev)); + if (!desc) { + log_err("Block device not found\n"); + return -ENODEV; + } + + return gpt_get_mdata(desc, mdata); +} + +int fwu_get_mdata_device(struct udevice **mdata_dev) +{ + u32 phandle; + int ret, size; + struct udevice *dev, *child; + ofnode fwu_mdata_node; + const fdt32_t *phandle_p = NULL; + + fwu_mdata_node = ofnode_path("/fwu-mdata"); + if (!ofnode_valid(fwu_mdata_node)) { + log_err("fwu-node not found\n"); + return -ENOENT; + } + + phandle_p = ofnode_get_property(fwu_mdata_node, "fwu-mdata-store", + &size); + if (!phandle_p) { + log_err("fwu-mdata-store property not found\n"); + return -ENOENT; + } + + phandle = fdt32_to_cpu(*phandle_p); + + ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle), + &dev); + if (ret) + return ret; + + ret = -ENODEV; + for (device_find_first_child(dev, &child); child; + device_find_next_child(&child)) { + if (device_get_uclass_id(child) == UCLASS_BLK) { + *mdata_dev = child; + ret = 0; + } + } + + return ret; +} + +static int fwu_mdata_gpt_blk_probe(struct udevice *dev) +{ + int ret; + struct udevice *mdata_dev = NULL; + + ret = fwu_get_mdata_device(&mdata_dev); + if (ret) + return ret; + + dev_set_priv(dev, mdata_dev); + + return 0; +} + +static const struct fwu_mdata_ops fwu_gpt_blk_ops = { + .get_image_alt_num = fwu_gpt_get_image_alt_num, + .mdata_check = fwu_gpt_mdata_check, + .get_mdata = fwu_gpt_get_mdata, + .update_mdata = fwu_gpt_update_mdata, +}; + +static const struct udevice_id fwu_mdata_ids[] = { + { .compatible = "u-boot,fwu-mdata" }, + { } +}; + +U_BOOT_DRIVER(fwu_mdata_gpt_blk) = { + .name = "fwu-mdata-gpt-blk", + .id = UCLASS_FWU_MDATA, + .of_match = fwu_mdata_ids, + .ops = &fwu_gpt_blk_ops, + .probe = fwu_mdata_gpt_blk_probe, +}; diff --git a/include/fwu.h b/include/fwu.h index 5a99c579fc..2c7db2dff9 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -43,6 +43,8 @@ int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, int *alt_num); +int fwu_get_mdata_device(struct udevice **mdata_dev); +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part); int fwu_mdata_check(void); int fwu_revert_boot_index(void); int fwu_accept_image(efi_guid_t *img_type_id, u32 bank);

Hi Sughosh,
While porting mdata-sf driver, I'm confusing on the devicetree usage.
2022年2月8日(火) 3:21 Sughosh Ganu sughosh.ganu@linaro.org:
+int fwu_get_mdata_device(struct udevice **mdata_dev) +{
u32 phandle;
int ret, size;
struct udevice *dev, *child;
ofnode fwu_mdata_node;
const fdt32_t *phandle_p = NULL;
fwu_mdata_node = ofnode_path("/fwu-mdata");
if (!ofnode_valid(fwu_mdata_node)) {
log_err("fwu-node not found\n");
return -ENOENT;
}
So this seems to get the udevice from path, but I think fwu-mdata node has "u-boot,fwu-mdata" compatible property, in that case probe function already gets the node. Why would you search it again by path?
phandle_p = ofnode_get_property(fwu_mdata_node, "fwu-mdata-store",
&size);
if (!phandle_p) {
log_err("fwu-mdata-store property not found\n");
return -ENOENT;
}
phandle = fdt32_to_cpu(*phandle_p);
ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
&dev);
if (ret)
return ret;
ret = -ENODEV;
for (device_find_first_child(dev, &child); child;
device_find_next_child(&child)) {
if (device_get_uclass_id(child) == UCLASS_BLK) {
*mdata_dev = child;
I thought that the blk device node directly passed by the "fwu-mdata-store" property. Would we need to search it from children nodes?
BTW, if we can use the devicetree, can we define the number of banks and the number of images can be described too? Of course as I said in the other thread, I would like to put the dfu_alt_info like information in the devicetree too. (But it maybe different from this discussion)
Thank you,
ret = 0;
}
}
return ret;
+}
+static int fwu_mdata_gpt_blk_probe(struct udevice *dev) +{
int ret;
struct udevice *mdata_dev = NULL;
ret = fwu_get_mdata_device(&mdata_dev);
if (ret)
return ret;
dev_set_priv(dev, mdata_dev);
return 0;
+}
+static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.get_mdata = fwu_gpt_get_mdata,
.update_mdata = fwu_gpt_update_mdata,
+};
+static const struct udevice_id fwu_mdata_ids[] = {
{ .compatible = "u-boot,fwu-mdata" },
{ }
+};
+U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
.name = "fwu-mdata-gpt-blk",
.id = UCLASS_FWU_MDATA,
.of_match = fwu_mdata_ids,
.ops = &fwu_gpt_blk_ops,
.probe = fwu_mdata_gpt_blk_probe,
+}; diff --git a/include/fwu.h b/include/fwu.h index 5a99c579fc..2c7db2dff9 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -43,6 +43,8 @@ int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, int *alt_num); +int fwu_get_mdata_device(struct udevice **mdata_dev); +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part); int fwu_mdata_check(void); int fwu_revert_boot_index(void); int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); -- 2.17.1
-- Masami Hiramatsu

hi Masami,
On Wed, 9 Feb 2022 at 10:26, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
While porting mdata-sf driver, I'm confusing on the devicetree usage.
2022年2月8日(火) 3:21 Sughosh Ganu sughosh.ganu@linaro.org:
+int fwu_get_mdata_device(struct udevice **mdata_dev) +{
u32 phandle;
int ret, size;
struct udevice *dev, *child;
ofnode fwu_mdata_node;
const fdt32_t *phandle_p = NULL;
fwu_mdata_node = ofnode_path("/fwu-mdata");
if (!ofnode_valid(fwu_mdata_node)) {
log_err("fwu-node not found\n");
return -ENOENT;
}
So this seems to get the udevice from path, but I think fwu-mdata node has "u-boot,fwu-mdata" compatible property, in that case probe function already gets the node. Why would you search it again by path?
Okay. Is there some other api that I can use which is faster than the approach currently taken? If so, do let me know.
phandle_p = ofnode_get_property(fwu_mdata_node, "fwu-mdata-store",
&size);
if (!phandle_p) {
log_err("fwu-mdata-store property not found\n");
return -ENOENT;
}
phandle = fdt32_to_cpu(*phandle_p);
ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
&dev);
if (ret)
return ret;
ret = -ENODEV;
for (device_find_first_child(dev, &child); child;
device_find_next_child(&child)) {
if (device_get_uclass_id(child) == UCLASS_BLK) {
*mdata_dev = child;
I thought that the blk device node directly passed by the "fwu-mdata-store" property. Would we need to search it from children nodes?
What the device tree is pointing to is the device like the mmc, which is described through a device tree node. The block device is the child of this device, which is not described in the device tree. The driver finally needs the block device.
BTW, if we can use the devicetree, can we define the number of banks and the number of images can be described too?
It is much easier to handle if these values are defined through Kconfig symbols. That way, this gets directly included in the config file, and can be used directly in the fwu_mdata.h metadata structure.
Of course as I said in the other thread, I would like to put the dfu_alt_info like information in the devicetree too. (But it maybe different from this discussion)
Just curious, why do you need to define a variable like dfu_alt_info in a device tree. If this has already been described earlier, you can point me to that discussion. Trying to understand what benefit does having the variables defined in a device tree brings. Thanks.
-sughosh
Thank you,
ret = 0;
}
}
return ret;
+}
+static int fwu_mdata_gpt_blk_probe(struct udevice *dev) +{
int ret;
struct udevice *mdata_dev = NULL;
ret = fwu_get_mdata_device(&mdata_dev);
if (ret)
return ret;
dev_set_priv(dev, mdata_dev);
return 0;
+}
+static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.get_mdata = fwu_gpt_get_mdata,
.update_mdata = fwu_gpt_update_mdata,
+};
+static const struct udevice_id fwu_mdata_ids[] = {
{ .compatible = "u-boot,fwu-mdata" },
{ }
+};
+U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
.name = "fwu-mdata-gpt-blk",
.id = UCLASS_FWU_MDATA,
.of_match = fwu_mdata_ids,
.ops = &fwu_gpt_blk_ops,
.probe = fwu_mdata_gpt_blk_probe,
+}; diff --git a/include/fwu.h b/include/fwu.h index 5a99c579fc..2c7db2dff9 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -43,6 +43,8 @@ int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, int *alt_num); +int fwu_get_mdata_device(struct udevice **mdata_dev); +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part); int fwu_mdata_check(void); int fwu_revert_boot_index(void); int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); -- 2.17.1
-- Masami Hiramatsu

Hi Sughosh,
2022年2月9日(水) 18:03 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Wed, 9 Feb 2022 at 10:26, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
While porting mdata-sf driver, I'm confusing on the devicetree usage.
2022年2月8日(火) 3:21 Sughosh Ganu sughosh.ganu@linaro.org:
+int fwu_get_mdata_device(struct udevice **mdata_dev) +{
u32 phandle;
int ret, size;
struct udevice *dev, *child;
ofnode fwu_mdata_node;
const fdt32_t *phandle_p = NULL;
fwu_mdata_node = ofnode_path("/fwu-mdata");
if (!ofnode_valid(fwu_mdata_node)) {
log_err("fwu-node not found\n");
return -ENOENT;
}
So this seems to get the udevice from path, but I think fwu-mdata node has "u-boot,fwu-mdata" compatible property, in that case probe function already gets the node. Why would you search it again by path?
Okay. Is there some other api that I can use which is faster than the approach currently taken? If so, do let me know.
I thought the ofnode which has "u-boot,fwu-mdata" compatible property is passed to fwu_mdata_gpt_blk_probe(), and that is , doesn't it?
If so, as you show in the example, fwu-mdata { compatible = "u-boot,fwu-mdata"; fwu-mdata-store = <&sdmmc1>; };
you already got the "/fwu-mdata" node. You don't need any API to find that node because you already has that. That is what I meant.
phandle_p = ofnode_get_property(fwu_mdata_node, "fwu-mdata-store",
&size);
if (!phandle_p) {
log_err("fwu-mdata-store property not found\n");
return -ENOENT;
}
phandle = fdt32_to_cpu(*phandle_p);
ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
&dev);
if (ret)
return ret;
ret = -ENODEV;
for (device_find_first_child(dev, &child); child;
device_find_next_child(&child)) {
if (device_get_uclass_id(child) == UCLASS_BLK) {
*mdata_dev = child;
I thought that the blk device node directly passed by the "fwu-mdata-store" property. Would we need to search it from children nodes?
What the device tree is pointing to is the device like the mmc, which is described through a device tree node. The block device is the child of this device, which is not described in the device tree. The driver finally needs the block device.
Ah, OK. Can't we specify the block device node to "fwu-mdata-store" directly?
BTW, if we can use the devicetree, can we define the number of banks and the number of images can be described too?
It is much easier to handle if these values are defined through Kconfig symbols. That way, this gets directly included in the config file, and can be used directly in the fwu_mdata.h metadata structure.
Yes, it is easier to implement. And that means the firmware bank configuration is embedded in the firmware binary (code) instead of the configuration data (devicetree). For the same reason I think dfu_alt_info (or the basement info like device and offsets) should be in the devicetree. Current implementation is very fragile (because dfu_alt_info can be changed by the user) or fixed in the code (like stm32, it generates the dfu_alt_info by the platform driver.)
Of course as I said in the other thread, I would like to put the dfu_alt_info like information in the devicetree too. (But it maybe different from this discussion)
Just curious, why do you need to define a variable like dfu_alt_info in a device tree. If this has already been described earlier, you can point me to that discussion. Trying to understand what benefit does having the variables defined in a device tree brings. Thanks.
If we can consolidate the configuration information related to the firmware layout on the devicetree, it is very easy to understand and manage the firmware update only by checking the devicetree. Current design is very fragile from the consistency viewpoint, because there are 3 different information we are using for FWU, Kconfig, devicetree and u-boot env-variables. If one of them sets inconsistent value, FWU may not work as we expected.
That is my impression felt from porting AB update on the DeveloperBox platform.
Thank you,
-sughosh
Thank you,
ret = 0;
}
}
return ret;
+}
+static int fwu_mdata_gpt_blk_probe(struct udevice *dev) +{
int ret;
struct udevice *mdata_dev = NULL;
ret = fwu_get_mdata_device(&mdata_dev);
if (ret)
return ret;
dev_set_priv(dev, mdata_dev);
return 0;
+}
+static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.get_mdata = fwu_gpt_get_mdata,
.update_mdata = fwu_gpt_update_mdata,
+};
+static const struct udevice_id fwu_mdata_ids[] = {
{ .compatible = "u-boot,fwu-mdata" },
{ }
+};
+U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
.name = "fwu-mdata-gpt-blk",
.id = UCLASS_FWU_MDATA,
.of_match = fwu_mdata_ids,
.ops = &fwu_gpt_blk_ops,
.probe = fwu_mdata_gpt_blk_probe,
+}; diff --git a/include/fwu.h b/include/fwu.h index 5a99c579fc..2c7db2dff9 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -43,6 +43,8 @@ int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, int *alt_num); +int fwu_get_mdata_device(struct udevice **mdata_dev); +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part); int fwu_mdata_check(void); int fwu_revert_boot_index(void); int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); -- 2.17.1
-- Masami Hiramatsu
-- Masami Hiramatsu

hi Masami,
On Wed, 9 Feb 2022 at 17:18, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2022年2月9日(水) 18:03 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Wed, 9 Feb 2022 at 10:26, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
While porting mdata-sf driver, I'm confusing on the devicetree usage.
2022年2月8日(火) 3:21 Sughosh Ganu sughosh.ganu@linaro.org:
+int fwu_get_mdata_device(struct udevice **mdata_dev) +{
u32 phandle;
int ret, size;
struct udevice *dev, *child;
ofnode fwu_mdata_node;
const fdt32_t *phandle_p = NULL;
fwu_mdata_node = ofnode_path("/fwu-mdata");
if (!ofnode_valid(fwu_mdata_node)) {
log_err("fwu-node not found\n");
return -ENOENT;
}
So this seems to get the udevice from path, but I think fwu-mdata node has "u-boot,fwu-mdata" compatible property, in that case probe function already gets the node. Why would you search it again by path?
Okay. Is there some other api that I can use which is faster than the approach currently taken? If so, do let me know.
I thought the ofnode which has "u-boot,fwu-mdata" compatible property is passed to fwu_mdata_gpt_blk_probe(), and that is , doesn't it?
If so, as you show in the example, fwu-mdata { compatible = "u-boot,fwu-mdata"; fwu-mdata-store = <&sdmmc1>; };
you already got the "/fwu-mdata" node. You don't need any API to find that node because you already has that. That is what I meant.
The probe function gets passed the corresponding udevice structure. This structure contains node_ member, which should correspond to the device node. I will try to use this member instead of searching for the node.
phandle_p = ofnode_get_property(fwu_mdata_node, "fwu-mdata-store",
&size);
if (!phandle_p) {
log_err("fwu-mdata-store property not found\n");
return -ENOENT;
}
phandle = fdt32_to_cpu(*phandle_p);
ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
&dev);
if (ret)
return ret;
ret = -ENODEV;
for (device_find_first_child(dev, &child); child;
device_find_next_child(&child)) {
if (device_get_uclass_id(child) == UCLASS_BLK) {
*mdata_dev = child;
I thought that the blk device node directly passed by the "fwu-mdata-store" property. Would we need to search it from children nodes?
What the device tree is pointing to is the device like the mmc, which is described through a device tree node. The block device is the child of this device, which is not described in the device tree. The driver finally needs the block device.
Ah, OK. Can't we specify the block device node to "fwu-mdata-store" directly?
I don't think so, since the fwu-mdata-store is pointing to one of the nodes in the device tree -- the block device does not show up as node on the device tree.
BTW, if we can use the devicetree, can we define the number of banks and the number of images can be described too?
It is much easier to handle if these values are defined through Kconfig symbols. That way, this gets directly included in the config file, and can be used directly in the fwu_mdata.h metadata structure.
Yes, it is easier to implement. And that means the firmware bank configuration is embedded in the firmware binary (code) instead of the configuration data (devicetree). For the same reason I think dfu_alt_info (or the basement info like device and offsets) should be in the devicetree. Current implementation is very fragile (because dfu_alt_info can be changed by the user) or fixed in the code (like stm32, it generates the dfu_alt_info by the platform driver.)
Of course as I said in the other thread, I would like to put the dfu_alt_info like information in the devicetree too. (But it maybe different from this discussion)
Just curious, why do you need to define a variable like dfu_alt_info in a device tree. If this has already been described earlier, you can point me to that discussion. Trying to understand what benefit does having the variables defined in a device tree brings. Thanks.
If we can consolidate the configuration information related to the firmware layout on the devicetree, it is very easy to understand and manage the firmware update only by checking the devicetree. Current design is very fragile from the consistency viewpoint, because there are 3 different information we are using for FWU, Kconfig, devicetree and u-boot env-variables. If one of them sets inconsistent value, FWU may not work as we expected.
I get your point. But I think generating the dfu_alt_info at runtime, like how it is done for the ST platforms is in general a better method, as against using a static variable defined in the device tree. With runtime generation of the variable, the same code can be used on multiple platforms and can be generated at runtime -- I feel that is better than defining the variable in every platform's device tree. Btw, there is also provision to define the variable(or part of it) statically through Kconfig variables. As against your concern about the feature using multiple methods for stating information, it is indeed valid. But I guess we can have documentation explaining how each of that information needs to be defined. Thanks.
-sughosh
That is my impression felt from porting AB update on the DeveloperBox platform.
Thank you,
-sughosh
Thank you,
ret = 0;
}
}
return ret;
+}
+static int fwu_mdata_gpt_blk_probe(struct udevice *dev) +{
int ret;
struct udevice *mdata_dev = NULL;
ret = fwu_get_mdata_device(&mdata_dev);
if (ret)
return ret;
dev_set_priv(dev, mdata_dev);
return 0;
+}
+static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.get_mdata = fwu_gpt_get_mdata,
.update_mdata = fwu_gpt_update_mdata,
+};
+static const struct udevice_id fwu_mdata_ids[] = {
{ .compatible = "u-boot,fwu-mdata" },
{ }
+};
+U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
.name = "fwu-mdata-gpt-blk",
.id = UCLASS_FWU_MDATA,
.of_match = fwu_mdata_ids,
.ops = &fwu_gpt_blk_ops,
.probe = fwu_mdata_gpt_blk_probe,
+}; diff --git a/include/fwu.h b/include/fwu.h index 5a99c579fc..2c7db2dff9 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -43,6 +43,8 @@ int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, int *alt_num); +int fwu_get_mdata_device(struct udevice **mdata_dev); +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part); int fwu_mdata_check(void); int fwu_revert_boot_index(void); int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); -- 2.17.1
-- Masami Hiramatsu
-- Masami Hiramatsu

Hi Sughosh,
2022年2月10日(木) 3:40 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Wed, 9 Feb 2022 at 17:18, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2022年2月9日(水) 18:03 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Wed, 9 Feb 2022 at 10:26, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
While porting mdata-sf driver, I'm confusing on the devicetree usage.
2022年2月8日(火) 3:21 Sughosh Ganu sughosh.ganu@linaro.org:
+int fwu_get_mdata_device(struct udevice **mdata_dev) +{
u32 phandle;
int ret, size;
struct udevice *dev, *child;
ofnode fwu_mdata_node;
const fdt32_t *phandle_p = NULL;
fwu_mdata_node = ofnode_path("/fwu-mdata");
if (!ofnode_valid(fwu_mdata_node)) {
log_err("fwu-node not found\n");
return -ENOENT;
}
So this seems to get the udevice from path, but I think fwu-mdata node has "u-boot,fwu-mdata" compatible property, in that case probe function already gets the node. Why would you search it again by path?
Okay. Is there some other api that I can use which is faster than the approach currently taken? If so, do let me know.
I thought the ofnode which has "u-boot,fwu-mdata" compatible property is passed to fwu_mdata_gpt_blk_probe(), and that is , doesn't it?
If so, as you show in the example, fwu-mdata { compatible = "u-boot,fwu-mdata"; fwu-mdata-store = <&sdmmc1>; };
you already got the "/fwu-mdata" node. You don't need any API to find that node because you already has that. That is what I meant.
The probe function gets passed the corresponding udevice structure. This structure contains node_ member, which should correspond to the device node. I will try to use this member instead of searching for the node.
Yeah, you can use "dev_ofnode()".
phandle_p = ofnode_get_property(fwu_mdata_node, "fwu-mdata-store",
&size);
if (!phandle_p) {
log_err("fwu-mdata-store property not found\n");
return -ENOENT;
}
phandle = fdt32_to_cpu(*phandle_p);
ret = device_get_global_by_ofnode(ofnode_get_by_phandle(phandle),
&dev);
if (ret)
return ret;
ret = -ENODEV;
for (device_find_first_child(dev, &child); child;
device_find_next_child(&child)) {
if (device_get_uclass_id(child) == UCLASS_BLK) {
*mdata_dev = child;
I thought that the blk device node directly passed by the "fwu-mdata-store" property. Would we need to search it from children nodes?
What the device tree is pointing to is the device like the mmc, which is described through a device tree node. The block device is the child of this device, which is not described in the device tree. The driver finally needs the block device.
Ah, OK. Can't we specify the block device node to "fwu-mdata-store" directly?
I don't think so, since the fwu-mdata-store is pointing to one of the nodes in the device tree -- the block device does not show up as node on the device tree.
Ah, I got it. Indeed. In my case spi-nor device will be on the devicetree, but mmc media is not. Sorry about that.
In that case, does fwu-mdata-store refer the controller node? If there are several blk devices under that (I'm not sure it can be) mdata must be in the first device (maybe decided by scanning order?). I think this should be documented for who ports AB-update on another platform.
BTW, if we can use the devicetree, can we define the number of banks and the number of images can be described too?
It is much easier to handle if these values are defined through Kconfig symbols. That way, this gets directly included in the config file, and can be used directly in the fwu_mdata.h metadata structure.
Yes, it is easier to implement. And that means the firmware bank configuration is embedded in the firmware binary (code) instead of the configuration data (devicetree). For the same reason I think dfu_alt_info (or the basement info like device and offsets) should be in the devicetree. Current implementation is very fragile (because dfu_alt_info can be changed by the user) or fixed in the code (like stm32, it generates the dfu_alt_info by the platform driver.)
Of course as I said in the other thread, I would like to put the dfu_alt_info like information in the devicetree too. (But it maybe different from this discussion)
Just curious, why do you need to define a variable like dfu_alt_info in a device tree. If this has already been described earlier, you can point me to that discussion. Trying to understand what benefit does having the variables defined in a device tree brings. Thanks.
If we can consolidate the configuration information related to the firmware layout on the devicetree, it is very easy to understand and manage the firmware update only by checking the devicetree. Current design is very fragile from the consistency viewpoint, because there are 3 different information we are using for FWU, Kconfig, devicetree and u-boot env-variables. If one of them sets inconsistent value, FWU may not work as we expected.
I get your point. But I think generating the dfu_alt_info at runtime, like how it is done for the ST platforms is in general a better method, as against using a static variable defined in the device tree.
Yeah, the GPT based one is able to store this information on the GPT, and it must be a primary definition.
With runtime generation of the variable, the same code can be used on multiple platforms and can be generated at runtime -- I feel that is better than defining the variable in every platform's device tree.
I don't agree this point at least for non-GPT devices, since the firmware storage layout depends on the platform hardware configuration statically in such cases. Of course if the device uses GPT to store the firmware, we have to follow the GPT layout and FWU Metadata to find the corresponding firmware partition.
Btw, there is also provision to define the variable(or part of it) statically through Kconfig variables. As against your concern about the feature using multiple methods for stating information, it is indeed valid. But I guess we can have documentation explaining how each of that information needs to be defined. Thanks.
Yeah, even using GPT, we need to set correct UUID to the FWU metadata, and the metadata depends on Kconfig if we keep putting the #of images-per-bank and the #of banks in the Kconfig, and storage (controller) is defined in the devicetree.
And I still feel this "chain of definitions" seems a bit fragile. This fragile comes from the FWU metadata is not enough self-described (it has no the #of images-per-bank and the #of banks, without this information we can not decode FWU metadata itself.) Anyway, if we can define the #of images-per-bank and the #of banks in the devicetree, we don't need to change the binary but just changing the devicetree for the different products which has different firmware layout. I think that is more flexible.
Thank you,
-sughosh
That is my impression felt from porting AB update on the DeveloperBox platform.
Thank you,
-sughosh
Thank you,
ret = 0;
}
}
return ret;
+}
+static int fwu_mdata_gpt_blk_probe(struct udevice *dev) +{
int ret;
struct udevice *mdata_dev = NULL;
ret = fwu_get_mdata_device(&mdata_dev);
if (ret)
return ret;
dev_set_priv(dev, mdata_dev);
return 0;
+}
+static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.get_mdata = fwu_gpt_get_mdata,
.update_mdata = fwu_gpt_update_mdata,
+};
+static const struct udevice_id fwu_mdata_ids[] = {
{ .compatible = "u-boot,fwu-mdata" },
{ }
+};
+U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
.name = "fwu-mdata-gpt-blk",
.id = UCLASS_FWU_MDATA,
.of_match = fwu_mdata_ids,
.ops = &fwu_gpt_blk_ops,
.probe = fwu_mdata_gpt_blk_probe,
+}; diff --git a/include/fwu.h b/include/fwu.h index 5a99c579fc..2c7db2dff9 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -43,6 +43,8 @@ int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, int *alt_num); +int fwu_get_mdata_device(struct udevice **mdata_dev); +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part); int fwu_mdata_check(void); int fwu_revert_boot_index(void); int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); -- 2.17.1
-- Masami Hiramatsu
-- Masami Hiramatsu

2022年2月10日(木) 10:43 Masami Hiramatsu masami.hiramatsu@linaro.org:
Of course as I said in the other thread, I would like to put the dfu_alt_info like information in the devicetree too. (But it maybe different from this discussion)
Just curious, why do you need to define a variable like dfu_alt_info in a device tree. If this has already been described earlier, you can point me to that discussion. Trying to understand what benefit does having the variables defined in a device tree brings. Thanks.
If we can consolidate the configuration information related to the firmware layout on the devicetree, it is very easy to understand and manage the firmware update only by checking the devicetree. Current design is very fragile from the consistency viewpoint, because there are 3 different information we are using for FWU, Kconfig, devicetree and u-boot env-variables. If one of them sets inconsistent value, FWU may not work as we expected.
I get your point. But I think generating the dfu_alt_info at runtime, like how it is done for the ST platforms is in general a better method, as against using a static variable defined in the device tree.
Yeah, the GPT based one is able to store this information on the GPT, and it must be a primary definition.
With runtime generation of the variable, the same code can be used on multiple platforms and can be generated at runtime -- I feel that is better than defining the variable in every platform's device tree.
I don't agree this point at least for non-GPT devices, since the firmware storage layout depends on the platform hardware configuration statically in such cases.
I changed my mind, it can be solved if we have "uuid" property for each partition in the devicetree. I will explain later.
Of course if the device uses GPT to store the firmware, we have to follow the GPT layout and FWU Metadata to find the corresponding firmware partition.
Btw, there is also provision to define the variable(or part of it) statically through Kconfig variables. As against your concern about the feature using multiple methods for stating information, it is indeed valid. But I guess we can have documentation explaining how each of that information needs to be defined. Thanks.
Yeah, even using GPT, we need to set correct UUID to the FWU metadata, and the metadata depends on Kconfig if we keep putting the #of images-per-bank and the #of banks in the Kconfig, and storage
Sorry, I confused. there are "#of images and #of banks per image".
(controller) is defined in the devicetree.
And I still feel this "chain of definitions" seems a bit fragile. This fragile comes from the FWU metadata is not enough self-described (it has no the #of images-per-bank and the #of banks, without this information we can not decode FWU metadata itself.) Anyway, if we can define the #of images-per-bank and the #of banks in the devicetree, we don't need to change the binary but just changing the devicetree for the different products which has different firmware layout. I think that is more flexible.
What I would like to suggest is
/* For GPT BLK backend */ fwu_mdata { compatible = "u-boot,fwu-mdata-gpt"; fwu-mdata-store = <&mmc1>; /* No need to specify the mdata partition, because it finds the mdata by partition type uuid. */ banks = <2>; images-per-bank = <1>; };
/* For SF backend */ fwu_mdata { compatible = "u-boot,fwu-mdata-sf"; fwu-mdata-store = <&spi-flash0>; mdata-offsets = <500000, 520000>; /* Or specified by partition label? */ banks = <6>; images-per-bank = <1>; };
Note that this is only for the metadata, the real firmware layout issue still exists. If we can add "uuid" property for the fixed-partitions node as a additional property, e.g.
spi-flash@0 { partitions { compatible = "fixed-partitions"; ... uuid = "aaaaaaaa-bbbb-cccc-dddd-eeeeffffgggg"; ... partition@600000 { label = "Firmware-Bank0"; reg = <600000, 400000>; uuid = "12345678-aaaa-bbbb-cccc-0123456789ab"; }; ... }; };
Then we can decode the real fwu-mdata and find corresponding partitions, and able to build dfu_alt_info in runtime.
What would you think?
Thank you,
Thank you,
-sughosh
That is my impression felt from porting AB update on the DeveloperBox platform.
Thank you,
-sughosh
Thank you,
ret = 0;
}
}
return ret;
+}
+static int fwu_mdata_gpt_blk_probe(struct udevice *dev) +{
int ret;
struct udevice *mdata_dev = NULL;
ret = fwu_get_mdata_device(&mdata_dev);
if (ret)
return ret;
dev_set_priv(dev, mdata_dev);
return 0;
+}
+static const struct fwu_mdata_ops fwu_gpt_blk_ops = {
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.get_mdata = fwu_gpt_get_mdata,
.update_mdata = fwu_gpt_update_mdata,
+};
+static const struct udevice_id fwu_mdata_ids[] = {
{ .compatible = "u-boot,fwu-mdata" },
{ }
+};
+U_BOOT_DRIVER(fwu_mdata_gpt_blk) = {
.name = "fwu-mdata-gpt-blk",
.id = UCLASS_FWU_MDATA,
.of_match = fwu_mdata_ids,
.ops = &fwu_gpt_blk_ops,
.probe = fwu_mdata_gpt_blk_probe,
+}; diff --git a/include/fwu.h b/include/fwu.h index 5a99c579fc..2c7db2dff9 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -43,6 +43,8 @@ int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, int *alt_num); +int fwu_get_mdata_device(struct udevice **mdata_dev); +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part); int fwu_mdata_check(void); int fwu_revert_boot_index(void); int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); -- 2.17.1
-- Masami Hiramatsu
-- Masami Hiramatsu
-- Masami Hiramatsu
-- Masami Hiramatsu

hi Masami,
On Thu, 10 Feb 2022 at 08:45, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
2022年2月10日(木) 10:43 Masami Hiramatsu masami.hiramatsu@linaro.org:
Of course as I said in the other thread, I would like to put the dfu_alt_info like information in the devicetree too. (But it maybe different from this discussion)
Just curious, why do you need to define a variable like dfu_alt_info in a device tree. If this has already been described earlier, you can point me to that discussion. Trying to understand what benefit does having the variables defined in a device tree brings. Thanks.
If we can consolidate the configuration information related to the firmware layout on the devicetree, it is very easy to understand and manage the firmware update only by checking the devicetree. Current design is very fragile from the consistency viewpoint, because there are 3 different information we are using for FWU, Kconfig, devicetree and u-boot env-variables. If one of them sets inconsistent value, FWU may not work as we expected.
I get your point. But I think generating the dfu_alt_info at runtime, like how it is done for the ST platforms is in general a better method, as against using a static variable defined in the device tree.
Yeah, the GPT based one is able to store this information on the GPT, and it must be a primary definition.
With runtime generation of the variable, the same code can be used on multiple platforms and can be generated at runtime -- I feel that is better than defining the variable in every platform's device tree.
I don't agree this point at least for non-GPT devices, since the firmware storage layout depends on the platform hardware configuration statically in such cases.
I changed my mind, it can be solved if we have "uuid" property for each partition in the devicetree. I will explain later.
Of course if the device uses GPT to store the firmware, we have to follow the GPT layout and FWU Metadata to find the corresponding firmware partition.
Btw, there is also provision to define the variable(or part of it) statically through Kconfig variables. As against your concern about the feature using multiple methods for stating information, it is indeed valid. But I guess we can have documentation explaining how each of that information needs to be defined. Thanks.
Yeah, even using GPT, we need to set correct UUID to the FWU metadata, and the metadata depends on Kconfig if we keep putting the #of images-per-bank and the #of banks in the Kconfig, and storage
Sorry, I confused. there are "#of images and #of banks per image".
(controller) is defined in the devicetree.
And I still feel this "chain of definitions" seems a bit fragile. This fragile comes from the FWU metadata is not enough self-described (it has no the #of images-per-bank and the #of banks, without this information we can not decode FWU metadata itself.) Anyway, if we can define the #of images-per-bank and the #of banks in the devicetree, we don't need to change the binary but just changing the devicetree for the different products which has different firmware layout. I think that is more flexible.
Do you really feel that using config values for #banks and #images_per_bank is such a bad idea. With the approach that you suggest, we will have to use variable sized arrays, and populate the values in the probe function of every driver. Also, since you are going to use the same fwu_mdata.h header in your other project, will you be able to use variable sized arrays there as well. I feel that we are complicating things without much benefits.
What I would like to suggest is
/* For GPT BLK backend */ fwu_mdata { compatible = "u-boot,fwu-mdata-gpt"; fwu-mdata-store = <&mmc1>; /* No need to specify the mdata partition, because it finds the mdata by partition type uuid. */ banks = <2>; images-per-bank = <1>; };
/* For SF backend */ fwu_mdata { compatible = "u-boot,fwu-mdata-sf"; fwu-mdata-store = <&spi-flash0>; mdata-offsets = <500000, 520000>; /* Or specified by partition label? */ banks = <6>; images-per-bank = <1>; };
Looks good overall. Should the mdata-offsets property be instead mdata-parts, where we define the start offset and size of the metadata partitions. Or are we going to figure out the size of the metadata partition through some other mechanism.
Also, do are using a different compatible string for every type of storage device type. Can we not do with a common string instead? I understand your reasoning here, of trying to identify the driver at runtime. Just that I wonder if we are going to build multiple drivers for a platform. Although I do not have a strong opinion on this.
Note that this is only for the metadata, the real firmware layout issue still exists. If we can add "uuid" property for the fixed-partitions node as a additional property, e.g.
spi-flash@0 { partitions { compatible = "fixed-partitions"; ... uuid = "aaaaaaaa-bbbb-cccc-dddd-eeeeffffgggg"; ... partition@600000 { label = "Firmware-Bank0"; reg = <600000, 400000>; uuid = "12345678-aaaa-bbbb-cccc-0123456789ab"; }; ... }; };
Then we can decode the real fwu-mdata and find corresponding partitions, and able to build dfu_alt_info in runtime.
This is a sound idea. With this method, we can still use the GUIDs in the metadata structure, and map those with the partitions using the above nodes. Only question is, are these partition nodes(partition@600000) standard, and are defined for all platforms, for all type of devices(like NOR, Nand). If so, this scheme will work.
-sughosh
What would you think?
Thank you,
Thank you,
-sughosh
That is my impression felt from porting AB update on the DeveloperBox platform.
Thank you,
-sughosh
Thank you,
> + ret = 0; > + } > + } > + > + return ret; > +} > + > +static int fwu_mdata_gpt_blk_probe(struct udevice *dev) > +{ > + int ret; > + struct udevice *mdata_dev = NULL; > + > + ret = fwu_get_mdata_device(&mdata_dev); > + if (ret) > + return ret; > + > + dev_set_priv(dev, mdata_dev); > + > + return 0; > +} > + > +static const struct fwu_mdata_ops fwu_gpt_blk_ops = { > + .get_image_alt_num = fwu_gpt_get_image_alt_num, > + .mdata_check = fwu_gpt_mdata_check, > + .get_mdata = fwu_gpt_get_mdata, > + .update_mdata = fwu_gpt_update_mdata, > +}; > + > +static const struct udevice_id fwu_mdata_ids[] = { > + { .compatible = "u-boot,fwu-mdata" },
> + { } > +}; > + > +U_BOOT_DRIVER(fwu_mdata_gpt_blk) = { > + .name = "fwu-mdata-gpt-blk", > + .id = UCLASS_FWU_MDATA, > + .of_match = fwu_mdata_ids, > + .ops = &fwu_gpt_blk_ops, > + .probe = fwu_mdata_gpt_blk_probe, > +}; > diff --git a/include/fwu.h b/include/fwu.h > index 5a99c579fc..2c7db2dff9 100644 > --- a/include/fwu.h > +++ b/include/fwu.h > @@ -43,6 +43,8 @@ int fwu_get_active_index(u32 *active_idx); > int fwu_update_active_index(u32 active_idx); > int fwu_get_image_alt_num(efi_guid_t image_type_id, u32 update_bank, > int *alt_num); > +int fwu_get_mdata_device(struct udevice **mdata_dev); > +int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part); > int fwu_mdata_check(void); > int fwu_revert_boot_index(void); > int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); > -- > 2.17.1 >
-- Masami Hiramatsu
-- Masami Hiramatsu
-- Masami Hiramatsu
-- Masami Hiramatsu

Hi Sughosh,
2022年2月10日(木) 21:25 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Thu, 10 Feb 2022 at 08:45, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
2022年2月10日(木) 10:43 Masami Hiramatsu masami.hiramatsu@linaro.org:
> Of course as I said in the other thread, I would like to put the > dfu_alt_info like information in the devicetree too. > (But it maybe different from this discussion)
Just curious, why do you need to define a variable like dfu_alt_info in a device tree. If this has already been described earlier, you can point me to that discussion. Trying to understand what benefit does having the variables defined in a device tree brings. Thanks.
If we can consolidate the configuration information related to the firmware layout on the devicetree, it is very easy to understand and manage the firmware update only by checking the devicetree. Current design is very fragile from the consistency viewpoint, because there are 3 different information we are using for FWU, Kconfig, devicetree and u-boot env-variables. If one of them sets inconsistent value, FWU may not work as we expected.
I get your point. But I think generating the dfu_alt_info at runtime, like how it is done for the ST platforms is in general a better method, as against using a static variable defined in the device tree.
Yeah, the GPT based one is able to store this information on the GPT, and it must be a primary definition.
With runtime generation of the variable, the same code can be used on multiple platforms and can be generated at runtime -- I feel that is better than defining the variable in every platform's device tree.
I don't agree this point at least for non-GPT devices, since the firmware storage layout depends on the platform hardware configuration statically in such cases.
I changed my mind, it can be solved if we have "uuid" property for each partition in the devicetree. I will explain later.
Of course if the device uses GPT to store the firmware, we have to follow the GPT layout and FWU Metadata to find the corresponding firmware partition.
Btw, there is also provision to define the variable(or part of it) statically through Kconfig variables. As against your concern about the feature using multiple methods for stating information, it is indeed valid. But I guess we can have documentation explaining how each of that information needs to be defined. Thanks.
Yeah, even using GPT, we need to set correct UUID to the FWU metadata, and the metadata depends on Kconfig if we keep putting the #of images-per-bank and the #of banks in the Kconfig, and storage
Sorry, I confused. there are "#of images and #of banks per image".
(controller) is defined in the devicetree.
And I still feel this "chain of definitions" seems a bit fragile. This fragile comes from the FWU metadata is not enough self-described (it has no the #of images-per-bank and the #of banks, without this information we can not decode FWU metadata itself.) Anyway, if we can define the #of images-per-bank and the #of banks in the devicetree, we don't need to change the binary but just changing the devicetree for the different products which has different firmware layout. I think that is more flexible.
Do you really feel that using config values for #banks and #images_per_bank is such a bad idea. With the approach that you suggest, we will have to use variable sized arrays, and populate the values in the probe function of every driver. Also, since you are going to use the same fwu_mdata.h header in your other project, will you be able to use variable sized arrays there as well. I feel that we are complicating things without much benefits.
Hm, indeed. It may make us to handle the metadata as a single data structure on memory. We may need allocate several objects (and arrays) and decode/encode the data from/to storage device. OK, then let those parameters keep in the kconfig.
What I would like to suggest is
/* For GPT BLK backend */ fwu_mdata { compatible = "u-boot,fwu-mdata-gpt"; fwu-mdata-store = <&mmc1>; /* No need to specify the mdata partition, because it finds the mdata by partition type uuid. */ banks = <2>; images-per-bank = <1>; };
/* For SF backend */ fwu_mdata { compatible = "u-boot,fwu-mdata-sf"; fwu-mdata-store = <&spi-flash0>; mdata-offsets = <500000, 520000>; /* Or specified by partition label? */ banks = <6>; images-per-bank = <1>; };
Looks good overall. Should the mdata-offsets property be instead mdata-parts, where we define the start offset and size of the metadata partitions. Or are we going to figure out the size of the metadata partition through some other mechanism.
mdata-parts may only need the label names, since we can find the partition by name. The partition size can be defined by partitions node. But do we really need the size? I'm reserving an enough bigger area for mdata. (And if it is NAND, we need to reserve "a page" for mdata)
Also, do are using a different compatible string for every type of storage device type. Can we not do with a common string instead? I understand your reasoning here, of trying to identify the driver at runtime. Just that I wonder if we are going to build multiple drivers for a platform. Although I do not have a strong opinion on this.
I can't imagine the case that a platform has different mdata store at the same time... Anyway, as you said, we need the different compatible strings for different drivers.
Note that this is only for the metadata, the real firmware layout issue still exists. If we can add "uuid" property for the fixed-partitions node as a additional property, e.g.
spi-flash@0 { partitions { compatible = "fixed-partitions"; ... uuid = "aaaaaaaa-bbbb-cccc-dddd-eeeeffffgggg"; ... partition@600000 { label = "Firmware-Bank0"; reg = <600000, 400000>; uuid = "12345678-aaaa-bbbb-cccc-0123456789ab"; }; ... }; };
Then we can decode the real fwu-mdata and find corresponding partitions, and able to build dfu_alt_info in runtime.
This is a sound idea. With this method, we can still use the GUIDs in the metadata structure, and map those with the partitions using the above nodes. Only question is, are these partition nodes(partition@600000) standard, and are defined for all platforms, for all type of devices(like NOR, Nand). If so, this scheme will work.
Yes, as far as I know, now mtd subsystem requires to define the partitions by the devicetree, and that is acceptable both U-Boot and Linux. You can find the "fixed-partitions" definition in the Linux dt-bindings.
https://www.kernel.org/doc/Documentation/devicetree/bindings/mtd/partitions/...
I think we can add uuid because there is "additionalProperties: true".
We need the image-type-id uuid, but we can get it from fwu mdata.
Thus, the boot sequence will be 1. parse devicetree. 2. probe fwu-mdata driver and load mdata. 3. platform driver builds dfu_alt_info according to the mdata. a. read mdata and identify the partitions ofnode by location uuid. b. find partition ofnodes by image-uuid. c. build dfu-alt-info by the ofnodes information. d. build guid-array by mdata's image-type uuid.
Thank you,
-- Masami Hiramatsu

Add helper functions needed for accessing the FWU metadata which contains information on the updatable images. These functions have been added for the STM32MP157C-DK2 board which has the updatable images on the uSD card, formatted as GPT partitions.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org ---
Changes since V3: * Remove function for getting the storage device containing the metadata as the information is now obtained from the device tree.
board/st/stm32mp1/stm32mp1.c | 78 ++++++++++++++++++++++++++++++++++++ include/fwu.h | 3 ++ 2 files changed, 81 insertions(+)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 84592677e4..5e8cb29067 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -7,10 +7,13 @@
#include <common.h> #include <adc.h> +#include <blk.h> #include <bootm.h> #include <clk.h> #include <config.h> +#include <dfu.h> #include <dm.h> +#include <efi_loader.h> #include <env.h> #include <env_internal.h> #include <fdt_support.h> @@ -23,9 +26,11 @@ #include <log.h> #include <malloc.h> #include <misc.h> +#include <mmc.h> #include <mtd_node.h> #include <net.h> #include <netdev.h> +#include <part.h> #include <phy.h> #include <remoteproc.h> #include <reset.h> @@ -938,3 +943,76 @@ static void board_copro_image_process(ulong fw_image, size_t fw_size) }
U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_COPRO, board_copro_image_process); + +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE) +#include <fwu.h> +#include <fwu_mdata.h> + +static int gpt_plat_get_alt_num(int dev_num, void *identifier) +{ + int i; + int ret = -1; + u32 part; + int alt_num = dfu_get_alt_number(); + struct dfu_entity *dfu; + + part = *(u32 *)identifier; + dfu_init_env_entities(NULL, NULL); + + for (i = 0; i < alt_num; i++) { + dfu = dfu_get_entity(i); + + if (!dfu) + continue; + + /* + * Currently, Multi Bank update + * feature is being supported + * only on GPT partitioned + * MMC/SD devices. + */ + if (dfu->dev_type != DFU_DEV_MMC) + continue; + + if (dfu->layout == DFU_RAW_ADDR && + dfu->data.mmc.dev_num == dev_num && + dfu->data.mmc.part == part) { + ret = dfu->alt; + break; + } + } + + dfu_free_entities(); + + return ret; +} + +int fwu_plat_get_alt_num(struct udevice *dev, void *identifier) +{ + struct blk_desc *desc; + + desc = dev_get_uclass_plat(dev); + if (!desc) { + log_err("Block device not found\n"); + return -ENODEV; + } + + return gpt_plat_get_alt_num(desc->devnum, identifier); +} + +int fwu_plat_get_update_index(u32 *update_idx) +{ + int ret; + u32 active_idx; + + ret = fwu_get_active_index(&active_idx); + + if (ret < 0) + return -1; + + *update_idx = active_idx ^= 0x1; + + return ret; +} + +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */ diff --git a/include/fwu.h b/include/fwu.h index 2c7db2dff9..b746e616b2 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -50,4 +50,7 @@ int fwu_revert_boot_index(void); int fwu_accept_image(efi_guid_t *img_type_id, u32 bank); int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank);
+int fwu_plat_get_update_index(u32 *update_idx); +int fwu_plat_get_alt_num(struct udevice *dev, void *identifier); + #endif /* _FWU_H_ */

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 ---
Changes since V3: None
board/st/stm32mp1/stm32mp1.c | 6 ++++++ include/fwu.h | 1 + 2 files changed, 7 insertions(+)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 5e8cb29067..5525b69392 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -1015,4 +1015,10 @@ int fwu_plat_get_update_index(u32 *update_idx) return ret; }
+void fwu_plat_get_bootidx(void *boot_idx) +{ + u32 *bootidx = boot_idx; + + *bootidx = readl(TAMP_BOOTCOUNT); +} #endif /* CONFIG_FWU_MULTI_BANK_UPDATE */ diff --git a/include/fwu.h b/include/fwu.h index b746e616b2..90b8cd41e5 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -52,5 +52,6 @@ int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank);
int fwu_plat_get_update_index(u32 *update_idx); int fwu_plat_get_alt_num(struct udevice *dev, void *identifier); +void fwu_plat_get_bootidx(void *boot_idx);
#endif /* _FWU_H_ */

The FWU Multi Banks Update feature allows updating different types of updatable firmware images on the platform. These image types are identified using the ImageTypeId GUID value. Add support in the GetImageInfo function of the FMP protocol to get the GUID values for the individual images and populate these in the image descriptor for the corresponding images.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org ---
Changes since V3: * Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs
include/efi_loader.h | 2 + lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h index f4860e87fc..ae60de0be5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); efi_status_t efi_load_capsule_drivers(void);
efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid, + efi_guid_t **part_guid_arr); #endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..5642be9f9a 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid, + efi_guid_t **part_guid_arr) +{ + int i; + int dfu_num = 0; + efi_guid_t *guid_arr; + struct dfu_entity *dfu; + efi_status_t ret = EFI_SUCCESS; + + dfu_init_env_entities(NULL, NULL); + + dfu_num = 0; + list_for_each_entry(dfu, &dfu_list, list) { + dfu_num++; + } + + if (!dfu_num) { + log_warning("Probably dfu_alt_info not defined\n"); + ret = EFI_NOT_READY; + goto out; + } + + *part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num); + if (!*part_guid_arr) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + + guid_arr = *part_guid_arr; + for (i = 0; i < dfu_num; i++) { + guidcpy(guid_arr, guid); + ++guid_arr; + } + +out: + dfu_free_entities(); + + return ret; +} + /** * efi_get_dfu_info - return information about the current firmware image * @this: Protocol instance @@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( * @descriptor_version: Pointer to version number * @descriptor_count: Pointer to number of descriptors * @descriptor_size: Pointer to descriptor size - * package_version: Package version - * package_version_name: Package version's name - * image_type: Image type GUID + * @package_version: Package version + * @package_version_name: Package version's name + * @guid_array: Image type GUID array * * Return information bout the current firmware image in @image_info. * @image_info will consist of a number of descriptors. @@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( efi_uintn_t *descriptor_size, u32 *package_version, u16 **package_version_name, - const efi_guid_t *image_type) + const efi_guid_t *guid_array) { struct dfu_entity *dfu; size_t names_len, total_size; @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( next = name; list_for_each_entry(dfu, &dfu_list, list) { image_info[i].image_index = dfu->alt + 1; - image_info[i].image_type_id = *image_type; + image_info[i].image_type_id = guid_array[i]; image_info[i].image_id = dfu->alt;
/* copy the DFU entity name */ @@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( u16 **package_version_name) { efi_status_t ret; + efi_guid_t *part_guid_arr = NULL;
EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info, @@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
+ ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit, + &part_guid_arr); + if (ret != EFI_SUCCESS) + goto out; + ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name, - &efi_firmware_image_type_uboot_fit); + part_guid_arr);
+out: + free(part_guid_arr); return EFI_EXIT(ret); }
@@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u16 **package_version_name) { efi_status_t ret = EFI_SUCCESS; + efi_guid_t *part_guid_arr = NULL;
EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info, @@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
+ ret = fill_image_type_guid_array( + &efi_firmware_image_type_uboot_raw, + &part_guid_arr); + if (ret != EFI_SUCCESS) + goto out; + ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name, - &efi_firmware_image_type_uboot_raw); + part_guid_arr);
+out: + free(part_guid_arr); return EFI_EXIT(ret); }

Hi Sughosh,
On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote:
The FWU Multi Banks Update feature allows updating different types of updatable firmware images on the platform. These image types are identified using the ImageTypeId GUID value. Add support in the GetImageInfo function of the FMP protocol to get the GUID values for the individual images and populate these in the image descriptor for the corresponding images.
After re-thinking of your approach here, I would have to say NAK.
You use ImageTypeId to identify a particular firmware object. (By "object," I mean one of firmware instances represented by "dfu_alto_info". Please don't confuse it with the binary blob embedded in a capsule file.) But ImageTypeId is not for that purpose, at least, as my intention in initially implementing capsule framework and FMP drivers.
1) ImageTypeId is used to uniquely identify a corresponding FMP driver, either FIT FMP driver or Raw FMP driver. 2) Each firmware object handled by a given FMP driver can further be identified by ImageIndex.
My implementation of efi_fmp_find() does (1) and Raw FMP driver does (2) in efi_firmware_raw_set_image() which takes "image_index" as a parameter.
Using ImageTypeId as an identifier is simply wrong in my opinion and doesn't meet the UEFI specification.
-Takahiro Akashi
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs
include/efi_loader.h | 2 + lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h index f4860e87fc..ae60de0be5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); efi_status_t efi_load_capsule_drivers(void);
efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid,
efi_guid_t **part_guid_arr);
#endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..5642be9f9a 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid,
efi_guid_t **part_guid_arr)
+{
- int i;
- int dfu_num = 0;
- efi_guid_t *guid_arr;
- struct dfu_entity *dfu;
- efi_status_t ret = EFI_SUCCESS;
- dfu_init_env_entities(NULL, NULL);
- dfu_num = 0;
- list_for_each_entry(dfu, &dfu_list, list) {
dfu_num++;
- }
- if (!dfu_num) {
log_warning("Probably dfu_alt_info not defined\n");
ret = EFI_NOT_READY;
goto out;
- }
- *part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num);
- if (!*part_guid_arr) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
- }
- guid_arr = *part_guid_arr;
- for (i = 0; i < dfu_num; i++) {
guidcpy(guid_arr, guid);
++guid_arr;
- }
+out:
- dfu_free_entities();
- return ret;
+}
/**
- efi_get_dfu_info - return information about the current firmware image
- @this: Protocol instance
@@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
- @descriptor_version: Pointer to version number
- @descriptor_count: Pointer to number of descriptors
- @descriptor_size: Pointer to descriptor size
- package_version: Package version
- package_version_name: Package version's name
- image_type: Image type GUID
- @package_version: Package version
- @package_version_name: Package version's name
- @guid_array: Image type GUID array
- Return information bout the current firmware image in @image_info.
- @image_info will consist of a number of descriptors.
@@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( efi_uintn_t *descriptor_size, u32 *package_version, u16 **package_version_name,
- const efi_guid_t *image_type)
- const efi_guid_t *guid_array)
{ struct dfu_entity *dfu; size_t names_len, total_size; @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( next = name; list_for_each_entry(dfu, &dfu_list, list) { image_info[i].image_index = dfu->alt + 1;
image_info[i].image_type_id = *image_type;
image_info[i].image_type_id = guid_array[i];
image_info[i].image_id = dfu->alt;
/* copy the DFU entity name */
@@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( u16 **package_version_name) { efi_status_t ret;
efi_guid_t *part_guid_arr = NULL;
EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
- ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
- if (ret != EFI_SUCCESS)
goto out;
- ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_fit);
part_guid_arr);
+out:
- free(part_guid_arr); return EFI_EXIT(ret);
}
@@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u16 **package_version_name) { efi_status_t ret = EFI_SUCCESS;
efi_guid_t *part_guid_arr = NULL;
EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
- ret = fill_image_type_guid_array(
&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
- if (ret != EFI_SUCCESS)
goto out;
- ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_raw);
part_guid_arr);
+out:
- free(part_guid_arr); return EFI_EXIT(ret);
}
-- 2.17.1

hi Takahiro,
On Thu, 10 Feb 2022 at 08:18, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote:
The FWU Multi Banks Update feature allows updating different types of updatable firmware images on the platform. These image types are identified using the ImageTypeId GUID value. Add support in the GetImageInfo function of the FMP protocol to get the GUID values for the individual images and populate these in the image descriptor for the corresponding images.
After re-thinking of your approach here, I would have to say NAK.
You use ImageTypeId to identify a particular firmware object. (By "object," I mean one of firmware instances represented by "dfu_alto_info". Please don't confuse it with the binary blob embedded in a capsule file.) But ImageTypeId is not for that purpose, at least, as my intention in initially implementing capsule framework and FMP drivers.
- ImageTypeId is used to uniquely identify a corresponding FMP driver, either FIT FMP driver or Raw FMP driver.
I believe the identification of an FMP protocol should be done by the FMP GUID, which is what is done in efi_fmp_find. The ImageTypeId is nowhere involved in this identification.
- Each firmware object handled by a given FMP driver can further be identified by ImageIndex.
My implementation of efi_fmp_find() does (1) and Raw FMP driver does (2) in efi_firmware_raw_set_image() which takes "image_index" as a parameter.
Using ImageTypeId as an identifier is simply wrong in my opinion and doesn't meet the UEFI specification.
So, as per what you are stating, all payloads under a given EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two values, the check in efi_fmp_find to compare the UpdateImageTypeId with the ImageTypeId retrieved from the image descriptor would simply fail.
I think this interpretation of the UEFI spec is incorrect, since the spec states that the ImageTypeId and the UpdateImageTypeId are fields used to identify the firmware component targeted for the update. If all values in the image descriptor array and the UpdateImageTypeId are the same, why have this field in the first place for individual images.
-sughosh
-Takahiro Akashi
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs
include/efi_loader.h | 2 + lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h index f4860e87fc..ae60de0be5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); efi_status_t efi_load_capsule_drivers(void);
efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid,
efi_guid_t **part_guid_arr);
#endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..5642be9f9a 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid,
efi_guid_t **part_guid_arr)
+{
int i;
int dfu_num = 0;
efi_guid_t *guid_arr;
struct dfu_entity *dfu;
efi_status_t ret = EFI_SUCCESS;
dfu_init_env_entities(NULL, NULL);
dfu_num = 0;
list_for_each_entry(dfu, &dfu_list, list) {
dfu_num++;
}
if (!dfu_num) {
log_warning("Probably dfu_alt_info not defined\n");
ret = EFI_NOT_READY;
goto out;
}
*part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num);
if (!*part_guid_arr) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
guid_arr = *part_guid_arr;
for (i = 0; i < dfu_num; i++) {
guidcpy(guid_arr, guid);
++guid_arr;
}
+out:
dfu_free_entities();
return ret;
+}
/**
- efi_get_dfu_info - return information about the current firmware image
- @this: Protocol instance
@@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
- @descriptor_version: Pointer to version number
- @descriptor_count: Pointer to number of descriptors
- @descriptor_size: Pointer to descriptor size
- package_version: Package version
- package_version_name: Package version's name
- image_type: Image type GUID
- @package_version: Package version
- @package_version_name: Package version's name
- @guid_array: Image type GUID array
- Return information bout the current firmware image in @image_info.
- @image_info will consist of a number of descriptors.
@@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( efi_uintn_t *descriptor_size, u32 *package_version, u16 **package_version_name,
const efi_guid_t *image_type)
const efi_guid_t *guid_array)
{ struct dfu_entity *dfu; size_t names_len, total_size; @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( next = name; list_for_each_entry(dfu, &dfu_list, list) { image_info[i].image_index = dfu->alt + 1;
image_info[i].image_type_id = *image_type;
image_info[i].image_type_id = guid_array[i]; image_info[i].image_id = dfu->alt; /* copy the DFU entity name */
@@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( u16 **package_version_name) { efi_status_t ret;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_fit);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
@@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u16 **package_version_name) { efi_status_t ret = EFI_SUCCESS;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(
&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_raw);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
-- 2.17.1

On Thu, Feb 10, 2022 at 12:48:13PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Thu, 10 Feb 2022 at 08:18, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote:
The FWU Multi Banks Update feature allows updating different types of updatable firmware images on the platform. These image types are identified using the ImageTypeId GUID value. Add support in the GetImageInfo function of the FMP protocol to get the GUID values for the individual images and populate these in the image descriptor for the corresponding images.
After re-thinking of your approach here, I would have to say NAK.
You use ImageTypeId to identify a particular firmware object. (By "object," I mean one of firmware instances represented by "dfu_alto_info". Please don't confuse it with the binary blob embedded in a capsule file.) But ImageTypeId is not for that purpose, at least, as my intention in initially implementing capsule framework and FMP drivers.
- ImageTypeId is used to uniquely identify a corresponding FMP driver, either FIT FMP driver or Raw FMP driver.
I believe the identification of an FMP protocol should be done by the FMP GUID,
What does FMP GUID stand for?
which is what is done in efi_fmp_find. The ImageTypeId is nowhere involved in this identification.
Please take a look at efi_capsule_update_firmware() carefully. efi_find_fmp() is called with the image's update_image_type_id which is to be set to EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID by mkeficapsule (see create_fwbin()).
- Each firmware object handled by a given FMP driver can further be identified by ImageIndex.
My implementation of efi_fmp_find() does (1) and Raw FMP driver does (2) in efi_firmware_raw_set_image() which takes "image_index" as a parameter.
Using ImageTypeId as an identifier is simply wrong in my opinion and doesn't meet the UEFI specification.
So, as per what you are stating, all payloads under a given EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two values, > the check in efi_fmp_find to compare the UpdateImageTypeId with the ImageTypeId retrieved from the image descriptor would simply fail.
I don't follow your point. Please elaborate a bit more.
I think this interpretation of the UEFI spec is incorrect, since the spec states that the ImageTypeId and the UpdateImageTypeId are fields used to identify the firmware component targeted for the update. If all values in the image descriptor array and the UpdateImageTypeId are the same, why have this field in the first place for individual images.
As I said, ImageIndex is for that purpose.
-Takahiro Akashi
-sughosh
-Takahiro Akashi
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs
include/efi_loader.h | 2 + lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h index f4860e87fc..ae60de0be5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); efi_status_t efi_load_capsule_drivers(void);
efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid,
efi_guid_t **part_guid_arr);
#endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..5642be9f9a 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid,
efi_guid_t **part_guid_arr)
+{
int i;
int dfu_num = 0;
efi_guid_t *guid_arr;
struct dfu_entity *dfu;
efi_status_t ret = EFI_SUCCESS;
dfu_init_env_entities(NULL, NULL);
dfu_num = 0;
list_for_each_entry(dfu, &dfu_list, list) {
dfu_num++;
}
if (!dfu_num) {
log_warning("Probably dfu_alt_info not defined\n");
ret = EFI_NOT_READY;
goto out;
}
*part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num);
if (!*part_guid_arr) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
guid_arr = *part_guid_arr;
for (i = 0; i < dfu_num; i++) {
guidcpy(guid_arr, guid);
++guid_arr;
}
+out:
dfu_free_entities();
return ret;
+}
/**
- efi_get_dfu_info - return information about the current firmware image
- @this: Protocol instance
@@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
- @descriptor_version: Pointer to version number
- @descriptor_count: Pointer to number of descriptors
- @descriptor_size: Pointer to descriptor size
- package_version: Package version
- package_version_name: Package version's name
- image_type: Image type GUID
- @package_version: Package version
- @package_version_name: Package version's name
- @guid_array: Image type GUID array
- Return information bout the current firmware image in @image_info.
- @image_info will consist of a number of descriptors.
@@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( efi_uintn_t *descriptor_size, u32 *package_version, u16 **package_version_name,
const efi_guid_t *image_type)
const efi_guid_t *guid_array)
{ struct dfu_entity *dfu; size_t names_len, total_size; @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( next = name; list_for_each_entry(dfu, &dfu_list, list) { image_info[i].image_index = dfu->alt + 1;
image_info[i].image_type_id = *image_type;
image_info[i].image_type_id = guid_array[i]; image_info[i].image_id = dfu->alt; /* copy the DFU entity name */
@@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( u16 **package_version_name) { efi_status_t ret;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_fit);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
@@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u16 **package_version_name) { efi_status_t ret = EFI_SUCCESS;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(
&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_raw);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
-- 2.17.1

On Thu, 10 Feb 2022 at 13:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Thu, Feb 10, 2022 at 12:48:13PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Thu, 10 Feb 2022 at 08:18, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote:
The FWU Multi Banks Update feature allows updating different types of updatable firmware images on the platform. These image types are identified using the ImageTypeId GUID value. Add support in the GetImageInfo function of the FMP protocol to get the GUID values for the individual images and populate these in the image descriptor for the corresponding images.
After re-thinking of your approach here, I would have to say NAK.
You use ImageTypeId to identify a particular firmware object. (By "object," I mean one of firmware instances represented by "dfu_alto_info". Please don't confuse it with the binary blob embedded in a capsule file.) But ImageTypeId is not for that purpose, at least, as my intention in initially implementing capsule framework and FMP drivers.
- ImageTypeId is used to uniquely identify a corresponding FMP driver, either FIT FMP driver or Raw FMP driver.
I believe the identification of an FMP protocol should be done by the FMP GUID,
What does FMP GUID stand for?
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID, defined in include/efi_api.h. What I mean is that even when installing the FMP protocol, the call to efi_install_multiple_protocol_interfaces takes the above FMP GUID as an argument -- nowhere is the ImageTypeId considered when installing the protocol.
which is what is done in efi_fmp_find. The ImageTypeId is nowhere involved in this identification.
Please take a look at efi_capsule_update_firmware() carefully. efi_find_fmp() is called with the image's update_image_type_id which is to be set to EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID by mkeficapsule (see create_fwbin()).
I think you are thinking from the point of view of the '--guid' value that is being passed to the capsule generation tool. But the thing is that it is the current design(or limitation) of the tool that it takes only a single guid parameter. So the mkeficapsule tool currently can generate only a single payload capsule. Please check the GenerateCapsule script in EDK2. In case of a multi payload based capsule, individual parameters like the UpdateImageTypeId are passed through the json file, where each of the UpdateImageTypeId has a different value per payload.
- Each firmware object handled by a given FMP driver can further be identified by ImageIndex.
My implementation of efi_fmp_find() does (1) and Raw FMP driver does (2) in efi_firmware_raw_set_image() which takes "image_index" as a parameter.
Using ImageTypeId as an identifier is simply wrong in my opinion and doesn't meet the UEFI specification.
So, as per what you are stating, all payloads under a given EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two values, > the check in efi_fmp_find to compare the UpdateImageTypeId with the ImageTypeId retrieved from the image descriptor would simply fail.
I don't follow your point. Please elaborate a bit more.
The current implementation of GetImageInfo, passes either of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image descriptor array. So, in case the capsule is generated with a '--guid' value which is different from these two values, the check in efi_fmp_find on line 204 will fail. This means that unless the --guid value passed to the capsule generation is either of u-boot FIT or u-boot raw, the current FMP protocol for raw devices cannot be used. Why do we need that restriction. It should be possible to use the raw FMP protocol for any other type of image types as well.
I think this interpretation of the UEFI spec is incorrect, since the spec states that the ImageTypeId and the UpdateImageTypeId are fields used to identify the firmware component targeted for the update. If all values in the image descriptor array and the UpdateImageTypeId are the same, why have this field in the first place for individual images.
As I said, ImageIndex is for that purpose.
Yes, that is one possible way in the scenario where the ImageIndex is determined at the capsule generation time. But, for the A/B update scenario, we do not know the ImageIndex at build time -- this is determined only at runtime, and is based on the bank to which the image is to be updated. Which is why I am finding out the alt_num at runtime in case the FWU Multi Bank feature is enabled. Like I said above, I do not see a reason why the current FMP protocols should be restricted to only the u-boot FIT and u-boot raw image types. It is being extended, without affecting the default non FWU behaviour.
-sughosh
-Takahiro Akashi
-sughosh
-Takahiro Akashi
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs
include/efi_loader.h | 2 + lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h index f4860e87fc..ae60de0be5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); efi_status_t efi_load_capsule_drivers(void);
efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid,
efi_guid_t **part_guid_arr);
#endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..5642be9f9a 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid,
efi_guid_t **part_guid_arr)
+{
int i;
int dfu_num = 0;
efi_guid_t *guid_arr;
struct dfu_entity *dfu;
efi_status_t ret = EFI_SUCCESS;
dfu_init_env_entities(NULL, NULL);
dfu_num = 0;
list_for_each_entry(dfu, &dfu_list, list) {
dfu_num++;
}
if (!dfu_num) {
log_warning("Probably dfu_alt_info not defined\n");
ret = EFI_NOT_READY;
goto out;
}
*part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num);
if (!*part_guid_arr) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
guid_arr = *part_guid_arr;
for (i = 0; i < dfu_num; i++) {
guidcpy(guid_arr, guid);
++guid_arr;
}
+out:
dfu_free_entities();
return ret;
+}
/**
- efi_get_dfu_info - return information about the current firmware image
- @this: Protocol instance
@@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
- @descriptor_version: Pointer to version number
- @descriptor_count: Pointer to number of descriptors
- @descriptor_size: Pointer to descriptor size
- package_version: Package version
- package_version_name: Package version's name
- image_type: Image type GUID
- @package_version: Package version
- @package_version_name: Package version's name
- @guid_array: Image type GUID array
- Return information bout the current firmware image in @image_info.
- @image_info will consist of a number of descriptors.
@@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( efi_uintn_t *descriptor_size, u32 *package_version, u16 **package_version_name,
const efi_guid_t *image_type)
const efi_guid_t *guid_array)
{ struct dfu_entity *dfu; size_t names_len, total_size; @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( next = name; list_for_each_entry(dfu, &dfu_list, list) { image_info[i].image_index = dfu->alt + 1;
image_info[i].image_type_id = *image_type;
image_info[i].image_type_id = guid_array[i]; image_info[i].image_id = dfu->alt; /* copy the DFU entity name */
@@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( u16 **package_version_name) { efi_status_t ret;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_fit);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
@@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u16 **package_version_name) { efi_status_t ret = EFI_SUCCESS;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(
&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_raw);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
-- 2.17.1

Sughosh,
On Thu, Feb 10, 2022 at 03:40:00PM +0530, Sughosh Ganu wrote:
On Thu, 10 Feb 2022 at 13:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Thu, Feb 10, 2022 at 12:48:13PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Thu, 10 Feb 2022 at 08:18, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote:
The FWU Multi Banks Update feature allows updating different types of updatable firmware images on the platform. These image types are identified using the ImageTypeId GUID value. Add support in the GetImageInfo function of the FMP protocol to get the GUID values for the individual images and populate these in the image descriptor for the corresponding images.
After re-thinking of your approach here, I would have to say NAK.
You use ImageTypeId to identify a particular firmware object. (By "object," I mean one of firmware instances represented by "dfu_alto_info". Please don't confuse it with the binary blob embedded in a capsule file.) But ImageTypeId is not for that purpose, at least, as my intention in initially implementing capsule framework and FMP drivers.
- ImageTypeId is used to uniquely identify a corresponding FMP driver, either FIT FMP driver or Raw FMP driver.
I believe the identification of an FMP protocol should be done by the FMP GUID,
What does FMP GUID stand for?
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID, defined in include/efi_api.h. What I mean is that even when installing the FMP protocol, the call to efi_install_multiple_protocol_interfaces takes the above FMP GUID as an argument -- nowhere is the ImageTypeId considered when installing the protocol.
Okay.
which is what is done in efi_fmp_find. The ImageTypeId is nowhere involved in this identification.
Please take a look at efi_capsule_update_firmware() carefully. efi_find_fmp() is called with the image's update_image_type_id which is to be set to EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID by mkeficapsule (see create_fwbin()).
I think you are thinking from the point of view of the '--guid' value that is being passed to the capsule generation tool. But the thing is that it is the current design(or limitation) of the tool that it takes only a single guid parameter. So the mkeficapsule tool currently can generate only a single payload capsule.
That is exactly what I intended to do here. We have only one FMP driver (either FIT or RAW) which is based on U-Boot's DFU framework and we need only one payload since, for multiple objects of firmware, we can use FIT format as a payload. That is what FIT is aimed for. Or you can use multiple RAW capsule files with different indexes ("--index" exists for this purpose).
Please check the GenerateCapsule script in EDK2. In case of a multi payload based capsule, individual parameters like the UpdateImageTypeId are passed through the json file, where each of the UpdateImageTypeId has a different value per payload.
- Each firmware object handled by a given FMP driver can further be identified by ImageIndex.
My implementation of efi_fmp_find() does (1) and Raw FMP driver does (2) in efi_firmware_raw_set_image() which takes "image_index" as a parameter.
Using ImageTypeId as an identifier is simply wrong in my opinion and doesn't meet the UEFI specification.
So, as per what you are stating, all payloads under a given EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two values, > the check in efi_fmp_find to compare the UpdateImageTypeId with the ImageTypeId retrieved from the image descriptor would simply fail.
I don't follow your point. Please elaborate a bit more.
The current implementation of GetImageInfo, passes either of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image descriptor array. So, in case the capsule is generated with a '--guid' value which is different from these two values, the check in efi_fmp_find on line 204 will fail.
That is an expected behavior, isn't it? If you want to use a different FMP driver (with another GUID), you naturally need to add your own FMP driver.
This means that unless the --guid value passed to the capsule generation is either of u-boot FIT or u-boot raw, the current FMP protocol for raw devices cannot be used. Why do we need that restriction. It should be possible to use the raw FMP protocol for any other type of image types as well.
I think this interpretation of the UEFI spec is incorrect, since the spec states that the ImageTypeId and the UpdateImageTypeId are fields used to identify the firmware component targeted for the update. If all values in the image descriptor array and the UpdateImageTypeId are the same, why have this field in the first place for individual images.
As I said, ImageIndex is for that purpose.
Yes, that is one possible way in the scenario where the ImageIndex is determined at the capsule generation time. But, for the A/B update scenario, we do not know the ImageIndex at build time
"Build time" of what? I think that users should know how "dfu_alt_info" is defined (in other words, where the firmware be located on the target system) when capsule files are created.
-Takahiro Akashi
-- this is determined only at runtime, and is based on the bank to which the image is to be updated. Which is why I am finding out the alt_num at runtime in case the FWU Multi Bank feature is enabled. Like I said above, I do not see a reason why the current FMP protocols should be restricted to only the u-boot FIT and u-boot raw image types. It is being extended, without affecting the default non FWU behaviour.
-sughosh
-Takahiro Akashi
-sughosh
-Takahiro Akashi
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs
include/efi_loader.h | 2 + lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h index f4860e87fc..ae60de0be5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); efi_status_t efi_load_capsule_drivers(void);
efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid,
efi_guid_t **part_guid_arr);
#endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..5642be9f9a 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid,
efi_guid_t **part_guid_arr)
+{
int i;
int dfu_num = 0;
efi_guid_t *guid_arr;
struct dfu_entity *dfu;
efi_status_t ret = EFI_SUCCESS;
dfu_init_env_entities(NULL, NULL);
dfu_num = 0;
list_for_each_entry(dfu, &dfu_list, list) {
dfu_num++;
}
if (!dfu_num) {
log_warning("Probably dfu_alt_info not defined\n");
ret = EFI_NOT_READY;
goto out;
}
*part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num);
if (!*part_guid_arr) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
guid_arr = *part_guid_arr;
for (i = 0; i < dfu_num; i++) {
guidcpy(guid_arr, guid);
++guid_arr;
}
+out:
dfu_free_entities();
return ret;
+}
/**
- efi_get_dfu_info - return information about the current firmware image
- @this: Protocol instance
@@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
- @descriptor_version: Pointer to version number
- @descriptor_count: Pointer to number of descriptors
- @descriptor_size: Pointer to descriptor size
- package_version: Package version
- package_version_name: Package version's name
- image_type: Image type GUID
- @package_version: Package version
- @package_version_name: Package version's name
- @guid_array: Image type GUID array
- Return information bout the current firmware image in @image_info.
- @image_info will consist of a number of descriptors.
@@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( efi_uintn_t *descriptor_size, u32 *package_version, u16 **package_version_name,
const efi_guid_t *image_type)
const efi_guid_t *guid_array)
{ struct dfu_entity *dfu; size_t names_len, total_size; @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( next = name; list_for_each_entry(dfu, &dfu_list, list) { image_info[i].image_index = dfu->alt + 1;
image_info[i].image_type_id = *image_type;
image_info[i].image_type_id = guid_array[i]; image_info[i].image_id = dfu->alt; /* copy the DFU entity name */
@@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( u16 **package_version_name) { efi_status_t ret;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_fit);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
@@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u16 **package_version_name) { efi_status_t ret = EFI_SUCCESS;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(
&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_raw);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
-- 2.17.1

hi Takahiro,
On Mon, 14 Feb 2022 at 08:54, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Thu, Feb 10, 2022 at 03:40:00PM +0530, Sughosh Ganu wrote:
On Thu, 10 Feb 2022 at 13:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Thu, Feb 10, 2022 at 12:48:13PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Thu, 10 Feb 2022 at 08:18, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote:
The FWU Multi Banks Update feature allows updating different types of updatable firmware images on the platform. These image types are identified using the ImageTypeId GUID value. Add support in the GetImageInfo function of the FMP protocol to get the GUID values for the individual images and populate these in the image descriptor for the corresponding images.
After re-thinking of your approach here, I would have to say NAK.
You use ImageTypeId to identify a particular firmware object. (By "object," I mean one of firmware instances represented by "dfu_alto_info". Please don't confuse it with the binary blob embedded in a capsule file.) But ImageTypeId is not for that purpose, at least, as my intention in initially implementing capsule framework and FMP drivers.
- ImageTypeId is used to uniquely identify a corresponding FMP driver, either FIT FMP driver or Raw FMP driver.
I believe the identification of an FMP protocol should be done by the FMP GUID,
What does FMP GUID stand for?
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID, defined in include/efi_api.h. What I mean is that even when installing the FMP protocol, the call to efi_install_multiple_protocol_interfaces takes the above FMP GUID as an argument -- nowhere is the ImageTypeId considered when installing the protocol.
Okay.
which is what is done in efi_fmp_find. The ImageTypeId is nowhere involved in this identification.
Please take a look at efi_capsule_update_firmware() carefully. efi_find_fmp() is called with the image's update_image_type_id which is to be set to EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID by mkeficapsule (see create_fwbin()).
I think you are thinking from the point of view of the '--guid' value that is being passed to the capsule generation tool. But the thing is that it is the current design(or limitation) of the tool that it takes only a single guid parameter. So the mkeficapsule tool currently can generate only a single payload capsule.
That is exactly what I intended to do here. We have only one FMP driver (either FIT or RAW) which is based on U-Boot's DFU framework and we need only one payload since, for multiple objects of firmware, we can use FIT format as a payload. That is what FIT is aimed for. Or you can use multiple RAW capsule files with different indexes ("--index" exists for this purpose).
Yes, we can use --index when we know the index value corresponding to the firmware image that we need to update. But like I mentioned in my earlier reply, for A/B updates, we do not know what the index value is going to be. That is going to be determined at runtime.
Also, the point I was making is that we can have a capsule which is consumed by an FMP protocol which has more than one image, and those images have different ImageTypeId/UpdateImageTypeId.
Please check the GenerateCapsule script in EDK2. In case of a multi payload based capsule, individual parameters like the UpdateImageTypeId are passed through the json file, where each of the UpdateImageTypeId has a different value per payload.
- Each firmware object handled by a given FMP driver can further be identified by ImageIndex.
My implementation of efi_fmp_find() does (1) and Raw FMP driver does (2) in efi_firmware_raw_set_image() which takes "image_index" as a parameter.
Using ImageTypeId as an identifier is simply wrong in my opinion and doesn't meet the UEFI specification.
So, as per what you are stating, all payloads under a given EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two values, > the check in efi_fmp_find to compare the UpdateImageTypeId with the ImageTypeId retrieved from the image descriptor would simply fail.
I don't follow your point. Please elaborate a bit more.
The current implementation of GetImageInfo, passes either of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image descriptor array. So, in case the capsule is generated with a '--guid' value which is different from these two values, the check in efi_fmp_find on line 204 will fail.
That is an expected behavior, isn't it?
Yes it is. Do not contest that.
If you want to use a different FMP driver (with another GUID), you naturally need to add your own FMP driver.
This is where I differ. We can use the same FMP protocol instance for any type of ImageTypeId. I do not see why we need to define a different FMP protocol instance for a GUID value other than what has been defined for u-boot raw and u-boot FIT GUIDs.
The platform can give us the image descriptor array, and with that, the same FMP instance can be used for any type of image(ImageTypeId).
This means that unless the --guid value passed to the capsule generation is either of u-boot FIT or u-boot raw, the current FMP protocol for raw devices cannot be used. Why do we need that restriction. It should be possible to use the raw FMP protocol for any other type of image types as well.
I think this interpretation of the UEFI spec is incorrect, since the spec states that the ImageTypeId and the UpdateImageTypeId are fields used to identify the firmware component targeted for the update. If all values in the image descriptor array and the UpdateImageTypeId are the same, why have this field in the first place for individual images.
As I said, ImageIndex is for that purpose.
Yes, that is one possible way in the scenario where the ImageIndex is determined at the capsule generation time. But, for the A/B update scenario, we do not know the ImageIndex at build time
"Build time" of what?
Of the capsule.
I think that users should know how "dfu_alt_info" is defined (in other words, where the firmware be located on the target system) when capsule files are created.
That is true for a non A/B scenario. And that is how it works in the non A/B updates case. But for A/B updates, since the determination of the "location" where the firmware image has to be written will be done only at runtime, we cannot use the --index to differentiate.
Like I mentioned earlier, this is not breaking the existing behaviour -- for the non A/B updates, the update procedure remains exactly the same, of using the index value to determine the location of the update. I have only extended the behaviour to use the same FMP instance for the A/B update(FWU) feature using ImageTypeId's.
-sughosh
-Takahiro Akashi
-- this is determined only at runtime, and is based on the bank to which the image is to be updated. Which is why I am finding out the alt_num at runtime in case the FWU Multi Bank feature is enabled. Like I said above, I do not see a reason why the current FMP protocols should be restricted to only the u-boot FIT and u-boot raw image types. It is being extended, without affecting the default non FWU behaviour.
-sughosh
-Takahiro Akashi
-sughosh
-Takahiro Akashi
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs
include/efi_loader.h | 2 + lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h index f4860e87fc..ae60de0be5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); efi_status_t efi_load_capsule_drivers(void);
efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid,
efi_guid_t **part_guid_arr);
#endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..5642be9f9a 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid,
efi_guid_t **part_guid_arr)
+{
int i;
int dfu_num = 0;
efi_guid_t *guid_arr;
struct dfu_entity *dfu;
efi_status_t ret = EFI_SUCCESS;
dfu_init_env_entities(NULL, NULL);
dfu_num = 0;
list_for_each_entry(dfu, &dfu_list, list) {
dfu_num++;
}
if (!dfu_num) {
log_warning("Probably dfu_alt_info not defined\n");
ret = EFI_NOT_READY;
goto out;
}
*part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num);
if (!*part_guid_arr) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
guid_arr = *part_guid_arr;
for (i = 0; i < dfu_num; i++) {
guidcpy(guid_arr, guid);
++guid_arr;
}
+out:
dfu_free_entities();
return ret;
+}
/**
- efi_get_dfu_info - return information about the current firmware image
- @this: Protocol instance
@@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
- @descriptor_version: Pointer to version number
- @descriptor_count: Pointer to number of descriptors
- @descriptor_size: Pointer to descriptor size
- package_version: Package version
- package_version_name: Package version's name
- image_type: Image type GUID
- @package_version: Package version
- @package_version_name: Package version's name
- @guid_array: Image type GUID array
- Return information bout the current firmware image in @image_info.
- @image_info will consist of a number of descriptors.
@@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( efi_uintn_t *descriptor_size, u32 *package_version, u16 **package_version_name,
const efi_guid_t *image_type)
const efi_guid_t *guid_array)
{ struct dfu_entity *dfu; size_t names_len, total_size; @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( next = name; list_for_each_entry(dfu, &dfu_list, list) { image_info[i].image_index = dfu->alt + 1;
image_info[i].image_type_id = *image_type;
image_info[i].image_type_id = guid_array[i]; image_info[i].image_id = dfu->alt; /* copy the DFU entity name */
@@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( u16 **package_version_name) { efi_status_t ret;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_fit);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
@@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u16 **package_version_name) { efi_status_t ret = EFI_SUCCESS;
efi_guid_t *part_guid_arr = NULL; EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, image_info,
@@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
ret = fill_image_type_guid_array(
&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
ret = efi_get_dfu_info(image_info_size, image_info, descriptor_version, descriptor_count, descriptor_size, package_version, package_version_name,
&efi_firmware_image_type_uboot_raw);
part_guid_arr);
+out:
free(part_guid_arr); return EFI_EXIT(ret);
}
-- 2.17.1

Sughosh,
On Mon, Feb 14, 2022 at 11:12:22AM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Mon, 14 Feb 2022 at 08:54, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Thu, Feb 10, 2022 at 03:40:00PM +0530, Sughosh Ganu wrote:
On Thu, 10 Feb 2022 at 13:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Thu, Feb 10, 2022 at 12:48:13PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Thu, 10 Feb 2022 at 08:18, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote: > The FWU Multi Banks Update feature allows updating different types of > updatable firmware images on the platform. These image types are > identified using the ImageTypeId GUID value. Add support in the > GetImageInfo function of the FMP protocol to get the GUID values for > the individual images and populate these in the image descriptor for > the corresponding images.
After re-thinking of your approach here, I would have to say NAK.
You use ImageTypeId to identify a particular firmware object. (By "object," I mean one of firmware instances represented by "dfu_alto_info". Please don't confuse it with the binary blob embedded in a capsule file.) But ImageTypeId is not for that purpose, at least, as my intention in initially implementing capsule framework and FMP drivers.
- ImageTypeId is used to uniquely identify a corresponding FMP driver, either FIT FMP driver or Raw FMP driver.
I believe the identification of an FMP protocol should be done by the FMP GUID,
What does FMP GUID stand for?
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID, defined in include/efi_api.h. What I mean is that even when installing the FMP protocol, the call to efi_install_multiple_protocol_interfaces takes the above FMP GUID as an argument -- nowhere is the ImageTypeId considered when installing the protocol.
Okay.
which is what is done in efi_fmp_find. The ImageTypeId is nowhere involved in this identification.
Please take a look at efi_capsule_update_firmware() carefully. efi_find_fmp() is called with the image's update_image_type_id which is to be set to EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID by mkeficapsule (see create_fwbin()).
I think you are thinking from the point of view of the '--guid' value that is being passed to the capsule generation tool. But the thing is that it is the current design(or limitation) of the tool that it takes only a single guid parameter. So the mkeficapsule tool currently can generate only a single payload capsule.
That is exactly what I intended to do here. We have only one FMP driver (either FIT or RAW) which is based on U-Boot's DFU framework and we need only one payload since, for multiple objects of firmware, we can use FIT format as a payload. That is what FIT is aimed for. Or you can use multiple RAW capsule files with different indexes ("--index" exists for this purpose).
Yes, we can use --index when we know the index value corresponding to the firmware image that we need to update. But like I mentioned in my earlier reply, for A/B updates, we do not know what the index value is going to be. That is going to be determined at runtime.
I don't think so. See below for alternative approach.
Also, the point I was making is that we can have a capsule which is consumed by an FMP protocol which has more than one image, and those images have different ImageTypeId/UpdateImageTypeId.
Yes, but it is a design choice in my first implementation. I didn't think that we need to "have a capsule which is consumed by an FMP protocol which has more than one image" as long as we use DFU framework (and FIT as standard format of aggregation on U-Boot).
Please check the GenerateCapsule script in EDK2. In case of a multi payload based capsule, individual parameters like the UpdateImageTypeId are passed through the json file, where each of the UpdateImageTypeId has a different value per payload.
- Each firmware object handled by a given FMP driver can further be identified by ImageIndex.
My implementation of efi_fmp_find() does (1) and Raw FMP driver does (2) in efi_firmware_raw_set_image() which takes "image_index" as a parameter.
Using ImageTypeId as an identifier is simply wrong in my opinion and doesn't meet the UEFI specification.
So, as per what you are stating, all payloads under a given EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two values, > the check in efi_fmp_find to compare the UpdateImageTypeId with the ImageTypeId retrieved from the image descriptor would simply fail.
I don't follow your point. Please elaborate a bit more.
The current implementation of GetImageInfo, passes either of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image descriptor array. So, in case the capsule is generated with a '--guid' value which is different from these two values, the check in efi_fmp_find on line 204 will fail.
That is an expected behavior, isn't it?
Yes it is. Do not contest that.
If you want to use a different FMP driver (with another GUID), you naturally need to add your own FMP driver.
This is where I differ. We can use the same FMP protocol instance for any type of ImageTypeId. I do not see why we need to define a different FMP protocol instance for a GUID value other than what has been defined for u-boot raw and u-boot FIT GUIDs.
I do understand part of your concern a bit. I thought of using the same ImageType GUID, say IMAGE_TYPE_DFU_GUID, at first but we needed different GUIDs here simply because we need to determine the format of payload, FIT format or raw binary.
The platform can give us the image descriptor array, and with that, the same FMP instance can be used for any type of image(ImageTypeId).
"any type of image"? Really?
This means that unless the --guid value passed to the capsule generation is either of u-boot FIT or u-boot raw, the current FMP protocol for raw devices cannot be used. Why do we need that restriction. It should be possible to use the raw FMP protocol for any other type of image types as well.
I think this interpretation of the UEFI spec is incorrect, since the spec states that the ImageTypeId and the UpdateImageTypeId are fields used to identify the firmware component targeted for the update. If all values in the image descriptor array and the UpdateImageTypeId are the same, why have this field in the first place for individual images.
As I said, ImageIndex is for that purpose.
Yes, that is one possible way in the scenario where the ImageIndex is determined at the capsule generation time. But, for the A/B update scenario, we do not know the ImageIndex at build time
"Build time" of what?
Of the capsule.
I think that users should know how "dfu_alt_info" is defined (in other words, where the firmware be located on the target system) when capsule files are created.
That is true for a non A/B scenario. And that is how it works in the non A/B updates case. But for A/B updates, since the determination of the "location" where the firmware image has to be written will be done only at runtime, we cannot use the --index to differentiate.
Yes, we can :)
First of all, my essential assumption in either FIT or RAW FMP driver is that U-Boot has (somehow conceptually) single firmware blob represented by DFU or dfu_alt_info. As I said, each object or location in dfu_alt_info can be further identified by index or "UpdateImageIndex".
Let's assume that we have two locations of firmware, fw1 and fw2, and that we have two bank A and B. Then we will define dfu_alt_info as follows: <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; |<--- 1st set --->|<--- 2nd set --->|
When you want to update bank A, we can use the first set of dfu_alt_info, and use the second set of dfu_alt_info for bank B. At runtime, you should know which bank you're working on, and therefore you should know the exact physical location from dfu_alt_info.
Please note that you don't have to change the syntax of dfu_alt_info at all. Simply offset the location with 0 for bank A and with 2 for bank B.
I don't think we need to introduce extra GUIDs.
-Takahiro Akashi
Like I mentioned earlier, this is not breaking the existing behaviour -- for the non A/B updates, the update procedure remains exactly the same, of using the index value to determine the location of the update. I have only extended the behaviour to use the same FMP instance for the A/B update(FWU) feature using ImageTypeId's.
-sughosh
-Takahiro Akashi
-- this is determined only at runtime, and is based on the bank to which the image is to be updated. Which is why I am finding out the alt_num at runtime in case the FWU Multi Bank feature is enabled. Like I said above, I do not see a reason why the current FMP protocols should be restricted to only the u-boot FIT and u-boot raw image types. It is being extended, without affecting the default non FWU behaviour.
-sughosh
-Takahiro Akashi
-sughosh
-Takahiro Akashi
> Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > --- > > Changes since V3: > * Define a weak function fill_image_type_guid_array for populating the > image descriptor array with u-boot's raw and fit image GUIDs > > include/efi_loader.h | 2 + > lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- > 2 files changed, 66 insertions(+), 7 deletions(-) > > diff --git a/include/efi_loader.h b/include/efi_loader.h > index f4860e87fc..ae60de0be5 100644 > --- a/include/efi_loader.h > +++ b/include/efi_loader.h > @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); > efi_status_t efi_load_capsule_drivers(void); > > efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); > +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid, > + efi_guid_t **part_guid_arr); > #endif /* _EFI_LOADER_H */ > diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c > index a1b88dbfc2..5642be9f9a 100644 > --- a/lib/efi_loader/efi_firmware.c > +++ b/lib/efi_loader/efi_firmware.c > @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( > return EFI_EXIT(EFI_UNSUPPORTED); > } > > +efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid, > + efi_guid_t **part_guid_arr) > +{ > + int i; > + int dfu_num = 0; > + efi_guid_t *guid_arr; > + struct dfu_entity *dfu; > + efi_status_t ret = EFI_SUCCESS; > + > + dfu_init_env_entities(NULL, NULL); > + > + dfu_num = 0; > + list_for_each_entry(dfu, &dfu_list, list) { > + dfu_num++; > + } > + > + if (!dfu_num) { > + log_warning("Probably dfu_alt_info not defined\n"); > + ret = EFI_NOT_READY; > + goto out; > + } > + > + *part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num); > + if (!*part_guid_arr) { > + ret = EFI_OUT_OF_RESOURCES; > + goto out; > + } > + > + guid_arr = *part_guid_arr; > + for (i = 0; i < dfu_num; i++) { > + guidcpy(guid_arr, guid); > + ++guid_arr; > + } > + > +out: > + dfu_free_entities(); > + > + return ret; > +} > + > /** > * efi_get_dfu_info - return information about the current firmware image > * @this: Protocol instance > @@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( > * @descriptor_version: Pointer to version number > * @descriptor_count: Pointer to number of descriptors > * @descriptor_size: Pointer to descriptor size > - * package_version: Package version > - * package_version_name: Package version's name > - * image_type: Image type GUID > + * @package_version: Package version > + * @package_version_name: Package version's name > + * @guid_array: Image type GUID array > * > * Return information bout the current firmware image in @image_info. > * @image_info will consist of a number of descriptors. > @@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( > efi_uintn_t *descriptor_size, > u32 *package_version, > u16 **package_version_name, > - const efi_guid_t *image_type) > + const efi_guid_t *guid_array) > { > struct dfu_entity *dfu; > size_t names_len, total_size; > @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( > next = name; > list_for_each_entry(dfu, &dfu_list, list) { > image_info[i].image_index = dfu->alt + 1; > - image_info[i].image_type_id = *image_type; > + image_info[i].image_type_id = guid_array[i]; > image_info[i].image_id = dfu->alt; > > /* copy the DFU entity name */ > @@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( > u16 **package_version_name) > { > efi_status_t ret; > + efi_guid_t *part_guid_arr = NULL; > > EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, > image_info_size, image_info, > @@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( > !descriptor_size || !package_version || !package_version_name)) > return EFI_EXIT(EFI_INVALID_PARAMETER); > > + ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit, > + &part_guid_arr); > + if (ret != EFI_SUCCESS) > + goto out; > + > ret = efi_get_dfu_info(image_info_size, image_info, > descriptor_version, descriptor_count, > descriptor_size, > package_version, package_version_name, > - &efi_firmware_image_type_uboot_fit); > + part_guid_arr); > > +out: > + free(part_guid_arr); > return EFI_EXIT(ret); > } > > @@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( > u16 **package_version_name) > { > efi_status_t ret = EFI_SUCCESS; > + efi_guid_t *part_guid_arr = NULL; > > EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, > image_info_size, image_info, > @@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( > !descriptor_size || !package_version || !package_version_name)) > return EFI_EXIT(EFI_INVALID_PARAMETER); > > + ret = fill_image_type_guid_array( > + &efi_firmware_image_type_uboot_raw, > + &part_guid_arr); > + if (ret != EFI_SUCCESS) > + goto out; > + > ret = efi_get_dfu_info(image_info_size, image_info, > descriptor_version, descriptor_count, > descriptor_size, > package_version, package_version_name, > - &efi_firmware_image_type_uboot_raw); > + part_guid_arr); > > +out: > + free(part_guid_arr); > return EFI_EXIT(ret); > } > > -- > 2.17.1 >

On Tue, 15 Feb 2022 at 07:21, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Mon, Feb 14, 2022 at 11:12:22AM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Mon, 14 Feb 2022 at 08:54, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Thu, Feb 10, 2022 at 03:40:00PM +0530, Sughosh Ganu wrote:
On Thu, 10 Feb 2022 at 13:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Thu, Feb 10, 2022 at 12:48:13PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Thu, 10 Feb 2022 at 08:18, AKASHI Takahiro takahiro.akashi@linaro.org wrote: > > Hi Sughosh, > > On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote: > > The FWU Multi Banks Update feature allows updating different types of > > updatable firmware images on the platform. These image types are > > identified using the ImageTypeId GUID value. Add support in the > > GetImageInfo function of the FMP protocol to get the GUID values for > > the individual images and populate these in the image descriptor for > > the corresponding images. > > After re-thinking of your approach here, I would have to say NAK. > > You use ImageTypeId to identify a particular firmware object. > (By "object," I mean one of firmware instances represented by "dfu_alto_info". > Please don't confuse it with the binary blob embedded in a capsule file.) > But ImageTypeId is not for that purpose, at least, as my intention > in initially implementing capsule framework and FMP drivers. > > 1) ImageTypeId is used to uniquely identify a corresponding FMP driver, > either FIT FMP driver or Raw FMP driver.
I believe the identification of an FMP protocol should be done by the FMP GUID,
What does FMP GUID stand for?
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID, defined in include/efi_api.h. What I mean is that even when installing the FMP protocol, the call to efi_install_multiple_protocol_interfaces takes the above FMP GUID as an argument -- nowhere is the ImageTypeId considered when installing the protocol.
Okay.
which is what is done in efi_fmp_find. The ImageTypeId is nowhere involved in this identification.
Please take a look at efi_capsule_update_firmware() carefully. efi_find_fmp() is called with the image's update_image_type_id which is to be set to EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID by mkeficapsule (see create_fwbin()).
I think you are thinking from the point of view of the '--guid' value that is being passed to the capsule generation tool. But the thing is that it is the current design(or limitation) of the tool that it takes only a single guid parameter. So the mkeficapsule tool currently can generate only a single payload capsule.
That is exactly what I intended to do here. We have only one FMP driver (either FIT or RAW) which is based on U-Boot's DFU framework and we need only one payload since, for multiple objects of firmware, we can use FIT format as a payload. That is what FIT is aimed for. Or you can use multiple RAW capsule files with different indexes ("--index" exists for this purpose).
Yes, we can use --index when we know the index value corresponding to the firmware image that we need to update. But like I mentioned in my earlier reply, for A/B updates, we do not know what the index value is going to be. That is going to be determined at runtime.
I don't think so. See below for alternative approach.
Also, the point I was making is that we can have a capsule which is consumed by an FMP protocol which has more than one image, and those images have different ImageTypeId/UpdateImageTypeId.
Yes, but it is a design choice in my first implementation. I didn't think that we need to "have a capsule which is consumed by an FMP protocol which has more than one image" as long as we use DFU framework (and FIT as standard format of aggregation on U-Boot).
But this design can be extended without any hassle, and more importantly without any regression, no? What kind of a problem does it create if the FMP can handle more than one image type.
Even as per the UEFI spec, we have the EFI_FIRMWARE_MANAGEMENT_CAPSULE header for all images to be managed by the FMP protocol which has multiple images with different UpdateImageTypeId.
Please check the GenerateCapsule script in EDK2. In case of a multi payload based capsule, individual parameters like the UpdateImageTypeId are passed through the json file, where each of the UpdateImageTypeId has a different value per payload.
> 2) Each firmware object handled by a given FMP driver can further be > identified by ImageIndex. > > My implementation of efi_fmp_find() does (1) and Raw FMP driver does > (2) in efi_firmware_raw_set_image() which takes "image_index" as > a parameter. > > Using ImageTypeId as an identifier is simply wrong in my opinion and > doesn't meet the UEFI specification.
So, as per what you are stating, all payloads under a given EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two values, > the check in efi_fmp_find to compare the UpdateImageTypeId with the ImageTypeId retrieved from the image descriptor would simply fail.
I don't follow your point. Please elaborate a bit more.
The current implementation of GetImageInfo, passes either of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image descriptor array. So, in case the capsule is generated with a '--guid' value which is different from these two values, the check in efi_fmp_find on line 204 will fail.
That is an expected behavior, isn't it?
Yes it is. Do not contest that.
If you want to use a different FMP driver (with another GUID), you naturally need to add your own FMP driver.
This is where I differ. We can use the same FMP protocol instance for any type of ImageTypeId. I do not see why we need to define a different FMP protocol instance for a GUID value other than what has been defined for u-boot raw and u-boot FIT GUIDs.
I do understand part of your concern a bit. I thought of using the same ImageType GUID, say IMAGE_TYPE_DFU_GUID, at first but we needed different GUIDs here simply because we need to determine the format of payload, FIT format or raw binary.
The platform can give us the image descriptor array, and with that, the same FMP instance can be used for any type of image(ImageTypeId).
"any type of image"? Really?
The raw FMP instance can certainly handle any type of binary payloads right. There is no restriction on what type of payload it is as long as it is all going as a single entity to a given dfu partition.
This means that unless the --guid value passed to the capsule generation is either of u-boot FIT or u-boot raw, the current FMP protocol for raw devices cannot be used. Why do we need that restriction. It should be possible to use the raw FMP protocol for any other type of image types as well.
I think this interpretation of the UEFI spec is incorrect, since the spec states that the ImageTypeId and the UpdateImageTypeId are fields used to identify the firmware component targeted for the update. If all values in the image descriptor array and the UpdateImageTypeId are the same, why have this field in the first place for individual images.
As I said, ImageIndex is for that purpose.
Yes, that is one possible way in the scenario where the ImageIndex is determined at the capsule generation time. But, for the A/B update scenario, we do not know the ImageIndex at build time
"Build time" of what?
Of the capsule.
I think that users should know how "dfu_alt_info" is defined (in other words, where the firmware be located on the target system) when capsule files are created.
That is true for a non A/B scenario. And that is how it works in the non A/B updates case. But for A/B updates, since the determination of the "location" where the firmware image has to be written will be done only at runtime, we cannot use the --index to differentiate.
Yes, we can :)
You know what I mean -- if we could use the same logic, I would not have added all that code :)
First of all, my essential assumption in either FIT or RAW FMP driver is that U-Boot has (somehow conceptually) single firmware blob represented by DFU or dfu_alt_info. As I said, each object or location in dfu_alt_info can be further identified by index or "UpdateImageIndex".
Let's assume that we have two locations of firmware, fw1 and fw2, and that we have two bank A and B. Then we will define dfu_alt_info as follows: <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; |<--- 1st set --->|<--- 2nd set --->|
When you want to update bank A, we can use the first set of dfu_alt_info, and use the second set of dfu_alt_info for bank B. At runtime, you should know which bank you're working on, and therefore you should know the exact physical location from dfu_alt_info.
Please note that you don't have to change the syntax of dfu_alt_info at all. Simply offset the location with 0 for bank A and with 2 for bank B.
We can use this logic yes. But please note, that with this, we need to a) Keep a definite order of the images in all the banks, and b) Know the order of the images.
With the way the FWU metadata is designed, we do not have these restrictions -- the firmware images can be placed on the device in any order, irrespective of the bank that they belong to. One might prefer clubbing images of a given bank together, but that is not the restriction put by the FWU spec. That is because the images are being identified using image GUIDs.
I really don't get your opposition to extending the current design. I would like to hear from Heinrich or Ilias on what their thoughts are on this.
-sughosh
I don't think we need to introduce extra GUIDs.
-Takahiro Akashi
Like I mentioned earlier, this is not breaking the existing behaviour -- for the non A/B updates, the update procedure remains exactly the same, of using the index value to determine the location of the update. I have only extended the behaviour to use the same FMP instance for the A/B update(FWU) feature using ImageTypeId's.
-sughosh
-Takahiro Akashi
-- this is determined only at runtime, and is based on the bank to which the image is to be updated. Which is why I am finding out the alt_num at runtime in case the FWU Multi Bank feature is enabled. Like I said above, I do not see a reason why the current FMP protocols should be restricted to only the u-boot FIT and u-boot raw image types. It is being extended, without affecting the default non FWU behaviour.
-sughosh
-Takahiro Akashi
-sughosh
> > -Takahiro Akashi > > > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > > --- > > > > Changes since V3: > > * Define a weak function fill_image_type_guid_array for populating the > > image descriptor array with u-boot's raw and fit image GUIDs > > > > include/efi_loader.h | 2 + > > lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- > > 2 files changed, 66 insertions(+), 7 deletions(-) > > > > diff --git a/include/efi_loader.h b/include/efi_loader.h > > index f4860e87fc..ae60de0be5 100644 > > --- a/include/efi_loader.h > > +++ b/include/efi_loader.h > > @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); > > efi_status_t efi_load_capsule_drivers(void); > > > > efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); > > +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid, > > + efi_guid_t **part_guid_arr); > > #endif /* _EFI_LOADER_H */ > > diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c > > index a1b88dbfc2..5642be9f9a 100644 > > --- a/lib/efi_loader/efi_firmware.c > > +++ b/lib/efi_loader/efi_firmware.c > > @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( > > return EFI_EXIT(EFI_UNSUPPORTED); > > } > > > > +efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid, > > + efi_guid_t **part_guid_arr) > > +{ > > + int i; > > + int dfu_num = 0; > > + efi_guid_t *guid_arr; > > + struct dfu_entity *dfu; > > + efi_status_t ret = EFI_SUCCESS; > > + > > + dfu_init_env_entities(NULL, NULL); > > + > > + dfu_num = 0; > > + list_for_each_entry(dfu, &dfu_list, list) { > > + dfu_num++; > > + } > > + > > + if (!dfu_num) { > > + log_warning("Probably dfu_alt_info not defined\n"); > > + ret = EFI_NOT_READY; > > + goto out; > > + } > > + > > + *part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num); > > + if (!*part_guid_arr) { > > + ret = EFI_OUT_OF_RESOURCES; > > + goto out; > > + } > > + > > + guid_arr = *part_guid_arr; > > + for (i = 0; i < dfu_num; i++) { > > + guidcpy(guid_arr, guid); > > + ++guid_arr; > > + } > > + > > +out: > > + dfu_free_entities(); > > + > > + return ret; > > +} > > + > > /** > > * efi_get_dfu_info - return information about the current firmware image > > * @this: Protocol instance > > @@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( > > * @descriptor_version: Pointer to version number > > * @descriptor_count: Pointer to number of descriptors > > * @descriptor_size: Pointer to descriptor size > > - * package_version: Package version > > - * package_version_name: Package version's name > > - * image_type: Image type GUID > > + * @package_version: Package version > > + * @package_version_name: Package version's name > > + * @guid_array: Image type GUID array > > * > > * Return information bout the current firmware image in @image_info. > > * @image_info will consist of a number of descriptors. > > @@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( > > efi_uintn_t *descriptor_size, > > u32 *package_version, > > u16 **package_version_name, > > - const efi_guid_t *image_type) > > + const efi_guid_t *guid_array) > > { > > struct dfu_entity *dfu; > > size_t names_len, total_size; > > @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( > > next = name; > > list_for_each_entry(dfu, &dfu_list, list) { > > image_info[i].image_index = dfu->alt + 1; > > - image_info[i].image_type_id = *image_type; > > + image_info[i].image_type_id = guid_array[i]; > > image_info[i].image_id = dfu->alt; > > > > /* copy the DFU entity name */ > > @@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( > > u16 **package_version_name) > > { > > efi_status_t ret; > > + efi_guid_t *part_guid_arr = NULL; > > > > EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, > > image_info_size, image_info, > > @@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( > > !descriptor_size || !package_version || !package_version_name)) > > return EFI_EXIT(EFI_INVALID_PARAMETER); > > > > + ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit, > > + &part_guid_arr); > > + if (ret != EFI_SUCCESS) > > + goto out; > > + > > ret = efi_get_dfu_info(image_info_size, image_info, > > descriptor_version, descriptor_count, > > descriptor_size, > > package_version, package_version_name, > > - &efi_firmware_image_type_uboot_fit); > > + part_guid_arr); > > > > +out: > > + free(part_guid_arr); > > return EFI_EXIT(ret); > > } > > > > @@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( > > u16 **package_version_name) > > { > > efi_status_t ret = EFI_SUCCESS; > > + efi_guid_t *part_guid_arr = NULL; > > > > EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, > > image_info_size, image_info, > > @@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( > > !descriptor_size || !package_version || !package_version_name)) > > return EFI_EXIT(EFI_INVALID_PARAMETER); > > > > + ret = fill_image_type_guid_array( > > + &efi_firmware_image_type_uboot_raw, > > + &part_guid_arr); > > + if (ret != EFI_SUCCESS) > > + goto out; > > + > > ret = efi_get_dfu_info(image_info_size, image_info, > > descriptor_version, descriptor_count, > > descriptor_size, > > package_version, package_version_name, > > - &efi_firmware_image_type_uboot_raw); > > + part_guid_arr); > > > > +out: > > + free(part_guid_arr); > > return EFI_EXIT(ret); > > } > > > > -- > > 2.17.1 > >

Hi,
Took me some time to go through the whole thread, but here it goes.
On Tue, Feb 15, 2022 at 12:08:30PM +0530, Sughosh Ganu wrote:
On Tue, 15 Feb 2022 at 07:21, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Mon, Feb 14, 2022 at 11:12:22AM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Mon, 14 Feb 2022 at 08:54, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Thu, Feb 10, 2022 at 03:40:00PM +0530, Sughosh Ganu wrote:
On Thu, 10 Feb 2022 at 13:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Thu, Feb 10, 2022 at 12:48:13PM +0530, Sughosh Ganu wrote: > hi Takahiro, > > On Thu, 10 Feb 2022 at 08:18, AKASHI Takahiro > takahiro.akashi@linaro.org wrote: > > > > Hi Sughosh, > > > > On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote: > > > The FWU Multi Banks Update feature allows updating different types of > > > updatable firmware images on the platform. These image types are > > > identified using the ImageTypeId GUID value. Add support in the > > > GetImageInfo function of the FMP protocol to get the GUID values for > > > the individual images and populate these in the image descriptor for > > > the corresponding images. > > > > After re-thinking of your approach here, I would have to say NAK. > > > > You use ImageTypeId to identify a particular firmware object. > > (By "object," I mean one of firmware instances represented by "dfu_alto_info". > > Please don't confuse it with the binary blob embedded in a capsule file.) > > But ImageTypeId is not for that purpose, at least, as my intention > > in initially implementing capsule framework and FMP drivers. > > > > 1) ImageTypeId is used to uniquely identify a corresponding FMP driver, > > either FIT FMP driver or Raw FMP driver. > > I believe the identification of an FMP protocol should be done by the > FMP GUID,
What does FMP GUID stand for?
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID, defined in include/efi_api.h. What I mean is that even when installing the FMP protocol, the call to efi_install_multiple_protocol_interfaces takes the above FMP GUID as an argument -- nowhere is the ImageTypeId considered when installing the protocol.
Okay.
> which is what is done in efi_fmp_find. The ImageTypeId is > nowhere involved in this identification.
Please take a look at efi_capsule_update_firmware() carefully. efi_find_fmp() is called with the image's update_image_type_id which is to be set to EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID by mkeficapsule (see create_fwbin()).
I think you are thinking from the point of view of the '--guid' value that is being passed to the capsule generation tool. But the thing is that it is the current design(or limitation) of the tool that it takes only a single guid parameter. So the mkeficapsule tool currently can generate only a single payload capsule.
That is exactly what I intended to do here. We have only one FMP driver (either FIT or RAW) which is based on U-Boot's DFU framework and we need only one payload since, for multiple objects of firmware, we can use FIT format as a payload. That is what FIT is aimed for. Or you can use multiple RAW capsule files with different indexes ("--index" exists for this purpose).
Yes, we can use --index when we know the index value corresponding to the firmware image that we need to update. But like I mentioned in my earlier reply, for A/B updates, we do not know what the index value is going to be. That is going to be determined at runtime.
I don't think so. See below for alternative approach.
Also, the point I was making is that we can have a capsule which is consumed by an FMP protocol which has more than one image, and those images have different ImageTypeId/UpdateImageTypeId.
Yes, but it is a design choice in my first implementation. I didn't think that we need to "have a capsule which is consumed by an FMP protocol which has more than one image" as long as we use DFU framework (and FIT as standard format of aggregation on U-Boot).
But this design can be extended without any hassle, and more importantly without any regression, no? What kind of a problem does it create if the FMP can handle more than one image type.
Even as per the UEFI spec, we have the EFI_FIRMWARE_MANAGEMENT_CAPSULE header for all images to be managed by the FMP protocol which has multiple images with different UpdateImageTypeId.
Please check the GenerateCapsule script in EDK2. In case of a multi payload based capsule, individual parameters like the UpdateImageTypeId are passed through the json file, where each of the UpdateImageTypeId has a different value per payload.
> > 2) Each firmware object handled by a given FMP driver can further be > > identified by ImageIndex. > > > > My implementation of efi_fmp_find() does (1) and Raw FMP driver does > > (2) in efi_firmware_raw_set_image() which takes "image_index" as > > a parameter. > > > > Using ImageTypeId as an identifier is simply wrong in my opinion and > > doesn't meet the UEFI specification. > > So, as per what you are stating, all payloads under a given > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same > ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or > EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in > the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two > values, > the check in efi_fmp_find to compare the UpdateImageTypeId > with the ImageTypeId retrieved from the image descriptor would simply > fail.
I don't follow your point. Please elaborate a bit more.
The current implementation of GetImageInfo, passes either of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image descriptor array. So, in case the capsule is generated with a '--guid' value which is different from these two values, the check in efi_fmp_find on line 204 will fail.
That is an expected behavior, isn't it?
Yes it is. Do not contest that.
If you want to use a different FMP driver (with another GUID), you naturally need to add your own FMP driver.
This is where I differ. We can use the same FMP protocol instance for any type of ImageTypeId. I do not see why we need to define a different FMP protocol instance for a GUID value other than what has been defined for u-boot raw and u-boot FIT GUIDs.
I do understand part of your concern a bit. I thought of using the same ImageType GUID, say IMAGE_TYPE_DFU_GUID, at first but we needed different GUIDs here simply because we need to determine the format of payload, FIT format or raw binary.
The platform can give us the image descriptor array, and with that, the same FMP instance can be used for any type of image(ImageTypeId).
"any type of image"? Really?
The raw FMP instance can certainly handle any type of binary payloads right. There is no restriction on what type of payload it is as long as it is all going as a single entity to a given dfu partition.
This means that unless the --guid value passed to the capsule generation is either of u-boot FIT or u-boot raw, the current FMP protocol for raw devices cannot be used. Why do we need that restriction. It should be possible to use the raw FMP protocol for any other type of image types as well.
> I think this interpretation of the UEFI spec is incorrect, since the > spec states that the ImageTypeId and the UpdateImageTypeId are fields > used to identify the firmware component targeted for the update. If > all values in the image descriptor array and the UpdateImageTypeId are > the same, why have this field in the first place for individual > images.
As I said, ImageIndex is for that purpose.
Yes, that is one possible way in the scenario where the ImageIndex is determined at the capsule generation time. But, for the A/B update scenario, we do not know the ImageIndex at build time
"Build time" of what?
Of the capsule.
I think that users should know how "dfu_alt_info" is defined (in other words, where the firmware be located on the target system) when capsule files are created.
That is true for a non A/B scenario. And that is how it works in the non A/B updates case. But for A/B updates, since the determination of the "location" where the firmware image has to be written will be done only at runtime, we cannot use the --index to differentiate.
Yes, we can :)
You know what I mean -- if we could use the same logic, I would not have added all that code :)
First of all, my essential assumption in either FIT or RAW FMP driver is that U-Boot has (somehow conceptually) single firmware blob represented by DFU or dfu_alt_info. As I said, each object or location in dfu_alt_info can be further identified by index or "UpdateImageIndex".
Let's assume that we have two locations of firmware, fw1 and fw2, and that we have two bank A and B. Then we will define dfu_alt_info as follows: <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; |<--- 1st set --->|<--- 2nd set --->|
When you want to update bank A, we can use the first set of dfu_alt_info, and use the second set of dfu_alt_info for bank B. At runtime, you should know which bank you're working on, and therefore you should know the exact physical location from dfu_alt_info.
Please note that you don't have to change the syntax of dfu_alt_info at all. Simply offset the location with 0 for bank A and with 2 for bank B.
I'll try digging a bit more, but I think the current approach is not working as it was intended wrt to the EFI spec. My reading of the spec and specifically section 23.3.2 is that a Capsule consists of an EFI capsule header and a payload. The payload now has an EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER which in it's turn can host multiple firmware images of different type described in EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
An FMP implementation should read the UpdateImageTypeId's used to identify the image you are updating and from that derive the UpdateImageIndex which SetImage will use. That would give you the ability to update the all the firmware components with a single capsule.
Sughosh what about the ESRT table generation? If you use different UpdateImageTypeId those should be reflected on the ESRT tables from the OS
Regards /Ilias
We can use this logic yes. But please note, that with this, we need to a) Keep a definite order of the images in all the banks, and b) Know the order of the images.
With the way the FWU metadata is designed, we do not have these restrictions -- the firmware images can be placed on the device in any order, irrespective of the bank that they belong to. One might prefer clubbing images of a given bank together, but that is not the restriction put by the FWU spec. That is because the images are being identified using image GUIDs.
I really don't get your opposition to extending the current design. I would like to hear from Heinrich or Ilias on what their thoughts are on this.
-sughosh
I don't think we need to introduce extra GUIDs.
-Takahiro Akashi
Like I mentioned earlier, this is not breaking the existing behaviour -- for the non A/B updates, the update procedure remains exactly the same, of using the index value to determine the location of the update. I have only extended the behaviour to use the same FMP instance for the A/B update(FWU) feature using ImageTypeId's.
-sughosh
-Takahiro Akashi
-- this is determined only at runtime, and is based on the bank to which the image is to be updated. Which is why I am finding out the alt_num at runtime in case the FWU Multi Bank feature is enabled. Like I said above, I do not see a reason why the current FMP protocols should be restricted to only the u-boot FIT and u-boot raw image types. It is being extended, without affecting the default non FWU behaviour.
-sughosh
-Takahiro Akashi
> > -sughosh > > > > > -Takahiro Akashi > > > > > > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > > > --- > > > > > > Changes since V3: > > > * Define a weak function fill_image_type_guid_array for populating the > > > image descriptor array with u-boot's raw and fit image GUIDs > > > > > > include/efi_loader.h | 2 + > > > lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- > > > 2 files changed, 66 insertions(+), 7 deletions(-) > > > > > > diff --git a/include/efi_loader.h b/include/efi_loader.h > > > index f4860e87fc..ae60de0be5 100644 > > > --- a/include/efi_loader.h > > > +++ b/include/efi_loader.h > > > @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); > > > efi_status_t efi_load_capsule_drivers(void); > > > > > > efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); > > > +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid, > > > + efi_guid_t **part_guid_arr); > > > #endif /* _EFI_LOADER_H */ > > > diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c > > > index a1b88dbfc2..5642be9f9a 100644 > > > --- a/lib/efi_loader/efi_firmware.c > > > +++ b/lib/efi_loader/efi_firmware.c > > > @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( > > > return EFI_EXIT(EFI_UNSUPPORTED); > > > } > > > > > > +efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid, > > > + efi_guid_t **part_guid_arr) > > > +{ > > > + int i; > > > + int dfu_num = 0; > > > + efi_guid_t *guid_arr; > > > + struct dfu_entity *dfu; > > > + efi_status_t ret = EFI_SUCCESS; > > > + > > > + dfu_init_env_entities(NULL, NULL); > > > + > > > + dfu_num = 0; > > > + list_for_each_entry(dfu, &dfu_list, list) { > > > + dfu_num++; > > > + } > > > + > > > + if (!dfu_num) { > > > + log_warning("Probably dfu_alt_info not defined\n"); > > > + ret = EFI_NOT_READY; > > > + goto out; > > > + } > > > + > > > + *part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num); > > > + if (!*part_guid_arr) { > > > + ret = EFI_OUT_OF_RESOURCES; > > > + goto out; > > > + } > > > + > > > + guid_arr = *part_guid_arr; > > > + for (i = 0; i < dfu_num; i++) { > > > + guidcpy(guid_arr, guid); > > > + ++guid_arr; > > > + } > > > + > > > +out: > > > + dfu_free_entities(); > > > + > > > + return ret; > > > +} > > > + > > > /** > > > * efi_get_dfu_info - return information about the current firmware image > > > * @this: Protocol instance > > > @@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( > > > * @descriptor_version: Pointer to version number > > > * @descriptor_count: Pointer to number of descriptors > > > * @descriptor_size: Pointer to descriptor size > > > - * package_version: Package version > > > - * package_version_name: Package version's name > > > - * image_type: Image type GUID > > > + * @package_version: Package version > > > + * @package_version_name: Package version's name > > > + * @guid_array: Image type GUID array > > > * > > > * Return information bout the current firmware image in @image_info. > > > * @image_info will consist of a number of descriptors. > > > @@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( > > > efi_uintn_t *descriptor_size, > > > u32 *package_version, > > > u16 **package_version_name, > > > - const efi_guid_t *image_type) > > > + const efi_guid_t *guid_array) > > > { > > > struct dfu_entity *dfu; > > > size_t names_len, total_size; > > > @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( > > > next = name; > > > list_for_each_entry(dfu, &dfu_list, list) { > > > image_info[i].image_index = dfu->alt + 1; > > > - image_info[i].image_type_id = *image_type; > > > + image_info[i].image_type_id = guid_array[i]; > > > image_info[i].image_id = dfu->alt; > > > > > > /* copy the DFU entity name */ > > > @@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( > > > u16 **package_version_name) > > > { > > > efi_status_t ret; > > > + efi_guid_t *part_guid_arr = NULL; > > > > > > EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, > > > image_info_size, image_info, > > > @@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( > > > !descriptor_size || !package_version || !package_version_name)) > > > return EFI_EXIT(EFI_INVALID_PARAMETER); > > > > > > + ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit, > > > + &part_guid_arr); > > > + if (ret != EFI_SUCCESS) > > > + goto out; > > > + > > > ret = efi_get_dfu_info(image_info_size, image_info, > > > descriptor_version, descriptor_count, > > > descriptor_size, > > > package_version, package_version_name, > > > - &efi_firmware_image_type_uboot_fit); > > > + part_guid_arr); > > > > > > +out: > > > + free(part_guid_arr); > > > return EFI_EXIT(ret); > > > } > > > > > > @@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( > > > u16 **package_version_name) > > > { > > > efi_status_t ret = EFI_SUCCESS; > > > + efi_guid_t *part_guid_arr = NULL; > > > > > > EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, > > > image_info_size, image_info, > > > @@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( > > > !descriptor_size || !package_version || !package_version_name)) > > > return EFI_EXIT(EFI_INVALID_PARAMETER); > > > > > > + ret = fill_image_type_guid_array( > > > + &efi_firmware_image_type_uboot_raw, > > > + &part_guid_arr); > > > + if (ret != EFI_SUCCESS) > > > + goto out; > > > + > > > ret = efi_get_dfu_info(image_info_size, image_info, > > > descriptor_version, descriptor_count, > > > descriptor_size, > > > package_version, package_version_name, > > > - &efi_firmware_image_type_uboot_raw); > > > + part_guid_arr); > > > > > > +out: > > > + free(part_guid_arr); > > > return EFI_EXIT(ret); > > > } > > > > > > -- > > > 2.17.1 > > >

hi Ilias,
On Tue, 15 Feb 2022 at 20:10, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi,
Took me some time to go through the whole thread, but here it goes.
On Tue, Feb 15, 2022 at 12:08:30PM +0530, Sughosh Ganu wrote:
On Tue, 15 Feb 2022 at 07:21, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Mon, Feb 14, 2022 at 11:12:22AM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Mon, 14 Feb 2022 at 08:54, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Thu, Feb 10, 2022 at 03:40:00PM +0530, Sughosh Ganu wrote:
On Thu, 10 Feb 2022 at 13:28, AKASHI Takahiro takahiro.akashi@linaro.org wrote: > > On Thu, Feb 10, 2022 at 12:48:13PM +0530, Sughosh Ganu wrote: > > hi Takahiro, > > > > On Thu, 10 Feb 2022 at 08:18, AKASHI Takahiro > > takahiro.akashi@linaro.org wrote: > > > > > > Hi Sughosh, > > > > > > On Mon, Feb 07, 2022 at 11:49:55PM +0530, Sughosh Ganu wrote: > > > > The FWU Multi Banks Update feature allows updating different types of > > > > updatable firmware images on the platform. These image types are > > > > identified using the ImageTypeId GUID value. Add support in the > > > > GetImageInfo function of the FMP protocol to get the GUID values for > > > > the individual images and populate these in the image descriptor for > > > > the corresponding images. > > > > > > After re-thinking of your approach here, I would have to say NAK. > > > > > > You use ImageTypeId to identify a particular firmware object. > > > (By "object," I mean one of firmware instances represented by "dfu_alto_info". > > > Please don't confuse it with the binary blob embedded in a capsule file.) > > > But ImageTypeId is not for that purpose, at least, as my intention > > > in initially implementing capsule framework and FMP drivers. > > > > > > 1) ImageTypeId is used to uniquely identify a corresponding FMP driver, > > > either FIT FMP driver or Raw FMP driver. > > > > I believe the identification of an FMP protocol should be done by the > > FMP GUID, > > What does FMP GUID stand for?
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID, defined in include/efi_api.h. What I mean is that even when installing the FMP protocol, the call to efi_install_multiple_protocol_interfaces takes the above FMP GUID as an argument -- nowhere is the ImageTypeId considered when installing the protocol.
Okay.
> > > which is what is done in efi_fmp_find. The ImageTypeId is > > nowhere involved in this identification. > > Please take a look at efi_capsule_update_firmware() carefully. > efi_find_fmp() is called with the image's update_image_type_id > which is to be set to EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or > EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID by mkeficapsule > (see create_fwbin()).
I think you are thinking from the point of view of the '--guid' value that is being passed to the capsule generation tool. But the thing is that it is the current design(or limitation) of the tool that it takes only a single guid parameter. So the mkeficapsule tool currently can generate only a single payload capsule.
That is exactly what I intended to do here. We have only one FMP driver (either FIT or RAW) which is based on U-Boot's DFU framework and we need only one payload since, for multiple objects of firmware, we can use FIT format as a payload. That is what FIT is aimed for. Or you can use multiple RAW capsule files with different indexes ("--index" exists for this purpose).
Yes, we can use --index when we know the index value corresponding to the firmware image that we need to update. But like I mentioned in my earlier reply, for A/B updates, we do not know what the index value is going to be. That is going to be determined at runtime.
I don't think so. See below for alternative approach.
Also, the point I was making is that we can have a capsule which is consumed by an FMP protocol which has more than one image, and those images have different ImageTypeId/UpdateImageTypeId.
Yes, but it is a design choice in my first implementation. I didn't think that we need to "have a capsule which is consumed by an FMP protocol which has more than one image" as long as we use DFU framework (and FIT as standard format of aggregation on U-Boot).
But this design can be extended without any hassle, and more importantly without any regression, no? What kind of a problem does it create if the FMP can handle more than one image type.
Even as per the UEFI spec, we have the EFI_FIRMWARE_MANAGEMENT_CAPSULE header for all images to be managed by the FMP protocol which has multiple images with different UpdateImageTypeId.
Please check the GenerateCapsule script in EDK2. In case of a multi payload based capsule, individual parameters like the UpdateImageTypeId are passed through the json file, where each of the UpdateImageTypeId has a different value per payload.
> > > > 2) Each firmware object handled by a given FMP driver can further be > > > identified by ImageIndex. > > > > > > My implementation of efi_fmp_find() does (1) and Raw FMP driver does > > > (2) in efi_firmware_raw_set_image() which takes "image_index" as > > > a parameter. > > > > > > Using ImageTypeId as an identifier is simply wrong in my opinion and > > > doesn't meet the UEFI specification. > > > > So, as per what you are stating, all payloads under a given > > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same > > ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or > > EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in > > the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two > > values, > the check in efi_fmp_find to compare the UpdateImageTypeId > > with the ImageTypeId retrieved from the image descriptor would simply > > fail. > > I don't follow your point. > Please elaborate a bit more.
The current implementation of GetImageInfo, passes either of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image descriptor array. So, in case the capsule is generated with a '--guid' value which is different from these two values, the check in efi_fmp_find on line 204 will fail.
That is an expected behavior, isn't it?
Yes it is. Do not contest that.
If you want to use a different FMP driver (with another GUID), you naturally need to add your own FMP driver.
This is where I differ. We can use the same FMP protocol instance for any type of ImageTypeId. I do not see why we need to define a different FMP protocol instance for a GUID value other than what has been defined for u-boot raw and u-boot FIT GUIDs.
I do understand part of your concern a bit. I thought of using the same ImageType GUID, say IMAGE_TYPE_DFU_GUID, at first but we needed different GUIDs here simply because we need to determine the format of payload, FIT format or raw binary.
The platform can give us the image descriptor array, and with that, the same FMP instance can be used for any type of image(ImageTypeId).
"any type of image"? Really?
The raw FMP instance can certainly handle any type of binary payloads right. There is no restriction on what type of payload it is as long as it is all going as a single entity to a given dfu partition.
This means that unless the --guid value passed to the capsule generation is either of u-boot FIT or u-boot raw, the current FMP protocol for raw devices cannot be used. Why do we need that restriction. It should be possible to use the raw FMP protocol for any other type of image types as well.
> > > I think this interpretation of the UEFI spec is incorrect, since the > > spec states that the ImageTypeId and the UpdateImageTypeId are fields > > used to identify the firmware component targeted for the update. If > > all values in the image descriptor array and the UpdateImageTypeId are > > the same, why have this field in the first place for individual > > images. > > As I said, ImageIndex is for that purpose.
Yes, that is one possible way in the scenario where the ImageIndex is determined at the capsule generation time. But, for the A/B update scenario, we do not know the ImageIndex at build time
"Build time" of what?
Of the capsule.
I think that users should know how "dfu_alt_info" is defined (in other words, where the firmware be located on the target system) when capsule files are created.
That is true for a non A/B scenario. And that is how it works in the non A/B updates case. But for A/B updates, since the determination of the "location" where the firmware image has to be written will be done only at runtime, we cannot use the --index to differentiate.
Yes, we can :)
You know what I mean -- if we could use the same logic, I would not have added all that code :)
First of all, my essential assumption in either FIT or RAW FMP driver is that U-Boot has (somehow conceptually) single firmware blob represented by DFU or dfu_alt_info. As I said, each object or location in dfu_alt_info can be further identified by index or "UpdateImageIndex".
Let's assume that we have two locations of firmware, fw1 and fw2, and that we have two bank A and B. Then we will define dfu_alt_info as follows: <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; |<--- 1st set --->|<--- 2nd set --->|
When you want to update bank A, we can use the first set of dfu_alt_info, and use the second set of dfu_alt_info for bank B. At runtime, you should know which bank you're working on, and therefore you should know the exact physical location from dfu_alt_info.
Please note that you don't have to change the syntax of dfu_alt_info at all. Simply offset the location with 0 for bank A and with 2 for bank B.
I'll try digging a bit more, but I think the current approach is not working as it was intended wrt to the EFI spec. My reading of the spec and specifically section 23.3.2 is that a Capsule consists of an EFI capsule header and a payload. The payload now has an EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER which in it's turn can host multiple firmware images of different type described in EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
An FMP implementation should read the UpdateImageTypeId's used to identify the image you are updating and from that derive the UpdateImageIndex which SetImage will use. That would give you the ability to update the all the firmware components with a single capsule.
Sughosh what about the ESRT table generation? If you use different UpdateImageTypeId those should be reflected on the ESRT tables from the OS
That would depend on the values populated in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array by the GetImageInfo function. The image descriptor structure has an ImageTypeId field. The value of ImageTypeId is what will be reflected in the ESRT table.
In the current implementation, all the images in the ESRT table will show the same ImageTypeId value, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID.
The UpdateImageTypeId value from the capsule is used to compare with the ImageTypeId values returned by the GetImageInfo function to check if the given FMP protocol can be used for the update.
-sughosh
Regards /Ilias
We can use this logic yes. But please note, that with this, we need to a) Keep a definite order of the images in all the banks, and b) Know the order of the images.
With the way the FWU metadata is designed, we do not have these restrictions -- the firmware images can be placed on the device in any order, irrespective of the bank that they belong to. One might prefer clubbing images of a given bank together, but that is not the restriction put by the FWU spec. That is because the images are being identified using image GUIDs.
I really don't get your opposition to extending the current design. I would like to hear from Heinrich or Ilias on what their thoughts are on this.
-sughosh
I don't think we need to introduce extra GUIDs.
-Takahiro Akashi
Like I mentioned earlier, this is not breaking the existing behaviour -- for the non A/B updates, the update procedure remains exactly the same, of using the index value to determine the location of the update. I have only extended the behaviour to use the same FMP instance for the A/B update(FWU) feature using ImageTypeId's.
-sughosh
-Takahiro Akashi
-- this is determined only at runtime, and is based on the bank to which the image is to be updated. Which is why I am finding out the alt_num at runtime in case the FWU Multi Bank feature is enabled. Like I said above, I do not see a reason why the current FMP protocols should be restricted to only the u-boot FIT and u-boot raw image types. It is being extended, without affecting the default non FWU behaviour.
-sughosh
> > -Takahiro Akashi > > > > > -sughosh > > > > > > > > -Takahiro Akashi > > > > > > > > > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > > > > --- > > > > > > > > Changes since V3: > > > > * Define a weak function fill_image_type_guid_array for populating the > > > > image descriptor array with u-boot's raw and fit image GUIDs > > > > > > > > include/efi_loader.h | 2 + > > > > lib/efi_loader/efi_firmware.c | 71 +++++++++++++++++++++++++++++++---- > > > > 2 files changed, 66 insertions(+), 7 deletions(-) > > > > > > > > diff --git a/include/efi_loader.h b/include/efi_loader.h > > > > index f4860e87fc..ae60de0be5 100644 > > > > --- a/include/efi_loader.h > > > > +++ b/include/efi_loader.h > > > > @@ -992,4 +992,6 @@ efi_status_t efi_esrt_populate(void); > > > > efi_status_t efi_load_capsule_drivers(void); > > > > > > > > efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); > > > > +efi_status_t fill_image_type_guid_array(const efi_guid_t *default_guid, > > > > + efi_guid_t **part_guid_arr); > > > > #endif /* _EFI_LOADER_H */ > > > > diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c > > > > index a1b88dbfc2..5642be9f9a 100644 > > > > --- a/lib/efi_loader/efi_firmware.c > > > > +++ b/lib/efi_loader/efi_firmware.c > > > > @@ -96,6 +96,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( > > > > return EFI_EXIT(EFI_UNSUPPORTED); > > > > } > > > > > > > > +efi_status_t __weak fill_image_type_guid_array(const efi_guid_t *guid, > > > > + efi_guid_t **part_guid_arr) > > > > +{ > > > > + int i; > > > > + int dfu_num = 0; > > > > + efi_guid_t *guid_arr; > > > > + struct dfu_entity *dfu; > > > > + efi_status_t ret = EFI_SUCCESS; > > > > + > > > > + dfu_init_env_entities(NULL, NULL); > > > > + > > > > + dfu_num = 0; > > > > + list_for_each_entry(dfu, &dfu_list, list) { > > > > + dfu_num++; > > > > + } > > > > + > > > > + if (!dfu_num) { > > > > + log_warning("Probably dfu_alt_info not defined\n"); > > > > + ret = EFI_NOT_READY; > > > > + goto out; > > > > + } > > > > + > > > > + *part_guid_arr = malloc(sizeof(efi_guid_t) * dfu_num); > > > > + if (!*part_guid_arr) { > > > > + ret = EFI_OUT_OF_RESOURCES; > > > > + goto out; > > > > + } > > > > + > > > > + guid_arr = *part_guid_arr; > > > > + for (i = 0; i < dfu_num; i++) { > > > > + guidcpy(guid_arr, guid); > > > > + ++guid_arr; > > > > + } > > > > + > > > > +out: > > > > + dfu_free_entities(); > > > > + > > > > + return ret; > > > > +} > > > > + > > > > /** > > > > * efi_get_dfu_info - return information about the current firmware image > > > > * @this: Protocol instance > > > > @@ -104,9 +144,9 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( > > > > * @descriptor_version: Pointer to version number > > > > * @descriptor_count: Pointer to number of descriptors > > > > * @descriptor_size: Pointer to descriptor size > > > > - * package_version: Package version > > > > - * package_version_name: Package version's name > > > > - * image_type: Image type GUID > > > > + * @package_version: Package version > > > > + * @package_version_name: Package version's name > > > > + * @guid_array: Image type GUID array > > > > * > > > > * Return information bout the current firmware image in @image_info. > > > > * @image_info will consist of a number of descriptors. > > > > @@ -122,7 +162,7 @@ static efi_status_t efi_get_dfu_info( > > > > efi_uintn_t *descriptor_size, > > > > u32 *package_version, > > > > u16 **package_version_name, > > > > - const efi_guid_t *image_type) > > > > + const efi_guid_t *guid_array) > > > > { > > > > struct dfu_entity *dfu; > > > > size_t names_len, total_size; > > > > @@ -172,7 +212,7 @@ static efi_status_t efi_get_dfu_info( > > > > next = name; > > > > list_for_each_entry(dfu, &dfu_list, list) { > > > > image_info[i].image_index = dfu->alt + 1; > > > > - image_info[i].image_type_id = *image_type; > > > > + image_info[i].image_type_id = guid_array[i]; > > > > image_info[i].image_id = dfu->alt; > > > > > > > > /* copy the DFU entity name */ > > > > @@ -250,6 +290,7 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( > > > > u16 **package_version_name) > > > > { > > > > efi_status_t ret; > > > > + efi_guid_t *part_guid_arr = NULL; > > > > > > > > EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, > > > > image_info_size, image_info, > > > > @@ -264,12 +305,19 @@ efi_status_t EFIAPI efi_firmware_fit_get_image_info( > > > > !descriptor_size || !package_version || !package_version_name)) > > > > return EFI_EXIT(EFI_INVALID_PARAMETER); > > > > > > > > + ret = fill_image_type_guid_array(&efi_firmware_image_type_uboot_fit, > > > > + &part_guid_arr); > > > > + if (ret != EFI_SUCCESS) > > > > + goto out; > > > > + > > > > ret = efi_get_dfu_info(image_info_size, image_info, > > > > descriptor_version, descriptor_count, > > > > descriptor_size, > > > > package_version, package_version_name, > > > > - &efi_firmware_image_type_uboot_fit); > > > > + part_guid_arr); > > > > > > > > +out: > > > > + free(part_guid_arr); > > > > return EFI_EXIT(ret); > > > > } > > > > > > > > @@ -359,6 +407,7 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( > > > > u16 **package_version_name) > > > > { > > > > efi_status_t ret = EFI_SUCCESS; > > > > + efi_guid_t *part_guid_arr = NULL; > > > > > > > > EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, > > > > image_info_size, image_info, > > > > @@ -373,12 +422,20 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( > > > > !descriptor_size || !package_version || !package_version_name)) > > > > return EFI_EXIT(EFI_INVALID_PARAMETER); > > > > > > > > + ret = fill_image_type_guid_array( > > > > + &efi_firmware_image_type_uboot_raw, > > > > + &part_guid_arr); > > > > + if (ret != EFI_SUCCESS) > > > > + goto out; > > > > + > > > > ret = efi_get_dfu_info(image_info_size, image_info, > > > > descriptor_version, descriptor_count, > > > > descriptor_size, > > > > package_version, package_version_name, > > > > - &efi_firmware_image_type_uboot_raw); > > > > + part_guid_arr); > > > > > > > > +out: > > > > + free(part_guid_arr); > > > > return EFI_EXIT(ret); > > > > } > > > > > > > > -- > > > > 2.17.1 > > > >

[...]
Yes, we can use --index when we know the index value corresponding to the firmware image that we need to update. But like I mentioned in my earlier reply, for A/B updates, we do not know what the index value is going to be. That is going to be determined at runtime.
I don't think so. See below for alternative approach.
Also, the point I was making is that we can have a capsule which is consumed by an FMP protocol which has more than one image, and those images have different ImageTypeId/UpdateImageTypeId.
Yes, but it is a design choice in my first implementation. I didn't think that we need to "have a capsule which is consumed by an FMP protocol which has more than one image" as long as we use DFU framework (and FIT as standard format of aggregation on U-Boot).
But this design can be extended without any hassle, and more importantly without any regression, no? What kind of a problem does it create if the FMP can handle more than one image type.
Even as per the UEFI spec, we have the EFI_FIRMWARE_MANAGEMENT_CAPSULE header for all images to be managed by the FMP protocol which has multiple images with different UpdateImageTypeId.
> Please check the > GenerateCapsule script in EDK2. In case of a multi payload based > capsule, individual parameters like the UpdateImageTypeId are passed > through the json file, where each of the UpdateImageTypeId has a > different value per payload. > > > > > > > 2) Each firmware object handled by a given FMP driver can further be > > > > identified by ImageIndex. > > > > > > > > My implementation of efi_fmp_find() does (1) and Raw FMP driver does > > > > (2) in efi_firmware_raw_set_image() which takes "image_index" as > > > > a parameter. > > > > > > > > Using ImageTypeId as an identifier is simply wrong in my opinion and > > > > doesn't meet the UEFI specification. > > > > > > So, as per what you are stating, all payloads under a given > > > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same > > > ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or > > > EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in > > > the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two > > > values, > the check in efi_fmp_find to compare the UpdateImageTypeId > > > with the ImageTypeId retrieved from the image descriptor would simply > > > fail. > > > > I don't follow your point. > > Please elaborate a bit more. > > The current implementation of GetImageInfo, passes either of > EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or > EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image > descriptor array. So, in case the capsule is generated with a '--guid' > value which is different from these two values, the check in > efi_fmp_find on line 204 will fail.
That is an expected behavior, isn't it?
Yes it is. Do not contest that.
If you want to use a different FMP driver (with another GUID), you naturally need to add your own FMP driver.
This is where I differ. We can use the same FMP protocol instance for any type of ImageTypeId. I do not see why we need to define a different FMP protocol instance for a GUID value other than what has been defined for u-boot raw and u-boot FIT GUIDs.
I do understand part of your concern a bit. I thought of using the same ImageType GUID, say IMAGE_TYPE_DFU_GUID, at first but we needed different GUIDs here simply because we need to determine the format of payload, FIT format or raw binary.
The platform can give us the image descriptor array, and with that, the same FMP instance can be used for any type of image(ImageTypeId).
"any type of image"? Really?
The raw FMP instance can certainly handle any type of binary payloads right. There is no restriction on what type of payload it is as long as it is all going as a single entity to a given dfu partition.
> This means that unless the --guid > value passed to the capsule generation is either of u-boot FIT or > u-boot raw, the current FMP protocol for raw devices cannot be used. > Why do we need that restriction. It should be possible to use the raw > FMP protocol for any other type of image types as well. > > > > > > > I think this interpretation of the UEFI spec is incorrect, since the > > > spec states that the ImageTypeId and the UpdateImageTypeId are fields > > > used to identify the firmware component targeted for the update. If > > > all values in the image descriptor array and the UpdateImageTypeId are > > > the same, why have this field in the first place for individual > > > images. > > > > As I said, ImageIndex is for that purpose. > > Yes, that is one possible way in the scenario where the ImageIndex is > determined at the capsule generation time. But, for the A/B update > scenario, we do not know the ImageIndex at build time
"Build time" of what?
Of the capsule.
I think that users should know how "dfu_alt_info" is defined (in other words, where the firmware be located on the target system) when capsule files are created.
That is true for a non A/B scenario. And that is how it works in the non A/B updates case. But for A/B updates, since the determination of the "location" where the firmware image has to be written will be done only at runtime, we cannot use the --index to differentiate.
Yes, we can :)
You know what I mean -- if we could use the same logic, I would not have added all that code :)
First of all, my essential assumption in either FIT or RAW FMP driver is that U-Boot has (somehow conceptually) single firmware blob represented by DFU or dfu_alt_info. As I said, each object or location in dfu_alt_info can be further identified by index or "UpdateImageIndex".
Let's assume that we have two locations of firmware, fw1 and fw2, and that we have two bank A and B. Then we will define dfu_alt_info as follows: <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; |<--- 1st set --->|<--- 2nd set --->|
When you want to update bank A, we can use the first set of dfu_alt_info, and use the second set of dfu_alt_info for bank B. At runtime, you should know which bank you're working on, and therefore you should know the exact physical location from dfu_alt_info.
Please note that you don't have to change the syntax of dfu_alt_info at all. Simply offset the location with 0 for bank A and with 2 for bank B.
I'll try digging a bit more, but I think the current approach is not working as it was intended wrt to the EFI spec. My reading of the spec and specifically section 23.3.2 is that a Capsule consists of an EFI capsule header and a payload. The payload now has an EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER which in it's turn can host multiple firmware images of different type described in EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
An FMP implementation should read the UpdateImageTypeId's used to identify the image you are updating and from that derive the UpdateImageIndex which SetImage will use. That would give you the ability to update the all the firmware components with a single capsule.
Sughosh what about the ESRT table generation? If you use different UpdateImageTypeId those should be reflected on the ESRT tables from the OS
That would depend on the values populated in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array by the GetImageInfo function. The image descriptor structure has an ImageTypeId field. The value of ImageTypeId is what will be reflected in the ESRT table.
In the current implementation, all the images in the ESRT table will show the same ImageTypeId value, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID.
Yea I was mostly asking wrt to A/B updates. Would the correct UUID be shown in the ESRT instead of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID?
The UpdateImageTypeId value from the capsule is used to compare with the ImageTypeId values returned by the GetImageInfo function to check if the given FMP protocol can be used for the update.
-sughosh
[...]
Regards /Ilias

On Thu, 17 Feb 2022 at 13:52, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
[...]
Yes, we can use --index when we know the index value corresponding to the firmware image that we need to update. But like I mentioned in my earlier reply, for A/B updates, we do not know what the index value is going to be. That is going to be determined at runtime.
I don't think so. See below for alternative approach.
Also, the point I was making is that we can have a capsule which is consumed by an FMP protocol which has more than one image, and those images have different ImageTypeId/UpdateImageTypeId.
Yes, but it is a design choice in my first implementation. I didn't think that we need to "have a capsule which is consumed by an FMP protocol which has more than one image" as long as we use DFU framework (and FIT as standard format of aggregation on U-Boot).
But this design can be extended without any hassle, and more importantly without any regression, no? What kind of a problem does it create if the FMP can handle more than one image type.
Even as per the UEFI spec, we have the EFI_FIRMWARE_MANAGEMENT_CAPSULE header for all images to be managed by the FMP protocol which has multiple images with different UpdateImageTypeId.
> > > Please check the > > GenerateCapsule script in EDK2. In case of a multi payload based > > capsule, individual parameters like the UpdateImageTypeId are passed > > through the json file, where each of the UpdateImageTypeId has a > > different value per payload. > > > > > > > > > > 2) Each firmware object handled by a given FMP driver can further be > > > > > identified by ImageIndex. > > > > > > > > > > My implementation of efi_fmp_find() does (1) and Raw FMP driver does > > > > > (2) in efi_firmware_raw_set_image() which takes "image_index" as > > > > > a parameter. > > > > > > > > > > Using ImageTypeId as an identifier is simply wrong in my opinion and > > > > > doesn't meet the UEFI specification. > > > > > > > > So, as per what you are stating, all payloads under a given > > > > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same > > > > ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or > > > > EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in > > > > the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two > > > > values, > the check in efi_fmp_find to compare the UpdateImageTypeId > > > > with the ImageTypeId retrieved from the image descriptor would simply > > > > fail. > > > > > > I don't follow your point. > > > Please elaborate a bit more. > > > > The current implementation of GetImageInfo, passes either of > > EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or > > EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image > > descriptor array. So, in case the capsule is generated with a '--guid' > > value which is different from these two values, the check in > > efi_fmp_find on line 204 will fail. > > That is an expected behavior, isn't it?
Yes it is. Do not contest that.
> If you want to use a different FMP driver (with another GUID), > you naturally need to add your own FMP driver.
This is where I differ. We can use the same FMP protocol instance for any type of ImageTypeId. I do not see why we need to define a different FMP protocol instance for a GUID value other than what has been defined for u-boot raw and u-boot FIT GUIDs.
I do understand part of your concern a bit. I thought of using the same ImageType GUID, say IMAGE_TYPE_DFU_GUID, at first but we needed different GUIDs here simply because we need to determine the format of payload, FIT format or raw binary.
The platform can give us the image descriptor array, and with that, the same FMP instance can be used for any type of image(ImageTypeId).
"any type of image"? Really?
The raw FMP instance can certainly handle any type of binary payloads right. There is no restriction on what type of payload it is as long as it is all going as a single entity to a given dfu partition.
> > > > This means that unless the --guid > > value passed to the capsule generation is either of u-boot FIT or > > u-boot raw, the current FMP protocol for raw devices cannot be used. > > Why do we need that restriction. It should be possible to use the raw > > FMP protocol for any other type of image types as well. > > > > > > > > > > > I think this interpretation of the UEFI spec is incorrect, since the > > > > spec states that the ImageTypeId and the UpdateImageTypeId are fields > > > > used to identify the firmware component targeted for the update. If > > > > all values in the image descriptor array and the UpdateImageTypeId are > > > > the same, why have this field in the first place for individual > > > > images. > > > > > > As I said, ImageIndex is for that purpose. > > > > Yes, that is one possible way in the scenario where the ImageIndex is > > determined at the capsule generation time. But, for the A/B update > > scenario, we do not know the ImageIndex at build time > > "Build time" of what?
Of the capsule.
> I think that users should know how "dfu_alt_info" is defined > (in other words, where the firmware be located on the target system) > when capsule files are created.
That is true for a non A/B scenario. And that is how it works in the non A/B updates case. But for A/B updates, since the determination of the "location" where the firmware image has to be written will be done only at runtime, we cannot use the --index to differentiate.
Yes, we can :)
You know what I mean -- if we could use the same logic, I would not have added all that code :)
First of all, my essential assumption in either FIT or RAW FMP driver is that U-Boot has (somehow conceptually) single firmware blob represented by DFU or dfu_alt_info. As I said, each object or location in dfu_alt_info can be further identified by index or "UpdateImageIndex".
Let's assume that we have two locations of firmware, fw1 and fw2, and that we have two bank A and B. Then we will define dfu_alt_info as follows: <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; |<--- 1st set --->|<--- 2nd set --->|
When you want to update bank A, we can use the first set of dfu_alt_info, and use the second set of dfu_alt_info for bank B. At runtime, you should know which bank you're working on, and therefore you should know the exact physical location from dfu_alt_info.
Please note that you don't have to change the syntax of dfu_alt_info at all. Simply offset the location with 0 for bank A and with 2 for bank B.
I'll try digging a bit more, but I think the current approach is not working as it was intended wrt to the EFI spec. My reading of the spec and specifically section 23.3.2 is that a Capsule consists of an EFI capsule header and a payload. The payload now has an EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER which in it's turn can host multiple firmware images of different type described in EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
An FMP implementation should read the UpdateImageTypeId's used to identify the image you are updating and from that derive the UpdateImageIndex which SetImage will use. That would give you the ability to update the all the firmware components with a single capsule.
Sughosh what about the ESRT table generation? If you use different UpdateImageTypeId those should be reflected on the ESRT tables from the OS
That would depend on the values populated in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array by the GetImageInfo function. The image descriptor structure has an ImageTypeId field. The value of ImageTypeId is what will be reflected in the ESRT table.
In the current implementation, all the images in the ESRT table will show the same ImageTypeId value, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID.
Yea I was mostly asking wrt to A/B updates. Would the correct UUID be shown in the ESRT instead of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID?
Yes, the platform would have to define the fill_image_type_guid_array function which would populate the ImageTypeId values in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array, and the image GUID values would then show up as part of the ESRT table.
As part of this patchset, I have added this function for the STM32MP1 DK2 board.
-sughosh
The UpdateImageTypeId value from the capsule is used to compare with the ImageTypeId values returned by the GetImageInfo function to check if the given FMP protocol can be used for the update.
-sughosh
[...]
Regards /Ilias

On 2/17/22 11:10, Sughosh Ganu wrote:
On Thu, 17 Feb 2022 at 13:52, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
>
[...]
> Yes, we can use --index when we know the index value corresponding to > the firmware image that we need to update. But like I mentioned in my > earlier reply, for A/B updates, we do not know what the index value is > going to be. That is going to be determined at runtime.
I don't think so. See below for alternative approach.
> Also, the point I was making is that we can have a capsule which is > consumed by an FMP protocol which has more than one image, and those > images have different ImageTypeId/UpdateImageTypeId.
Yes, but it is a design choice in my first implementation. I didn't think that we need to "have a capsule which is consumed by an FMP protocol which has more than one image" as long as we use DFU framework (and FIT as standard format of aggregation on U-Boot).
But this design can be extended without any hassle, and more importantly without any regression, no? What kind of a problem does it create if the FMP can handle more than one image type.
Even as per the UEFI spec, we have the EFI_FIRMWARE_MANAGEMENT_CAPSULE header for all images to be managed by the FMP protocol which has multiple images with different UpdateImageTypeId.
>> >>> Please check the >>> GenerateCapsule script in EDK2. In case of a multi payload based >>> capsule, individual parameters like the UpdateImageTypeId are passed >>> through the json file, where each of the UpdateImageTypeId has a >>> different value per payload. >>> >>>> >>>>>> 2) Each firmware object handled by a given FMP driver can further be >>>>>> identified by ImageIndex. >>>>>> >>>>>> My implementation of efi_fmp_find() does (1) and Raw FMP driver does >>>>>> (2) in efi_firmware_raw_set_image() which takes "image_index" as >>>>>> a parameter. >>>>>> >>>>>> Using ImageTypeId as an identifier is simply wrong in my opinion and >>>>>> doesn't meet the UEFI specification. >>>>> >>>>> So, as per what you are stating, all payloads under a given >>>>> EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same >>>>> ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or >>>>> EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in >>>>> the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two >>>>> values, > the check in efi_fmp_find to compare the UpdateImageTypeId >>>>> with the ImageTypeId retrieved from the image descriptor would simply >>>>> fail. >>>> >>>> I don't follow your point. >>>> Please elaborate a bit more. >>> >>> The current implementation of GetImageInfo, passes either of >>> EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or >>> EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image >>> descriptor array. So, in case the capsule is generated with a '--guid' >>> value which is different from these two values, the check in >>> efi_fmp_find on line 204 will fail. >> >> That is an expected behavior, isn't it? > > Yes it is. Do not contest that. > >> If you want to use a different FMP driver (with another GUID), >> you naturally need to add your own FMP driver. > > This is where I differ. We can use the same FMP protocol instance for > any type of ImageTypeId. I do not see why we need to define a > different FMP protocol instance for a GUID value other than what has > been defined for u-boot raw and u-boot FIT GUIDs.
I do understand part of your concern a bit. I thought of using the same ImageType GUID, say IMAGE_TYPE_DFU_GUID, at first but we needed different GUIDs here simply because we need to determine the format of payload, FIT format or raw binary.
> The platform can give us the image descriptor array, and with that, > the same FMP instance can be used for any type of image(ImageTypeId).
"any type of image"? Really?
The raw FMP instance can certainly handle any type of binary payloads right. There is no restriction on what type of payload it is as long as it is all going as a single entity to a given dfu partition.
> >> >> >>> This means that unless the --guid >>> value passed to the capsule generation is either of u-boot FIT or >>> u-boot raw, the current FMP protocol for raw devices cannot be used. >>> Why do we need that restriction. It should be possible to use the raw >>> FMP protocol for any other type of image types as well. >>> >>> >>>> >>>>> I think this interpretation of the UEFI spec is incorrect, since the >>>>> spec states that the ImageTypeId and the UpdateImageTypeId are fields >>>>> used to identify the firmware component targeted for the update. If >>>>> all values in the image descriptor array and the UpdateImageTypeId are >>>>> the same, why have this field in the first place for individual >>>>> images. >>>> >>>> As I said, ImageIndex is for that purpose. >>> >>> Yes, that is one possible way in the scenario where the ImageIndex is >>> determined at the capsule generation time. But, for the A/B update >>> scenario, we do not know the ImageIndex at build time >> >> "Build time" of what? > > Of the capsule. > >> I think that users should know how "dfu_alt_info" is defined >> (in other words, where the firmware be located on the target system) >> when capsule files are created. > > That is true for a non A/B scenario. And that is how it works in the > non A/B updates case. But for A/B updates, since the determination of > the "location" where the firmware image has to be written will be done > only at runtime, we cannot use the --index to differentiate.
Yes, we can :)
You know what I mean -- if we could use the same logic, I would not have added all that code :)
First of all, my essential assumption in either FIT or RAW FMP driver is that U-Boot has (somehow conceptually) single firmware blob represented by DFU or dfu_alt_info. As I said, each object or location in dfu_alt_info can be further identified by index or "UpdateImageIndex".
Let's assume that we have two locations of firmware, fw1 and fw2, and that we have two bank A and B. Then we will define dfu_alt_info as follows: <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; |<--- 1st set --->|<--- 2nd set --->|
When you want to update bank A, we can use the first set of dfu_alt_info, and use the second set of dfu_alt_info for bank B. At runtime, you should know which bank you're working on, and therefore you should know the exact physical location from dfu_alt_info.
Please note that you don't have to change the syntax of dfu_alt_info at all. Simply offset the location with 0 for bank A and with 2 for bank B.
I'll try digging a bit more, but I think the current approach is not working as it was intended wrt to the EFI spec. My reading of the spec and specifically section 23.3.2 is that a Capsule consists of an EFI capsule header and a payload. The payload now has an EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER which in it's turn can host multiple firmware images of different type described in EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
An FMP implementation should read the UpdateImageTypeId's used to identify the image you are updating and from that derive the UpdateImageIndex which SetImage will use. That would give you the ability to update the all the firmware components with a single capsule.
Sughosh what about the ESRT table generation? If you use different UpdateImageTypeId those should be reflected on the ESRT tables from the OS
That would depend on the values populated in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array by the GetImageInfo function. The image descriptor structure has an ImageTypeId field. The value of ImageTypeId is what will be reflected in the ESRT table.
In the current implementation, all the images in the ESRT table will show the same ImageTypeId value, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID.
This is wrong. According to the the UEFI 2.9 specification the UpdateImageTypeId is used to "identify (the) device firmware targeted by this update". It does not identify the format in which the firmware is delivered.
So this needs to be fixed in the next revision of this patch series.
For each firmware part that can be updated provide a unique GUID.
Best regards
Heinrich
Yea I was mostly asking wrt to A/B updates. Would the correct UUID be shown in the ESRT instead of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID?
Yes, the platform would have to define the fill_image_type_guid_array function which would populate the ImageTypeId values in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array, and the image GUID values would then show up as part of the ESRT table.
As part of this patchset, I have added this function for the STM32MP1 DK2 board.
-sughosh
The UpdateImageTypeId value from the capsule is used to compare with the ImageTypeId values returned by the GetImageInfo function to check if the given FMP protocol can be used for the update.
-sughosh
[...]
Regards /Ilias

hello Heinrich,
On Sat, 26 Feb 2022 at 12:24, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 2/17/22 11:10, Sughosh Ganu wrote:
On Thu, 17 Feb 2022 at 13:52, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
>>
[...]
>> Yes, we can use --index when we know the index value corresponding to >> the firmware image that we need to update. But like I mentioned in my >> earlier reply, for A/B updates, we do not know what the index value is >> going to be. That is going to be determined at runtime. > > I don't think so. See below for alternative approach. > >> Also, the point I was making is that we can have a capsule which is >> consumed by an FMP protocol which has more than one image, and those >> images have different ImageTypeId/UpdateImageTypeId. > > Yes, but it is a design choice in my first implementation. > I didn't think that we need to "have a capsule which is consumed > by an FMP protocol which has more than one image" as long as we > use DFU framework (and FIT as standard format of aggregation on U-Boot).
But this design can be extended without any hassle, and more importantly without any regression, no? What kind of a problem does it create if the FMP can handle more than one image type.
Even as per the UEFI spec, we have the EFI_FIRMWARE_MANAGEMENT_CAPSULE header for all images to be managed by the FMP protocol which has multiple images with different UpdateImageTypeId.
> >>> >>>> Please check the >>>> GenerateCapsule script in EDK2. In case of a multi payload based >>>> capsule, individual parameters like the UpdateImageTypeId are passed >>>> through the json file, where each of the UpdateImageTypeId has a >>>> different value per payload. >>>> >>>>> >>>>>>> 2) Each firmware object handled by a given FMP driver can further be >>>>>>> identified by ImageIndex. >>>>>>> >>>>>>> My implementation of efi_fmp_find() does (1) and Raw FMP driver does >>>>>>> (2) in efi_firmware_raw_set_image() which takes "image_index" as >>>>>>> a parameter. >>>>>>> >>>>>>> Using ImageTypeId as an identifier is simply wrong in my opinion and >>>>>>> doesn't meet the UEFI specification. >>>>>> >>>>>> So, as per what you are stating, all payloads under a given >>>>>> EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same >>>>>> ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or >>>>>> EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in >>>>>> the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two >>>>>> values, > the check in efi_fmp_find to compare the UpdateImageTypeId >>>>>> with the ImageTypeId retrieved from the image descriptor would simply >>>>>> fail. >>>>> >>>>> I don't follow your point. >>>>> Please elaborate a bit more. >>>> >>>> The current implementation of GetImageInfo, passes either of >>>> EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or >>>> EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image >>>> descriptor array. So, in case the capsule is generated with a '--guid' >>>> value which is different from these two values, the check in >>>> efi_fmp_find on line 204 will fail. >>> >>> That is an expected behavior, isn't it? >> >> Yes it is. Do not contest that. >> >>> If you want to use a different FMP driver (with another GUID), >>> you naturally need to add your own FMP driver. >> >> This is where I differ. We can use the same FMP protocol instance for >> any type of ImageTypeId. I do not see why we need to define a >> different FMP protocol instance for a GUID value other than what has >> been defined for u-boot raw and u-boot FIT GUIDs. > > I do understand part of your concern a bit. > I thought of using the same ImageType GUID, say IMAGE_TYPE_DFU_GUID, at first > but we needed different GUIDs here simply because we need to determine > the format of payload, FIT format or raw binary. > >> The platform can give us the image descriptor array, and with that, >> the same FMP instance can be used for any type of image(ImageTypeId). > > "any type of image"? Really?
The raw FMP instance can certainly handle any type of binary payloads right. There is no restriction on what type of payload it is as long as it is all going as a single entity to a given dfu partition.
>> >>> >>> >>>> This means that unless the --guid >>>> value passed to the capsule generation is either of u-boot FIT or >>>> u-boot raw, the current FMP protocol for raw devices cannot be used. >>>> Why do we need that restriction. It should be possible to use the raw >>>> FMP protocol for any other type of image types as well. >>>> >>>> >>>>> >>>>>> I think this interpretation of the UEFI spec is incorrect, since the >>>>>> spec states that the ImageTypeId and the UpdateImageTypeId are fields >>>>>> used to identify the firmware component targeted for the update. If >>>>>> all values in the image descriptor array and the UpdateImageTypeId are >>>>>> the same, why have this field in the first place for individual >>>>>> images. >>>>> >>>>> As I said, ImageIndex is for that purpose. >>>> >>>> Yes, that is one possible way in the scenario where the ImageIndex is >>>> determined at the capsule generation time. But, for the A/B update >>>> scenario, we do not know the ImageIndex at build time >>> >>> "Build time" of what? >> >> Of the capsule. >> >>> I think that users should know how "dfu_alt_info" is defined >>> (in other words, where the firmware be located on the target system) >>> when capsule files are created. >> >> That is true for a non A/B scenario. And that is how it works in the >> non A/B updates case. But for A/B updates, since the determination of >> the "location" where the firmware image has to be written will be done >> only at runtime, we cannot use the --index to differentiate. > > Yes, we can :)
You know what I mean -- if we could use the same logic, I would not have added all that code :)
> > First of all, my essential assumption in either FIT or RAW FMP driver > is that U-Boot has (somehow conceptually) single firmware blob represented > by DFU or dfu_alt_info. As I said, each object or location in > dfu_alt_info can be further identified by index or "UpdateImageIndex". > > Let's assume that we have two locations of firmware, fw1 and fw2, and > that we have two bank A and B. > Then we will define dfu_alt_info as follows: > <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; > |<--- 1st set --->|<--- 2nd set --->| > > When you want to update bank A, we can use the first set of dfu_alt_info, > and use the second set of dfu_alt_info for bank B. > At runtime, you should know which bank you're working on, and therefore > you should know the exact physical location from dfu_alt_info. > > Please note that you don't have to change the syntax of dfu_alt_info > at all. Simply offset the location with 0 for bank A and with 2 for bank B.
I'll try digging a bit more, but I think the current approach is not working as it was intended wrt to the EFI spec. My reading of the spec and specifically section 23.3.2 is that a Capsule consists of an EFI capsule header and a payload. The payload now has an EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER which in it's turn can host multiple firmware images of different type described in EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
An FMP implementation should read the UpdateImageTypeId's used to identify the image you are updating and from that derive the UpdateImageIndex which SetImage will use. That would give you the ability to update the all the firmware components with a single capsule.
Sughosh what about the ESRT table generation? If you use different UpdateImageTypeId those should be reflected on the ESRT tables from the OS
That would depend on the values populated in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array by the GetImageInfo function. The image descriptor structure has an ImageTypeId field. The value of ImageTypeId is what will be reflected in the ESRT table.
In the current implementation, all the images in the ESRT table will show the same ImageTypeId value, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID.
This is wrong. According to the the UEFI 2.9 specification the UpdateImageTypeId is used to "identify (the) device firmware targeted by this update". It does not identify the format in which the firmware is delivered.
So this needs to be fixed in the next revision of this patch series.
This patch series is actually adding that platform function which populates the image descriptor array with the image GUID's -- patch 6 of this series[1] actually does that for the ST DK2 platform. This discussion was because Takahiro wanted to use the same image GUID(u-boot raw/FIT) for all the images, and use the image index for identifying where the image is to be written.
I guess with what you are stating, along with Ilias's opinion on this, I will send the next version with the same approach, i.e. using a platform function to populate the image GUIDs in the firmware image descriptor array. With this, each firmware image will have a different GUID which can be used to identify the image.
-sughosh
[1] - https://lists.denx.de/pipermail/u-boot/2022-February/474434.html
For each firmware part that can be updated provide a unique GUID.
Best regards
Heinrich
Yea I was mostly asking wrt to A/B updates. Would the correct UUID be shown in the ESRT instead of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID?
Yes, the platform would have to define the fill_image_type_guid_array function which would populate the ImageTypeId values in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array, and the image GUID values would then show up as part of the ESRT table.
As part of this patchset, I have added this function for the STM32MP1 DK2 board.
-sughosh
The UpdateImageTypeId value from the capsule is used to compare with the ImageTypeId values returned by the GetImageInfo function to check if the given FMP protocol can be used for the update.
-sughosh
[...]
Regards /Ilias

On Sat, Feb 26, 2022 at 03:24:10PM +0530, Sughosh Ganu wrote:
hello Heinrich,
On Sat, 26 Feb 2022 at 12:24, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 2/17/22 11:10, Sughosh Ganu wrote:
On Thu, 17 Feb 2022 at 13:52, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
>>>
[...]
>>> Yes, we can use --index when we know the index value corresponding to >>> the firmware image that we need to update. But like I mentioned in my >>> earlier reply, for A/B updates, we do not know what the index value is >>> going to be. That is going to be determined at runtime. >> >> I don't think so. See below for alternative approach. >> >>> Also, the point I was making is that we can have a capsule which is >>> consumed by an FMP protocol which has more than one image, and those >>> images have different ImageTypeId/UpdateImageTypeId. >> >> Yes, but it is a design choice in my first implementation. >> I didn't think that we need to "have a capsule which is consumed >> by an FMP protocol which has more than one image" as long as we >> use DFU framework (and FIT as standard format of aggregation on U-Boot). > > But this design can be extended without any hassle, and more > importantly without any regression, no? What kind of a problem does it > create if the FMP can handle more than one image type. > > Even as per the UEFI spec, we have the EFI_FIRMWARE_MANAGEMENT_CAPSULE > header for all images to be managed by the FMP protocol which has > multiple images with different UpdateImageTypeId. > >> >>>> >>>>> Please check the >>>>> GenerateCapsule script in EDK2. In case of a multi payload based >>>>> capsule, individual parameters like the UpdateImageTypeId are passed >>>>> through the json file, where each of the UpdateImageTypeId has a >>>>> different value per payload. >>>>> >>>>>> >>>>>>>> 2) Each firmware object handled by a given FMP driver can further be >>>>>>>> identified by ImageIndex. >>>>>>>> >>>>>>>> My implementation of efi_fmp_find() does (1) and Raw FMP driver does >>>>>>>> (2) in efi_firmware_raw_set_image() which takes "image_index" as >>>>>>>> a parameter. >>>>>>>> >>>>>>>> Using ImageTypeId as an identifier is simply wrong in my opinion and >>>>>>>> doesn't meet the UEFI specification. >>>>>>> >>>>>>> So, as per what you are stating, all payloads under a given >>>>>>> EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER should have the same >>>>>>> ImageTypeId, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or >>>>>>> EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID. Same applies for all images in >>>>>>> the EFI_FIRMWARE_IMAGE_DESCRIPTOR. Because, without one of the two >>>>>>> values, > the check in efi_fmp_find to compare the UpdateImageTypeId >>>>>>> with the ImageTypeId retrieved from the image descriptor would simply >>>>>>> fail. >>>>>> >>>>>> I don't follow your point. >>>>>> Please elaborate a bit more. >>>>> >>>>> The current implementation of GetImageInfo, passes either of >>>>> EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or >>>>> EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID for all the images of the image >>>>> descriptor array. So, in case the capsule is generated with a '--guid' >>>>> value which is different from these two values, the check in >>>>> efi_fmp_find on line 204 will fail. >>>> >>>> That is an expected behavior, isn't it? >>> >>> Yes it is. Do not contest that. >>> >>>> If you want to use a different FMP driver (with another GUID), >>>> you naturally need to add your own FMP driver. >>> >>> This is where I differ. We can use the same FMP protocol instance for >>> any type of ImageTypeId. I do not see why we need to define a >>> different FMP protocol instance for a GUID value other than what has >>> been defined for u-boot raw and u-boot FIT GUIDs. >> >> I do understand part of your concern a bit. >> I thought of using the same ImageType GUID, say IMAGE_TYPE_DFU_GUID, at first >> but we needed different GUIDs here simply because we need to determine >> the format of payload, FIT format or raw binary. >> >>> The platform can give us the image descriptor array, and with that, >>> the same FMP instance can be used for any type of image(ImageTypeId). >> >> "any type of image"? Really? > > The raw FMP instance can certainly handle any type of binary payloads > right. There is no restriction on what type of payload it is as long > as it is all going as a single entity to a given dfu partition. > >>> >>>> >>>> >>>>> This means that unless the --guid >>>>> value passed to the capsule generation is either of u-boot FIT or >>>>> u-boot raw, the current FMP protocol for raw devices cannot be used. >>>>> Why do we need that restriction. It should be possible to use the raw >>>>> FMP protocol for any other type of image types as well. >>>>> >>>>> >>>>>> >>>>>>> I think this interpretation of the UEFI spec is incorrect, since the >>>>>>> spec states that the ImageTypeId and the UpdateImageTypeId are fields >>>>>>> used to identify the firmware component targeted for the update. If >>>>>>> all values in the image descriptor array and the UpdateImageTypeId are >>>>>>> the same, why have this field in the first place for individual >>>>>>> images. >>>>>> >>>>>> As I said, ImageIndex is for that purpose. >>>>> >>>>> Yes, that is one possible way in the scenario where the ImageIndex is >>>>> determined at the capsule generation time. But, for the A/B update >>>>> scenario, we do not know the ImageIndex at build time >>>> >>>> "Build time" of what? >>> >>> Of the capsule. >>> >>>> I think that users should know how "dfu_alt_info" is defined >>>> (in other words, where the firmware be located on the target system) >>>> when capsule files are created. >>> >>> That is true for a non A/B scenario. And that is how it works in the >>> non A/B updates case. But for A/B updates, since the determination of >>> the "location" where the firmware image has to be written will be done >>> only at runtime, we cannot use the --index to differentiate. >> >> Yes, we can :) > > You know what I mean -- if we could use the same logic, I would not > have added all that code :) > >> >> First of all, my essential assumption in either FIT or RAW FMP driver >> is that U-Boot has (somehow conceptually) single firmware blob represented >> by DFU or dfu_alt_info. As I said, each object or location in >> dfu_alt_info can be further identified by index or "UpdateImageIndex". >> >> Let's assume that we have two locations of firmware, fw1 and fw2, and >> that we have two bank A and B. >> Then we will define dfu_alt_info as follows: >> <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; >> |<--- 1st set --->|<--- 2nd set --->| >> >> When you want to update bank A, we can use the first set of dfu_alt_info, >> and use the second set of dfu_alt_info for bank B. >> At runtime, you should know which bank you're working on, and therefore >> you should know the exact physical location from dfu_alt_info. >> >> Please note that you don't have to change the syntax of dfu_alt_info >> at all. Simply offset the location with 0 for bank A and with 2 for bank B.
I'll try digging a bit more, but I think the current approach is not working as it was intended wrt to the EFI spec. My reading of the spec and specifically section 23.3.2 is that a Capsule consists of an EFI capsule header and a payload. The payload now has an EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER which in it's turn can host multiple firmware images of different type described in EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
An FMP implementation should read the UpdateImageTypeId's used to identify the image you are updating and from that derive the UpdateImageIndex which SetImage will use. That would give you the ability to update the all the firmware components with a single capsule.
Sughosh what about the ESRT table generation? If you use different UpdateImageTypeId those should be reflected on the ESRT tables from the OS
That would depend on the values populated in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array by the GetImageInfo function. The image descriptor structure has an ImageTypeId field. The value of ImageTypeId is what will be reflected in the ESRT table.
In the current implementation, all the images in the ESRT table will show the same ImageTypeId value, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID.
This is wrong. According to the the UEFI 2.9 specification the UpdateImageTypeId is used to "identify (the) device firmware targeted by this update". It does not identify the format in which the firmware is delivered.
So this needs to be fixed in the next revision of this patch series.
This patch series is actually adding that platform function which populates the image descriptor array with the image GUID's -- patch 6 of this series[1] actually does that for the ST DK2 platform. This discussion was because Takahiro wanted to use the same image GUID(u-boot raw/FIT) for all the images, and use the image index for identifying where the image is to be written.
The discussion depends on what the *firmware* means. With my FMP drivers (either FIT or raw), I intended a *set of firmware* managed with a *single* "dfu_alt_info", which may include various *images* for different target *components* as the original DFU framework does.
-Takahiro Akashi
I guess with what you are stating, along with Ilias's opinion on this, I will send the next version with the same approach, i.e. using a platform function to populate the image GUIDs in the firmware image descriptor array. With this, each firmware image will have a different GUID which can be used to identify the image.
-sughosh
[1] - https://lists.denx.de/pipermail/u-boot/2022-February/474434.html
For each firmware part that can be updated provide a unique GUID.
Best regards
Heinrich
Yea I was mostly asking wrt to A/B updates. Would the correct UUID be shown in the ESRT instead of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID?
Yes, the platform would have to define the fill_image_type_guid_array function which would populate the ImageTypeId values in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array, and the image GUID values would then show up as part of the ESRT table.
As part of this patchset, I have added this function for the STM32MP1 DK2 board.
-sughosh
The UpdateImageTypeId value from the capsule is used to compare with the ImageTypeId values returned by the GetImageInfo function to check if the given FMP protocol can be used for the update.
-sughosh
[...]
Regards /Ilias

Akashi-san
[...]
>>>>> I think that users should know how "dfu_alt_info" is defined >>>>> (in other words, where the firmware be located on the target system) >>>>> when capsule files are created. >>>> >>>> That is true for a non A/B scenario. And that is how it works in the >>>> non A/B updates case. But for A/B updates, since the determination of >>>> the "location" where the firmware image has to be written will be done >>>> only at runtime, we cannot use the --index to differentiate. >>> >>> Yes, we can :) >> >> You know what I mean -- if we could use the same logic, I would not >> have added all that code :) >> >>> >>> First of all, my essential assumption in either FIT or RAW FMP driver >>> is that U-Boot has (somehow conceptually) single firmware blob represented >>> by DFU or dfu_alt_info. As I said, each object or location in >>> dfu_alt_info can be further identified by index or "UpdateImageIndex". >>> >>> Let's assume that we have two locations of firmware, fw1 and fw2, and >>> that we have two bank A and B. >>> Then we will define dfu_alt_info as follows: >>> <loc of fw1 for A>;<loc of fw2 for A>;<loc of fw1 for B>;<loc of fw2 for B>; >>> |<--- 1st set --->|<--- 2nd set --->| >>> >>> When you want to update bank A, we can use the first set of dfu_alt_info, >>> and use the second set of dfu_alt_info for bank B. >>> At runtime, you should know which bank you're working on, and therefore >>> you should know the exact physical location from dfu_alt_info. >>> >>> Please note that you don't have to change the syntax of dfu_alt_info >>> at all. Simply offset the location with 0 for bank A and with 2 for bank B. > > I'll try digging a bit more, but I think the current approach is not > working as it was intended wrt to the EFI spec. My reading of the spec > and specifically section 23.3.2 is that a Capsule consists of an > EFI capsule header and a payload. The payload now has an > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER which in it's turn can host multiple > firmware images of different type described in EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER. > > An FMP implementation should read the UpdateImageTypeId's used to identify > the image you are updating and from that derive the UpdateImageIndex > which SetImage will use. That would give you the ability to update the > all the firmware components with a single capsule. > > Sughosh what about the ESRT table generation? If you use different UpdateImageTypeId > those should be reflected on the ESRT tables from the OS
That would depend on the values populated in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array by the GetImageInfo function. The image descriptor structure has an ImageTypeId field. The value of ImageTypeId is what will be reflected in the ESRT table.
In the current implementation, all the images in the ESRT table will show the same ImageTypeId value, either EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID or EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID.
This is wrong. According to the the UEFI 2.9 specification the UpdateImageTypeId is used to "identify (the) device firmware targeted by this update". It does not identify the format in which the firmware is delivered.
So this needs to be fixed in the next revision of this patch series.
This patch series is actually adding that platform function which populates the image descriptor array with the image GUID's -- patch 6 of this series[1] actually does that for the ST DK2 platform. This discussion was because Takahiro wanted to use the same image GUID(u-boot raw/FIT) for all the images, and use the image index for identifying where the image is to be written.
The discussion depends on what the *firmware* means. With my FMP drivers (either FIT or raw), I intended a *set of firmware* managed with a *single* "dfu_alt_info", which may include various *images* for different target *components* as the original DFU framework does.
I still think we should fix that. The current code is working, but it's not what the EFI spec describes. I think we should do it the other way around.
IOW the board defines the UUID's for the firmware partitions it needs to update. The FMP driver should then populate those properly in an ESRT table and also generate an appropriate dfu_alt_info (or similar) on the fly.
Regards /Ilias
-Takahiro Akashi
I guess with what you are stating, along with Ilias's opinion on this, I will send the next version with the same approach, i.e. using a platform function to populate the image GUIDs in the firmware image descriptor array. With this, each firmware image will have a different GUID which can be used to identify the image.
-sughosh
[1] - https://lists.denx.de/pipermail/u-boot/2022-February/474434.html
For each firmware part that can be updated provide a unique GUID.
Best regards
Heinrich
Yea I was mostly asking wrt to A/B updates. Would the correct UUID be shown in the ESRT instead of EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID?
Yes, the platform would have to define the fill_image_type_guid_array function which would populate the ImageTypeId values in the EFI_FIRMWARE_IMAGE_DESCRIPTOR array, and the image GUID values would then show up as part of the ESRT table.
As part of this patchset, I have added this function for the STM32MP1 DK2 board.
-sughosh
The UpdateImageTypeId value from the capsule is used to compare with the ImageTypeId values returned by the GetImageInfo function to check if the given FMP protocol can be used for the update.
-sughosh
[...]
Regards /Ilias

The EFI_FIRMWARE_IMAGE_DESCRIPTOR array is returned by the Firmware Management Protocol's(FMP) GetImageInfo function. The image descriptor array contains the ImageTypeId which is a GUID identifying the firmware images that are supported by the instance of the FMP. These ImageTypeId values are compared against the value in the capsule to identify the FMP instance to be used for the capsule.
Add a function for the GPT partitioned device based ST platforms for filling up the image descriptor array with the ImageTypeId values. For the GPT partitioned devices, the array can be populated by reading the GPT header which contains the Partition Entry Array, where each entry contains the PartitionTypeGUID for the corresponding image.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org ---
Changes since V3: * Define the function fill_image_type_guid_array for the ST DK2 board for GPT partitioned devices.
board/st/stm32mp1/stm32mp1.c | 94 ++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 5525b69392..fc14c9808b 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -1021,4 +1021,98 @@ void fwu_plat_get_bootidx(void *boot_idx)
*bootidx = readl(TAMP_BOOTCOUNT); } + +static int fill_gpt_partition_guids(struct blk_desc *desc, + efi_guid_t **part_guid_arr) +{ + int i; + u32 part; + int alt_num; + struct dfu_entity *dfu; + struct disk_partition info; + efi_guid_t part_type_guid; + efi_guid_t null_guid = NULL_GUID; + efi_status_t ret = EFI_SUCCESS; + + dfu_init_env_entities(NULL, NULL); + + alt_num = 0; + list_for_each_entry(dfu, &dfu_list, list) { + ++alt_num; + } + + if (!alt_num) { + log_warning("Probably dfu_alt_info not defined\n"); + ret = EFI_NOT_READY; + goto out; + } + + *part_guid_arr = malloc(sizeof(efi_guid_t) * alt_num); + if (!*part_guid_arr) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + + for (i = 0; i < alt_num; i++) + guidcpy((*part_guid_arr + i), &null_guid); + + for (i = 0, part = 1; i < alt_num; i++) { + dfu = dfu_get_entity(i); + + if (!dfu) + continue; + + /* + * Currently, Multi Bank update + * feature is being supported + * only on GPT partitioned + * MMC/SD devices. + */ + if (dfu->dev_type != DFU_DEV_MMC) + continue; + + if (part_get_info(desc, part, &info)) { + part++; + continue; + } + + uuid_str_to_bin(info.type_guid, part_type_guid.b, + UUID_STR_FORMAT_GUID); + guidcpy((*part_guid_arr + i), &part_type_guid); + part++; + } + +out: + dfu_free_entities(); + + return ret; +} + +efi_status_t fill_image_type_guid_array(const efi_guid_t __always_unused + *default_guid, + efi_guid_t **part_guid_arr) +{ + int ret; + struct udevice *dev; + struct blk_desc *desc; + + /* + * Get the storage device on which the + * FWU metadata has been stored + */ + ret = fwu_get_mdata_device(&dev); + if (ret) { + log_err("Unable to get FWU metadata device\n"); + return EFI_DEVICE_ERROR; + } + + desc = dev_get_uclass_plat(dev); + if (!desc) { + log_err("Block device not found\n"); + return EFI_DEVICE_ERROR; + } + + return fill_gpt_partition_guids(desc, part_guid_arr); +} + #endif /* CONFIG_FWU_MULTI_BANK_UPDATE */

The FWU Multi Bank Update specification requires the Update Agent to carry out certain checks at the time of platform boot. The Update Agent is the component which is responsible for updating the firmware components and maintaining and keeping the metadata in sync.
The spec requires that the Update Agent perform the following checks at the time of boot * Sanity check of both the metadata copies maintained by the platform. * Get the boot index passed to U-Boot by the prior stage bootloader and use this value for metadata bookkeeping. * Check if the system is booting in Trial State. If the system boots in the Trial State for more than a specified number of boot counts, change the Active Bank to be booting the platform from.
Add these checks in the board initialisation sequence, invoked after relocation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org ---
Changes since V3: * Change the TrialStateCtr efi variable attribute to remove the runtime attribute
common/board_r.c | 6 ++ include/fwu.h | 3 + lib/fwu_updates/fwu.c | 178 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 lib/fwu_updates/fwu.c
diff --git a/common/board_r.c b/common/board_r.c index 31a59c585a..81678870b9 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -78,6 +78,9 @@ #ifdef CONFIG_EFI_SETUP_EARLY #include <efi_loader.h> #endif +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE +#include <fwu.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -805,6 +808,9 @@ static init_fnc_t init_sequence_r[] = { #endif #ifdef CONFIG_EFI_SETUP_EARLY (init_fnc_t)efi_init_obj_list, +#endif +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE + fwu_boottime_checks, #endif run_main_loop, }; diff --git a/include/fwu.h b/include/fwu.h index 90b8cd41e5..5a329d9ef7 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -37,6 +37,9 @@ struct fwu_mdata_ops { EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+int fwu_boottime_checks(void); +u8 fwu_update_checks_pass(void); + int fwu_get_mdata(struct fwu_mdata **mdata); int fwu_update_mdata(struct fwu_mdata *mdata); int fwu_get_active_index(u32 *active_idx); diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c new file mode 100644 index 0000000000..86933123e7 --- /dev/null +++ b/lib/fwu_updates/fwu.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <dm.h> +#include <efi.h> +#include <efi_loader.h> +#include <efi_variable.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <malloc.h> + +#include <linux/errno.h> +#include <linux/types.h> + +static u8 trial_state = 0; +static u8 boottime_check = 0; + +static int fwu_trial_state_check(void) +{ + int ret, i; + efi_status_t status; + efi_uintn_t var_size; + u16 trial_state_ctr; + u32 nimages, active_bank, var_attributes, active_idx; + struct fwu_mdata *mdata = NULL; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_bank_info; + + ret = fwu_get_mdata(&mdata); + if (ret < 0) + return ret; + + ret = 0; + nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK; + active_bank = mdata->active_index; + img_entry = &mdata->img_entry[0]; + for (i = 0; i < nimages; i++) { + img_bank_info = &img_entry[i].img_bank_info[active_bank]; + if (!img_bank_info->accepted) { + trial_state = 1; + break; + } + } + + if (trial_state) { + var_size = (efi_uintn_t)sizeof(trial_state_ctr); + log_info("System booting in Trial State\n"); + var_attributes = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS; + status = efi_get_variable_int(L"TrialStateCtr", + &efi_global_variable_guid, + &var_attributes, + &var_size, &trial_state_ctr, + NULL); + if (status != EFI_SUCCESS) { + log_err("Unable to read TrialStateCtr variable\n"); + ret = -1; + goto out; + } + + ++trial_state_ctr; + if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) { + log_info("Trial State count exceeded. Revert back to previous_active_index\n"); + active_idx = mdata->active_index; + ret = fwu_revert_boot_index(); + if (ret < 0) { + log_err("Unable to revert active_index\n"); + goto out; + } + + trial_state_ctr = 0; + status = efi_set_variable_int(L"TrialStateCtr", + &efi_global_variable_guid, + var_attributes, + 0, + &trial_state_ctr, false); + if (status != EFI_SUCCESS) { + log_err("Unable to clear TrialStateCtr variable\n"); + ret = -1; + goto out; + } + } else { + status = efi_set_variable_int(L"TrialStateCtr", + &efi_global_variable_guid, + var_attributes, + var_size, + &trial_state_ctr, false); + if (status != EFI_SUCCESS) { + log_err("Unable to increment TrialStateCtr variable\n"); + ret = -1; + goto out; + } else { + ret = 0; + } + } + } else { + trial_state_ctr = 0; + ret = 0; + status = efi_set_variable_int(L"TrialStateCtr", + &efi_global_variable_guid, + 0, + 0, &trial_state_ctr, + NULL); + } + +out: + free(mdata); + return ret; +} + +u8 fwu_update_checks_pass(void) +{ + return !trial_state && boottime_check; +} + +int fwu_boottime_checks(void) +{ + int ret; + struct udevice *dev; + u32 boot_idx, active_idx; + + if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) { + log_err("FWU Metadata device not found\n"); + boottime_check = 0; + return 0; + } + + ret = fwu_mdata_check(); + if (ret < 0) { + boottime_check = 0; + 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"); + boottime_check = 0; + return 0; + } + + ret = fwu_get_active_index(&active_idx); + if (ret < 0) { + log_err("Unable to read active_index\n"); + boottime_check = 0; + return 0; + } + + if (boot_idx != active_idx) { + log_info("Boot idx %u is not matching active idx %u, changing active_idx\n", + boot_idx, active_idx); + ret = fwu_update_active_index(boot_idx); + if (ret < 0) + boottime_check = 0; + else + boottime_check = 1; + + return 0; + } + + ret = fwu_trial_state_check(); + if (ret < 0) + boottime_check = 0; + else + boottime_check = 1; + + return 0; +}

po 7. 2. 2022 v 19:22 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
The FWU Multi Bank Update specification requires the Update Agent to carry out certain checks at the time of platform boot. The Update Agent is the component which is responsible for updating the firmware components and maintaining and keeping the metadata in sync.
The spec requires that the Update Agent perform the following checks at the time of boot
- Sanity check of both the metadata copies maintained by the platform.
- Get the boot index passed to U-Boot by the prior stage bootloader and use this value for metadata bookkeeping.
- Check if the system is booting in Trial State. If the system boots in the Trial State for more than a specified number of boot counts, change the Active Bank to be booting the platform from.
Add these checks in the board initialisation sequence, invoked after relocation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Change the TrialStateCtr efi variable attribute to remove the runtime attribute
common/board_r.c | 6 ++ include/fwu.h | 3 + lib/fwu_updates/fwu.c | 178 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 lib/fwu_updates/fwu.c
diff --git a/common/board_r.c b/common/board_r.c index 31a59c585a..81678870b9 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -78,6 +78,9 @@ #ifdef CONFIG_EFI_SETUP_EARLY #include <efi_loader.h> #endif +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE +#include <fwu.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -805,6 +808,9 @@ static init_fnc_t init_sequence_r[] = { #endif #ifdef CONFIG_EFI_SETUP_EARLY (init_fnc_t)efi_init_obj_list, +#endif +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
fwu_boottime_checks,
#endif run_main_loop, }; diff --git a/include/fwu.h b/include/fwu.h index 90b8cd41e5..5a329d9ef7 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -37,6 +37,9 @@ struct fwu_mdata_ops { EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+int fwu_boottime_checks(void); +u8 fwu_update_checks_pass(void);
int fwu_get_mdata(struct fwu_mdata **mdata); int fwu_update_mdata(struct fwu_mdata *mdata); int fwu_get_active_index(u32 *active_idx); diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c new file mode 100644 index 0000000000..86933123e7 --- /dev/null +++ b/lib/fwu_updates/fwu.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <dm.h> +#include <efi.h> +#include <efi_loader.h> +#include <efi_variable.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <malloc.h>
+#include <linux/errno.h> +#include <linux/types.h>
+static u8 trial_state = 0; +static u8 boottime_check = 0;
you don't need to initialize them to 0. They are in bss which is setup to 0 already.
+static int fwu_trial_state_check(void) +{
int ret, i;
efi_status_t status;
efi_uintn_t var_size;
u16 trial_state_ctr;
u32 nimages, active_bank, var_attributes, active_idx;
struct fwu_mdata *mdata = NULL;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
ret = fwu_get_mdata(&mdata);
if (ret < 0)
Isn't it easier to have if (ret) here?
return ret;
ret = 0;
Then you can remove this and the whole ret handling below is weird.
nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
active_bank = mdata->active_index;
img_entry = &mdata->img_entry[0];
for (i = 0; i < nimages; i++) {
img_bank_info = &img_entry[i].img_bank_info[active_bank];
if (!img_bank_info->accepted) {
trial_state = 1;
break;
}
}
if (trial_state) {
var_size = (efi_uintn_t)sizeof(trial_state_ctr);
log_info("System booting in Trial State\n");
var_attributes = EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS;
status = efi_get_variable_int(L"TrialStateCtr",
&efi_global_variable_guid,
&var_attributes,
&var_size, &trial_state_ctr,
NULL);
if (status != EFI_SUCCESS) {
log_err("Unable to read TrialStateCtr variable\n");
ret = -1;
Any reason not to use standard return macros? The same I see below too.
goto out;
}
++trial_state_ctr;
if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
log_info("Trial State count exceeded. Revert back to previous_active_index\n");
active_idx = mdata->active_index;
ret = fwu_revert_boot_index();
if (ret < 0) {
I would use if (ret) here.
log_err("Unable to revert active_index\n");
goto out;
}
trial_state_ctr = 0;
status = efi_set_variable_int(L"TrialStateCtr",
&efi_global_variable_guid,
var_attributes,
0,
&trial_state_ctr, false);
if (status != EFI_SUCCESS) {
log_err("Unable to clear TrialStateCtr variable\n");
ret = -1;
goto out;
}
} else {
status = efi_set_variable_int(L"TrialStateCtr",
&efi_global_variable_guid,
var_attributes,
var_size,
&trial_state_ctr, false);
if (status != EFI_SUCCESS) {
log_err("Unable to increment TrialStateCtr variable\n");
ret = -1;
goto out;
} else {
ret = 0;
Why do you need this? ret should be 0 when you get here.
}
}
} else {
trial_state_ctr = 0;
ret = 0;
the same here. You have ret=0 above that's why I think this is just an additional line here.
status = efi_set_variable_int(L"TrialStateCtr",
&efi_global_variable_guid,
0,
0, &trial_state_ctr,
NULL);
}
+out:
free(mdata);
return ret;
+}
+u8 fwu_update_checks_pass(void) +{
return !trial_state && boottime_check;
+}
+int fwu_boottime_checks(void) +{
int ret;
struct udevice *dev;
u32 boot_idx, active_idx;
if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
log_err("FWU Metadata device not found\n");
boottime_check = 0;
All these boottime_check initialization to 0 seems to me useless.
return 0;
}
ret = fwu_mdata_check();
if (ret < 0) {
up to you but I would also use if (ret) here.
boottime_check = 0;
It is zero already when you get here that's why all these = 0 lines should be IMHO removed.
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");
boottime_check = 0;
ditto.
return 0;
}
ret = fwu_get_active_index(&active_idx);
if (ret < 0) {
ditto.
log_err("Unable to read active_index\n");
boottime_check = 0;
ditto.
return 0;
}
if (boot_idx != active_idx) {
log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
boot_idx, active_idx);
ret = fwu_update_active_index(boot_idx);
if (ret < 0)
ditto.
boottime_check = 0;
ditto
else
boottime_check = 1;
return 0;
}
ret = fwu_trial_state_check();
if (ret < 0)
ditto
boottime_check = 0;
ditto.
else
boottime_check = 1;
return 0;
+}
2.17.1
Thanks, Michal

On Tue, 8 Feb 2022 at 16:23, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:22 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
The FWU Multi Bank Update specification requires the Update Agent to carry out certain checks at the time of platform boot. The Update Agent is the component which is responsible for updating the firmware components and maintaining and keeping the metadata in sync.
The spec requires that the Update Agent perform the following checks at the time of boot
- Sanity check of both the metadata copies maintained by the platform.
- Get the boot index passed to U-Boot by the prior stage bootloader and use this value for metadata bookkeeping.
- Check if the system is booting in Trial State. If the system boots in the Trial State for more than a specified number of boot counts, change the Active Bank to be booting the platform from.
Add these checks in the board initialisation sequence, invoked after relocation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Change the TrialStateCtr efi variable attribute to remove the runtime attribute
common/board_r.c | 6 ++ include/fwu.h | 3 + lib/fwu_updates/fwu.c | 178 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 lib/fwu_updates/fwu.c
diff --git a/common/board_r.c b/common/board_r.c index 31a59c585a..81678870b9 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -78,6 +78,9 @@ #ifdef CONFIG_EFI_SETUP_EARLY #include <efi_loader.h> #endif +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE +#include <fwu.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -805,6 +808,9 @@ static init_fnc_t init_sequence_r[] = { #endif #ifdef CONFIG_EFI_SETUP_EARLY (init_fnc_t)efi_init_obj_list, +#endif +#ifdef CONFIG_FWU_MULTI_BANK_UPDATE
fwu_boottime_checks,
#endif run_main_loop, }; diff --git a/include/fwu.h b/include/fwu.h index 90b8cd41e5..5a329d9ef7 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -37,6 +37,9 @@ struct fwu_mdata_ops { EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+int fwu_boottime_checks(void); +u8 fwu_update_checks_pass(void);
int fwu_get_mdata(struct fwu_mdata **mdata); int fwu_update_mdata(struct fwu_mdata *mdata); int fwu_get_active_index(u32 *active_idx); diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c new file mode 100644 index 0000000000..86933123e7 --- /dev/null +++ b/lib/fwu_updates/fwu.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <dm.h> +#include <efi.h> +#include <efi_loader.h> +#include <efi_variable.h> +#include <fwu.h> +#include <fwu_mdata.h> +#include <malloc.h>
+#include <linux/errno.h> +#include <linux/types.h>
+static u8 trial_state = 0; +static u8 boottime_check = 0;
you don't need to initialize them to 0. They are in bss which is setup to 0 already.
+static int fwu_trial_state_check(void) +{
int ret, i;
efi_status_t status;
efi_uintn_t var_size;
u16 trial_state_ctr;
u32 nimages, active_bank, var_attributes, active_idx;
struct fwu_mdata *mdata = NULL;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
ret = fwu_get_mdata(&mdata);
if (ret < 0)
Isn't it easier to have if (ret) here?
return ret;
ret = 0;
Then you can remove this and the whole ret handling below is weird.
nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK;
active_bank = mdata->active_index;
img_entry = &mdata->img_entry[0];
for (i = 0; i < nimages; i++) {
img_bank_info = &img_entry[i].img_bank_info[active_bank];
if (!img_bank_info->accepted) {
trial_state = 1;
break;
}
}
if (trial_state) {
var_size = (efi_uintn_t)sizeof(trial_state_ctr);
log_info("System booting in Trial State\n");
var_attributes = EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS;
status = efi_get_variable_int(L"TrialStateCtr",
&efi_global_variable_guid,
&var_attributes,
&var_size, &trial_state_ctr,
NULL);
if (status != EFI_SUCCESS) {
log_err("Unable to read TrialStateCtr variable\n");
ret = -1;
Any reason not to use standard return macros? The same I see below too.
This is because the ret is just used to indicate whether the function has returned successfully, or not. The value is not getting passed anywhere from the caller function -- it is only used to either return back or continue with further processing. And the error reason is also being printed in all cases.
I have incorporated all your other comments. Thanks.
-sughosh
goto out;
}
++trial_state_ctr;
if (trial_state_ctr > CONFIG_FWU_TRIAL_STATE_CNT) {
log_info("Trial State count exceeded. Revert back to previous_active_index\n");
active_idx = mdata->active_index;
ret = fwu_revert_boot_index();
if (ret < 0) {
I would use if (ret) here.
log_err("Unable to revert active_index\n");
goto out;
}
trial_state_ctr = 0;
status = efi_set_variable_int(L"TrialStateCtr",
&efi_global_variable_guid,
var_attributes,
0,
&trial_state_ctr, false);
if (status != EFI_SUCCESS) {
log_err("Unable to clear TrialStateCtr variable\n");
ret = -1;
goto out;
}
} else {
status = efi_set_variable_int(L"TrialStateCtr",
&efi_global_variable_guid,
var_attributes,
var_size,
&trial_state_ctr, false);
if (status != EFI_SUCCESS) {
log_err("Unable to increment TrialStateCtr variable\n");
ret = -1;
goto out;
} else {
ret = 0;
Why do you need this? ret should be 0 when you get here.
}
}
} else {
trial_state_ctr = 0;
ret = 0;
the same here. You have ret=0 above that's why I think this is just an additional line here.
status = efi_set_variable_int(L"TrialStateCtr",
&efi_global_variable_guid,
0,
0, &trial_state_ctr,
NULL);
}
+out:
free(mdata);
return ret;
+}
+u8 fwu_update_checks_pass(void) +{
return !trial_state && boottime_check;
+}
+int fwu_boottime_checks(void) +{
int ret;
struct udevice *dev;
u32 boot_idx, active_idx;
if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) {
log_err("FWU Metadata device not found\n");
boottime_check = 0;
All these boottime_check initialization to 0 seems to me useless.
return 0;
}
ret = fwu_mdata_check();
if (ret < 0) {
up to you but I would also use if (ret) here.
boottime_check = 0;
It is zero already when you get here that's why all these = 0 lines should be IMHO removed.
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");
boottime_check = 0;
ditto.
return 0;
}
ret = fwu_get_active_index(&active_idx);
if (ret < 0) {
ditto.
log_err("Unable to read active_index\n");
boottime_check = 0;
ditto.
return 0;
}
if (boot_idx != active_idx) {
log_info("Boot idx %u is not matching active idx %u, changing active_idx\n",
boot_idx, active_idx);
ret = fwu_update_active_index(boot_idx);
if (ret < 0)
ditto.
boottime_check = 0;
ditto
else
boottime_check = 1;
return 0;
}
ret = fwu_trial_state_check();
if (ret < 0)
ditto
boottime_check = 0;
ditto.
else
boottime_check = 1;
return 0;
+}
2.17.1
Thanks, Michal
-- Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91 w: www.monstr.eu p: +42-0-721842854 Maintainer of Linux kernel - Xilinx Microblaze Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs

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 V3: * Rebase the change on top of the patch from Masami to call efi_capsule_update_firmware directly. * Put the FWU related checks which were earlier in efi_update_capsule function to separate functions fwu_empty_capsule and fwu_empty_capsule_process.
include/fwu.h | 12 +- lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 221 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 +++++ lib/fwu_updates/Makefile | 6 + lib/fwu_updates/fwu.c | 26 +++++ 8 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 lib/fwu_updates/Kconfig create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 5a329d9ef7..88dc4a4b9a 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -32,13 +32,23 @@ struct fwu_mdata_ops { };
#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_OS_REQUEST_FW_REVERT_GUID \ + EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \ + 0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0) + +#define FWU_OS_REQUEST_FW_ACCEPT_GUID \ + EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \ + 0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8) + u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_mdata(struct fwu_mdata **mdata); int fwu_update_mdata(struct fwu_mdata *mdata); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..d8ff672354 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,9 @@ config PHANDLE_CHECK_SEQ When there are multiple device tree nodes with same name, enable this config option to distinguish them using phandles in fdtdec_get_alias_seq() function. + +menu "FWU Multi Bank Updates" + +source lib/fwu_updates/Kconfig + +endmenu diff --git a/lib/Makefile b/lib/Makefile index 5ddbc77ed6..bc5c1e22fc 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_EFI_LOADER) += efi_driver/ obj-$(CONFIG_EFI_LOADER) += efi_loader/ obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/ +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_updates/ obj-$(CONFIG_LZMA) += lzma/ obj-$(CONFIG_BZIP2) += bzip2/ obj-$(CONFIG_TIZEN) += tizen/ diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index 708668a5de..7292439106 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 <malloc.h> #include <mapmem.h> #include <sort.h> @@ -30,6 +31,16 @@ static const efi_guid_t efi_guid_firmware_management_capsule_id = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; const efi_guid_t efi_guid_firmware_management_protocol = EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID; +const efi_guid_t fwu_guid_os_request_fw_revert = + FWU_OS_REQUEST_FW_REVERT_GUID; +const efi_guid_t fwu_guid_os_request_fw_accept = + FWU_OS_REQUEST_FW_ACCEPT_GUID; + +#define FW_ACCEPT_OS (u32)0x8000 + +__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update; +__maybe_unused static bool fw_accept_os;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -384,6 +395,88 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s } #endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
+static bool fwu_empty_capsule(struct efi_capsule_header *capsule) +{ + return !guidcmp(&capsule->capsule_guid, + &fwu_guid_os_request_fw_revert) || + !guidcmp(&capsule->capsule_guid, + &fwu_guid_os_request_fw_accept); +} + +static efi_status_t fwu_empty_capsule_process( + struct efi_capsule_header *capsule) +{ + int status; + u32 active_idx; + efi_status_t ret; + efi_guid_t *image_guid; + + if (!guidcmp(&capsule->capsule_guid, + &fwu_guid_os_request_fw_revert)) { + /* + * One of the previously updated image has + * failed the OS acceptance test. OS has + * requested to revert back to the earlier + * boot index + */ + status = fwu_revert_boot_index(); + if (status < 0) { + log_err("Failed to revert the FWU boot index\n"); + if (status == -ENODEV || + status == -ERANGE || + status == -EIO) + ret = EFI_DEVICE_ERROR; + else if (status == -EINVAL) + ret = EFI_INVALID_PARAMETER; + else if (status == -ENOMEM) + ret = EFI_OUT_OF_RESOURCES; + } else { + ret = EFI_SUCCESS; + log_err("Reverted the FWU active_index. Recommend rebooting the system\n"); + } + } else if (!guidcmp(&capsule->capsule_guid, + &fwu_guid_os_request_fw_accept)) { + /* + * Image accepted by the OS. Set the acceptance + * status for the image. + */ + image_guid = (void *)(char *)capsule + + capsule->header_size; + + status = fwu_get_active_index(&active_idx); + if (status < 0) { + log_err("Unable to get the active_index from the FWU metadata\n"); + if (status == -ENODEV || + status == -ERANGE || + status == -EIO) + ret = EFI_DEVICE_ERROR; + else if (status == -EINVAL) + ret = EFI_INVALID_PARAMETER; + else if (status == -ENOMEM) + ret = EFI_OUT_OF_RESOURCES; + + return ret; + } + + status = fwu_accept_image(image_guid, active_idx); + if (status < 0) { + log_err("Unable to set the Accept bit for the image %pUl\n", + image_guid); + if (status == -ENODEV || + status == -ERANGE || + status == -EIO) + ret = EFI_DEVICE_ERROR; + else if (status == -EINVAL) + ret = EFI_INVALID_PARAMETER; + else if (status == -ENOMEM) + ret = EFI_OUT_OF_RESOURCES; + } else { + ret = EFI_SUCCESS; + } + } + + return ret; +}
/** * efi_capsule_update_firmware - update firmware from capsule @@ -403,10 +496,37 @@ static efi_status_t efi_capsule_update_firmware( void *image_binary, *vendor_code; efi_handle_t *handles; efi_uintn_t no_handles; - int item; + int item, alt_no; struct efi_firmware_management_protocol *fmp; u16 *abort_reason; + efi_guid_t image_type_id; efi_status_t ret = EFI_SUCCESS; + int status; + u8 image_index; + + if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { + if (!fwu_empty_capsule(capsule_data) && + !fwu_update_checks_pass()) { + log_err("FWU checks failed. Cannot start update\n"); + return EFI_INVALID_PARAMETER; + } + + /* 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; + } + + if (fwu_empty_capsule(capsule_data)) { + capsule_update = false; + return fwu_empty_capsule_process(capsule_data); + } else { + capsule_update = true; + } + + fw_accept_os = capsule_data->flags & FW_ACCEPT_OS ? 0x1 : 0x0; + }
/* sanity check */ if (capsule_data->header_size < sizeof(*capsule) || @@ -481,8 +601,36 @@ static efi_status_t efi_capsule_update_firmware( goto out; }
+ if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { + /* + * Based on the value of update_image_type_id, + * derive the alt number value. This will be + * passed as update_image_index to the + * set_image function. + */ + image_type_id = image->update_image_type_id; + status = fwu_get_image_alt_num(image_type_id, + update_index, + &alt_no); + if (status < 0) { + log_err("Unable to get the alt no for the image type %pUl\n", + &image_type_id); + if (status == -ENODEV || status == -EIO) + ret = EFI_DEVICE_ERROR; + else if (status == -ENOMEM) + ret = EFI_OUT_OF_RESOURCES; + else if (status == -ERANGE || status == -EINVAL) + ret = EFI_INVALID_PARAMETER; + goto out; + } + log_debug("alt_no %u for Image Type Id %pUl\n", + alt_no, &image_type_id); + image_index = alt_no + 1; + } else { + image_index = image->update_image_index; + } abort_reason = NULL; - ret = EFI_CALL(fmp->set_image(fmp, image->update_image_index, + ret = EFI_CALL(fmp->set_image(fmp, image_index, image_binary, image_binary_size, vendor_code, NULL, @@ -493,6 +641,38 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; } + + if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { + if (!fw_accept_os) { + /* + * The OS will not be accepting the firmware + * images. Set the accept bit of all the + * images contained in this capsule. + */ + status = fwu_accept_image(&image_type_id, + update_index); + } else { + status = fwu_clear_accept_image(&image_type_id, + update_index); + } + + if (status < 0) { + log_err("Unable to %s the accept bit for the image %pUl\n", + fw_accept_os ? "clear" : "set", + &image_type_id); + if (status == -ENODEV || status == -EIO) + ret = EFI_DEVICE_ERROR; + else if (status == -ENOMEM) + ret = EFI_OUT_OF_RESOURCES; + else if (status == -ERANGE || status == -EINVAL) + ret = EFI_INVALID_PARAMETER; + goto out; + } + log_debug("%s the accepted bit for Image %pUl\n", + fw_accept_os ? "Cleared" : "Set", + &image_type_id); + } + }
out: @@ -1090,8 +1270,10 @@ efi_status_t efi_launch_capsules(void) { struct efi_capsule_header *capsule = NULL; u16 **files; + int status; unsigned int nfiles, index, i; efi_status_t ret; + bool update_status = true;
if (check_run_capsules() != EFI_SUCCESS) return EFI_SUCCESS; @@ -1119,9 +1301,11 @@ 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]); + update_status = false; + }
/* create CapsuleXXXX */ set_capsule_result(index, capsule, ret); @@ -1129,6 +1313,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]); @@ -1136,7 +1321,37 @@ efi_status_t efi_launch_capsules(void) log_err("Deleting capsule %ls failed\n", files[i]); } + efi_capsule_scan_done(); + if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { + if (update_status == true && capsule_update == true) { + /* + * All the capsules have been updated successfully, + * update the FWU metadata. + */ + log_debug("Update Complete. Now updating active_index to %u\n", + update_index); + status = fwu_update_active_index(update_index); + if (status < 0) { + log_err("Failed to update FWU metadata index values\n"); + if (status == -EINVAL || status == -ERANGE) + ret = EFI_INVALID_PARAMETER; + else if (status == -ENODEV || status == -EIO) + ret = EFI_DEVICE_ERROR; + else if (status == -ENOMEM) + ret = EFI_OUT_OF_RESOURCES; + } else { + log_debug("Successfully updated the active_index\n"); + status = fwu_trial_state_ctr_start(); + if (status < 0) + ret = EFI_DEVICE_ERROR; + else + ret = EFI_SUCCESS; + } + } else if (capsule_update == true && update_status == false) { + log_err("All capsules were not updated. Not updating FWU metadata\n"); + } + }
for (i = 0; i < nfiles; i++) free(files[i]); diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 49172e3579..df41510340 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -302,7 +302,8 @@ efi_status_t efi_init_obj_list(void) goto out;
/* Execute capsules after reboot */ - if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) && + if (!IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE) && + IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) && !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY)) ret = efi_launch_capsules(); out: diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig new file mode 100644 index 0000000000..6de28e0c9c --- /dev/null +++ b/lib/fwu_updates/Kconfig @@ -0,0 +1,31 @@ +config FWU_MULTI_BANK_UPDATE + bool "Enable FWU Multi Bank Update Feature" + depends on EFI_HAVE_CAPSULE_SUPPORT + select PARTITION_TYPE_GUID + select EFI_SETUP_EARLY + help + Feature for updating firmware images on platforms having + multiple banks(copies) of the firmware images. One of the + bank is selected for updating all the firmware components + +config FWU_NUM_BANKS + int "Number of Banks defined by the platform" + depends on FWU_MULTI_BANK_UPDATE + help + Define the number of banks of firmware images on a platform + +config FWU_NUM_IMAGES_PER_BANK + int "Number of firmware images per bank" + depends on FWU_MULTI_BANK_UPDATE + help + Define the number of firmware images per bank. This value + should be the same for all the banks. + +config FWU_TRIAL_STATE_CNT + int "Number of times system boots in Trial State" + depends on FWU_MULTI_BANK_UPDATE + default 3 + help + With FWU Multi Bank Update feature enabled, number of times + the platform is allowed to boot in Trial State after an + update. diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile new file mode 100644 index 0000000000..1b17051f32 --- /dev/null +++ b/lib/fwu_updates/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2021, Linaro Limited +# + +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index 86933123e7..ca3cf6b560 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -115,6 +115,32 @@ u8 fwu_update_checks_pass(void) return !trial_state && boottime_check; }
+int fwu_trial_state_ctr_start(void) +{ + int ret; + u32 var_attributes; + efi_status_t status; + efi_uintn_t var_size; + u16 trial_state_ctr; + + var_size = (efi_uintn_t)sizeof(trial_state_ctr); + var_attributes = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS; + + trial_state_ctr = ret = 0; + status = efi_set_variable_int(L"TrialStateCtr", + &efi_global_variable_guid, + var_attributes, + var_size, + &trial_state_ctr, false); + if (status != EFI_SUCCESS) { + log_err("Unable to increment TrialStateCtr variable\n"); + ret = -1; + } + + return ret; +} + int fwu_boottime_checks(void) { int ret;

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

The Dependable Boot specification 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.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org ---
Changes since V3: * Add related documentation for empty capsules in the mkeficapsule man page. * Add separate usage for empty capsules, with corresponding valid options. * Use ternary operators where possible. * Put a exclusivity check for the empty capsule options.
doc/mkeficapsule.1 | 23 +++++++- tools/eficapsule.h | 8 +++ tools/mkeficapsule.c | 131 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 139 insertions(+), 23 deletions(-)
diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 index 8babb27ee8..75fc15906a 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. @@ -43,7 +48,7 @@ specify a guid for the FMP driver. .SH "OPTIONS" One of .BR --fit ", " --raw " or " --guid -option must be specified. +option must be specified for non empty capsules.
.TP .BR -f ", " --fit @@ -69,6 +74,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 8c1560bb06..6001952bdc 100644 --- a/tools/eficapsule.h +++ b/tools/eficapsule.h @@ -50,6 +50,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 161affdd15..e5dbec3a92 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +unsigned char accept_fw_capsule, revert_fw_capsule, empty_capsule;
efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; efi_guid_t efi_guid_image_type_uboot_fit = @@ -38,9 +39,9 @@ efi_guid_t efi_guid_image_type_uboot_raw = efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
#ifdef CONFIG_TOOLS_LIBCRYPTO -static const char *opts_short = "frg:i:I:v:p:c:m:dh"; +static const char *opts_short = "frg:i:I:v:p:c:m:dhAR"; #else -static const char *opts_short = "frg:i:I:v:h"; +static const char *opts_short = "frg:i:I:v:hAR"; #endif
static struct option options[] = { @@ -55,28 +56,50 @@ static struct option options[] = { {"monotonic-count", required_argument, NULL, 'm'}, {"dump-sig", no_argument, NULL, 'd'}, #endif + {"fw-accept", no_argument, NULL, 'A'}, + {"fw-revert", no_argument, NULL, 'R'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, };
static void print_usage(void) { - fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n" - "Options:\n" - - "\t-f, --fit FIT image type\n" - "\t-r, --raw raw image type\n" - "\t-g, --guid <guid string> guid for image blob type\n" - "\t-i, --index <index> update image index\n" - "\t-I, --instance <instance> update hardware instance\n" + if (empty_capsule) { + if (accept_fw_capsule) { + fprintf(stderr, "Usage: %s [options] <output file>\n", + tool_name); + fprintf(stderr, "Options:\n" + "\t-A, --fw-accept firmware accept capsule\n" + "\t-g, --guid <guid string> guid for image blob type\n" + "\t-h, --help print a help message\n" + ); + } else { + fprintf(stderr, "Usage: %s [options] <output file>\n", + tool_name); + fprintf(stderr, "Options:\n" + "\t-R, --fw-revert firmware revert capsule\n" + "\t-h, --help print a help message\n" + ); + } + } else { + fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n", + tool_name); + fprintf(stderr, "Options:\n" + "\t-f, --fit FIT image type\n" + "\t-r, --raw raw image type\n" + "\t-g, --guid <guid string> guid for image blob type\n" + "\t-i, --index <index> update image index\n" + "\t-I, --instance <instance> update hardware instance\n" #ifdef CONFIG_TOOLS_LIBCRYPTO - "\t-p, --private-key <privkey file> private key file\n" - "\t-c, --certificate <cert file> signer's certificate file\n" - "\t-m, --monotonic-count <count> monotonic count\n" - "\t-d, --dump_sig dump signature (*.p7)\n" + "\t-p, --private-key <privkey file> private key file\n" + "\t-c, --certificate <cert file> signer's certificate file\n" + "\t-m, --monotonic-count <count> monotonic count\n" + "\t-d, --dump_sig dump signature (*.p7)\n" #endif - "\t-h, --help print a help message\n", - tool_name); + "\t-A, --fw-accept firmware accept capsule\n" + "\t-R, --fw-revert firmware revert capsule\n" + "\t-h, --help print a help message\n"); + } }
/** @@ -598,6 +621,50 @@ void convert_uuid_to_guid(unsigned char *buf) buf[7] = c; }
+static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept) +{ + struct efi_capsule_header header; + FILE *f = NULL; + int ret = -1; + efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID; + efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID; + efi_guid_t payload, capsule_guid; + + f = fopen(path, "w"); + if (!f) { + fprintf(stderr, "cannot open %s\n", path); + goto err; + } + + capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid; + + memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t)); + header.header_size = sizeof(header); + header.flags = 0; + + header.capsule_image_size = fw_accept ? + sizeof(header) + sizeof(efi_guid_t) : sizeof(header); + + if (write_capsule_file(f, &header, sizeof(header), + "Capsule header")) + goto err; + + if (fw_accept) { + memcpy(&payload, guid, sizeof(efi_guid_t)); + if (write_capsule_file(f, &payload, sizeof(payload), + "FW Accept Capsule Payload")) + goto err; + } + + ret = 0; + +err: + if (f) + fclose(f); + + return ret; +} + /** * main - main entry function of mkeficapsule * @argc: Number of arguments @@ -625,6 +692,8 @@ int main(int argc, char **argv) mcount = 0; privkey_file = NULL; cert_file = NULL; + accept_fw_capsule = 0; + revert_fw_capsule = 0; dump_sig = 0; for (;;) { c = getopt_long(argc, argv, opts_short, options, &idx); @@ -691,22 +760,44 @@ int main(int argc, char **argv) dump_sig = 1; break; #endif /* CONFIG_TOOLS_LIBCRYPTO */ + case 'A': + accept_fw_capsule = 1; + break; + case 'R': + revert_fw_capsule = 1; + break; case 'h': print_usage(); exit(EXIT_SUCCESS); } }
+ if (accept_fw_capsule && revert_fw_capsule) { + fprintf(stderr, + "Select either of Accept or Revert capsule generation\n"); + exit(EXIT_FAILURE); + } + + empty_capsule = (accept_fw_capsule || revert_fw_capsule); + /* check necessary parameters */ - if ((argc != optind + 2) || !guid || - ((privkey_file && !cert_file) || + if ((!empty_capsule && argc != optind + 2) || + (empty_capsule && argc != optind + 1) || + (!revert_fw_capsule && !guid) || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) { print_usage(); exit(EXIT_FAILURE); }
- if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance, - mcount, privkey_file, cert_file) < 0) { + if (empty_capsule) { + if (create_empty_capsule(argv[argc - 1], guid, + accept_fw_capsule ? 1 : 0) < 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); }

Hi Sughosh,
On Mon, Feb 07, 2022 at 11:50:00PM +0530, Sughosh Ganu wrote:
The Dependable Boot specification describes the structure of the
What is this specification? Please specify the link to the doc.
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.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Add related documentation for empty capsules in the mkeficapsule man page.
- Add separate usage for empty capsules, with corresponding valid options.
- Use ternary operators where possible.
- Put a exclusivity check for the empty capsule options.
doc/mkeficapsule.1 | 23 +++++++- tools/eficapsule.h | 8 +++ tools/mkeficapsule.c | 131 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 139 insertions(+), 23 deletions(-)
diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 index 8babb27ee8..75fc15906a 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
With this formatting, "capsule-file" will get italic.
=> .RI [ options "] [" image-blob "] " capsule-file
Right?
Furthermore, I think we can describe the command syntax of the two different cases (normal or empty capsule) more specifically.
.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. @@ -43,7 +48,7 @@ specify a guid for the FMP driver. .SH "OPTIONS" One of .BR --fit ", " --raw " or " --guid -option must be specified. +option must be specified for non empty capsules.
.TP .BR -f ", " --fit @@ -69,6 +74,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
I don't still understand why we need GUID for accept empty capsule. We should have only one choice, whether all the new firmware be permanently applied or completely reverted.
That's A/B update, isn't it?
+.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 8c1560bb06..6001952bdc 100644 --- a/tools/eficapsule.h +++ b/tools/eficapsule.h @@ -50,6 +50,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 161affdd15..e5dbec3a92 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +unsigned char accept_fw_capsule, revert_fw_capsule, empty_capsule;
Bool? but those variables are redundant.
As Ilias suggested, introducing a new enum type here can simplify the code in the following code. enum { CAPSULE_NORMAL_BLOB = 0, CAPSULE_ACCEPT, CAPSULE_REVERT, } capsule_type;
efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; efi_guid_t efi_guid_image_type_uboot_fit = @@ -38,9 +39,9 @@ efi_guid_t efi_guid_image_type_uboot_raw = efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
#ifdef CONFIG_TOOLS_LIBCRYPTO
Please rebase your patch to my v10 or later. I have already removed the dependency on openssl library.
-static const char *opts_short = "frg:i:I:v:p:c:m:dh"; +static const char *opts_short = "frg:i:I:v:p:c:m:dhAR"; #else -static const char *opts_short = "frg:i:I:v:h"; +static const char *opts_short = "frg:i:I:v:hAR"; #endif
static struct option options[] = { @@ -55,28 +56,50 @@ static struct option options[] = { {"monotonic-count", required_argument, NULL, 'm'}, {"dump-sig", no_argument, NULL, 'd'}, #endif
- {"fw-accept", no_argument, NULL, 'A'},
- {"fw-revert", no_argument, NULL, 'R'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0},
};
static void print_usage(void) {
- fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
"Options:\n"
"\t-f, --fit FIT image type\n"
"\t-r, --raw raw image type\n"
"\t-g, --guid <guid string> guid for image blob type\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
- if (empty_capsule) {
if (accept_fw_capsule) {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-A, --fw-accept firmware accept capsule\n"
"\t-g, --guid <guid string> guid for image blob type\n"
While I doubt the necessity of "--guid," why not accept "-f" or "-r" as a guid of image blob type? (It seems that your actual code does.)
"\t-h, --help print a help message\n"
);
} else {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-R, --fw-revert firmware revert capsule\n"
"\t-h, --help print a help message\n"
);
}
- } else {
fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-f, --fit FIT image type\n"
"\t-r, --raw raw image type\n"
"\t-g, --guid <guid string> guid for image blob type\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
#ifdef CONFIG_TOOLS_LIBCRYPTO
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
#endif
"\t-h, --help print a help message\n",
tool_name);
"\t-A, --fw-accept firmware accept capsule\n"
"\t-R, --fw-revert firmware revert capsule\n"
"\t-h, --help print a help message\n");
- }
}
/** @@ -598,6 +621,50 @@ void convert_uuid_to_guid(unsigned char *buf) buf[7] = c; }
+static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept) +{
- struct efi_capsule_header header;
- FILE *f = NULL;
- int ret = -1;
- efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
- efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
- efi_guid_t payload, capsule_guid;
- f = fopen(path, "w");
- if (!f) {
fprintf(stderr, "cannot open %s\n", path);
goto err;
- }
- capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
- memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
- header.header_size = sizeof(header);
- header.flags = 0;
- header.capsule_image_size = fw_accept ?
sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
- if (write_capsule_file(f, &header, sizeof(header),
"Capsule header"))
goto err;
- if (fw_accept) {
memcpy(&payload, guid, sizeof(efi_guid_t));
if (write_capsule_file(f, &payload, sizeof(payload),
"FW Accept Capsule Payload"))
goto err;
- }
- ret = 0;
+err:
- if (f)
fclose(f);
- return ret;
+}
/**
- main - main entry function of mkeficapsule
- @argc: Number of arguments
@@ -625,6 +692,8 @@ int main(int argc, char **argv) mcount = 0; privkey_file = NULL; cert_file = NULL;
- accept_fw_capsule = 0;
- revert_fw_capsule = 0; dump_sig = 0; for (;;) { c = getopt_long(argc, argv, opts_short, options, &idx);
@@ -691,22 +760,44 @@ int main(int argc, char **argv) dump_sig = 1; break; #endif /* CONFIG_TOOLS_LIBCRYPTO */
case 'A':
accept_fw_capsule = 1;
break;
case 'R':
revert_fw_capsule = 1;
break;
case 'h': print_usage(); exit(EXIT_SUCCESS); } }
if (accept_fw_capsule && revert_fw_capsule) {
fprintf(stderr,
"Select either of Accept or Revert capsule generation\n");
exit(EXIT_FAILURE);
}
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
/* check necessary parameters */
- if ((argc != optind + 2) || !guid ||
((privkey_file && !cert_file) ||
- if ((!empty_capsule && argc != optind + 2) ||
(empty_capsule && argc != optind + 1) ||
(!revert_fw_capsule && !guid) || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) {
Well, the error condition looks complicated due to mixing two cases and can be hard to maintain in the future. How about if (!empty_capsule && ((argc != optind + 2) || !guid || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) || empty_capsule && ((argc != optind + 1) || (accept_fw_capsule && revert_fw_capsule) || (accept_fw_capsule && !guid)) # arguable as mentioned above (revert_fw_capsule && guid)) ...
print_usage(); exit(EXIT_FAILURE);
}
- if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
mcount, privkey_file, cert_file) < 0) {
- if (empty_capsule) {
if (create_empty_capsule(argv[argc - 1], guid,
accept_fw_capsule ? 1 : 0) < 0) {
The third argument can be simplified to "accept_fw_capsule".
-Takahiro Akashi
fprintf(stderr, "Creating empty capsule failed\n");
exit(EXIT_FAILURE);
}
- } else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
index, instance, mcount, privkey_file,
fprintf(stderr, "Creating firmware capsule failed\n"); exit(EXIT_FAILURE); }cert_file) < 0) {
-- 2.17.1

On Wed, Feb 09, 2022 at 12:05:06PM +0900, AKASHI Takahiro wrote:
Hi Sughosh,
On Mon, Feb 07, 2022 at 11:50:00PM +0530, Sughosh Ganu wrote:
The Dependable Boot specification describes the structure of the
What is this specification? Please specify the link to the doc.
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.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Add related documentation for empty capsules in the mkeficapsule man page.
- Add separate usage for empty capsules, with corresponding valid options.
- Use ternary operators where possible.
- Put a exclusivity check for the empty capsule options.
doc/mkeficapsule.1 | 23 +++++++- tools/eficapsule.h | 8 +++ tools/mkeficapsule.c | 131 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 139 insertions(+), 23 deletions(-)
diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 index 8babb27ee8..75fc15906a 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
With this formatting, "capsule-file" will get italic.
oops, I meant to say "roman."
=> .RI [ options "] [" image-blob "] " capsule-file
Right?
Furthermore, I think we can describe the command syntax of the two different cases (normal or empty capsule) more specifically.
.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. @@ -43,7 +48,7 @@ specify a guid for the FMP driver. .SH "OPTIONS" One of .BR --fit ", " --raw " or " --guid -option must be specified. +option must be specified for non empty capsules.
.TP .BR -f ", " --fit @@ -69,6 +74,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
I don't still understand why we need GUID for accept empty capsule. We should have only one choice, whether all the new firmware be permanently applied or completely reverted.
That's A/B update, isn't it?
+.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 8c1560bb06..6001952bdc 100644 --- a/tools/eficapsule.h +++ b/tools/eficapsule.h @@ -50,6 +50,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 161affdd15..e5dbec3a92 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +unsigned char accept_fw_capsule, revert_fw_capsule, empty_capsule;
Bool? but those variables are redundant.
As Ilias suggested, introducing a new enum type here can simplify the code in the following code. enum { CAPSULE_NORMAL_BLOB = 0, CAPSULE_ACCEPT, CAPSULE_REVERT, } capsule_type;
efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; efi_guid_t efi_guid_image_type_uboot_fit = @@ -38,9 +39,9 @@ efi_guid_t efi_guid_image_type_uboot_raw = efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
#ifdef CONFIG_TOOLS_LIBCRYPTO
Please rebase your patch to my v10 or later. I have already removed the dependency on openssl library.
-static const char *opts_short = "frg:i:I:v:p:c:m:dh"; +static const char *opts_short = "frg:i:I:v:p:c:m:dhAR"; #else -static const char *opts_short = "frg:i:I:v:h"; +static const char *opts_short = "frg:i:I:v:hAR"; #endif
static struct option options[] = { @@ -55,28 +56,50 @@ static struct option options[] = { {"monotonic-count", required_argument, NULL, 'm'}, {"dump-sig", no_argument, NULL, 'd'}, #endif
- {"fw-accept", no_argument, NULL, 'A'},
- {"fw-revert", no_argument, NULL, 'R'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0},
};
static void print_usage(void) {
- fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
"Options:\n"
"\t-f, --fit FIT image type\n"
"\t-r, --raw raw image type\n"
"\t-g, --guid <guid string> guid for image blob type\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
- if (empty_capsule) {
if (accept_fw_capsule) {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-A, --fw-accept firmware accept capsule\n"
"\t-g, --guid <guid string> guid for image blob type\n"
While I doubt the necessity of "--guid," why not accept "-f" or "-r" as a guid of image blob type? (It seems that your actual code does.)
"\t-h, --help print a help message\n"
);
} else {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-R, --fw-revert firmware revert capsule\n"
"\t-h, --help print a help message\n"
);
}
- } else {
fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-f, --fit FIT image type\n"
"\t-r, --raw raw image type\n"
"\t-g, --guid <guid string> guid for image blob type\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
#ifdef CONFIG_TOOLS_LIBCRYPTO
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
#endif
"\t-h, --help print a help message\n",
tool_name);
"\t-A, --fw-accept firmware accept capsule\n"
"\t-R, --fw-revert firmware revert capsule\n"
"\t-h, --help print a help message\n");
- }
}
/** @@ -598,6 +621,50 @@ void convert_uuid_to_guid(unsigned char *buf) buf[7] = c; }
+static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept) +{
- struct efi_capsule_header header;
- FILE *f = NULL;
- int ret = -1;
- efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
- efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
- efi_guid_t payload, capsule_guid;
- f = fopen(path, "w");
- if (!f) {
fprintf(stderr, "cannot open %s\n", path);
goto err;
- }
- capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
- memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
- header.header_size = sizeof(header);
- header.flags = 0;
- header.capsule_image_size = fw_accept ?
sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
- if (write_capsule_file(f, &header, sizeof(header),
"Capsule header"))
goto err;
- if (fw_accept) {
memcpy(&payload, guid, sizeof(efi_guid_t));
if (write_capsule_file(f, &payload, sizeof(payload),
"FW Accept Capsule Payload"))
goto err;
- }
- ret = 0;
+err:
- if (f)
fclose(f);
- return ret;
+}
/**
- main - main entry function of mkeficapsule
- @argc: Number of arguments
@@ -625,6 +692,8 @@ int main(int argc, char **argv) mcount = 0; privkey_file = NULL; cert_file = NULL;
- accept_fw_capsule = 0;
- revert_fw_capsule = 0; dump_sig = 0; for (;;) { c = getopt_long(argc, argv, opts_short, options, &idx);
@@ -691,22 +760,44 @@ int main(int argc, char **argv) dump_sig = 1; break; #endif /* CONFIG_TOOLS_LIBCRYPTO */
case 'A':
accept_fw_capsule = 1;
break;
case 'R':
revert_fw_capsule = 1;
break;
case 'h': print_usage(); exit(EXIT_SUCCESS); } }
if (accept_fw_capsule && revert_fw_capsule) {
fprintf(stderr,
"Select either of Accept or Revert capsule generation\n");
exit(EXIT_FAILURE);
}
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
/* check necessary parameters */
- if ((argc != optind + 2) || !guid ||
((privkey_file && !cert_file) ||
- if ((!empty_capsule && argc != optind + 2) ||
(empty_capsule && argc != optind + 1) ||
(!revert_fw_capsule && !guid) || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) {
Well, the error condition looks complicated due to mixing two cases and can be hard to maintain in the future. How about if (!empty_capsule && ((argc != optind + 2) || !guid || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) || empty_capsule && ((argc != optind + 1) || (accept_fw_capsule && revert_fw_capsule) || (accept_fw_capsule && !guid)) # arguable as mentioned above (revert_fw_capsule && guid)) ...
I've got one concern here; Can we sign an empty capsule file? I think we should. If so, the help message (by print_usage()) doesn't reflect it.
-Takahiro Akashi
print_usage(); exit(EXIT_FAILURE);
}
- if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
mcount, privkey_file, cert_file) < 0) {
- if (empty_capsule) {
if (create_empty_capsule(argv[argc - 1], guid,
accept_fw_capsule ? 1 : 0) < 0) {
The third argument can be simplified to "accept_fw_capsule".
-Takahiro Akashi
fprintf(stderr, "Creating empty capsule failed\n");
exit(EXIT_FAILURE);
}
- } else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
index, instance, mcount, privkey_file,
fprintf(stderr, "Creating firmware capsule failed\n"); exit(EXIT_FAILURE); }cert_file) < 0) {
-- 2.17.1

On Thu, 10 Feb 2022 at 06:57, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Wed, Feb 09, 2022 at 12:05:06PM +0900, AKASHI Takahiro wrote:
Hi Sughosh,
On Mon, Feb 07, 2022 at 11:50:00PM +0530, Sughosh Ganu wrote:
The Dependable Boot specification describes the structure of the
What is this specification? Please specify the link to the doc.
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.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Add related documentation for empty capsules in the mkeficapsule man page.
- Add separate usage for empty capsules, with corresponding valid options.
- Use ternary operators where possible.
- Put a exclusivity check for the empty capsule options.
doc/mkeficapsule.1 | 23 +++++++- tools/eficapsule.h | 8 +++ tools/mkeficapsule.c | 131 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 139 insertions(+), 23 deletions(-)
diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 index 8babb27ee8..75fc15906a 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
With this formatting, "capsule-file" will get italic.
oops, I meant to say "roman."
=> .RI [ options "] [" image-blob "] " capsule-file
Right?
Furthermore, I think we can describe the command syntax of the two different cases (normal or empty capsule) more specifically.
.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. @@ -43,7 +48,7 @@ specify a guid for the FMP driver. .SH "OPTIONS" One of .BR --fit ", " --raw " or " --guid -option must be specified. +option must be specified for non empty capsules.
.TP .BR -f ", " --fit @@ -69,6 +74,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
I don't still understand why we need GUID for accept empty capsule. We should have only one choice, whether all the new firmware be permanently applied or completely reverted.
That's A/B update, isn't it?
+.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 8c1560bb06..6001952bdc 100644 --- a/tools/eficapsule.h +++ b/tools/eficapsule.h @@ -50,6 +50,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 161affdd15..e5dbec3a92 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +unsigned char accept_fw_capsule, revert_fw_capsule, empty_capsule;
Bool? but those variables are redundant.
As Ilias suggested, introducing a new enum type here can simplify the code in the following code. enum { CAPSULE_NORMAL_BLOB = 0, CAPSULE_ACCEPT, CAPSULE_REVERT, } capsule_type;
efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; efi_guid_t efi_guid_image_type_uboot_fit = @@ -38,9 +39,9 @@ efi_guid_t efi_guid_image_type_uboot_raw = efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
#ifdef CONFIG_TOOLS_LIBCRYPTO
Please rebase your patch to my v10 or later. I have already removed the dependency on openssl library.
-static const char *opts_short = "frg:i:I:v:p:c:m:dh"; +static const char *opts_short = "frg:i:I:v:p:c:m:dhAR"; #else -static const char *opts_short = "frg:i:I:v:h"; +static const char *opts_short = "frg:i:I:v:hAR"; #endif
static struct option options[] = { @@ -55,28 +56,50 @@ static struct option options[] = { {"monotonic-count", required_argument, NULL, 'm'}, {"dump-sig", no_argument, NULL, 'd'}, #endif
- {"fw-accept", no_argument, NULL, 'A'},
- {"fw-revert", no_argument, NULL, 'R'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0},
};
static void print_usage(void) {
- fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
"Options:\n"
"\t-f, --fit FIT image type\n"
"\t-r, --raw raw image type\n"
"\t-g, --guid <guid string> guid for image blob type\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
- if (empty_capsule) {
if (accept_fw_capsule) {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-A, --fw-accept firmware accept capsule\n"
"\t-g, --guid <guid string> guid for image blob type\n"
While I doubt the necessity of "--guid," why not accept "-f" or "-r" as a guid of image blob type? (It seems that your actual code does.)
"\t-h, --help print a help message\n"
);
} else {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-R, --fw-revert firmware revert capsule\n"
"\t-h, --help print a help message\n"
);
}
- } else {
fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-f, --fit FIT image type\n"
"\t-r, --raw raw image type\n"
"\t-g, --guid <guid string> guid for image blob type\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
#ifdef CONFIG_TOOLS_LIBCRYPTO
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
#endif
"\t-h, --help print a help message\n",
tool_name);
"\t-A, --fw-accept firmware accept capsule\n"
"\t-R, --fw-revert firmware revert capsule\n"
"\t-h, --help print a help message\n");
- }
}
/** @@ -598,6 +621,50 @@ void convert_uuid_to_guid(unsigned char *buf) buf[7] = c; }
+static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept) +{
- struct efi_capsule_header header;
- FILE *f = NULL;
- int ret = -1;
- efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
- efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
- efi_guid_t payload, capsule_guid;
- f = fopen(path, "w");
- if (!f) {
fprintf(stderr, "cannot open %s\n", path);
goto err;
- }
- capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
- memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
- header.header_size = sizeof(header);
- header.flags = 0;
- header.capsule_image_size = fw_accept ?
sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
- if (write_capsule_file(f, &header, sizeof(header),
"Capsule header"))
goto err;
- if (fw_accept) {
memcpy(&payload, guid, sizeof(efi_guid_t));
if (write_capsule_file(f, &payload, sizeof(payload),
"FW Accept Capsule Payload"))
goto err;
- }
- ret = 0;
+err:
- if (f)
fclose(f);
- return ret;
+}
/**
- main - main entry function of mkeficapsule
- @argc: Number of arguments
@@ -625,6 +692,8 @@ int main(int argc, char **argv) mcount = 0; privkey_file = NULL; cert_file = NULL;
- accept_fw_capsule = 0;
- revert_fw_capsule = 0; dump_sig = 0; for (;;) { c = getopt_long(argc, argv, opts_short, options, &idx);
@@ -691,22 +760,44 @@ int main(int argc, char **argv) dump_sig = 1; break; #endif /* CONFIG_TOOLS_LIBCRYPTO */
case 'A':
accept_fw_capsule = 1;
break;
case 'R':
revert_fw_capsule = 1;
break; case 'h': print_usage(); exit(EXIT_SUCCESS); }
}
if (accept_fw_capsule && revert_fw_capsule) {
fprintf(stderr,
"Select either of Accept or Revert capsule generation\n");
exit(EXIT_FAILURE);
}
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
/* check necessary parameters */
- if ((argc != optind + 2) || !guid ||
((privkey_file && !cert_file) ||
- if ((!empty_capsule && argc != optind + 2) ||
(empty_capsule && argc != optind + 1) ||
(!revert_fw_capsule && !guid) || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) {
Well, the error condition looks complicated due to mixing two cases and can be hard to maintain in the future. How about if (!empty_capsule && ((argc != optind + 2) || !guid || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) || empty_capsule && ((argc != optind + 1) || (accept_fw_capsule && revert_fw_capsule) || (accept_fw_capsule && !guid)) # arguable as mentioned above (revert_fw_capsule && guid)) ...
I've got one concern here; Can we sign an empty capsule file? I think we should. If so, the help message (by print_usage()) doesn't reflect it.
We do have plans to sign the empty capsule, although it is not being added currently. I will keep this on my Todo list. Hope that is fine. Thanks.
-sughosh
-Takahiro Akashi
print_usage(); exit(EXIT_FAILURE); }
- if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
mcount, privkey_file, cert_file) < 0) {
- if (empty_capsule) {
if (create_empty_capsule(argv[argc - 1], guid,
accept_fw_capsule ? 1 : 0) < 0) {
The third argument can be simplified to "accept_fw_capsule".
-Takahiro Akashi
fprintf(stderr, "Creating empty capsule failed\n");
exit(EXIT_FAILURE);
}
- } else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
index, instance, mcount, privkey_file,
}cert_file) < 0) { fprintf(stderr, "Creating firmware capsule failed\n"); exit(EXIT_FAILURE);
-- 2.17.1

hi Takahiro,
On Wed, 9 Feb 2022 at 08:35, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
On Mon, Feb 07, 2022 at 11:50:00PM +0530, Sughosh Ganu wrote:
The Dependable Boot specification describes the structure of the
What is this specification? Please specify the link to the doc.
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.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Add related documentation for empty capsules in the mkeficapsule man page.
- Add separate usage for empty capsules, with corresponding valid options.
- Use ternary operators where possible.
- Put a exclusivity check for the empty capsule options.
doc/mkeficapsule.1 | 23 +++++++- tools/eficapsule.h | 8 +++ tools/mkeficapsule.c | 131 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 139 insertions(+), 23 deletions(-)
diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 index 8babb27ee8..75fc15906a 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
With this formatting, "capsule-file" will get italic.
=> .RI [ options "] [" image-blob "] " capsule-file
Right?
Furthermore, I think we can describe the command syntax of the two different cases (normal or empty capsule) more specifically.
The syntax of the two empty capsules is described in detail in the documentation patch. Is that not sufficient. Moreover, the usage shows the arguments for the -A and -R options separately.
.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. @@ -43,7 +48,7 @@ specify a guid for the FMP driver. .SH "OPTIONS" One of .BR --fit ", " --raw " or " --guid -option must be specified. +option must be specified for non empty capsules.
.TP .BR -f ", " --fit @@ -69,6 +74,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
I don't still understand why we need GUID for accept empty capsule. We should have only one choice, whether all the new firmware be permanently applied or completely reverted.
The accept capsule is accepting a given firmware image in the active bank(active_index). The specification requires that all firmware images be accepted separately and explicitly. With firmware revert, the idea is that if the OS reverts even one of the images, we need to switch to booting from a different bank. Hence no GUID specified with the revert capsule.
That's A/B update, isn't it?
+.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 8c1560bb06..6001952bdc 100644 --- a/tools/eficapsule.h +++ b/tools/eficapsule.h @@ -50,6 +50,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 161affdd15..e5dbec3a92 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +unsigned char accept_fw_capsule, revert_fw_capsule, empty_capsule;
Bool? but those variables are redundant.
As Ilias suggested, introducing a new enum type here can simplify the code in the following code. enum { CAPSULE_NORMAL_BLOB = 0, CAPSULE_ACCEPT, CAPSULE_REVERT, } capsule_type;
Okay. Actually, I forgot about Ilias's this particular review comment. Will incorporate.
efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; efi_guid_t efi_guid_image_type_uboot_fit = @@ -38,9 +39,9 @@ efi_guid_t efi_guid_image_type_uboot_raw = efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
#ifdef CONFIG_TOOLS_LIBCRYPTO
Please rebase your patch to my v10 or later. I have already removed the dependency on openssl library.
Yes, I will have to now rebase on your V11.
-static const char *opts_short = "frg:i:I:v:p:c:m:dh"; +static const char *opts_short = "frg:i:I:v:p:c:m:dhAR"; #else -static const char *opts_short = "frg:i:I:v:h"; +static const char *opts_short = "frg:i:I:v:hAR"; #endif
static struct option options[] = { @@ -55,28 +56,50 @@ static struct option options[] = { {"monotonic-count", required_argument, NULL, 'm'}, {"dump-sig", no_argument, NULL, 'd'}, #endif
{"fw-accept", no_argument, NULL, 'A'},
{"fw-revert", no_argument, NULL, 'R'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0},
};
static void print_usage(void) {
fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
"Options:\n"
"\t-f, --fit FIT image type\n"
"\t-r, --raw raw image type\n"
"\t-g, --guid <guid string> guid for image blob type\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
if (empty_capsule) {
if (accept_fw_capsule) {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-A, --fw-accept firmware accept capsule\n"
"\t-g, --guid <guid string> guid for image blob type\n"
While I doubt the necessity of "--guid," why not accept "-f" or "-r" as a guid of image blob type? (It seems that your actual code does.)
I don't get this point. The --guid is needed for the firmware accept capsule, since the GUID value will be that of the firmware image that is being accepted. Like I mentioned above, firmware acceptance works on a per image basis.
"\t-h, --help print a help message\n"
);
} else {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-R, --fw-revert firmware revert capsule\n"
"\t-h, --help print a help message\n"
);
}
} else {
fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n",
tool_name);
fprintf(stderr, "Options:\n"
"\t-f, --fit FIT image type\n"
"\t-r, --raw raw image type\n"
"\t-g, --guid <guid string> guid for image blob type\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
#ifdef CONFIG_TOOLS_LIBCRYPTO
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
#endif
"\t-h, --help print a help message\n",
tool_name);
"\t-A, --fw-accept firmware accept capsule\n"
"\t-R, --fw-revert firmware revert capsule\n"
"\t-h, --help print a help message\n");
}
}
/** @@ -598,6 +621,50 @@ void convert_uuid_to_guid(unsigned char *buf) buf[7] = c; }
+static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept) +{
struct efi_capsule_header header;
FILE *f = NULL;
int ret = -1;
efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
efi_guid_t payload, capsule_guid;
f = fopen(path, "w");
if (!f) {
fprintf(stderr, "cannot open %s\n", path);
goto err;
}
capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
header.header_size = sizeof(header);
header.flags = 0;
header.capsule_image_size = fw_accept ?
sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
if (write_capsule_file(f, &header, sizeof(header),
"Capsule header"))
goto err;
if (fw_accept) {
memcpy(&payload, guid, sizeof(efi_guid_t));
if (write_capsule_file(f, &payload, sizeof(payload),
"FW Accept Capsule Payload"))
goto err;
}
ret = 0;
+err:
if (f)
fclose(f);
return ret;
+}
/**
- main - main entry function of mkeficapsule
- @argc: Number of arguments
@@ -625,6 +692,8 @@ int main(int argc, char **argv) mcount = 0; privkey_file = NULL; cert_file = NULL;
accept_fw_capsule = 0;
revert_fw_capsule = 0; dump_sig = 0; for (;;) { c = getopt_long(argc, argv, opts_short, options, &idx);
@@ -691,22 +760,44 @@ int main(int argc, char **argv) dump_sig = 1; break; #endif /* CONFIG_TOOLS_LIBCRYPTO */
case 'A':
accept_fw_capsule = 1;
break;
case 'R':
revert_fw_capsule = 1;
break; case 'h': print_usage(); exit(EXIT_SUCCESS); } }
if (accept_fw_capsule && revert_fw_capsule) {
fprintf(stderr,
"Select either of Accept or Revert capsule generation\n");
exit(EXIT_FAILURE);
}
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
/* check necessary parameters */
if ((argc != optind + 2) || !guid ||
((privkey_file && !cert_file) ||
if ((!empty_capsule && argc != optind + 2) ||
(empty_capsule && argc != optind + 1) ||
(!revert_fw_capsule && !guid) || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) {
Well, the error condition looks complicated due to mixing two cases and can be hard to maintain in the future. How about if (!empty_capsule && ((argc != optind + 2) || !guid || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) || empty_capsule && ((argc != optind + 1) || (accept_fw_capsule && revert_fw_capsule) || (accept_fw_capsule && !guid)) # arguable as mentioned above (revert_fw_capsule && guid))
Okay. Will change.
...
print_usage(); exit(EXIT_FAILURE); }
if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
mcount, privkey_file, cert_file) < 0) {
if (empty_capsule) {
if (create_empty_capsule(argv[argc - 1], guid,
accept_fw_capsule ? 1 : 0) < 0) {
The third argument can be simplified to "accept_fw_capsule".
Will change.
-sughosh
-Takahiro Akashi
fprintf(stderr, "Creating empty capsule failed\n");
exit(EXIT_FAILURE);
}
} else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
index, instance, mcount, privkey_file,
cert_file) < 0) { fprintf(stderr, "Creating firmware capsule failed\n"); exit(EXIT_FAILURE); }
-- 2.17.1

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

po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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 board which boots a FIP image from a uSD card partitioned with the GPT partioning scheme. This also requires changes in the previous stage of bootloader, which parses the metadata and selects the bank to boot the image(s) from. Support is 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's integration branch[3].
These patches are based on top of the series from Takahiro to add Authentication support to mkeficapsule utility[4] and a couple of other patches[5][6]
TODO's
- Add a unit test case for the newly added FWU_MDATA uclass. Some involved effort is needed on this since the host device interface on sandbox cannot be used with the UT framework.
- Add test case for the feature with the python test suite, along the lines of capsule update testing.
[1] - https://developer.arm.com/documentation/den0118/a [2] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e... [3] - https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/log/?h=integrati... [4] - https://patchwork.ozlabs.org/project/uboot/list/?series=281549 [5] - https://patchwork.ozlabs.org/project/uboot/patch/164388019634.446835.1827148... [6] - https://patchwork.ozlabs.org/project/uboot/patch/20220129192108.6618-1-sugho...
Changes since V3:
- Move the FWU metadata access to driver model
- Get the storage device containing the metadata from a device tree property instead of a platform helper function
- Move the metadata access driver for GPT partitioned block devices under drivers/fwu-mdata/ directory, complying with driver model.
- Move functionality to get the active index under the common function instead of the GPT block device specific driver.
- Remove function for getting the storage device containing the metadata as the information is now obtained from the device tree.
- Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs
- Define the function fill_image_type_guid_array for the ST DK2 board for GPT partitioned devices.
- Change the TrialStateCtr efi variable attribute to remove the runtime attribute
- Rebase the change on top of the patch from Masami to call efi_capsule_update_firmware directly.
- Put the FWU related checks which were earlier in efi_update_capsule function to separate functions fwu_empty_capsule and fwu_empty_capsule_process.
- Use the device model api uclass_get_device to probe and get the FWU Metadata device.
- Add related documentation for empty capsules in the mkeficapsule man page.
- Add separate usage for empty capsules, with corresponding valid options.
- Use ternary operators where possible.
- Put a exclusivity check for the empty capsule options.
Sughosh Ganu (11): FWU: Add FWU metadata structure and driver for accessing metadata FWU: Add FWU metadata access driver for GPT partitioned block devices FWU: stm32mp1: Add helper functions for accessing FWU metadata FWU: STM32MP1: Add support to read boot index from backup register EFI: FMP: Add provision to update image's ImageTypeId in image descriptor stm32mp1: Populate ImageTypeId values in EFI_FIRMWARE_IMAGE_DESCRIPTOR array FWU: Add boot time checks as highlighted by the FWU specification FWU: Add support for FWU Multi Bank Update feature FWU: cmd: Add a command to read FWU metadata mkeficapsule: Add support for generating empty capsules FWU: doc: Add documentation for the FWU feature
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + board/st/stm32mp1/stm32mp1.c | 178 +++++++ cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/fwu_mdata.c | 74 +++ common/board_r.c | 6 + doc/develop/uefi/fwu_updates.rst | 142 +++++ doc/develop/uefi/index.rst | 1 + doc/develop/uefi/uefi.rst | 2 + .../firmware/fwu-mdata.txt | 18 + doc/mkeficapsule.1 | 23 +- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 16 + drivers/fwu-mdata/Makefile | 7 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 +++++++++++++++ drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 501 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/efi_loader.h | 2 + include/fwu.h | 70 +++ include/fwu_mdata.h | 67 +++ lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 221 +++++++- lib/efi_loader/efi_firmware.c | 71 ++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 ++ lib/fwu_updates/Makefile | 6 + lib/fwu_updates/fwu.c | 204 +++++++ tools/eficapsule.h | 8 + tools/mkeficapsule.c | 131 ++++- 31 files changed, 2208 insertions(+), 34 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.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c create mode 100644 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
-- 2.17.1
What's the git base you use for this series?
Thanks, Michal

On Tue, 8 Feb 2022 at 16:36, Michal Simek monstr@monstr.eu wrote:
po 7. 2. 2022 v 19:21 odesílatel Sughosh Ganu sughosh.ganu@linaro.org napsal:
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 board which boots a FIP image from a uSD card partitioned with the GPT partioning scheme. This also requires changes in the previous stage of bootloader, which parses the metadata and selects the bank to boot the image(s) from. Support is 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's integration branch[3].
These patches are based on top of the series from Takahiro to add Authentication support to mkeficapsule utility[4] and a couple of other patches[5][6]
TODO's
- Add a unit test case for the newly added FWU_MDATA uclass. Some involved effort is needed on this since the host device interface on sandbox cannot be used with the UT framework.
- Add test case for the feature with the python test suite, along the lines of capsule update testing.
[1] - https://developer.arm.com/documentation/den0118/a [2] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e... [3] - https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/log/?h=integrati... [4] - https://patchwork.ozlabs.org/project/uboot/list/?series=281549 [5] - https://patchwork.ozlabs.org/project/uboot/patch/164388019634.446835.1827148... [6] - https://patchwork.ozlabs.org/project/uboot/patch/20220129192108.6618-1-sugho...
Changes since V3:
- Move the FWU metadata access to driver model
- Get the storage device containing the metadata from a device tree property instead of a platform helper function
- Move the metadata access driver for GPT partitioned block devices under drivers/fwu-mdata/ directory, complying with driver model.
- Move functionality to get the active index under the common function instead of the GPT block device specific driver.
- Remove function for getting the storage device containing the metadata as the information is now obtained from the device tree.
- Define a weak function fill_image_type_guid_array for populating the image descriptor array with u-boot's raw and fit image GUIDs
- Define the function fill_image_type_guid_array for the ST DK2 board for GPT partitioned devices.
- Change the TrialStateCtr efi variable attribute to remove the runtime attribute
- Rebase the change on top of the patch from Masami to call efi_capsule_update_firmware directly.
- Put the FWU related checks which were earlier in efi_update_capsule function to separate functions fwu_empty_capsule and fwu_empty_capsule_process.
- Use the device model api uclass_get_device to probe and get the FWU Metadata device.
- Add related documentation for empty capsules in the mkeficapsule man page.
- Add separate usage for empty capsules, with corresponding valid options.
- Use ternary operators where possible.
- Put a exclusivity check for the empty capsule options.
Sughosh Ganu (11): FWU: Add FWU metadata structure and driver for accessing metadata FWU: Add FWU metadata access driver for GPT partitioned block devices FWU: stm32mp1: Add helper functions for accessing FWU metadata FWU: STM32MP1: Add support to read boot index from backup register EFI: FMP: Add provision to update image's ImageTypeId in image descriptor stm32mp1: Populate ImageTypeId values in EFI_FIRMWARE_IMAGE_DESCRIPTOR array FWU: Add boot time checks as highlighted by the FWU specification FWU: Add support for FWU Multi Bank Update feature FWU: cmd: Add a command to read FWU metadata mkeficapsule: Add support for generating empty capsules FWU: doc: Add documentation for the FWU feature
arch/arm/dts/stm32mp157c-dk2-u-boot.dtsi | 7 + board/st/stm32mp1/stm32mp1.c | 178 +++++++ cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/fwu_mdata.c | 74 +++ common/board_r.c | 6 + doc/develop/uefi/fwu_updates.rst | 142 +++++ doc/develop/uefi/index.rst | 1 + doc/develop/uefi/uefi.rst | 2 + .../firmware/fwu-mdata.txt | 18 + doc/mkeficapsule.1 | 23 +- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/fwu-mdata/Kconfig | 16 + drivers/fwu-mdata/Makefile | 7 + drivers/fwu-mdata/fwu-mdata-uclass.c | 434 +++++++++++++++ drivers/fwu-mdata/fwu_mdata_gpt_blk.c | 501 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/efi_loader.h | 2 + include/fwu.h | 70 +++ include/fwu_mdata.h | 67 +++ lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 221 +++++++- lib/efi_loader/efi_firmware.c | 71 ++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 ++ lib/fwu_updates/Makefile | 6 + lib/fwu_updates/fwu.c | 204 +++++++ tools/eficapsule.h | 8 + tools/mkeficapsule.c | 131 ++++- 31 files changed, 2208 insertions(+), 34 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.txt create mode 100644 drivers/fwu-mdata/Kconfig create mode 100644 drivers/fwu-mdata/Makefile create mode 100644 drivers/fwu-mdata/fwu-mdata-uclass.c create mode 100644 drivers/fwu-mdata/fwu_mdata_gpt_blk.c create mode 100644 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
-- 2.17.1
What's the git base you use for this series?
You can clone my linaro git repo branch[1] to get the entire series.
-sughosh
[1] - https://git.linaro.org/people/sughosh.ganu/u-boot.git/log/?h=non_rfc_v1_mdat...
Thanks, Michal
-- Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91 w: www.monstr.eu p: +42-0-721842854 Maintainer of Linux kernel - Xilinx Microblaze Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs
participants (7)
-
AKASHI Takahiro
-
Heinrich Schuchardt
-
Ilias Apalodimas
-
Masami Hiramatsu
-
Michal Simek
-
Michal Simek
-
Sughosh Ganu