[RFC PATCH v3 0/9] 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 are under review currently[3].
These patches are based on top of the series from Takahiro to add Authentication support to mkeficapsule utility[4]
[1] - https://developer.arm.com/documentation/den0118/a [2] - https://staging-git.codelinaro.org/linaro/firmware-dual-banked-updates/test [3] - https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/12566 [4] - https://patchwork.ozlabs.org/project/uboot/list/?series=281549
Changes since V2: * Use uint*_t types in fwu_mdata.h since the file is to be reused in other projects * Keep only the FWU metadata structures in fwu_mdata.h * Move all other function and macro declarations in fwu.h * Keep common implementations of fwu_update_active_index and fwu_revert_boot_index in fwu_mdata.c * Add a update_mdata function pointer in the fwu_mdata_ops structure * Move the function definition of fwu_verify_mdata to fwu_mdata.c to facilitate reuse * Remove the block device specific desc->devnum parameter for the fwu_plat_get_alt_num function call * Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num * Add logic to delete the TrialStateCtr variable if system is not in Trial State * Add logic to check if bit 15(OS Acceptance) of the Flags member in the capsule header is set * Add logic to set the accept bit of all images from a capsule if the OS Acceptance bit in the capsule header is not set * Include the log.h and stdio.h header files
Sughosh Ganu (9): FWU: Add FWU metadata structure and functions for accessing metadata FWU: Add FWU metadata access functions 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 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
board/st/stm32mp1/stm32mp1.c | 183 ++++++++++ cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/fwu_mdata.c | 67 ++++ common/board_r.c | 6 + include/fwu.h | 81 +++++ include/fwu_mdata.h | 69 ++++ lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 233 ++++++++++++- lib/efi_loader/efi_firmware.c | 90 ++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 ++ lib/fwu_updates/Makefile | 11 + lib/fwu_updates/fwu.c | 198 +++++++++++ lib/fwu_updates/fwu_mdata.c | 358 +++++++++++++++++++ lib/fwu_updates/fwu_mdata_gpt_blk.c | 521 ++++++++++++++++++++++++++++ tools/eficapsule.h | 8 + tools/mkeficapsule.c | 102 +++++- 19 files changed, 1955 insertions(+), 21 deletions(-) create mode 100644 cmd/fwu_mdata.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h create mode 100644 lib/fwu_updates/Kconfig create mode 100644 lib/fwu_updates/Makefile create mode 100644 lib/fwu_updates/fwu.c create mode 100644 lib/fwu_updates/fwu_mdata.c create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.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 functions to access the metadata. These are generic API's, and implementations can be added based on parameters like how the metadata partition is accessed and what type of storage device houses the metadata.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org ---
Changes since V2: * Use uint*_t types in fwu_mdata.h since the file is to be reused in other projects * Keep only the FWU metadata structures in fwu_mdata.h * Move all other function and macro declarations in fwu.h * Keep common implementations of fwu_update_active_index and fwu_revert_boot_index in fwu_mdata.c * Add a update_mdata function pointer in the fwu_mdata_ops structure
include/fwu.h | 61 +++++++ include/fwu_mdata.h | 67 ++++++++ lib/fwu_updates/fwu_mdata.c | 329 ++++++++++++++++++++++++++++++++++++ 3 files changed, 457 insertions(+) create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h create mode 100644 lib/fwu_updates/fwu_mdata.c
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..acba725bc8 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#if !defined _FWU_H_ +#define _FWU_H_ + +#include <blk.h> +#include <efi.h> + +#include <linux/types.h> + +struct fwu_mdata; + +/** + * @get_active_index: get the current active_index value + * @get_image_alt_num: get the alt number to be used for the image + * @mdata_check: check the validity of the FWU metadata partitions + * @set_accept_image: set the accepted bit for the image + * @clear_accept_image: clear the accepted bit for the image + * @get_mdata() - Get a FWU metadata copy + * @update_mdata() - Update the FWU metadata copy + */ +struct fwu_mdata_ops { + int (*get_active_index)(u32 *active_idx); + + int (*get_image_alt_num)(efi_guid_t image_type_id, u32 update_bank, + int *alt_num); + + int (*mdata_check)(void); + + int (*set_accept_image)(efi_guid_t *img_type_id, u32 bank); + + int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank); + + int (*get_mdata)(struct fwu_mdata **mdata); + + int (*update_mdata)(struct fwu_mdata *mdata); +}; + +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void); + +#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..d788eb69e7 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021, 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_ */ diff --git a/lib/fwu_updates/fwu_mdata.c b/lib/fwu_updates/fwu_mdata.c new file mode 100644 index 0000000000..58e838fe28 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#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> + +static struct fwu_mdata_ops *get_fwu_mdata_ops(void) +{ + struct fwu_mdata_ops *ops; + + ops = get_plat_fwu_mdata_ops(); + if (!ops) { + log_err("Unable to get fwu ops\n"); + return NULL; + } + + return ops; +} + +/** + * 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) +{ + struct fwu_mdata_ops *ops; + + ops = get_fwu_mdata_ops(); + if (!ops) + return -EPROTONOSUPPORT; + + if (!ops->get_active_index) { + log_err("get_active_index() method not defined for the platform\n"); + return -ENOSYS; + } + + return ops->get_active_index(active_idx); +} + +/** + * 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) { + printf("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) +{ + struct fwu_mdata_ops *ops; + + ops = get_fwu_mdata_ops(); + if (!ops) + return -EPROTONOSUPPORT; + + if (!ops->get_image_alt_num) { + log_err("get_image_alt_num() method not defined for the platform\n"); + return -ENOSYS; + } + + return ops->get_image_alt_num(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) +{ + struct fwu_mdata_ops *ops; + + ops = get_fwu_mdata_ops(); + if (!ops) + return -EPROTONOSUPPORT; + + if (!ops->mdata_check) { + log_err("mdata_check() method not defined for the platform\n"); + return -ENOSYS; + } + + return ops->mdata_check(); +} + +/** + * 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_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) +{ + struct fwu_mdata_ops *ops; + + ops = get_fwu_mdata_ops(); + if (!ops) + return -EPROTONOSUPPORT; + + if (!ops->set_accept_image) { + log_err("set_accept_image() method not defined for the platform\n"); + return -ENOSYS; + } + + return ops->set_accept_image(img_type_id, bank); +} + +/** + * fwu_clear_accept_image() - Clear the Acceptance bit for the image + * @img_type_id: Guid of the image type for which the accepted bit is to be + * cleared + * @bank: Bank of which the image's Accept bit is to be cleared + * + * Clear the accepted bit for the image type specified by the img_type_id parameter. + * This function is called after the image has been updated. The accepted bit is + * cleared to be set subsequently after passing the image acceptance criteria, by + * either the OS(or firmware) + * + * Return: 0 if OK, -ve on error + * + */ +int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{ + struct fwu_mdata_ops *ops; + + ops = get_fwu_mdata_ops(); + if (!ops) + return -EPROTONOSUPPORT; + + if (!ops->clear_accept_image) { + log_err("clear_accept_image() method not defined for the platform\n"); + return -ENOSYS; + } + + return ops->clear_accept_image(img_type_id, bank); +} + +/** + * 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) +{ + struct fwu_mdata_ops *ops; + + ops = get_fwu_mdata_ops(); + if (!ops) + return -EPROTONOSUPPORT; + + if (!ops->get_mdata) { + log_err("get_mdata() method not defined for the platform\n"); + return -ENOSYS; + } + + return ops->get_mdata(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) +{ + struct fwu_mdata_ops *ops; + + ops = get_fwu_mdata_ops(); + if (!ops) + return -EPROTONOSUPPORT; + + if (!ops->update_mdata) { + log_err("get_mdata() method not defined for the platform\n"); + return -ENOSYS; + } + + return ops->update_mdata(mdata); +}

Hello Sughosh,
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
In the FWU Multi Bank Update feature, the information about the updatable images is stored as part of the metadata, which is stored on a dedicated partition. Add the metadata structure, and functions to access the metadata. These are generic API's, and implementations can be added based on parameters like how the metadata partition is accessed and what type of storage device houses the metadata.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V2:
- Use uint*_t types in fwu_mdata.h since the file is to be reused in other projects
- Keep only the FWU metadata structures in fwu_mdata.h
- Move all other function and macro declarations in fwu.h
- Keep common implementations of fwu_update_active_index and fwu_revert_boot_index in fwu_mdata.c
- Add a update_mdata function pointer in the fwu_mdata_ops structure
include/fwu.h | 61 +++++++ include/fwu_mdata.h | 67 ++++++++ lib/fwu_updates/fwu_mdata.c | 329 ++++++++++++++++++++++++++++++++++++ 3 files changed, 457 insertions(+) create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h create mode 100644 lib/fwu_updates/fwu_mdata.c
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..acba725bc8 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <blk.h> +#include <efi.h>
+#include <linux/types.h>
+struct fwu_mdata;
+/**
- @get_active_index: get the current active_index value
- @get_image_alt_num: get the alt number to be used for the image
- @mdata_check: check the validity of the FWU metadata partitions
- @set_accept_image: set the accepted bit for the image
- @clear_accept_image: clear the accepted bit for the image
- @get_mdata() - Get a FWU metadata copy
- @update_mdata() - Update the FWU metadata copy
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*get_image_alt_num)(efi_guid_t image_type_id, u32 update_bank,
int *alt_num);
int (*mdata_check)(void);
int (*set_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*get_mdata)(struct fwu_mdata **mdata);
int (*update_mdata)(struct fwu_mdata *mdata);
+};
We also can remove - get_active_index - set_accept_image - clear_accept_image from these operations, because those are just reading or modifying metadata. Such functions can be written as below
ops() { op->get_mdata(&mdata); do_some_operation(mdata); if (updated) op->update_mdata(mdata); }
I'll make a series of patches on top of your series for DeveloperBox, which does not use GPT.
Thank you,

hi Masami,
On Thu, 20 Jan 2022 at 11:23, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hello Sughosh,
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
In the FWU Multi Bank Update feature, the information about the updatable images is stored as part of the metadata, which is stored on a dedicated partition. Add the metadata structure, and functions to access the metadata. These are generic API's, and implementations can be added based on parameters like how the metadata partition is accessed and what type of storage device houses the metadata.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V2:
- Use uint*_t types in fwu_mdata.h since the file is to be reused in other projects
- Keep only the FWU metadata structures in fwu_mdata.h
- Move all other function and macro declarations in fwu.h
- Keep common implementations of fwu_update_active_index and fwu_revert_boot_index in fwu_mdata.c
- Add a update_mdata function pointer in the fwu_mdata_ops structure
include/fwu.h | 61 +++++++ include/fwu_mdata.h | 67 ++++++++ lib/fwu_updates/fwu_mdata.c | 329 ++++++++++++++++++++++++++++++++++++ 3 files changed, 457 insertions(+) create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h create mode 100644 lib/fwu_updates/fwu_mdata.c
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..acba725bc8 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <blk.h> +#include <efi.h>
+#include <linux/types.h>
+struct fwu_mdata;
+/**
- @get_active_index: get the current active_index value
- @get_image_alt_num: get the alt number to be used for the image
- @mdata_check: check the validity of the FWU metadata partitions
- @set_accept_image: set the accepted bit for the image
- @clear_accept_image: clear the accepted bit for the image
- @get_mdata() - Get a FWU metadata copy
- @update_mdata() - Update the FWU metadata copy
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*get_image_alt_num)(efi_guid_t image_type_id, u32 update_bank,
int *alt_num);
int (*mdata_check)(void);
int (*set_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*get_mdata)(struct fwu_mdata **mdata);
int (*update_mdata)(struct fwu_mdata *mdata);
+};
We also can remove
- get_active_index
- set_accept_image
- clear_accept_image
from these operations, because those are just reading or modifying metadata. Such functions can be written as below
ops() { op->get_mdata(&mdata); do_some_operation(mdata); if (updated) op->update_mdata(mdata); }
I'll make a series of patches on top of your series for DeveloperBox, which does not use GPT.
I will check how these functions can be put in the common fwu_mdata.c file. Thanks.
-sughosh
Thank you,
-- Masami Hiramatsu

Hi Sughosh,
I have another comment on this patch.
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
+/**
- 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) {
Since active_index must be 0 .. CONFIG_FWU_NUM_BANKS - 1, it should cap the new active_index with "CONFIG_FWU_NUM_BANKS - 1" instead of "CONFIG_FWU_NUM_BANKS".
printf("Active index value to be updated is incorrect\n");
Could you use log_err() instead of printf() for error messages?
Thank you,

hi Masami,
On Thu, 20 Jan 2022 at 11:35, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
I have another comment on this patch.
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
+/**
- 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) {
Since active_index must be 0 .. CONFIG_FWU_NUM_BANKS - 1, it should cap the new active_index with "CONFIG_FWU_NUM_BANKS - 1" instead of "CONFIG_FWU_NUM_BANKS".
Will update the check. Thanks.
printf("Active index value to be updated is incorrect\n");
Could you use log_err() instead of printf() for error messages?
Will do.
-sughosh
Thank you,
-- Masami Hiramatsu

On 1/19/22 19:55, Sughosh Ganu wrote:
In the FWU Multi Bank Update feature, the information about the updatable images is stored as part of the metadata, which is stored on a dedicated partition. Add the metadata structure, and functions to access the metadata. These are generic API's, and implementations can be added based on parameters like how the metadata partition is accessed and what type of storage device houses the metadata.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
I would have expected a new uclass implementing
* FFA_PARTITION_INFO_GET()
as defined in [1] and suggested by [2].
Reading the data from a partition could be implemented in one of the drivers.
Please, have a look at https://u-boot.readthedocs.io/en/latest/develop/driver-model/index.html
[1] Arm Firmware Framework for Arm A-profile (https://developer.arm.com/documentation/den0077/latest) [2] Platform Security Firmware Update for the A-profile Arm Architecture Beta (https://developer.arm.com/documentation/den0118/a)
Best regards
Heinrich
Changes since V2:
Use uint*_t types in fwu_mdata.h since the file is to be reused in other projects
Keep only the FWU metadata structures in fwu_mdata.h
Move all other function and macro declarations in fwu.h
Keep common implementations of fwu_update_active_index and fwu_revert_boot_index in fwu_mdata.c
Add a update_mdata function pointer in the fwu_mdata_ops structure
include/fwu.h | 61 +++++++ include/fwu_mdata.h | 67 ++++++++ lib/fwu_updates/fwu_mdata.c | 329 ++++++++++++++++++++++++++++++++++++ 3 files changed, 457 insertions(+) create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h create mode 100644 lib/fwu_updates/fwu_mdata.c
diff --git a/include/fwu.h b/include/fwu.h new file mode 100644 index 0000000000..acba725bc8 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <blk.h> +#include <efi.h>
+#include <linux/types.h>
+struct fwu_mdata;
+/**
- @get_active_index: get the current active_index value
- @get_image_alt_num: get the alt number to be used for the image
- @mdata_check: check the validity of the FWU metadata partitions
- @set_accept_image: set the accepted bit for the image
- @clear_accept_image: clear the accepted bit for the image
- @get_mdata() - Get a FWU metadata copy
- @update_mdata() - Update the FWU metadata copy
- */
+struct fwu_mdata_ops {
- int (*get_active_index)(u32 *active_idx);
- int (*get_image_alt_num)(efi_guid_t image_type_id, u32 update_bank,
int *alt_num);
- int (*mdata_check)(void);
- int (*set_accept_image)(efi_guid_t *img_type_id, u32 bank);
- int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank);
- int (*get_mdata)(struct fwu_mdata **mdata);
- int (*update_mdata)(struct fwu_mdata *mdata);
+};
+struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
+#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..d788eb69e7 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, 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_ */ diff --git a/lib/fwu_updates/fwu_mdata.c b/lib/fwu_updates/fwu_mdata.c new file mode 100644 index 0000000000..58e838fe28 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#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>
+static struct fwu_mdata_ops *get_fwu_mdata_ops(void) +{
- struct fwu_mdata_ops *ops;
- ops = get_plat_fwu_mdata_ops();
- if (!ops) {
log_err("Unable to get fwu ops\n");
return NULL;
- }
- return ops;
+}
+/**
- 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) +{
- struct fwu_mdata_ops *ops;
- ops = get_fwu_mdata_ops();
- if (!ops)
return -EPROTONOSUPPORT;
- if (!ops->get_active_index) {
log_err("get_active_index() method not defined for the platform\n");
return -ENOSYS;
- }
- return ops->get_active_index(active_idx);
+}
+/**
- 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) {
printf("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)
+{
- struct fwu_mdata_ops *ops;
- ops = get_fwu_mdata_ops();
- if (!ops)
return -EPROTONOSUPPORT;
- if (!ops->get_image_alt_num) {
log_err("get_image_alt_num() method not defined for the platform\n");
return -ENOSYS;
- }
- return ops->get_image_alt_num(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) +{
- struct fwu_mdata_ops *ops;
- ops = get_fwu_mdata_ops();
- if (!ops)
return -EPROTONOSUPPORT;
- if (!ops->mdata_check) {
log_err("mdata_check() method not defined for the platform\n");
return -ENOSYS;
- }
- return ops->mdata_check();
+}
+/**
- 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_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) +{
- struct fwu_mdata_ops *ops;
- ops = get_fwu_mdata_ops();
- if (!ops)
return -EPROTONOSUPPORT;
- if (!ops->set_accept_image) {
log_err("set_accept_image() method not defined for the platform\n");
return -ENOSYS;
- }
- return ops->set_accept_image(img_type_id, bank);
+}
+/**
- fwu_clear_accept_image() - Clear the Acceptance bit for the image
- @img_type_id: Guid of the image type for which the accepted bit is to be
cleared
- @bank: Bank of which the image's Accept bit is to be cleared
- Clear the accepted bit for the image type specified by the img_type_id parameter.
- This function is called after the image has been updated. The accepted bit is
- cleared to be set subsequently after passing the image acceptance criteria, by
- either the OS(or firmware)
- Return: 0 if OK, -ve on error
- */
+int fwu_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{
- struct fwu_mdata_ops *ops;
- ops = get_fwu_mdata_ops();
- if (!ops)
return -EPROTONOSUPPORT;
- if (!ops->clear_accept_image) {
log_err("clear_accept_image() method not defined for the platform\n");
return -ENOSYS;
- }
- return ops->clear_accept_image(img_type_id, bank);
+}
+/**
- 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) +{
- struct fwu_mdata_ops *ops;
- ops = get_fwu_mdata_ops();
- if (!ops)
return -EPROTONOSUPPORT;
- if (!ops->get_mdata) {
log_err("get_mdata() method not defined for the platform\n");
return -ENOSYS;
- }
- return ops->get_mdata(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) +{
- struct fwu_mdata_ops *ops;
- ops = get_fwu_mdata_ops();
- if (!ops)
return -EPROTONOSUPPORT;
- if (!ops->update_mdata) {
log_err("get_mdata() method not defined for the platform\n");
return -ENOSYS;
- }
- return ops->update_mdata(mdata);
+}

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 functions 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 V2: * Move the function definition of fwu_verify_mdata to fwu_mdata.c to facilitate reuse * Remove the block device specific desc->devnum parameter for the fwu_plat_get_alt_num function call
include/fwu.h | 1 + include/fwu_mdata.h | 2 + lib/fwu_updates/fwu_mdata.c | 29 ++ lib/fwu_updates/fwu_mdata_gpt_blk.c | 520 ++++++++++++++++++++++++++++ 4 files changed, 552 insertions(+) create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.c
diff --git a/include/fwu.h b/include/fwu.h index acba725bc8..12f7eecdb0 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -53,6 +53,7 @@ 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_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); diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h index d788eb69e7..53e39f9af6 100644 --- a/include/fwu_mdata.h +++ b/include/fwu_mdata.h @@ -64,4 +64,6 @@ struct fwu_mdata { struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK]; } __attribute__((__packed__));
+extern struct fwu_mdata_ops fwu_gpt_blk_ops; + #endif /* _FWU_MDATA_H_ */ diff --git a/lib/fwu_updates/fwu_mdata.c b/lib/fwu_updates/fwu_mdata.c index 58e838fe28..252fcf50f6 100644 --- a/lib/fwu_updates/fwu_mdata.c +++ b/lib/fwu_updates/fwu_mdata.c @@ -25,6 +25,35 @@ static struct fwu_mdata_ops *get_fwu_mdata_ops(void) return ops; }
+/** + * 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 diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c new file mode 100644 index 0000000000..cb47ddf4a7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <blk.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 <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) + +#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR 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; + + 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 fwu_mdata *mdata) +{ + int ret; + struct blk_desc *desc; + u16 primary_mpart = 0, secondary_mpart = 0; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + 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 fwu_mdata **mdata) +{ + int ret; + struct blk_desc *desc; + u16 primary_mpart = 0, secondary_mpart = 0; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + 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; + } + + *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(void) +{ + 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; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + /* + * Two FWU metadata partitions are expected. + * If we don't have two, user needs to create + * them first + */ + valid_partitions = 0; + ret = gpt_get_mdata_partitions(desc, &primary_mpart, + &secondary_mpart); + + if (ret < 0) { + log_err("Error getting the FWU metadata partitions\n"); + return -ENODEV; + } + + ret = gpt_read_mdata(desc, &pri_mdata, primary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + goto secondary_read; + } + + ret = fwu_verify_mdata(&pri_mdata, 1); + if (!ret) + valid_partitions |= PRIMARY_PART; + +secondary_read: + /* Now check the secondary partition */ + ret = gpt_read_mdata(desc, &secondary_mdata, secondary_mpart); + if (ret < 0) { + log_err("Failed to read the FWU metadata from the device\n"); + goto mdata_restore; + } + + ret = fwu_verify_mdata(&secondary_mdata, 0); + if (!ret) + valid_partitions |= SECONDARY_PART; + +mdata_restore: + if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) { + ret = -1; + /* + * Before returning, check that both the + * FWU metadata copies are the same. If not, + * the FWU metadata copies need to be + * re-populated. + */ + if (!memcmp(&pri_mdata, &secondary_mdata, + sizeof(struct fwu_mdata))) { + ret = 0; + } else { + log_err("Both FWU metadata copies are valid but do not match. Please check!\n"); + } + goto out; + } + + ret = -1; + if (!(valid_partitions & BOTH_PARTS)) + goto out; + + invalid_partitions = valid_partitions ^ BOTH_PARTS; + ret = gpt_write_mdata_partition(desc, + (invalid_partitions == PRIMARY_PART) ? + &secondary_mdata : &pri_mdata, + (invalid_partitions == PRIMARY_PART) ? + primary_mpart : secondary_mpart); + + if (ret < 0) + log_err("Restoring %s FWU metadata partition failed\n", + (invalid_partitions == PRIMARY_PART) ? + "primary" : "secondary"); + +out: + return ret; +} + +int fwu_gpt_get_active_index(u32 *active_idx) +{ + int ret; + struct fwu_mdata *mdata; + + ret = gpt_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) { + printf("Active index value read is incorrect\n"); + ret = -EINVAL; + goto out; + } + +out: + free(mdata); + + return ret; +} + +static int gpt_get_image_alt_num(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; + 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(&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(&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(efi_guid_t image_type_id, u32 update_bank, + int *alt_no) +{ + int ret; + struct blk_desc *desc; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + return gpt_get_image_alt_num(desc, image_type_id, update_bank, alt_no); +} + +int fwu_gpt_mdata_check(void) +{ + /* + * 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(); +} + +int fwu_gpt_get_mdata(struct fwu_mdata **mdata) +{ + return gpt_get_mdata(mdata); +} + +static int fwu_gpt_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; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_bank_info; + + ret = gpt_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_gpt_update_mdata(mdata); + goto out; + } + } + + /* Image not found */ + ret = -EINVAL; + +out: + free(mdata); + + return ret; +} + +static int fwu_gpt_accept_image(efi_guid_t *img_type_id, u32 bank) +{ + return fwu_gpt_set_clear_image_accept(img_type_id, bank, + IMAGE_ACCEPT_SET); +} + +static int fwu_gpt_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{ + return fwu_gpt_set_clear_image_accept(img_type_id, bank, + IMAGE_ACCEPT_CLEAR); +} + +struct fwu_mdata_ops fwu_gpt_blk_ops = { + .get_active_index = fwu_gpt_get_active_index, + .get_image_alt_num = fwu_gpt_get_image_alt_num, + .mdata_check = fwu_gpt_mdata_check, + .set_accept_image = fwu_gpt_accept_image, + .clear_accept_image = fwu_gpt_clear_accept_image, + .get_mdata = fwu_gpt_get_mdata, + .update_mdata = fwu_gpt_update_mdata, +};

Hi Sughosh,
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
+static int fwu_gpt_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
I think this update_mdata() method (or fwu_update_mdata() wrapper) should always update mdata::crc32. calculate crc32 at each call site is inefficient and easy to introduce bugs.
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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 fwu_mdata **mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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;
}
*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");
Also, please release mdata inside the gpt_get_mdata() itself.
I think it is not a good design to ask caller to free mdata if get_mdata() operation is failed because mdata may or may not allocated in error case.
In success case, user must free it because it is allocated (user accessed it), and in error case, user can ignore it because it should not be allocated. This is simpler mind model and less memory leak chance.
Thank you,

hi Masami,
On Thu, 20 Jan 2022 at 14:13, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
+static int fwu_gpt_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
I think this update_mdata() method (or fwu_update_mdata() wrapper) should always update mdata::crc32. calculate crc32 at each call site is inefficient and easy to introduce bugs.
Okay. Will do.
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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 fwu_mdata **mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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;
}
*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");
Also, please release mdata inside the gpt_get_mdata() itself.
I think it is not a good design to ask caller to free mdata if get_mdata() operation is failed because mdata may or may not allocated in error case.
In success case, user must free it because it is allocated (user accessed it), and in error case, user can ignore it because it should not be allocated. This is simpler mind model and less memory leak chance.
I think this is confusing. It would be better to be consistent and have the caller free up the allocated/not allocated memory. If you check, the mdata pointer is being initialised to NULL in every instance. Calling free with a NULL pointer is a valid case, which the free call handles. There are multiple places in u-boot where the caller is freeing up the allocated memory. So i think this should not be an issue.
-sughosh
Thank you,
Masami Hiramatsu

Hi Sughosh,
2022年1月24日(月) 15:58 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Thu, 20 Jan 2022 at 14:13, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
+static int fwu_gpt_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
I think this update_mdata() method (or fwu_update_mdata() wrapper) should always update mdata::crc32. calculate crc32 at each call site is inefficient and easy to introduce bugs.
Okay. Will do.
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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 fwu_mdata **mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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;
}
*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");
Also, please release mdata inside the gpt_get_mdata() itself.
I think it is not a good design to ask caller to free mdata if get_mdata() operation is failed because mdata may or may not allocated in error case.
In success case, user must free it because it is allocated (user accessed it), and in error case, user can ignore it because it should not be allocated. This is simpler mind model and less memory leak chance.
I think this is confusing. It would be better to be consistent and have the caller free up the allocated/not allocated memory. If you check, the mdata pointer is being initialised to NULL in every instance. Calling free with a NULL pointer is a valid case, which the free call handles. There are multiple places in u-boot where the caller is freeing up the allocated memory. So i think this should not be an issue.
Of course it is sane. What I was that is easier to introduce mistakes.
If it requires the caller to prepare mdata = NULL as an input, it easily causes memory leak or other issues, because it seems not an input but just an output parameter.
My concern is that this method is not a local one, but it is directly exported via fwu_mdata_opts. That is a problem because this means other developers can use it. And also, it forces the other backend driver (like my fwu_mdata_sf.c) to do so.
Thank you,

On Mon, Jan 24, 2022 at 12:28:24PM +0530, Sughosh Ganu wrote:
hi Masami,
On Thu, 20 Jan 2022 at 14:13, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
+static int fwu_gpt_update_mdata(struct fwu_mdata *mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
I think this update_mdata() method (or fwu_update_mdata() wrapper) should always update mdata::crc32. calculate crc32 at each call site is inefficient and easy to introduce bugs.
Okay. Will do.
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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 fwu_mdata **mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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;
}
*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");
Also, please release mdata inside the gpt_get_mdata() itself.
I think it is not a good design to ask caller to free mdata if get_mdata() operation is failed because mdata may or may not allocated in error case.
In success case, user must free it because it is allocated (user accessed it), and in error case, user can ignore it because it should not be allocated. This is simpler mind model and less memory leak chance.
I think this is confusing. It would be better to be consistent and have the caller free up the allocated/not allocated memory. If you check, the mdata pointer is being initialised to NULL in every instance. Calling free with a NULL pointer is a valid case, which the free call handles. There are multiple places in u-boot where the caller is freeing up the allocated memory. So i think this should not be an issue.
The simple rule should be that, if the function returns 0 (successfully), the area will be allocated. If not (i.e. returns an error), the area will not be allocated.
This will be a much more common behavior.
-Takahiro Akashi
-sughosh
Thank you,
Masami Hiramatsu

On 1/19/22 19:55, Sughosh Ganu wrote:
In the FWU Multi Bank Update feature, the information about the updatable images is stored as part of the metadata, on a separate partition. Add functions 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
Will a GPT partition remain the only place to store that information? Should this be implemented according to the dirver model?
Changes since V2:
Move the function definition of fwu_verify_mdata to fwu_mdata.c to facilitate reuse
Remove the block device specific desc->devnum parameter for the fwu_plat_get_alt_num function call
include/fwu.h | 1 + include/fwu_mdata.h | 2 + lib/fwu_updates/fwu_mdata.c | 29 ++ lib/fwu_updates/fwu_mdata_gpt_blk.c | 520 ++++++++++++++++++++++++++++ 4 files changed, 552 insertions(+) create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.c
diff --git a/include/fwu.h b/include/fwu.h index acba725bc8..12f7eecdb0 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -53,6 +53,7 @@ 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_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); diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h index d788eb69e7..53e39f9af6 100644 --- a/include/fwu_mdata.h +++ b/include/fwu_mdata.h @@ -64,4 +64,6 @@ struct fwu_mdata { struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK]; } __attribute__((__packed__));
+extern struct fwu_mdata_ops fwu_gpt_blk_ops;
- #endif /* _FWU_MDATA_H_ */
diff --git a/lib/fwu_updates/fwu_mdata.c b/lib/fwu_updates/fwu_mdata.c index 58e838fe28..252fcf50f6 100644 --- a/lib/fwu_updates/fwu_mdata.c +++ b/lib/fwu_updates/fwu_mdata.c @@ -25,6 +25,35 @@ static struct fwu_mdata_ops *get_fwu_mdata_ops(void) return ops; }
+/**
- 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));
CRC32 does not offer any security against manipulation. What are the security implications?
Best regards
Heinrich
- 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
diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c new file mode 100644 index 0000000000..cb47ddf4a7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <blk.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 <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)
+#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR 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;
- 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 fwu_mdata *mdata) +{
- int ret;
- struct blk_desc *desc;
- u16 primary_mpart = 0, secondary_mpart = 0;
- ret = fwu_plat_get_blk_desc(&desc);
- if (ret < 0) {
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 fwu_mdata **mdata) +{
- int ret;
- struct blk_desc *desc;
- u16 primary_mpart = 0, secondary_mpart = 0;
- ret = fwu_plat_get_blk_desc(&desc);
- if (ret < 0) {
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;
- }
- *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(void) +{
- 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;
- ret = fwu_plat_get_blk_desc(&desc);
- if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
- }
- /*
* Two FWU metadata partitions are expected.
* If we don't have two, user needs to create
* them first
*/
- valid_partitions = 0;
- ret = gpt_get_mdata_partitions(desc, &primary_mpart,
&secondary_mpart);
- if (ret < 0) {
log_err("Error getting the FWU metadata partitions\n");
return -ENODEV;
- }
- ret = gpt_read_mdata(desc, &pri_mdata, primary_mpart);
- if (ret < 0) {
log_err("Failed to read the FWU metadata from the device\n");
goto secondary_read;
- }
- ret = fwu_verify_mdata(&pri_mdata, 1);
- if (!ret)
valid_partitions |= PRIMARY_PART;
+secondary_read:
- /* Now check the secondary partition */
- ret = gpt_read_mdata(desc, &secondary_mdata, secondary_mpart);
- if (ret < 0) {
log_err("Failed to read the FWU metadata from the device\n");
goto mdata_restore;
- }
- ret = fwu_verify_mdata(&secondary_mdata, 0);
- if (!ret)
valid_partitions |= SECONDARY_PART;
+mdata_restore:
- if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) {
ret = -1;
/*
* Before returning, check that both the
* FWU metadata copies are the same. If not,
* the FWU metadata copies need to be
* re-populated.
*/
if (!memcmp(&pri_mdata, &secondary_mdata,
sizeof(struct fwu_mdata))) {
ret = 0;
} else {
log_err("Both FWU metadata copies are valid but do not match. Please check!\n");
}
goto out;
- }
- ret = -1;
- if (!(valid_partitions & BOTH_PARTS))
goto out;
- invalid_partitions = valid_partitions ^ BOTH_PARTS;
- ret = gpt_write_mdata_partition(desc,
(invalid_partitions == PRIMARY_PART) ?
&secondary_mdata : &pri_mdata,
(invalid_partitions == PRIMARY_PART) ?
primary_mpart : secondary_mpart);
- if (ret < 0)
log_err("Restoring %s FWU metadata partition failed\n",
(invalid_partitions == PRIMARY_PART) ?
"primary" : "secondary");
+out:
- return ret;
+}
+int fwu_gpt_get_active_index(u32 *active_idx) +{
- int ret;
- struct fwu_mdata *mdata;
- ret = gpt_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) {
printf("Active index value read is incorrect\n");
ret = -EINVAL;
goto out;
- }
+out:
- free(mdata);
- return ret;
+}
+static int gpt_get_image_alt_num(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;
- 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(&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(&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(efi_guid_t image_type_id, u32 update_bank,
int *alt_no)
+{
- int ret;
- struct blk_desc *desc;
- ret = fwu_plat_get_blk_desc(&desc);
- if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
- }
- return gpt_get_image_alt_num(desc, image_type_id, update_bank, alt_no);
+}
+int fwu_gpt_mdata_check(void) +{
- /*
* 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();
+}
+int fwu_gpt_get_mdata(struct fwu_mdata **mdata) +{
- return gpt_get_mdata(mdata);
+}
+static int fwu_gpt_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;
- struct fwu_image_entry *img_entry;
- struct fwu_image_bank_info *img_bank_info;
- ret = gpt_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_gpt_update_mdata(mdata);
goto out;
}
- }
- /* Image not found */
- ret = -EINVAL;
+out:
- free(mdata);
- return ret;
+}
+static int fwu_gpt_accept_image(efi_guid_t *img_type_id, u32 bank) +{
- return fwu_gpt_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_SET);
+}
+static int fwu_gpt_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{
- return fwu_gpt_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_CLEAR);
+}
+struct fwu_mdata_ops fwu_gpt_blk_ops = {
- .get_active_index = fwu_gpt_get_active_index,
- .get_image_alt_num = fwu_gpt_get_image_alt_num,
- .mdata_check = fwu_gpt_mdata_check,
- .set_accept_image = fwu_gpt_accept_image,
- .clear_accept_image = fwu_gpt_clear_accept_image,
- .get_mdata = fwu_gpt_get_mdata,
- .update_mdata = fwu_gpt_update_mdata,
+};

On Thu, 20 Jan 2022 at 16:57, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 1/19/22 19:55, Sughosh Ganu wrote:
In the FWU Multi Bank Update feature, the information about the updatable images is stored as part of the metadata, on a separate partition. Add functions 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
Will a GPT partition remain the only place to store that information? Should this be implemented according to the dirver model?
Even the current implementation provides a fwu_mdata_ops structure which contains function pointers for accessing the metadata. So there can be multiple implementations of the access methods. I have implemented the access methods for GPT partitioned block devices. But it should not be very difficult to move the metadata access to driver model. Let me know if you prefer that instead of the current implementation.
Changes since V2:
Move the function definition of fwu_verify_mdata to fwu_mdata.c to facilitate reuse
Remove the block device specific desc->devnum parameter for the fwu_plat_get_alt_num function call
include/fwu.h | 1 + include/fwu_mdata.h | 2 + lib/fwu_updates/fwu_mdata.c | 29 ++ lib/fwu_updates/fwu_mdata_gpt_blk.c | 520 ++++++++++++++++++++++++++++ 4 files changed, 552 insertions(+) create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.c
diff --git a/include/fwu.h b/include/fwu.h index acba725bc8..12f7eecdb0 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -53,6 +53,7 @@ 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_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); diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h index d788eb69e7..53e39f9af6 100644 --- a/include/fwu_mdata.h +++ b/include/fwu_mdata.h @@ -64,4 +64,6 @@ struct fwu_mdata { struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK]; } __attribute__((__packed__));
+extern struct fwu_mdata_ops fwu_gpt_blk_ops;
- #endif /* _FWU_MDATA_H_ */
diff --git a/lib/fwu_updates/fwu_mdata.c b/lib/fwu_updates/fwu_mdata.c index 58e838fe28..252fcf50f6 100644 --- a/lib/fwu_updates/fwu_mdata.c +++ b/lib/fwu_updates/fwu_mdata.c @@ -25,6 +25,35 @@ static struct fwu_mdata_ops *get_fwu_mdata_ops(void) return ops; }
+/**
- 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));
CRC32 does not offer any security against manipulation. What are the security implications?
The CRC32 value I believe is used only for integrity check of the metadata against any kind of bitflip type errors of the hardware device which stores the metadata. The metadata itself is stored on a non-secure storage medium.
-sughosh
Best regards
Heinrich
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
diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c new file mode 100644 index 0000000000..cb47ddf4a7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <blk.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 <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)
+#define IMAGE_ACCEPT_SET BIT(0) +#define IMAGE_ACCEPT_CLEAR 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;
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 fwu_mdata *mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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 fwu_mdata **mdata) +{
int ret;
struct blk_desc *desc;
u16 primary_mpart = 0, secondary_mpart = 0;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
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;
}
*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(void) +{
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;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
}
/*
* Two FWU metadata partitions are expected.
* If we don't have two, user needs to create
* them first
*/
valid_partitions = 0;
ret = gpt_get_mdata_partitions(desc, &primary_mpart,
&secondary_mpart);
if (ret < 0) {
log_err("Error getting the FWU metadata partitions\n");
return -ENODEV;
}
ret = gpt_read_mdata(desc, &pri_mdata, primary_mpart);
if (ret < 0) {
log_err("Failed to read the FWU metadata from the device\n");
goto secondary_read;
}
ret = fwu_verify_mdata(&pri_mdata, 1);
if (!ret)
valid_partitions |= PRIMARY_PART;
+secondary_read:
/* Now check the secondary partition */
ret = gpt_read_mdata(desc, &secondary_mdata, secondary_mpart);
if (ret < 0) {
log_err("Failed to read the FWU metadata from the device\n");
goto mdata_restore;
}
ret = fwu_verify_mdata(&secondary_mdata, 0);
if (!ret)
valid_partitions |= SECONDARY_PART;
+mdata_restore:
if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) {
ret = -1;
/*
* Before returning, check that both the
* FWU metadata copies are the same. If not,
* the FWU metadata copies need to be
* re-populated.
*/
if (!memcmp(&pri_mdata, &secondary_mdata,
sizeof(struct fwu_mdata))) {
ret = 0;
} else {
log_err("Both FWU metadata copies are valid but do not match. Please check!\n");
}
goto out;
}
ret = -1;
if (!(valid_partitions & BOTH_PARTS))
goto out;
invalid_partitions = valid_partitions ^ BOTH_PARTS;
ret = gpt_write_mdata_partition(desc,
(invalid_partitions == PRIMARY_PART) ?
&secondary_mdata : &pri_mdata,
(invalid_partitions == PRIMARY_PART) ?
primary_mpart : secondary_mpart);
if (ret < 0)
log_err("Restoring %s FWU metadata partition failed\n",
(invalid_partitions == PRIMARY_PART) ?
"primary" : "secondary");
+out:
return ret;
+}
+int fwu_gpt_get_active_index(u32 *active_idx) +{
int ret;
struct fwu_mdata *mdata;
ret = gpt_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) {
printf("Active index value read is incorrect\n");
ret = -EINVAL;
goto out;
}
+out:
free(mdata);
return ret;
+}
+static int gpt_get_image_alt_num(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;
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(&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(&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(efi_guid_t image_type_id, u32 update_bank,
int *alt_no)
+{
int ret;
struct blk_desc *desc;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
}
return gpt_get_image_alt_num(desc, image_type_id, update_bank, alt_no);
+}
+int fwu_gpt_mdata_check(void) +{
/*
* 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();
+}
+int fwu_gpt_get_mdata(struct fwu_mdata **mdata) +{
return gpt_get_mdata(mdata);
+}
+static int fwu_gpt_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;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
ret = gpt_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_gpt_update_mdata(mdata);
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+static int fwu_gpt_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_gpt_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_SET);
+}
+static int fwu_gpt_clear_accept_image(efi_guid_t *img_type_id, u32 bank) +{
return fwu_gpt_set_clear_image_accept(img_type_id, bank,
IMAGE_ACCEPT_CLEAR);
+}
+struct fwu_mdata_ops fwu_gpt_blk_ops = {
.get_active_index = fwu_gpt_get_active_index,
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.set_accept_image = fwu_gpt_accept_image,
.clear_accept_image = fwu_gpt_clear_accept_image,
.get_mdata = fwu_gpt_get_mdata,
.update_mdata = fwu_gpt_update_mdata,
+};

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 V2: * Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num
board/st/stm32mp1/stm32mp1.c | 176 ++++++++++++++++++++++++++++ include/fwu.h | 5 + lib/fwu_updates/fwu_mdata_gpt_blk.c | 7 +- 3 files changed, 185 insertions(+), 3 deletions(-)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 84592677e4..66cbe3f798 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,174 @@ 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(void *identifier) +{ + int ret; + struct blk_desc *desc; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + return gpt_plat_get_alt_num(desc->devnum, identifier); +} + +static int plat_fill_gpt_partition_guids(struct blk_desc *desc, + efi_guid_t **part_guid_arr) +{ + int i, ret = 0; + u32 part; + struct dfu_entity *dfu; + struct disk_partition info; + efi_guid_t part_type_guid; + int alt_num = dfu_get_alt_number(); + + dfu_init_env_entities(NULL, NULL); + + 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++; + } + + dfu_free_entities(); + + return ret; +} + +int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr) +{ + int ret; + struct blk_desc *desc; + + ret = fwu_plat_get_blk_desc(&desc); + if (ret < 0) { + log_err("Block device not found\n"); + return -ENODEV; + } + + return plat_fill_gpt_partition_guids(desc, part_guid_arr); +} + +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; +} + +int fwu_plat_get_blk_desc(struct blk_desc **desc) +{ + int ret; + struct mmc *mmc; + struct udevice *dev; + + /* + * Initial support is being added for the DK2 + * platform + */ + if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) && + (of_machine_is_compatible("st,stm32mp157c-dk2"))) { + ret = uclass_get_device(UCLASS_MMC, 0, &dev); + if (ret) + return -1; + + mmc = mmc_get_mmc_dev(dev); + if (!mmc) + return -1; + + if (mmc_init(mmc)) + return -1; + + *desc = mmc_get_blk_desc(mmc); + if (!*desc) + return -1; + } + + return 0; +} + +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void) +{ + if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) && + (of_machine_is_compatible("st,stm32mp157c-dk2"))) { + return &fwu_gpt_blk_ops; + } + + return NULL; +} +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */ diff --git a/include/fwu.h b/include/fwu.h index 12f7eecdb0..b23a93ac40 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -59,4 +59,9 @@ 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_blk_desc(struct blk_desc **desc); +int fwu_plat_get_alt_num(void *identifier); +int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr); + #endif /* _FWU_H_ */ diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c index cb47ddf4a7..796b08e76f 100644 --- a/lib/fwu_updates/fwu_mdata_gpt_blk.c +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -37,6 +37,7 @@ static int gpt_get_mdata_partitions(struct blk_desc *desc, 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; @@ -324,7 +325,7 @@ out: int fwu_gpt_get_active_index(u32 *active_idx) { int ret; - struct fwu_mdata *mdata; + struct fwu_mdata *mdata = NULL;
ret = gpt_get_mdata(&mdata); if (ret < 0) { @@ -355,7 +356,7 @@ static int gpt_get_image_alt_num(struct blk_desc *desc, { int ret, i; u32 part; - struct fwu_mdata *mdata; + struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info; struct disk_partition info; @@ -459,7 +460,7 @@ static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, void *buf; int ret, i; u32 nimages; - struct fwu_mdata *mdata; + struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info;

On 1/19/22 19:55, Sughosh Ganu wrote:
Add helper functions needed for accessing the FWU metadata which contains information on the updatable images. These functions have been added for the STM32MP157C-DK2 board which has the updatable images on the uSD card, formatted as GPT partitions.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
It is unclear why you are creating platform specific code here.
All of this metadata can be put into the control devicetree? If not create a driver class for it.
Unfortunately you don't provide any design document.
Best regards
Heinrich
Changes since V2:
Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num
board/st/stm32mp1/stm32mp1.c | 176 ++++++++++++++++++++++++++++ include/fwu.h | 5 + lib/fwu_updates/fwu_mdata_gpt_blk.c | 7 +- 3 files changed, 185 insertions(+), 3 deletions(-)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 84592677e4..66cbe3f798 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,174 @@ 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(void *identifier) +{
- int ret;
- struct blk_desc *desc;
- ret = fwu_plat_get_blk_desc(&desc);
- if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
- }
- return gpt_plat_get_alt_num(desc->devnum, identifier);
+}
+static int plat_fill_gpt_partition_guids(struct blk_desc *desc,
efi_guid_t **part_guid_arr)
+{
- int i, ret = 0;
- u32 part;
- struct dfu_entity *dfu;
- struct disk_partition info;
- efi_guid_t part_type_guid;
- int alt_num = dfu_get_alt_number();
- dfu_init_env_entities(NULL, NULL);
- 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++;
- }
- dfu_free_entities();
- return ret;
+}
+int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr) +{
- int ret;
- struct blk_desc *desc;
- ret = fwu_plat_get_blk_desc(&desc);
- if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
- }
- return plat_fill_gpt_partition_guids(desc, part_guid_arr);
+}
+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;
+}
+int fwu_plat_get_blk_desc(struct blk_desc **desc) +{
- int ret;
- struct mmc *mmc;
- struct udevice *dev;
- /*
* Initial support is being added for the DK2
* platform
*/
- if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
ret = uclass_get_device(UCLASS_MMC, 0, &dev);
if (ret)
return -1;
mmc = mmc_get_mmc_dev(dev);
if (!mmc)
return -1;
if (mmc_init(mmc))
return -1;
*desc = mmc_get_blk_desc(mmc);
if (!*desc)
return -1;
- }
- return 0;
+}
+struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void) +{
- if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
return &fwu_gpt_blk_ops;
- }
- return NULL;
+} +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */ diff --git a/include/fwu.h b/include/fwu.h index 12f7eecdb0..b23a93ac40 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -59,4 +59,9 @@ 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_blk_desc(struct blk_desc **desc); +int fwu_plat_get_alt_num(void *identifier); +int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr);
- #endif /* _FWU_H_ */
diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c index cb47ddf4a7..796b08e76f 100644 --- a/lib/fwu_updates/fwu_mdata_gpt_blk.c +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -37,6 +37,7 @@ static int gpt_get_mdata_partitions(struct blk_desc *desc, 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;
@@ -324,7 +325,7 @@ out: int fwu_gpt_get_active_index(u32 *active_idx) { int ret;
- struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL;
ret = gpt_get_mdata(&mdata); if (ret < 0) {
@@ -355,7 +356,7 @@ static int gpt_get_image_alt_num(struct blk_desc *desc, { int ret, i; u32 part;
- struct fwu_mdata *mdata;
- struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info; struct disk_partition info;
@@ -459,7 +460,7 @@ static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, void *buf; int ret, i; u32 nimages;
- struct fwu_mdata *mdata;
- struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info;

On Thu, 20 Jan 2022 at 16:29, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 1/19/22 19:55, Sughosh Ganu wrote:
Add helper functions needed for accessing the FWU metadata which contains information on the updatable images. These functions have been added for the STM32MP157C-DK2 board which has the updatable images on the uSD card, formatted as GPT partitions.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
It is unclear why you are creating platform specific code here.
This is primarily code that will be dependent on the platform. For e.g. the number of banks of firmware is a decision of the platform. So, there is a function, fwu_plat_get_update_index which will return the bank number which should be used for updating the firmware images. Similarly for getting the DFU alt_num. This will depend on things like the device that the platform uses for storing the firmware images. There aren't too many functions defined here. I will cover this aspect in the documentation patch which you have asked for.
All of this metadata can be put into the control devicetree? If not create a driver class for it.
Creating a driver class for accessing the metadata seems like a decent solution to me. I will work on this.
-sughosh
Unfortunately you don't provide any design document.
Best regards
Heinrich
Changes since V2:
Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num
board/st/stm32mp1/stm32mp1.c | 176 ++++++++++++++++++++++++++++ include/fwu.h | 5 + lib/fwu_updates/fwu_mdata_gpt_blk.c | 7 +- 3 files changed, 185 insertions(+), 3 deletions(-)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 84592677e4..66cbe3f798 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,174 @@ 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(void *identifier) +{
int ret;
struct blk_desc *desc;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
}
return gpt_plat_get_alt_num(desc->devnum, identifier);
+}
+static int plat_fill_gpt_partition_guids(struct blk_desc *desc,
efi_guid_t **part_guid_arr)
+{
int i, ret = 0;
u32 part;
struct dfu_entity *dfu;
struct disk_partition info;
efi_guid_t part_type_guid;
int alt_num = dfu_get_alt_number();
dfu_init_env_entities(NULL, NULL);
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++;
}
dfu_free_entities();
return ret;
+}
+int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr) +{
int ret;
struct blk_desc *desc;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
}
return plat_fill_gpt_partition_guids(desc, part_guid_arr);
+}
+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;
+}
+int fwu_plat_get_blk_desc(struct blk_desc **desc) +{
int ret;
struct mmc *mmc;
struct udevice *dev;
/*
* Initial support is being added for the DK2
* platform
*/
if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
ret = uclass_get_device(UCLASS_MMC, 0, &dev);
if (ret)
return -1;
mmc = mmc_get_mmc_dev(dev);
if (!mmc)
return -1;
if (mmc_init(mmc))
return -1;
*desc = mmc_get_blk_desc(mmc);
if (!*desc)
return -1;
}
return 0;
+}
+struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void) +{
if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
return &fwu_gpt_blk_ops;
}
return NULL;
+} +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */ diff --git a/include/fwu.h b/include/fwu.h index 12f7eecdb0..b23a93ac40 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -59,4 +59,9 @@ 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_blk_desc(struct blk_desc **desc); +int fwu_plat_get_alt_num(void *identifier); +int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr);
- #endif /* _FWU_H_ */
diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c index cb47ddf4a7..796b08e76f 100644 --- a/lib/fwu_updates/fwu_mdata_gpt_blk.c +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -37,6 +37,7 @@ static int gpt_get_mdata_partitions(struct blk_desc *desc, 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;
@@ -324,7 +325,7 @@ out: int fwu_gpt_get_active_index(u32 *active_idx) { int ret;
struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL; ret = gpt_get_mdata(&mdata); if (ret < 0) {
@@ -355,7 +356,7 @@ static int gpt_get_image_alt_num(struct blk_desc *desc, { int ret, i; u32 part;
struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info; struct disk_partition info;
@@ -459,7 +460,7 @@ static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, void *buf; int ret, i; u32 nimages;
struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info;

Hi Sughosh,
[...]
}
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;
And that's fine. But can you add a pr_warn or something on this check? So if anyone tries to implement this on a non-sd card can get a clear indication of what's not working?
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(void *identifier) +{
- int ret;
- struct blk_desc *desc;
- ret = fwu_plat_get_blk_desc(&desc);
- if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
- }
- return gpt_plat_get_alt_num(desc->devnum, identifier);
+}
+static int plat_fill_gpt_partition_guids(struct blk_desc *desc,
efi_guid_t **part_guid_arr)
+{
- int i, ret = 0;
- u32 part;
- struct dfu_entity *dfu;
- struct disk_partition info;
- efi_guid_t part_type_guid;
- int alt_num = dfu_get_alt_number();
- dfu_init_env_entities(NULL, NULL);
- 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)
ditto
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++;
- }
- dfu_free_entities();
- return ret;
+}
+int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr) +{
- int ret;
- struct blk_desc *desc;
- ret = fwu_plat_get_blk_desc(&desc);
- if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
- }
- return plat_fill_gpt_partition_guids(desc, part_guid_arr);
+}
+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;
+}
+int fwu_plat_get_blk_desc(struct blk_desc **desc) +{
- int ret;
- struct mmc *mmc;
- struct udevice *dev;
- /*
* Initial support is being added for the DK2
* platform
*/
- if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
ret = uclass_get_device(UCLASS_MMC, 0, &dev);
if (ret)
return -1;
mmc = mmc_get_mmc_dev(dev);
if (!mmc)
return -1;
if (mmc_init(mmc))
return -1;
*desc = mmc_get_blk_desc(mmc);
if (!*desc)
return -1;
- }
- return 0;
+}
+struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void) +{
- if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
return &fwu_gpt_blk_ops;
- }
- return NULL;
+} +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */ diff --git a/include/fwu.h b/include/fwu.h index 12f7eecdb0..b23a93ac40 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -59,4 +59,9 @@ 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_blk_desc(struct blk_desc **desc); +int fwu_plat_get_alt_num(void *identifier); +int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr);
#endif /* _FWU_H_ */ diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c index cb47ddf4a7..796b08e76f 100644 --- a/lib/fwu_updates/fwu_mdata_gpt_blk.c +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -37,6 +37,7 @@ static int gpt_get_mdata_partitions(struct blk_desc *desc, 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;
@@ -324,7 +325,7 @@ out: int fwu_gpt_get_active_index(u32 *active_idx) { int ret;
- struct fwu_mdata *mdata;
- struct fwu_mdata *mdata = NULL;
Should these be part of the original patch?
ret = gpt_get_mdata(&mdata); if (ret < 0) { @@ -355,7 +356,7 @@ static int gpt_get_image_alt_num(struct blk_desc *desc, { int ret, i; u32 part;
- struct fwu_mdata *mdata;
- struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info; struct disk_partition info;
@@ -459,7 +460,7 @@ static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, void *buf; int ret, i; u32 nimages;
- struct fwu_mdata *mdata;
- struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info;
-- 2.17.1

Hi Sughosh,
BTW, I can't find the definition of CONFIG_FWU_NUM_IMAGES_PER_BANK and CONFIG_FWU_NUM_BANKS for this platform. Is it really possible to build this platform with FWU_MULTI_BANK_UPDATE?
Thank you,
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
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 V2:
- Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num
board/st/stm32mp1/stm32mp1.c | 176 ++++++++++++++++++++++++++++ include/fwu.h | 5 + lib/fwu_updates/fwu_mdata_gpt_blk.c | 7 +- 3 files changed, 185 insertions(+), 3 deletions(-)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 84592677e4..66cbe3f798 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,174 @@ 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(void *identifier) +{
int ret;
struct blk_desc *desc;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
}
return gpt_plat_get_alt_num(desc->devnum, identifier);
+}
+static int plat_fill_gpt_partition_guids(struct blk_desc *desc,
efi_guid_t **part_guid_arr)
+{
int i, ret = 0;
u32 part;
struct dfu_entity *dfu;
struct disk_partition info;
efi_guid_t part_type_guid;
int alt_num = dfu_get_alt_number();
dfu_init_env_entities(NULL, NULL);
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++;
}
dfu_free_entities();
return ret;
+}
+int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr) +{
int ret;
struct blk_desc *desc;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
}
return plat_fill_gpt_partition_guids(desc, part_guid_arr);
+}
+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;
+}
+int fwu_plat_get_blk_desc(struct blk_desc **desc) +{
int ret;
struct mmc *mmc;
struct udevice *dev;
/*
* Initial support is being added for the DK2
* platform
*/
if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
ret = uclass_get_device(UCLASS_MMC, 0, &dev);
if (ret)
return -1;
mmc = mmc_get_mmc_dev(dev);
if (!mmc)
return -1;
if (mmc_init(mmc))
return -1;
*desc = mmc_get_blk_desc(mmc);
if (!*desc)
return -1;
}
return 0;
+}
+struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void) +{
if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
return &fwu_gpt_blk_ops;
}
return NULL;
+} +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */ diff --git a/include/fwu.h b/include/fwu.h index 12f7eecdb0..b23a93ac40 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -59,4 +59,9 @@ 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_blk_desc(struct blk_desc **desc); +int fwu_plat_get_alt_num(void *identifier); +int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr);
#endif /* _FWU_H_ */ diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c index cb47ddf4a7..796b08e76f 100644 --- a/lib/fwu_updates/fwu_mdata_gpt_blk.c +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -37,6 +37,7 @@ static int gpt_get_mdata_partitions(struct blk_desc *desc, 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;
@@ -324,7 +325,7 @@ out: int fwu_gpt_get_active_index(u32 *active_idx) { int ret;
struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL; ret = gpt_get_mdata(&mdata); if (ret < 0) {
@@ -355,7 +356,7 @@ static int gpt_get_image_alt_num(struct blk_desc *desc, { int ret, i; u32 part;
struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info; struct disk_partition info;
@@ -459,7 +460,7 @@ static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, void *buf; int ret, i; u32 nimages;
struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info;
-- 2.17.1
-- Masami Hiramatsu

hi Masami,
On Mon, 24 Jan 2022 at 08:16, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
BTW, I can't find the definition of CONFIG_FWU_NUM_IMAGES_PER_BANK and CONFIG_FWU_NUM_BANKS for this platform. Is it really possible to build this platform with FWU_MULTI_BANK_UPDATE?
Yes, I have actually tested my code :). The reason I did not add that particular patch to this series is that the number of images per bank and number of banks might change on a case by case basis. It is expected that the user will set these to the values that she is using on the platform.
-sughosh
Thank you,
2022年1月20日(木) 3:56 Sughosh Ganu sughosh.ganu@linaro.org:
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 V2:
- Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num
board/st/stm32mp1/stm32mp1.c | 176 ++++++++++++++++++++++++++++ include/fwu.h | 5 + lib/fwu_updates/fwu_mdata_gpt_blk.c | 7 +- 3 files changed, 185 insertions(+), 3 deletions(-)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 84592677e4..66cbe3f798 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,174 @@ 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(void *identifier) +{
int ret;
struct blk_desc *desc;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
}
return gpt_plat_get_alt_num(desc->devnum, identifier);
+}
+static int plat_fill_gpt_partition_guids(struct blk_desc *desc,
efi_guid_t **part_guid_arr)
+{
int i, ret = 0;
u32 part;
struct dfu_entity *dfu;
struct disk_partition info;
efi_guid_t part_type_guid;
int alt_num = dfu_get_alt_number();
dfu_init_env_entities(NULL, NULL);
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++;
}
dfu_free_entities();
return ret;
+}
+int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr) +{
int ret;
struct blk_desc *desc;
ret = fwu_plat_get_blk_desc(&desc);
if (ret < 0) {
log_err("Block device not found\n");
return -ENODEV;
}
return plat_fill_gpt_partition_guids(desc, part_guid_arr);
+}
+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;
+}
+int fwu_plat_get_blk_desc(struct blk_desc **desc) +{
int ret;
struct mmc *mmc;
struct udevice *dev;
/*
* Initial support is being added for the DK2
* platform
*/
if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
ret = uclass_get_device(UCLASS_MMC, 0, &dev);
if (ret)
return -1;
mmc = mmc_get_mmc_dev(dev);
if (!mmc)
return -1;
if (mmc_init(mmc))
return -1;
*desc = mmc_get_blk_desc(mmc);
if (!*desc)
return -1;
}
return 0;
+}
+struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void) +{
if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
(of_machine_is_compatible("st,stm32mp157c-dk2"))) {
return &fwu_gpt_blk_ops;
}
return NULL;
+} +#endif /* CONFIG_FWU_MULTI_BANK_UPDATE */ diff --git a/include/fwu.h b/include/fwu.h index 12f7eecdb0..b23a93ac40 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -59,4 +59,9 @@ 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_blk_desc(struct blk_desc **desc); +int fwu_plat_get_alt_num(void *identifier); +int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr);
#endif /* _FWU_H_ */ diff --git a/lib/fwu_updates/fwu_mdata_gpt_blk.c b/lib/fwu_updates/fwu_mdata_gpt_blk.c index cb47ddf4a7..796b08e76f 100644 --- a/lib/fwu_updates/fwu_mdata_gpt_blk.c +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -37,6 +37,7 @@ static int gpt_get_mdata_partitions(struct blk_desc *desc, 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;
@@ -324,7 +325,7 @@ out: int fwu_gpt_get_active_index(u32 *active_idx) { int ret;
struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL; ret = gpt_get_mdata(&mdata); if (ret < 0) {
@@ -355,7 +356,7 @@ static int gpt_get_image_alt_num(struct blk_desc *desc, { int ret, i; u32 part;
struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info; struct disk_partition info;
@@ -459,7 +460,7 @@ static int fwu_gpt_set_clear_image_accept(efi_guid_t *img_type_id, void *buf; int ret, i; u32 nimages;
struct fwu_mdata *mdata;
struct fwu_mdata *mdata = NULL; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info;
-- 2.17.1
-- Masami Hiramatsu

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 V2: None
board/st/stm32mp1/stm32mp1.c | 7 +++++++ include/fwu.h | 1 + 2 files changed, 8 insertions(+)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 66cbe3f798..6e7aaaa8a4 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -1104,6 +1104,13 @@ int fwu_plat_get_blk_desc(struct blk_desc **desc) return 0; }
+void fwu_plat_get_bootidx(void *boot_idx) +{ + u32 *bootidx = boot_idx; + + *bootidx = readl(TAMP_BOOTCOUNT); +} + struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void) { if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) && diff --git a/include/fwu.h b/include/fwu.h index b23a93ac40..6393a1dbb5 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -63,5 +63,6 @@ int fwu_plat_get_update_index(u32 *update_idx); int fwu_plat_get_blk_desc(struct blk_desc **desc); int fwu_plat_get_alt_num(void *identifier); int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr); +void fwu_plat_get_bootidx(void *boot_idx);
#endif /* _FWU_H_ */

On 1/19/22 19:55, Sughosh Ganu wrote:
The FWU Multi Bank Update feature allows the platform to boot the firmware images from one of the partitions(banks). The first stage bootloader(fsbl) passes the value of the boot index, i.e. the bank from which the firmware images were booted from to U-Boot. On the STM32MP157C-DK2 board, this value is passed through one of the SoC's backup register. Add a function to read the boot index value from the backup register.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V2: None
board/st/stm32mp1/stm32mp1.c | 7 +++++++ include/fwu.h | 1 + 2 files changed, 8 insertions(+)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 66cbe3f798..6e7aaaa8a4 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -1104,6 +1104,13 @@ int fwu_plat_get_blk_desc(struct blk_desc **desc) return 0; }
+void fwu_plat_get_bootidx(void *boot_idx) +{
- u32 *bootidx = boot_idx;
- *bootidx = readl(TAMP_BOOTCOUNT);
+}
Please, follow the driver model in your implementation.
https://u-boot.readthedocs.io/en/latest/develop/driver-model/index.html
Best regards
Heinrich
struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void) { if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) && diff --git a/include/fwu.h b/include/fwu.h index b23a93ac40..6393a1dbb5 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -63,5 +63,6 @@ int fwu_plat_get_update_index(u32 *update_idx); int fwu_plat_get_blk_desc(struct blk_desc **desc); int fwu_plat_get_alt_num(void *identifier); int fwu_plat_fill_partition_guids(efi_guid_t **part_guid_arr); +void fwu_plat_get_bootidx(void *boot_idx);
#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 V2: None
lib/efi_loader/efi_firmware.c | 90 ++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 7 deletions(-)
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..648342ae72 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -10,6 +10,7 @@ #include <charset.h> #include <dfu.h> #include <efi_loader.h> +#include <fwu.h> #include <image.h> #include <signatures.h>
@@ -96,6 +97,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+static efi_status_t fill_part_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 +145,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 +163,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 +213,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 +291,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 +306,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_part_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); }
@@ -358,7 +407,10 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u32 *package_version, u16 **package_version_name) { + int status; efi_status_t ret = EFI_SUCCESS; + const efi_guid_t null_guid = NULL_GUID; + 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 +425,36 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
+ if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { + ret = fill_part_guid_array(&null_guid, &part_guid_arr); + if (ret != EFI_SUCCESS) + goto out; + + /* + * Call the platform function to fill the GUID array + * with the corresponding partition GUID values + */ + status = fwu_plat_fill_partition_guids(&part_guid_arr); + if (status < 0) { + log_err("Unable to get partiion guid's\n"); + ret = EFI_DEVICE_ERROR; + goto out; + } + } else { + ret = fill_part_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); }

On Thu, Jan 20, 2022 at 12:25:44AM +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.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V2: None
lib/efi_loader/efi_firmware.c | 90 ++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 7 deletions(-)
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..648342ae72 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -10,6 +10,7 @@ #include <charset.h> #include <dfu.h> #include <efi_loader.h> +#include <fwu.h> #include <image.h> #include <signatures.h>
@@ -96,6 +97,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+static efi_status_t fill_part_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 +145,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 +163,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 +213,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 +291,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 +306,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_part_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
- if (ret != EFI_SUCCESS)
goto out;
Why do you not call fwu_plat_fill_partition_guids() for FIT FMP driver? If you have a specific reason, please describe it.
- 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);
}
@@ -358,7 +407,10 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u32 *package_version, u16 **package_version_name) {
int status; efi_status_t ret = EFI_SUCCESS;
const efi_guid_t null_guid = NULL_GUID;
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 +425,36 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
- if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
ret = fill_part_guid_array(&null_guid, &part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
/*
* Call the platform function to fill the GUID array
* with the corresponding partition GUID values
*/
status = fwu_plat_fill_partition_guids(&part_guid_arr);
if (status < 0) {
log_err("Unable to get partiion guid's\n");
ret = EFI_DEVICE_ERROR;
goto out;
}
- } else {
ret = fill_part_guid_array(&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
- }
The code: ret = fill_part_guid_array(&efi_firmware_image_type_uboot_raw, &part_guid_arr); if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) status = fwu_plat_fill_partition_guids(&part_guid_arr);
would be much simpler here.
But I don't know why you want to call fwu_plat_fill_partition_guids() only in case of CONFIG_FWU_MULTI_BANK_UPDATE. The functionality should be the same whether A/B update or not.
-Takahiro Akashi
- 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, 20 Jan 2022 at 10:54, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Thu, Jan 20, 2022 at 12:25:44AM +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.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V2: None
lib/efi_loader/efi_firmware.c | 90 ++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 7 deletions(-)
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..648342ae72 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -10,6 +10,7 @@ #include <charset.h> #include <dfu.h> #include <efi_loader.h> +#include <fwu.h> #include <image.h> #include <signatures.h>
@@ -96,6 +97,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+static efi_status_t fill_part_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 +145,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 +163,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 +213,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 +291,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 +306,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_part_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
Why do you not call fwu_plat_fill_partition_guids() for FIT FMP driver? If you have a specific reason, please describe it.
The idea here was to retain the current behaviour for the non FWU use case, where for both raw and FIT images, the same ImageTypeId is being used. Do you want to have a weak function which fills the array with a specific ImageTypeId value. Then, if any platform wants to have a different implementation, they can define a function which fills the array with relevant GUID values.
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);
}
@@ -358,7 +407,10 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u32 *package_version, u16 **package_version_name) {
int status; efi_status_t ret = EFI_SUCCESS;
const efi_guid_t null_guid = NULL_GUID;
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 +425,36 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
ret = fill_part_guid_array(&null_guid, &part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
/*
* Call the platform function to fill the GUID array
* with the corresponding partition GUID values
*/
status = fwu_plat_fill_partition_guids(&part_guid_arr);
if (status < 0) {
log_err("Unable to get partiion guid's\n");
ret = EFI_DEVICE_ERROR;
goto out;
}
} else {
ret = fill_part_guid_array(&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
}
The code: ret = fill_part_guid_array(&efi_firmware_image_type_uboot_raw, &part_guid_arr); if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) status = fwu_plat_fill_partition_guids(&part_guid_arr);
would be much simpler here.
Yep, will change.
But I don't know why you want to call fwu_plat_fill_partition_guids() only in case of CONFIG_FWU_MULTI_BANK_UPDATE. The functionality should be the same whether A/B update or not.
Let me know if you are okay with what I have proposed above.
-sughosh
-Takahiro Akashi
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 Fri, Jan 21, 2022 at 12:32:04PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Thu, 20 Jan 2022 at 10:54, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Thu, Jan 20, 2022 at 12:25:44AM +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.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V2: None
lib/efi_loader/efi_firmware.c | 90 ++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 7 deletions(-)
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..648342ae72 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -10,6 +10,7 @@ #include <charset.h> #include <dfu.h> #include <efi_loader.h> +#include <fwu.h> #include <image.h> #include <signatures.h>
@@ -96,6 +97,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+static efi_status_t fill_part_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 +145,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 +163,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 +213,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 +291,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 +306,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_part_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
Why do you not call fwu_plat_fill_partition_guids() for FIT FMP driver? If you have a specific reason, please describe it.
The idea here was to retain the current behaviour for the non FWU use case, where for both raw and FIT images, the same ImageTypeId is being used.
What I meant to say was fwu_plat_fill_partition_guids() is not called even in case of CONFIG_FWU_MULTI_BANK_UPDATE.
Do you want to have a weak function which fills the array with a specific ImageTypeId value. Then, if any platform wants to have a different implementation, they can define a function which fills the array with relevant GUID values.
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);
}
@@ -358,7 +407,10 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u32 *package_version, u16 **package_version_name) {
int status; efi_status_t ret = EFI_SUCCESS;
const efi_guid_t null_guid = NULL_GUID;
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 +425,36 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
ret = fill_part_guid_array(&null_guid, &part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
/*
* Call the platform function to fill the GUID array
* with the corresponding partition GUID values
*/
status = fwu_plat_fill_partition_guids(&part_guid_arr);
if (status < 0) {
log_err("Unable to get partiion guid's\n");
ret = EFI_DEVICE_ERROR;
goto out;
}
} else {
ret = fill_part_guid_array(&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
}
The code: ret = fill_part_guid_array(&efi_firmware_image_type_uboot_raw, &part_guid_arr); if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) status = fwu_plat_fill_partition_guids(&part_guid_arr);
would be much simpler here.
Yep, will change.
But I don't know why you want to call fwu_plat_fill_partition_guids() only in case of CONFIG_FWU_MULTI_BANK_UPDATE. The functionality should be the same whether A/B update or not.
Let me know if you are okay with what I have proposed above.
Yes. The weak "plat" function will be expected to be optimized away.
-Takahiro Akashi
-sughosh
-Takahiro Akashi
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 Mon, 24 Jan 2022 at 08:03, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Fri, Jan 21, 2022 at 12:32:04PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Thu, 20 Jan 2022 at 10:54, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Thu, Jan 20, 2022 at 12:25:44AM +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.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V2: None
lib/efi_loader/efi_firmware.c | 90 ++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 7 deletions(-)
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc2..648342ae72 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -10,6 +10,7 @@ #include <charset.h> #include <dfu.h> #include <efi_loader.h> +#include <fwu.h> #include <image.h> #include <signatures.h>
@@ -96,6 +97,46 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported( return EFI_EXIT(EFI_UNSUPPORTED); }
+static efi_status_t fill_part_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 +145,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 +163,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 +213,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 +291,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 +306,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_part_guid_array(&efi_firmware_image_type_uboot_fit,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
Why do you not call fwu_plat_fill_partition_guids() for FIT FMP driver? If you have a specific reason, please describe it.
The idea here was to retain the current behaviour for the non FWU use case, where for both raw and FIT images, the same ImageTypeId is being used.
What I meant to say was fwu_plat_fill_partition_guids() is not called even in case of CONFIG_FWU_MULTI_BANK_UPDATE.
Ah, that is because I am testing the FWU code with the raw capsules and not FIT. I will add a weak function. If there is FWU support added for FIT based capsules in the future, the relevant plat function will have to be added.
-sughosh
Do you want to have a weak function which fills the array with a specific ImageTypeId value. Then, if any platform wants to have a different implementation, they can define a function which fills the array with relevant GUID values.
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);
}
@@ -358,7 +407,10 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( u32 *package_version, u16 **package_version_name) {
int status; efi_status_t ret = EFI_SUCCESS;
const efi_guid_t null_guid = NULL_GUID;
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 +425,36 @@ efi_status_t EFIAPI efi_firmware_raw_get_image_info( !descriptor_size || !package_version || !package_version_name)) return EFI_EXIT(EFI_INVALID_PARAMETER);
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
ret = fill_part_guid_array(&null_guid, &part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
/*
* Call the platform function to fill the GUID array
* with the corresponding partition GUID values
*/
status = fwu_plat_fill_partition_guids(&part_guid_arr);
if (status < 0) {
log_err("Unable to get partiion guid's\n");
ret = EFI_DEVICE_ERROR;
goto out;
}
} else {
ret = fill_part_guid_array(&efi_firmware_image_type_uboot_raw,
&part_guid_arr);
if (ret != EFI_SUCCESS)
goto out;
}
The code: ret = fill_part_guid_array(&efi_firmware_image_type_uboot_raw, &part_guid_arr); if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) status = fwu_plat_fill_partition_guids(&part_guid_arr);
would be much simpler here.
Yep, will change.
But I don't know why you want to call fwu_plat_fill_partition_guids() only in case of CONFIG_FWU_MULTI_BANK_UPDATE. The functionality should be the same whether A/B update or not.
Let me know if you are okay with what I have proposed above.
Yes. The weak "plat" function will be expected to be optimized away.
-Takahiro Akashi
-sughosh
-Takahiro Akashi
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

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 V2: * Add logic to delete the TrialStateCtr variable if system is not in Trial State
common/board_r.c | 6 ++ include/fwu.h | 3 + lib/fwu_updates/fwu.c | 171 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 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 6393a1dbb5..950a816dbd 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -47,6 +47,9 @@ struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void); 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..906b5e622a --- /dev/null +++ b/lib/fwu_updates/fwu.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#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 | + EFI_VARIABLE_RUNTIME_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; + u32 boot_idx, active_idx; + + 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; +}

Hi Sughosh
[...]
+#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) {
That's personal preference and feel free to ignore it, but I generally find the code easier to read like if (!trial_state) do stuff; goto out;
<rest of the code follows here>
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 |
EFI_VARIABLE_RUNTIME_ACCESS;
Do we really need it with runtime 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);
We can't completely ignore the failed setvariable here, as it will affect the entire code path from that point onwards. Any checks after an update will fail since the variable wont be there.
- }
+out:
- free(mdata);
- return ret;
+}
+u8 fwu_update_checks_pass(void) +{
- return !trial_state && boottime_check;
+}
+int fwu_boottime_checks(void) +{
- int ret;
- u32 boot_idx, active_idx;
- 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;
+}
cheers /Ilias
2.17.1

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 V2: * Add logic to check if bit 15(OS Acceptance) of the Flags member in the capsule header is set * Add logic to set the accept bit of all images from a capsule if the OS Acceptance bit in the capsule header is not set
include/fwu.h | 12 +- lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 233 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 +++++ lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 ++++ 8 files changed, 319 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 950a816dbd..6c9b64a9f1 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -42,13 +42,23 @@ struct fwu_mdata_ops { struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
#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 8301eed631..83c89a0cbb 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 */ @@ -403,10 +414,13 @@ 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;
/* sanity check */ if (capsule_data->header_size < sizeof(*capsule) || @@ -481,8 +495,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 +535,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: @@ -527,6 +601,9 @@ efi_status_t EFIAPI efi_update_capsule( u64 scatter_gather_list) { struct efi_capsule_header *capsule; + efi_guid_t *image_guid; + u32 active_idx; + int status; unsigned int i; efi_status_t ret;
@@ -538,6 +615,16 @@ efi_status_t EFIAPI efi_update_capsule( goto out; }
+ if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { + /* 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"); + ret = EFI_DEVICE_ERROR; + goto out; + } + } + ret = EFI_SUCCESS; for (i = 0, capsule = *capsule_header_array; i < capsule_count; i++, capsule = *(++capsule_header_array)) { @@ -552,7 +639,82 @@ efi_status_t EFIAPI efi_update_capsule( i, &capsule->capsule_guid); if (!guidcmp(&capsule->capsule_guid, &efi_guid_firmware_management_capsule_id)) { + if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { + if (!fwu_update_checks_pass()) { + log_err("FWU checks failed. Cannot start update\n"); + ret = EFI_INVALID_PARAMETER; + goto out; + } + if (capsule->flags & FW_ACCEPT_OS) + fw_accept_os = 0x1; + } + ret = efi_capsule_update_firmware(capsule); + capsule_update = true; + } else if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { + capsule_update = false; + 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; + goto out; + } + + 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; + } + } } else { log_err("Unsupported capsule type: %pUl\n", &capsule->capsule_guid); @@ -563,6 +725,36 @@ efi_status_t EFIAPI efi_update_capsule( goto out; }
+ /* + * Update the FWU metadata once all the capsules have + * been updated. This is done only for the Runtime + * capsule update service. + * The update_index value now gets written to the + * active_index and the update_index value also + * gets updated. + * For the capsule-on-disk feature, the updation + * of the FWU metadata happens in efi_launch_capsules + */ + if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE) && + !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK)) { + 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 { + status = fwu_trial_state_ctr_start(); + if (status < 0) + ret = EFI_DEVICE_ERROR; + else + ret = EFI_SUCCESS; + } + } + if (IS_ENABLED(CONFIG_EFI_ESRT)) { /* Rebuild the ESRT to reflect any updated FW images. */ ret = efi_esrt_populate(); @@ -1090,8 +1282,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 +1313,11 @@ efi_status_t efi_launch_capsules(void) ret = efi_capsule_read_file(files[i], &capsule); if (ret == EFI_SUCCESS) { ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0)); - 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 +1325,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 +1333,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..73099a30cb --- /dev/null +++ b/lib/fwu_updates/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2021, Linaro Limited +# + +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_mdata.o +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o + +ifdef CONFIG_EFI_PARTITION +obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu_mdata_gpt_blk.o +endif diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index 906b5e622a..fd0eccd5c6 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -115,6 +115,33 @@ 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 | + EFI_VARIABLE_RUNTIME_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;

Hello Sughosh,
2022年1月20日(木) 3:57 Sughosh Ganu sughosh.ganu@linaro.org:
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
It is clear that the FWU_MULTI_BANK_UPDATE depends on EFI_CAPSULE_FIRMWARE_RAW, please select it here.
Thank you,
-- Masami Hiramatsu

hi Masami,
On Thu, 20 Jan 2022 at 11:37, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hello Sughosh,
2022年1月20日(木) 3:57 Sughosh Ganu sughosh.ganu@linaro.org:
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
It is clear that the FWU_MULTI_BANK_UPDATE depends on EFI_CAPSULE_FIRMWARE_RAW, please select it here.
I can do that, but are you sure that this functionality will not be used for FIT images? Or do I use an imply instead of select?
-sughosh
Thank you,
-- Masami Hiramatsu

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 V2: * Include the log.h and stdio.h header files
cmd/Kconfig | 7 ++++++ cmd/Makefile | 1 + cmd/fwu_mdata.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 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..81e4850442 --- /dev/null +++ b/cmd/fwu_mdata.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <command.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 Read\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[]) +{ + int ret = CMD_RET_SUCCESS; + struct fwu_mdata *mdata = NULL; + + 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", + "" +);

On 1/19/22 19:55, Sughosh Ganu wrote:
Add a command to read the metadata as specified in the FWU specification and print the fields of the metadata.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V2:
Include the log.h and stdio.h header files
cmd/Kconfig | 7 ++++++ cmd/Makefile | 1 + cmd/fwu_mdata.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 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..81e4850442 --- /dev/null +++ b/cmd/fwu_mdata.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <command.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 Read\n");
:%/ Read//
Nobody expects that this is data written.
- 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[])
+{
- int ret = CMD_RET_SUCCESS;
- struct fwu_mdata *mdata = NULL;
- 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",
- ""
+);
For any new command, please, add documentation in /doc/usage/.
Best regards
Heinrich

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 V2: * New patch for generating empty capsules
tools/eficapsule.h | 8 ++++ tools/mkeficapsule.c | 102 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 100 insertions(+), 10 deletions(-)
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..643da3849d 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +static unsigned char 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,15 +56,23 @@ 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" + if (empty_capsule) { + fprintf(stderr, "Usage: %s [options] <output file>\n", + tool_name); + } 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" @@ -75,8 +84,9 @@ static void print_usage(void) "\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 +608,59 @@ 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; + int ret; + 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 = NULL; + ret = -1; + + f = fopen(path, "w"); + if (!f) { + printf("cannot open %s\n", path); + goto err; + } + + if (fw_accept) + capsule_guid = fw_accept_guid; + else + capsule_guid = fw_revert_guid; + + memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t)); + header.header_size = sizeof(header); + header.flags = 0; + + if (fw_accept) { + header.capsule_image_size = sizeof(header) + sizeof(efi_guid_t); + } else { + header.capsule_image_size = 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 @@ -616,6 +679,7 @@ int main(int argc, char **argv) unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount; + unsigned char accept_fw_capsule, revert_fw_capsule; char *privkey_file, *cert_file; int c, idx;
@@ -625,6 +689,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 +757,38 @@ 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); } }
+ 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) { + printf("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,
From user's point of view,
On Thu, Jan 20, 2022 at 12:25:48AM +0530, Sughosh Ganu wrote:
The Dependable Boot specification describes the structure of the
May we have a pointer or reference to it?
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 V2:
- New patch for generating empty capsules
tools/eficapsule.h | 8 ++++ tools/mkeficapsule.c | 102 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 100 insertions(+), 10 deletions(-)
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..643da3849d 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +static unsigned char 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,15 +56,23 @@ 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"
- if (empty_capsule) {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
- } else {
fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n",
tool_name);
- }
We should always show both cases regardless of "empty_capsule".
Or if you have any restrictions on a combination of options, you'd better describe them more specifically in help message.
I'd also like to encourage you to update the man page as well as uefi.rst.
- 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"
@@ -75,8 +84,9 @@ static void print_usage(void) "\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 +608,59 @@ 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;
- int ret;
- 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 = NULL;
- ret = -1;
- f = fopen(path, "w");
- if (!f) {
printf("cannot open %s\n", path);
To stderr as Heinrich has requested.
goto err;
- }
- if (fw_accept)
capsule_guid = fw_accept_guid;
- else
capsule_guid = fw_revert_guid;
- memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
- header.header_size = sizeof(header);
- header.flags = 0;
- if (fw_accept) {
header.capsule_image_size = sizeof(header) + sizeof(efi_guid_t);
- } else {
header.capsule_image_size = sizeof(header);
- }
I wonder why we don't need GUID in revert case (and why need GUID in fw case. Since we want to add A/B update, there seems to be no ambiguity.
- 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
@@ -616,6 +679,7 @@ int main(int argc, char **argv) unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount;
- unsigned char accept_fw_capsule, revert_fw_capsule; char *privkey_file, *cert_file; int c, idx;
@@ -625,6 +689,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 +757,38 @@ 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); } }
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
Please check that two options are exclusive here.
/* check necessary parameters */
- if ((argc != optind + 2) || !guid ||
((privkey_file && !cert_file) ||
- if ((!empty_capsule && argc != optind + 2) ||
(empty_capsule && argc != optind + 1) ||
print_usage(); exit(EXIT_FAILURE); }(!revert_fw_capsule && !guid) || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) {
- 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) {
printf("Creating empty capsule failed\n");
To stderr
-Takahiro Akashi
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

hi Takahiro,
On Thu, 20 Jan 2022 at 07:43, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
From user's point of view,
On Thu, Jan 20, 2022 at 12:25:48AM +0530, Sughosh Ganu wrote:
The Dependable Boot specification describes the structure of the
May we have a pointer or reference to it?
Okay.
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 V2:
- New patch for generating empty capsules
tools/eficapsule.h | 8 ++++ tools/mkeficapsule.c | 102 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 100 insertions(+), 10 deletions(-)
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..643da3849d 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +static unsigned char 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,15 +56,23 @@ 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"
if (empty_capsule) {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
} else {
fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n",
tool_name);
}
We should always show both cases regardless of "empty_capsule".
Or if you have any restrictions on a combination of options, you'd better describe them more specifically in help message.
Yes, there are restrictions on the combination of options. I will call a separate function, like empty_capsule_usage for these.
I'd also like to encourage you to update the man page as well as uefi.rst.
Okay
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"
@@ -75,8 +84,9 @@ static void print_usage(void) "\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 +608,59 @@ 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;
int ret;
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 = NULL;
ret = -1;
f = fopen(path, "w");
if (!f) {
printf("cannot open %s\n", path);
To stderr as Heinrich has requested.
I thought I saw an email from Heinrich in which he said that he did not want a fprintf call, and was going to revert those hunks from your patch. I will recheck this bit.
goto err;
}
if (fw_accept)
capsule_guid = fw_accept_guid;
else
capsule_guid = fw_revert_guid;
memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
header.header_size = sizeof(header);
header.flags = 0;
if (fw_accept) {
header.capsule_image_size = sizeof(header) + sizeof(efi_guid_t);
} else {
header.capsule_image_size = sizeof(header);
}
I wonder why we don't need GUID in revert case (and why need GUID in fw case. Since we want to add A/B update, there seems to be no ambiguity.
The revert capsule is used not as a rejection of a specific individual image, but for reverting the platform to the other bank. Which does not require a image specific GUID.
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
@@ -616,6 +679,7 @@ int main(int argc, char **argv) unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount;
unsigned char accept_fw_capsule, revert_fw_capsule; char *privkey_file, *cert_file; int c, idx;
@@ -625,6 +689,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 +757,38 @@ 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); } }
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
Please check that two options are exclusive here.
Okay
/* 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) {
printf("Creating empty capsule failed\n");
To stderr
Okay, will check.
-sughosh
-Takahiro Akashi
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

On Fri, Jan 21, 2022 at 12:18:38PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Thu, 20 Jan 2022 at 07:43, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
From user's point of view,
On Thu, Jan 20, 2022 at 12:25:48AM +0530, Sughosh Ganu wrote:
The Dependable Boot specification describes the structure of the
May we have a pointer or reference to it?
Okay.
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 V2:
- New patch for generating empty capsules
tools/eficapsule.h | 8 ++++ tools/mkeficapsule.c | 102 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 100 insertions(+), 10 deletions(-)
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..643da3849d 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +static unsigned char 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,15 +56,23 @@ 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"
if (empty_capsule) {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
} else {
fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n",
tool_name);
}
We should always show both cases regardless of "empty_capsule".
Or if you have any restrictions on a combination of options, you'd better describe them more specifically in help message.
Yes, there are restrictions on the combination of options. I will call a separate function, like empty_capsule_usage for these.
I'd also like to encourage you to update the man page as well as uefi.rst.
Okay
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"
@@ -75,8 +84,9 @@ static void print_usage(void) "\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 +608,59 @@ 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;
int ret;
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 = NULL;
ret = -1;
f = fopen(path, "w");
if (!f) {
printf("cannot open %s\n", path);
To stderr as Heinrich has requested.
I thought I saw an email from Heinrich in which he said that he did not want a fprintf call, and was going to revert those hunks from your patch. I will recheck this bit.
I think that his said comment goes only against the help message. (I object it though.)
goto err;
}
if (fw_accept)
capsule_guid = fw_accept_guid;
else
capsule_guid = fw_revert_guid;
memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
header.header_size = sizeof(header);
header.flags = 0;
if (fw_accept) {
header.capsule_image_size = sizeof(header) + sizeof(efi_guid_t);
} else {
header.capsule_image_size = sizeof(header);
}
I wonder why we don't need GUID in revert case (and why need GUID in fw case. Since we want to add A/B update, there seems to be no ambiguity.
The revert capsule is used not as a rejection of a specific individual image, but for reverting the platform to the other bank. Which does not require a image specific GUID.
If so, why not apply the same rule to *accept* case to make the change permanent?
-Takahiro Akashi
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
@@ -616,6 +679,7 @@ int main(int argc, char **argv) unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount;
unsigned char accept_fw_capsule, revert_fw_capsule; char *privkey_file, *cert_file; int c, idx;
@@ -625,6 +689,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 +757,38 @@ 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); } }
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
Please check that two options are exclusive here.
Okay
/* 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) {
printf("Creating empty capsule failed\n");
To stderr
Okay, will check.
-sughosh
-Takahiro Akashi
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,
2022年1月24日(月) 11:08 AKASHI Takahiro takahiro.akashi@linaro.org:
memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
header.header_size = sizeof(header);
header.flags = 0;
if (fw_accept) {
header.capsule_image_size = sizeof(header) + sizeof(efi_guid_t);
} else {
header.capsule_image_size = sizeof(header);
}
I wonder why we don't need GUID in revert case (and why need GUID in fw case. Since we want to add A/B update, there seems to be no ambiguity.
The revert capsule is used not as a rejection of a specific individual image, but for reverting the platform to the other bank. Which does not require a image specific GUID.
If so, why not apply the same rule to *accept* case to make the change permanent?
Perhaps, we can make a special "acceptance" capsule file which accept all image types. I guess originally it is considered to test each image by the image provider and each provider decides the firmware is acceptable or not. For example, TF-A test program passed the test but U-Boot test program doesn't. In that case, we may need a partial acceptance flags.
However, at least the DeveloperBox has only one image type and maybe most of platforms doesn't want to split it. Thus the acceptance image-type uuid can be optional.
Thank you,
-Takahiro Akashi
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
@@ -616,6 +679,7 @@ int main(int argc, char **argv) unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount;
unsigned char accept_fw_capsule, revert_fw_capsule; char *privkey_file, *cert_file; int c, idx;
@@ -625,6 +689,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 +757,38 @@ 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); } }
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
Please check that two options are exclusive here.
Okay
/* 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) {
printf("Creating empty capsule failed\n");
To stderr
Okay, will check.
-sughosh
-Takahiro Akashi
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
-- Masami Hiramatsu

Hi Sughosh,
On Thu, Jan 20, 2022 at 12:25:48AM +0530, Sughosh Ganu wrote:
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 V2:
- New patch for generating empty capsules
tools/eficapsule.h | 8 ++++ tools/mkeficapsule.c | 102 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 100 insertions(+), 10 deletions(-)
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..643da3849d 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +static unsigned char 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,15 +56,23 @@ 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"
if (empty_capsule) {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
} 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"
@@ -75,8 +84,9 @@ static void print_usage(void) "\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 +608,59 @@ 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;
- int ret;
- 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 = NULL;
- ret = -1;
Can we init those at their declaration?
- f = fopen(path, "w");
- if (!f) {
printf("cannot open %s\n", path);
goto err;
- }
- if (fw_accept)
capsule_guid = fw_accept_guid;
- else
capsule_guid = fw_revert_guid;
ternary operator would look better here.
- memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
- header.header_size = sizeof(header);
- header.flags = 0;
Is it the flags only you need? Or maybe memset the entire headeri to 0?
- if (fw_accept) {
header.capsule_image_size = sizeof(header) + sizeof(efi_guid_t);
- } else {
header.capsule_image_size = sizeof(header);
- }
ternary again?
- 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
@@ -616,6 +679,7 @@ int main(int argc, char **argv) unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount;
- unsigned char accept_fw_capsule, revert_fw_capsule; char *privkey_file, *cert_file; int c, idx;
@@ -625,6 +689,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 +757,38 @@ 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); } }
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
Why do we need 3 variables here? Would it be better to have an enum and just use a single variable like "is_accept_capsule"?
- /* check necessary parameters */
- if ((argc != optind + 2) || !guid ||
((privkey_file && !cert_file) ||
- if ((!empty_capsule && argc != optind + 2) ||
(empty_capsule && argc != optind + 1) ||
print_usage(); exit(EXIT_FAILURE); }(!revert_fw_capsule && !guid) || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) {
- 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) {
printf("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
Thanks /Ilias

hi Ilias,
On Fri, 21 Jan 2022 at 18:30, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Sughosh,
On Thu, Jan 20, 2022 at 12:25:48AM +0530, Sughosh Ganu wrote:
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 V2:
- New patch for generating empty capsules
tools/eficapsule.h | 8 ++++ tools/mkeficapsule.c | 102 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 100 insertions(+), 10 deletions(-)
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..643da3849d 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,6 +29,7 @@ #include "eficapsule.h"
static const char *tool_name = "mkeficapsule"; +static unsigned char 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,15 +56,23 @@ 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"
if (empty_capsule) {
fprintf(stderr, "Usage: %s [options] <output file>\n",
tool_name);
} 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"
@@ -75,8 +84,9 @@ static void print_usage(void) "\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 +608,59 @@ 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;
int ret;
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 = NULL;
ret = -1;
Can we init those at their declaration?
Okay. I followed the initialisation style that was used in other functions. But I can init the variables like you mention.
f = fopen(path, "w");
if (!f) {
printf("cannot open %s\n", path);
goto err;
}
if (fw_accept)
capsule_guid = fw_accept_guid;
else
capsule_guid = fw_revert_guid;
ternary operator would look better here.
Okay
memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
header.header_size = sizeof(header);
header.flags = 0;
Is it the flags only you need? Or maybe memset the entire headeri to 0?
All members of the capsule header structure are being initialised. So no need to memset the struct to 0.
if (fw_accept) {
header.capsule_image_size = sizeof(header) + sizeof(efi_guid_t);
} else {
header.capsule_image_size = sizeof(header);
}
ternary again?
Okay
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
@@ -616,6 +679,7 @@ int main(int argc, char **argv) unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount;
unsigned char accept_fw_capsule, revert_fw_capsule; char *privkey_file, *cert_file; int c, idx;
@@ -625,6 +689,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 +757,38 @@ 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); } }
empty_capsule = (accept_fw_capsule || revert_fw_capsule);
Why do we need 3 variables here? Would it be better to have an enum and just use a single variable like "is_accept_capsule"?
For printing the usage, I need to differentiate between an accept capsule and revert capsule, since they take different options. If you don't have a strong view on this, I will keep it as is.
-sughosh
/* 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) {
printf("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
Thanks /Ilias

Sughosh,
On Thu, Jan 20, 2022 at 12:25:39AM +0530, Sughosh Ganu wrote:
The patchset adds support for the FWU Multi Bank Update[1] feature. Certain aspects of the Dependable Boot[2] specification have also been implemented.
The FWU multi bank update feature is used for supporting multiple sets(also called banks) of firmware image(s), allowing the platform to boot from a different bank, in case it fails to boot from the active bank. This functionality is supported by keeping the relevant information in a structure called metadata, which provides information on the images. Among other parameters, the metadata structure contains information on the currect active bank that is being used to boot image(s).
Functionality is being added to work with the UEFI capsule driver in u-boot. The metadata is read to gather information on the update bank, which is the bank to which the firmware images would be flashed to. On a successful completion of the update of all components, the active bank field in the metadata is updated, to reflect the bank from which the platform will boot on the subsequent boots.
Currently, the feature is being enabled on the STM32MP157C-DK2 board which boots a FIP image from a uSD card partitioned with the GPT partioning scheme.
Do you have a plan to develop any test cases for sandbox, especially in pytest framework?
I don't see much difficulty to do so and it would be very helpful for U-Boot CI process.
-Takahiro Akashi
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 are under review currently[3].
These patches are based on top of the series from Takahiro to add Authentication support to mkeficapsule utility[4]
[1] - https://developer.arm.com/documentation/den0118/a [2] - https://staging-git.codelinaro.org/linaro/firmware-dual-banked-updates/test [3] - https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/12566 [4] - https://patchwork.ozlabs.org/project/uboot/list/?series=281549
Changes since V2:
- Use uint*_t types in fwu_mdata.h since the file is to be reused in other projects
- Keep only the FWU metadata structures in fwu_mdata.h
- Move all other function and macro declarations in fwu.h
- Keep common implementations of fwu_update_active_index and fwu_revert_boot_index in fwu_mdata.c
- Add a update_mdata function pointer in the fwu_mdata_ops structure
- Move the function definition of fwu_verify_mdata to fwu_mdata.c to facilitate reuse
- Remove the block device specific desc->devnum parameter for the fwu_plat_get_alt_num function call
- Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num
- Add logic to delete the TrialStateCtr variable if system is not in Trial State
- Add logic to check if bit 15(OS Acceptance) of the Flags member in the capsule header is set
- Add logic to set the accept bit of all images from a capsule if the OS Acceptance bit in the capsule header is not set
- Include the log.h and stdio.h header files
Sughosh Ganu (9): FWU: Add FWU metadata structure and functions for accessing metadata FWU: Add FWU metadata access functions 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 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
board/st/stm32mp1/stm32mp1.c | 183 ++++++++++ cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/fwu_mdata.c | 67 ++++ common/board_r.c | 6 + include/fwu.h | 81 +++++ include/fwu_mdata.h | 69 ++++ lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 233 ++++++++++++- lib/efi_loader/efi_firmware.c | 90 ++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 ++ lib/fwu_updates/Makefile | 11 + lib/fwu_updates/fwu.c | 198 +++++++++++ lib/fwu_updates/fwu_mdata.c | 358 +++++++++++++++++++ lib/fwu_updates/fwu_mdata_gpt_blk.c | 521 ++++++++++++++++++++++++++++ tools/eficapsule.h | 8 + tools/mkeficapsule.c | 102 +++++- 19 files changed, 1955 insertions(+), 21 deletions(-) create mode 100644 cmd/fwu_mdata.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h create mode 100644 lib/fwu_updates/Kconfig create mode 100644 lib/fwu_updates/Makefile create mode 100644 lib/fwu_updates/fwu.c create mode 100644 lib/fwu_updates/fwu_mdata.c create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.c
-- 2.17.1

hi Takahiro,
On Thu, 20 Jan 2022 at 11:01, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Thu, Jan 20, 2022 at 12:25:39AM +0530, Sughosh Ganu wrote:
The patchset adds support for the FWU Multi Bank Update[1] feature. Certain aspects of the Dependable Boot[2] specification have also been implemented.
The FWU multi bank update feature is used for supporting multiple sets(also called banks) of firmware image(s), allowing the platform to boot from a different bank, in case it fails to boot from the active bank. This functionality is supported by keeping the relevant information in a structure called metadata, which provides information on the images. Among other parameters, the metadata structure contains information on the currect active bank that is being used to boot image(s).
Functionality is being added to work with the UEFI capsule driver in u-boot. The metadata is read to gather information on the update bank, which is the bank to which the firmware images would be flashed to. On a successful completion of the update of all components, the active bank field in the metadata is updated, to reflect the bank from which the platform will boot on the subsequent boots.
Currently, the feature is being enabled on the STM32MP157C-DK2 board which boots a FIP image from a uSD card partitioned with the GPT partioning scheme.
Do you have a plan to develop any test cases for sandbox, especially in pytest framework?
I don't see much difficulty to do so and it would be very helpful for U-Boot CI process.
Okay, will check on adding the test cases.
-sughosh
-Takahiro Akashi
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 are under review currently[3].
These patches are based on top of the series from Takahiro to add Authentication support to mkeficapsule utility[4]
[1] - https://developer.arm.com/documentation/den0118/a [2] - https://staging-git.codelinaro.org/linaro/firmware-dual-banked-updates/test [3] - https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/12566 [4] - https://patchwork.ozlabs.org/project/uboot/list/?series=281549
Changes since V2:
- Use uint*_t types in fwu_mdata.h since the file is to be reused in other projects
- Keep only the FWU metadata structures in fwu_mdata.h
- Move all other function and macro declarations in fwu.h
- Keep common implementations of fwu_update_active_index and fwu_revert_boot_index in fwu_mdata.c
- Add a update_mdata function pointer in the fwu_mdata_ops structure
- Move the function definition of fwu_verify_mdata to fwu_mdata.c to facilitate reuse
- Remove the block device specific desc->devnum parameter for the fwu_plat_get_alt_num function call
- Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num
- Add logic to delete the TrialStateCtr variable if system is not in Trial State
- Add logic to check if bit 15(OS Acceptance) of the Flags member in the capsule header is set
- Add logic to set the accept bit of all images from a capsule if the OS Acceptance bit in the capsule header is not set
- Include the log.h and stdio.h header files
Sughosh Ganu (9): FWU: Add FWU metadata structure and functions for accessing metadata FWU: Add FWU metadata access functions 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 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
board/st/stm32mp1/stm32mp1.c | 183 ++++++++++ cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/fwu_mdata.c | 67 ++++ common/board_r.c | 6 + include/fwu.h | 81 +++++ include/fwu_mdata.h | 69 ++++ lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 233 ++++++++++++- lib/efi_loader/efi_firmware.c | 90 ++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 ++ lib/fwu_updates/Makefile | 11 + lib/fwu_updates/fwu.c | 198 +++++++++++ lib/fwu_updates/fwu_mdata.c | 358 +++++++++++++++++++ lib/fwu_updates/fwu_mdata_gpt_blk.c | 521 ++++++++++++++++++++++++++++ tools/eficapsule.h | 8 + tools/mkeficapsule.c | 102 +++++- 19 files changed, 1955 insertions(+), 21 deletions(-) create mode 100644 cmd/fwu_mdata.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h create mode 100644 lib/fwu_updates/Kconfig create mode 100644 lib/fwu_updates/Makefile create mode 100644 lib/fwu_updates/fwu.c create mode 100644 lib/fwu_updates/fwu_mdata.c create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.c
-- 2.17.1

On 1/19/22 19:55, Sughosh Ganu wrote:
The patchset adds support for the FWU Multi Bank Update[1] feature. Certain aspects of the Dependable Boot[2] specification have also been implemented.
The document "Platform Security Firmware Update for the A-profile Arm Architecture Beta" [1] that you relate to describes updating using FF-A [5] as a communication protocol between a normal world client and an update agent in the secure world. [1] further describes an API for this communication. I cannot see that you are implementing this:
* U-Boot is living in the normal world, so it cannot be the update agent of [1]. * Implementing the client of [1] in U-Boot would not require board specific changes.
This patch set comes without any documentation update. We need a patch which adds documents to U-Boot describing
* the design of the update mechanism * the usage of the update mechanism
before we can start the review of the patches.
Best regards
Heinrich
[1] Platform Security Firmware Update for the A-profile Arm Architecture Beta https://developer.arm.com/documentation/den0118/a
[5] Arm Firmware Framework for Arm A-profile https://developer.arm.com/documentation/den0077/latest
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 are under review currently[3].
These patches are based on top of the series from Takahiro to add Authentication support to mkeficapsule utility[4]
[1] - https://developer.arm.com/documentation/den0118/a [2] - https://staging-git.codelinaro.org/linaro/firmware-dual-banked-updates/test [3] - https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/12566 [4] - https://patchwork.ozlabs.org/project/uboot/list/?series=281549
Changes since V2:
- Use uint*_t types in fwu_mdata.h since the file is to be reused in other projects
- Keep only the FWU metadata structures in fwu_mdata.h
- Move all other function and macro declarations in fwu.h
- Keep common implementations of fwu_update_active_index and fwu_revert_boot_index in fwu_mdata.c
- Add a update_mdata function pointer in the fwu_mdata_ops structure
- Move the function definition of fwu_verify_mdata to fwu_mdata.c to facilitate reuse
- Remove the block device specific desc->devnum parameter for the fwu_plat_get_alt_num function call
- Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num
- Add logic to delete the TrialStateCtr variable if system is not in Trial State
- Add logic to check if bit 15(OS Acceptance) of the Flags member in the capsule header is set
- Add logic to set the accept bit of all images from a capsule if the OS Acceptance bit in the capsule header is not set
- Include the log.h and stdio.h header files
Sughosh Ganu (9): FWU: Add FWU metadata structure and functions for accessing metadata FWU: Add FWU metadata access functions 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 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
board/st/stm32mp1/stm32mp1.c | 183 ++++++++++ cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/fwu_mdata.c | 67 ++++ common/board_r.c | 6 + include/fwu.h | 81 +++++ include/fwu_mdata.h | 69 ++++ lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 233 ++++++++++++- lib/efi_loader/efi_firmware.c | 90 ++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 ++ lib/fwu_updates/Makefile | 11 + lib/fwu_updates/fwu.c | 198 +++++++++++ lib/fwu_updates/fwu_mdata.c | 358 +++++++++++++++++++ lib/fwu_updates/fwu_mdata_gpt_blk.c | 521 ++++++++++++++++++++++++++++ tools/eficapsule.h | 8 + tools/mkeficapsule.c | 102 +++++- 19 files changed, 1955 insertions(+), 21 deletions(-) create mode 100644 cmd/fwu_mdata.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h create mode 100644 lib/fwu_updates/Kconfig create mode 100644 lib/fwu_updates/Makefile create mode 100644 lib/fwu_updates/fwu.c create mode 100644 lib/fwu_updates/fwu_mdata.c create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.c

hi Heinrich,
On Thu, 20 Jan 2022 at 15:39, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 1/19/22 19:55, Sughosh Ganu wrote:
The patchset adds support for the FWU Multi Bank Update[1] feature. Certain aspects of the Dependable Boot[2] specification have also been implemented.
The document "Platform Security Firmware Update for the A-profile Arm Architecture Beta" [1] that you relate to describes updating using FF-A [5] as a communication protocol between a normal world client and an update agent in the secure world. [1] further describes an API for this communication. I cannot see that you are implementing this:
- U-Boot is living in the normal world, so it cannot be the update agent
of [1].
- Implementing the client of [1] in U-Boot would not require board
specific changes.
This document also describes, in brief, the scenario where the firmware store is controlled by Normal World firmware. Please check "Normal World Controlled Firmware Store" on pg 39 of this document. This section mentions that for such a scenario the Client is the Update Agent.
This patch set comes without any documentation update. We need a patch which adds documents to U-Boot describing
- the design of the update mechanism
- the usage of the update mechanism
before we can start the review of the patches.
Okay. Will add some documentation for this patch series in my next version.
-sughosh
Best regards
Heinrich
[1] Platform Security Firmware Update for the A-profile Arm Architecture Beta https://developer.arm.com/documentation/den0118/a
[5] Arm Firmware Framework for Arm A-profile https://developer.arm.com/documentation/den0077/latest
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 are under review currently[3].
These patches are based on top of the series from Takahiro to add Authentication support to mkeficapsule utility[4]
[1] - https://developer.arm.com/documentation/den0118/a [2] - https://staging-git.codelinaro.org/linaro/firmware-dual-banked-updates/test [3] - https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/12566 [4] - https://patchwork.ozlabs.org/project/uboot/list/?series=281549
Changes since V2:
- Use uint*_t types in fwu_mdata.h since the file is to be reused in other projects
- Keep only the FWU metadata structures in fwu_mdata.h
- Move all other function and macro declarations in fwu.h
- Keep common implementations of fwu_update_active_index and fwu_revert_boot_index in fwu_mdata.c
- Add a update_mdata function pointer in the fwu_mdata_ops structure
- Move the function definition of fwu_verify_mdata to fwu_mdata.c to facilitate reuse
- Remove the block device specific desc->devnum parameter for the fwu_plat_get_alt_num function call
- Change the implementation of fwu_plat_get_alt_num to get the devnum in the function before calling gpt_plat_get_alt_num
- Add logic to delete the TrialStateCtr variable if system is not in Trial State
- Add logic to check if bit 15(OS Acceptance) of the Flags member in the capsule header is set
- Add logic to set the accept bit of all images from a capsule if the OS Acceptance bit in the capsule header is not set
- Include the log.h and stdio.h header files
Sughosh Ganu (9): FWU: Add FWU metadata structure and functions for accessing metadata FWU: Add FWU metadata access functions 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 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
board/st/stm32mp1/stm32mp1.c | 183 ++++++++++ cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/fwu_mdata.c | 67 ++++ common/board_r.c | 6 + include/fwu.h | 81 +++++ include/fwu_mdata.h | 69 ++++ lib/Kconfig | 6 + lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 233 ++++++++++++- lib/efi_loader/efi_firmware.c | 90 ++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Kconfig | 31 ++ lib/fwu_updates/Makefile | 11 + lib/fwu_updates/fwu.c | 198 +++++++++++ lib/fwu_updates/fwu_mdata.c | 358 +++++++++++++++++++ lib/fwu_updates/fwu_mdata_gpt_blk.c | 521 ++++++++++++++++++++++++++++ tools/eficapsule.h | 8 + tools/mkeficapsule.c | 102 +++++- 19 files changed, 1955 insertions(+), 21 deletions(-) create mode 100644 cmd/fwu_mdata.c create mode 100644 include/fwu.h create mode 100644 include/fwu_mdata.h create mode 100644 lib/fwu_updates/Kconfig create mode 100644 lib/fwu_updates/Makefile create mode 100644 lib/fwu_updates/fwu.c create mode 100644 lib/fwu_updates/fwu_mdata.c create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.c
participants (5)
-
AKASHI Takahiro
-
Heinrich Schuchardt
-
Ilias Apalodimas
-
Masami Hiramatsu
-
Sughosh Ganu