[RFC PATCH v2 0/8] 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].
Changes since V1: * Rename metadata with mdata for all symbols. Applicable for all patches * Move all function declarations to a separate header fwu.h * Drop the patch which added the get_gpt_hdr_parts api, as suggested by Patrick * Use the logic suggested by Patrick to get the partition type guids and partition guid's instead of defining a new api * Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne * Use BIT for all macros * Call the platform function fwu_plat_get_alt_num for getting the alt_num for the image partition, instead of the earlier hard-coded approach. * Change the logic in gpt_check_mdata_validity as suggested by Ilias. * Other smaller code style changes suggested by Ilias * Define a new function fwu_plat_get_alt_num using logic suggested by Patrick for returning the alt_num for the partition * Define a new function plat_fill_gpt_partition_guids to fill the guid array with Partition Type guids * Use the TAMP_BOOTCOUNT register as suggested by Yann Gautier instead of the earlier unused register 10 * Define a new function fwu_plat_get_alt_num for filling up all the dfu partitions with a preset ImageTypeId guid * Remove the distinction made in the earlier version for setting image_type_id as suggested by Heinrich * Define a funtion fwu_update_checks_pass to do the checks before initiating the update * Log the status of the boottime checks using boottime_check variable and allow system to boot instead of hanging the platform(fwu_boottime_checks) * Call function fwu_update_checks_pass to check if the update can be initiated * Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
Todo's ------ 1) Add a test(selftest) for the metadata access. 2) Add a tool for generation of the metadata. Not sure if this needs to be part of the u-boot repository though. 3) Add a tool for generation of the firmware accept/reject dummy capsule. Need to check if this can be added to the mkeficapsule tool in u-boot.
[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
Sughosh Ganu (8): 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
board/st/stm32mp1/stm32mp1.c | 169 ++++++++ cmd/Kconfig | 7 + cmd/Makefile | 1 + cmd/fwu_mdata.c | 64 +++ common/board_r.c | 6 + include/fwu.h | 51 +++ include/fwu_mdata.h | 104 +++++ lib/Kconfig | 32 ++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++- lib/efi_loader/efi_firmware.c | 90 +++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 + lib/fwu_updates/fwu.c | 190 +++++++++ lib/fwu_updates/fwu_mdata.c | 236 +++++++++++ lib/fwu_updates/fwu_mdata_gpt_blk.c | 635 ++++++++++++++++++++++++++++ 16 files changed, 1787 insertions(+), 11 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/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 V1: * Move all function declarations to a separate header fwu.h * Rename metadata with mdata for all symbols * Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne
include/fwu.h | 28 +++++ include/fwu_mdata.h | 102 ++++++++++++++++ lib/fwu_updates/fwu_mdata.c | 236 ++++++++++++++++++++++++++++++++++++ 3 files changed, 366 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..e6bc3e6b73 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#if !defined _FWU_H_ +#define _FWU_H_ + +#include <efi.h> + +#include <linux/types.h> + +#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_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); +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..11eb570012 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_ + +#include <efi.h> +#include <uuid.h> + +#include <linux/types.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; + u32 accepted; + u32 reserved; +}; + +/** + * struct fwu_image_entry - information for a particular type of image + * @image_type_uuid: Guid value for identifying the image type + * @location_uuid: Guid of the storage volume where the image is located + * @img_bank_info: Array containing properties of images + * + * This structure contains information on various types of updatable + * firmware images. Each image type then contains an array of image + * information per bank. + */ +struct fwu_image_entry { + efi_guid_t image_type_uuid; + efi_guid_t location_uuid; + struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS]; +}; + +/** + * struct fwu_mdata - FWU metadata structure for multi-bank updates + * @crc32: crc32 value for the FWU metadata + * @version: FWU metadata version + * @active_index: Index of the bank currently used for booting images + * @previous_active_inde: Index of the bank used before the current bank + * being used for booting + * @img_entry: Array of information on various firmware images that can + * be updated + * + * This structure is used to store all the needed information for performing + * multi bank updates on the platform. This contains info on the bank being + * used to boot along with the information needed for identification of + * individual images + */ +struct fwu_mdata { + u32 crc32; + u32 version; + u32 active_index; + u32 previous_active_index; + + struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK]; +}; + +/** + * @get_active_index: get the current active_index value + * @update_active_index: update the 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 + * @revert_boot_index: set the active_index to previous_active_index + * @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 + */ +struct fwu_mdata_ops { + int (*get_active_index)(u32 *active_idx); + + int (*update_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 (*revert_boot_index)(void); + + int (*set_accept_image)(efi_guid_t *img_type_id); + + int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank); + + int (*get_mdata)(struct fwu_mdata **mdata); +}; + +int fwu_get_mdata(struct fwu_mdata **mdata); +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void); + +#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..348e9c85f7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <fwu_mdata.h> + +#include <linux/errno.h> +#include <linux/types.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) +{ + struct fwu_mdata_ops *ops; + + ops = get_fwu_mdata_ops(); + if (!ops) + return -EPROTONOSUPPORT; + + if (!ops->update_active_index) { + log_err("update_active_index() method not defined for the platform\n"); + return -ENOSYS; + } + + return ops->update_active_index(active_idx); +} + +/** + * 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) +{ + struct fwu_mdata_ops *ops; + + ops = get_fwu_mdata_ops(); + if (!ops) + return -EPROTONOSUPPORT; + + if (!ops->revert_boot_index) { + log_err("revert_boot_index() method not defined for the platform\n"); + return -ENOSYS; + } + + return ops->revert_boot_index(); +} + +/** + * 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 + * + * 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) +{ + 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); +} + +/** + * 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 + * + * 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); +}

Hi Sughosh,
2021年12月19日(日) 16:06 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 V1:
- Move all function declarations to a separate header fwu.h
- Rename metadata with mdata for all symbols
- Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne
include/fwu.h | 28 +++++ include/fwu_mdata.h | 102 ++++++++++++++++ lib/fwu_updates/fwu_mdata.c | 236 ++++++++++++++++++++++++++++++++++++ 3 files changed, 366 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..e6bc3e6b73 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <efi.h>
+#include <linux/types.h>
+#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_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); +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..11eb570012 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h> +#include <uuid.h>
+#include <linux/types.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;
u32 accepted;
u32 reserved;
+};
Could you explicitly pack these metadata data structures? Since these metadata will be shared among bootloaders (TF-A, SCP-firmware), it is better to ensure that those are packed and fixed offset for each field.
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+};
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for performing
- multi bank updates on the platform. This contains info on the bank being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
u32 crc32;
u32 version;
u32 active_index;
u32 previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+};
+/**
- @get_active_index: get the current active_index value
- @update_active_index: update the 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
- @revert_boot_index: set the active_index to previous_active_index
- @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
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*update_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 (*revert_boot_index)(void);
int (*set_accept_image)(efi_guid_t *img_type_id);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*get_mdata)(struct fwu_mdata **mdata);
+};
+int fwu_get_mdata(struct fwu_mdata **mdata); +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
Also, could you also move these function prototypes and operators to fwu? I would like to copy this header file to the boot loaders as is. In that case, I just need the definition of the metadata data structure, but no function prototypes.
Thank you,
+#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..348e9c85f7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <fwu_mdata.h>
+#include <linux/errno.h> +#include <linux/types.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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->update_active_index) {
log_err("update_active_index() method not defined for the platform\n");
return -ENOSYS;
}
return ops->update_active_index(active_idx);
+}
+/**
- 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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->revert_boot_index) {
log_err("revert_boot_index() method not defined for the platform\n");
return -ENOSYS;
}
return ops->revert_boot_index();
+}
+/**
- 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
- 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) +{
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);
+}
+/**
- 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
- 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);
+}
2.17.1

hi Masami,
On Tue, 21 Dec 2021 at 05:40, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2021年12月19日(日) 16:06 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 V1:
- Move all function declarations to a separate header fwu.h
- Rename metadata with mdata for all symbols
- Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne
include/fwu.h | 28 +++++ include/fwu_mdata.h | 102 ++++++++++++++++ lib/fwu_updates/fwu_mdata.c | 236 ++++++++++++++++++++++++++++++++++++ 3 files changed, 366 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..e6bc3e6b73 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <efi.h>
+#include <linux/types.h>
+#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_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); +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..11eb570012 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h> +#include <uuid.h>
+#include <linux/types.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;
u32 accepted;
u32 reserved;
+};
Could you explicitly pack these metadata data structures? Since these metadata will be shared among bootloaders (TF-A, SCP-firmware), it is better to ensure that those are packed and fixed offset for each field.
Okay. WIll do it.
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+};
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for
performing
- multi bank updates on the platform. This contains info on the bank
being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
u32 crc32;
u32 version;
u32 active_index;
u32 previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+};
+/**
- @get_active_index: get the current active_index value
- @update_active_index: update the 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
- @revert_boot_index: set the active_index to previous_active_index
- @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
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*update_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 (*revert_boot_index)(void);
int (*set_accept_image)(efi_guid_t *img_type_id);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*get_mdata)(struct fwu_mdata **mdata);
+};
+int fwu_get_mdata(struct fwu_mdata **mdata); +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
Also, could you also move these function prototypes and operators to fwu? I would like to copy this header file to the boot loaders as is. In that case, I just need the definition of the metadata data structure, but no function prototypes.
I have moved the function declarations to fwu.h. The one function prototype that I have in fwu_mdata.h is the one which has the metadata structure as one of it's parameters. Same for the ops as well. The get_mdata function has the metadata structure as its parameter. Are you facing any issues with the current structure of the files.
-sughosh
Thank you,
+#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..348e9c85f7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <fwu_mdata.h>
+#include <linux/errno.h> +#include <linux/types.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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->update_active_index) {
log_err("update_active_index() method not defined for
the platform\n");
return -ENOSYS;
}
return ops->update_active_index(active_idx);
+}
+/**
- 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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->revert_boot_index) {
log_err("revert_boot_index() method not defined for the
platform\n");
return -ENOSYS;
}
return ops->revert_boot_index();
+}
+/**
- 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
- 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) +{
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);
+}
+/**
- 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
- 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);
+}
2.17.1
-- Masami Hiramatsu

On Tue, Dec 21, 2021 at 10:05:57AM +0530, Sughosh Ganu wrote:
hi Masami,
On Tue, 21 Dec 2021 at 05:40, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2021年12月19日(日) 16:06 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 V1:
- Move all function declarations to a separate header fwu.h
- Rename metadata with mdata for all symbols
- Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne
include/fwu.h | 28 +++++ include/fwu_mdata.h | 102 ++++++++++++++++ lib/fwu_updates/fwu_mdata.c | 236 ++++++++++++++++++++++++++++++++++++ 3 files changed, 366 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..e6bc3e6b73 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <efi.h>
+#include <linux/types.h>
+#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_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); +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..11eb570012 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h> +#include <uuid.h>
+#include <linux/types.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;
u32 accepted;
u32 reserved;
+};
Could you explicitly pack these metadata data structures? Since these metadata will be shared among bootloaders (TF-A, SCP-firmware), it is better to ensure that those are packed and fixed offset for each field.
Okay. WIll do it.
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+};
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for
performing
- multi bank updates on the platform. This contains info on the bank
being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
u32 crc32;
u32 version;
u32 active_index;
u32 previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+};
+/**
- @get_active_index: get the current active_index value
- @update_active_index: update the 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
- @revert_boot_index: set the active_index to previous_active_index
- @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
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*update_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 (*revert_boot_index)(void);
int (*set_accept_image)(efi_guid_t *img_type_id);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*get_mdata)(struct fwu_mdata **mdata);
+};
+int fwu_get_mdata(struct fwu_mdata **mdata); +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
Also, could you also move these function prototypes and operators to fwu? I would like to copy this header file to the boot loaders as is. In that case, I just need the definition of the metadata data structure, but no function prototypes.
I have moved the function declarations to fwu.h. The one function prototype that I have in fwu_mdata.h is the one which has the metadata structure as one of it's parameters. Same for the ops as well. The get_mdata function has the metadata structure as its parameter. Are you facing any issues with the current structure of the files.
struct fwu_mdata; int fwu_get_mdata(struct fwu_**mdata);
would be good enough?
I'm not sure whether it is a good idea that we re-use the *same* file in other software, but I would suggest you to use standard POSIX types like 'uint32_t' instead of 'u32' anyway.
-Takahiro Akashi
-sughosh
Thank you,
+#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..348e9c85f7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <fwu_mdata.h>
+#include <linux/errno.h> +#include <linux/types.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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->update_active_index) {
log_err("update_active_index() method not defined for
the platform\n");
return -ENOSYS;
}
return ops->update_active_index(active_idx);
+}
+/**
- 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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->revert_boot_index) {
log_err("revert_boot_index() method not defined for the
platform\n");
return -ENOSYS;
}
return ops->revert_boot_index();
+}
+/**
- 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
- 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) +{
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);
+}
+/**
- 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
- 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);
+}
2.17.1
-- Masami Hiramatsu

On Tue, 21 Dec 2021 at 10:33, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Tue, Dec 21, 2021 at 10:05:57AM +0530, Sughosh Ganu wrote:
hi Masami,
On Tue, 21 Dec 2021 at 05:40, Masami Hiramatsu <
masami.hiramatsu@linaro.org>
wrote:
Hi Sughosh,
2021年12月19日(日) 16:06 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 V1:
- Move all function declarations to a separate header fwu.h
- Rename metadata with mdata for all symbols
- Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne
include/fwu.h | 28 +++++ include/fwu_mdata.h | 102 ++++++++++++++++ lib/fwu_updates/fwu_mdata.c | 236
++++++++++++++++++++++++++++++++++++
3 files changed, 366 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..e6bc3e6b73 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <efi.h>
+#include <linux/types.h>
+#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_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); +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..11eb570012 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h> +#include <uuid.h>
+#include <linux/types.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;
u32 accepted;
u32 reserved;
+};
Could you explicitly pack these metadata data structures? Since these metadata will be shared among bootloaders (TF-A,
SCP-firmware),
it is better to ensure that those are packed and fixed offset for each field.
Okay. WIll do it.
+/**
- struct fwu_image_entry - information for a particular type of
image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is
located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info
img_bank_info[CONFIG_FWU_NUM_BANKS];
+};
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting
images
- @previous_active_inde: Index of the bank used before the current
bank
being used for booting
- @img_entry: Array of information on various firmware images that
can
be updated
- This structure is used to store all the needed information for
performing
- multi bank updates on the platform. This contains info on the
bank
being
- used to boot along with the information needed for
identification of
- individual images
- */
+struct fwu_mdata {
u32 crc32;
u32 version;
u32 active_index;
u32 previous_active_index;
struct fwu_image_entry
img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+};
+/**
- @get_active_index: get the current active_index value
- @update_active_index: update the 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
- @revert_boot_index: set the active_index to previous_active_index
- @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
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*update_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 (*revert_boot_index)(void);
int (*set_accept_image)(efi_guid_t *img_type_id);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*get_mdata)(struct fwu_mdata **mdata);
+};
+int fwu_get_mdata(struct fwu_mdata **mdata); +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
Also, could you also move these function prototypes and operators to fwu? I would like to copy this header file to the boot loaders as is. In that case, I just need the definition of the metadata data
structure,
but no function prototypes.
I have moved the function declarations to fwu.h. The one function
prototype
that I have in fwu_mdata.h is the one which has the metadata structure as one of it's parameters. Same for the ops as well. The get_mdata function has the metadata structure as its parameter. Are you facing any issues
with
the current structure of the files.
struct fwu_mdata; int fwu_get_mdata(struct fwu_**mdata);
would be good enough?
Yes, I had considered putting this kind of declaration in fwu.h. But I decided against it thinking that any function declaration that involved the fwu metadata structure can be put in one file. But I just want to understand if there is some issue in putting these declarations in the fwu_mdata.h. The rest of the function declarations and symbols are put in the fwu.h header. If you see, I only include the fwu.h in the efi_firmware.c and efi_capsule.c.
I'm not sure whether it is a good idea that we re-use the *same* file in other software, but I would suggest you to use standard POSIX types like 'uint32_t' instead of 'u32' anyway.
Hmm, this is on the same lines to the types used in the capsule code. That was the primary reason that I stuck with u<size> types. Any issue with using the short type? The Linux kernel seems to be using it.
-sughosh
-Takahiro Akashi
-sughosh
Thank you,
+#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..348e9c85f7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <fwu_mdata.h>
+#include <linux/errno.h> +#include <linux/types.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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->update_active_index) {
log_err("update_active_index() method not defined for
the platform\n");
return -ENOSYS;
}
return ops->update_active_index(active_idx);
+}
+/**
- 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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->revert_boot_index) {
log_err("revert_boot_index() method not defined for
the
platform\n");
return -ENOSYS;
}
return ops->revert_boot_index();
+}
+/**
- 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
- 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) +{
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);
+}
+/**
- 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
- 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);
+}
2.17.1
-- Masami Hiramatsu

Hi Sughosh,
2021年12月21日(火) 14:47 Sughosh Ganu sughosh.ganu@linaro.org:
On Tue, 21 Dec 2021 at 10:33, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Tue, Dec 21, 2021 at 10:05:57AM +0530, Sughosh Ganu wrote:
hi Masami,
On Tue, 21 Dec 2021 at 05:40, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2021年12月19日(日) 16:06 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 V1:
- Move all function declarations to a separate header fwu.h
- Rename metadata with mdata for all symbols
- Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne
include/fwu.h | 28 +++++ include/fwu_mdata.h | 102 ++++++++++++++++ lib/fwu_updates/fwu_mdata.c | 236 ++++++++++++++++++++++++++++++++++++ 3 files changed, 366 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..e6bc3e6b73 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <efi.h>
+#include <linux/types.h>
+#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_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); +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..11eb570012 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h> +#include <uuid.h>
+#include <linux/types.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;
u32 accepted;
u32 reserved;
+};
Could you explicitly pack these metadata data structures? Since these metadata will be shared among bootloaders (TF-A, SCP-firmware), it is better to ensure that those are packed and fixed offset for each field.
Okay. WIll do it.
+/**
- struct fwu_image_entry - information for a particular type of image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS];
+};
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting images
- @previous_active_inde: Index of the bank used before the current bank
being used for booting
- @img_entry: Array of information on various firmware images that can
be updated
- This structure is used to store all the needed information for
performing
- multi bank updates on the platform. This contains info on the bank
being
- used to boot along with the information needed for identification of
- individual images
- */
+struct fwu_mdata {
u32 crc32;
u32 version;
u32 active_index;
u32 previous_active_index;
struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+};
+/**
- @get_active_index: get the current active_index value
- @update_active_index: update the 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
- @revert_boot_index: set the active_index to previous_active_index
- @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
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*update_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 (*revert_boot_index)(void);
int (*set_accept_image)(efi_guid_t *img_type_id);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*get_mdata)(struct fwu_mdata **mdata);
+};
+int fwu_get_mdata(struct fwu_mdata **mdata); +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
Also, could you also move these function prototypes and operators to fwu? I would like to copy this header file to the boot loaders as is. In that case, I just need the definition of the metadata data structure, but no function prototypes.
I have moved the function declarations to fwu.h. The one function prototype that I have in fwu_mdata.h is the one which has the metadata structure as one of it's parameters. Same for the ops as well. The get_mdata function has the metadata structure as its parameter. Are you facing any issues with the current structure of the files.
The structure is OK (if it is packed). But the prototypes, interfaces are no needed because the metadata access method is not needed for the bootloader, like TF-A and SCP-firmware. Of course I can write it again for those firmwares, as far as it's coding style suits to the project, I would like to reuse it. If any update applied, I can apply the change to the other firmware too.
struct fwu_mdata; int fwu_get_mdata(struct fwu_**mdata);
would be good enough?
Yes, I had considered putting this kind of declaration in fwu.h. But I decided against it thinking that any function declaration that involved the fwu metadata structure can be put in one file. But I just want to understand if there is some issue in putting these declarations in the fwu_mdata.h. The rest of the function declarations and symbols are put in the fwu.h header. If you see, I only include the fwu.h in the efi_firmware.c and efi_capsule.c.
I just want to share the metadata definition among firmware projects. In that case, the metadata is on the storage media, but the operation will be re-implemented for each firmware. I think it is better to split it. :)
Thank you,
I'm not sure whether it is a good idea that we re-use the *same* file in other software, but I would suggest you to use standard POSIX types like 'uint32_t' instead of 'u32' anyway.
Hmm, this is on the same lines to the types used in the capsule code. That was the primary reason that I stuck with u<size> types. Any issue with using the short type? The Linux kernel seems to be using it.
-sughosh
-Takahiro Akashi
-sughosh
Thank you,
+#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..348e9c85f7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <fwu_mdata.h>
+#include <linux/errno.h> +#include <linux/types.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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->update_active_index) {
log_err("update_active_index() method not defined for
the platform\n");
return -ENOSYS;
}
return ops->update_active_index(active_idx);
+}
+/**
- 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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->revert_boot_index) {
log_err("revert_boot_index() method not defined for the
platform\n");
return -ENOSYS;
}
return ops->revert_boot_index();
+}
+/**
- 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
- 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) +{
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);
+}
+/**
- 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
- 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);
+}
2.17.1
-- Masami Hiramatsu

hi Masami,
On Tue, 21 Dec 2021 at 11:31, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2021年12月21日(火) 14:47 Sughosh Ganu sughosh.ganu@linaro.org:
On Tue, 21 Dec 2021 at 10:33, AKASHI Takahiro <
takahiro.akashi@linaro.org> wrote:
On Tue, Dec 21, 2021 at 10:05:57AM +0530, Sughosh Ganu wrote:
hi Masami,
On Tue, 21 Dec 2021 at 05:40, Masami Hiramatsu <
masami.hiramatsu@linaro.org>
wrote:
Hi Sughosh,
2021年12月19日(日) 16:06 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 V1:
- Move all function declarations to a separate header fwu.h
- Rename metadata with mdata for all symbols
- Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne
include/fwu.h | 28 +++++ include/fwu_mdata.h | 102 ++++++++++++++++ lib/fwu_updates/fwu_mdata.c | 236
++++++++++++++++++++++++++++++++++++
3 files changed, 366 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..e6bc3e6b73 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <efi.h>
+#include <linux/types.h>
+#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_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); +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..11eb570012 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h> +#include <uuid.h>
+#include <linux/types.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;
u32 accepted;
u32 reserved;
+};
Could you explicitly pack these metadata data structures? Since these metadata will be shared among bootloaders (TF-A,
SCP-firmware),
it is better to ensure that those are packed and fixed offset for
each
field.
Okay. WIll do it.
+/**
- struct fwu_image_entry - information for a particular type of
image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is
located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of
updatable
- firmware images. Each image type then contains an array of
image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info
img_bank_info[CONFIG_FWU_NUM_BANKS];
+};
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank
updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting
images
- @previous_active_inde: Index of the bank used before the
current bank
being used for booting
- @img_entry: Array of information on various firmware images
that can
be updated
- This structure is used to store all the needed information for
performing
- multi bank updates on the platform. This contains info on the
bank
being
- used to boot along with the information needed for
identification of
- individual images
- */
+struct fwu_mdata {
u32 crc32;
u32 version;
u32 active_index;
u32 previous_active_index;
struct fwu_image_entry
img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+};
+/**
- @get_active_index: get the current active_index value
- @update_active_index: update the 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
- @revert_boot_index: set the active_index to
previous_active_index
- @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
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*update_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 (*revert_boot_index)(void);
int (*set_accept_image)(efi_guid_t *img_type_id);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32
bank);
int (*get_mdata)(struct fwu_mdata **mdata);
+};
+int fwu_get_mdata(struct fwu_mdata **mdata); +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
Also, could you also move these function prototypes and operators to fwu? I would like to copy this header file to the boot loaders as
is.
In that case, I just need the definition of the metadata data
structure,
but no function prototypes.
I have moved the function declarations to fwu.h. The one function
prototype
that I have in fwu_mdata.h is the one which has the metadata
structure as
one of it's parameters. Same for the ops as well. The get_mdata
function
has the metadata structure as its parameter. Are you facing any
issues with
the current structure of the files.
The structure is OK (if it is packed). But the prototypes, interfaces are no needed because the metadata access method is not needed for the bootloader, like TF-A and SCP-firmware. Of course I can write it again for those firmwares, as far as it's coding style suits to the project, I would like to reuse it. If any update applied, I can apply the change to the other firmware too.
Okay, I now get why you want the metadata structure in a separate file :). That makes sense. I will remove all other stuff apart from the structure definitions in my next version. Thanks for your explanation.
-sughosh
struct fwu_mdata; int fwu_get_mdata(struct fwu_**mdata);
would be good enough?
Yes, I had considered putting this kind of declaration in fwu.h. But I
decided against it thinking that any function declaration that involved the fwu metadata structure can be put in one file. But I just want to understand if there is some issue in putting these declarations in the fwu_mdata.h. The rest of the function declarations and symbols are put in the fwu.h header. If you see, I only include the fwu.h in the efi_firmware.c and efi_capsule.c.
I just want to share the metadata definition among firmware projects. In that case, the metadata is on the storage media, but the operation will be re-implemented for each firmware. I think it is better to split it. :)
Thank you,
I'm not sure whether it is a good idea that we re-use the *same* file in other software, but I would suggest you to use standard POSIX types like 'uint32_t' instead of 'u32' anyway.
Hmm, this is on the same lines to the types used in the capsule code.
That was the primary reason that I stuck with u<size> types. Any issue with using the short type? The Linux kernel seems to be using it.
-sughosh
-Takahiro Akashi
-sughosh
Thank you,
+#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..348e9c85f7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <fwu_mdata.h>
+#include <linux/errno.h> +#include <linux/types.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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->update_active_index) {
log_err("update_active_index() method not defined
for
the platform\n");
return -ENOSYS;
}
return ops->update_active_index(active_idx);
+}
+/**
- 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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->revert_boot_index) {
log_err("revert_boot_index() method not defined
for the
platform\n");
return -ENOSYS;
}
return ops->revert_boot_index();
+}
+/**
- 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
- 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) +{
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);
+}
+/**
- 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
- 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);
+}
2.17.1
-- Masami Hiramatsu
-- Masami Hiramatsu

On Tue, Dec 21, 2021 at 11:17:47AM +0530, Sughosh Ganu wrote:
On Tue, 21 Dec 2021 at 10:33, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Tue, Dec 21, 2021 at 10:05:57AM +0530, Sughosh Ganu wrote:
hi Masami,
On Tue, 21 Dec 2021 at 05:40, Masami Hiramatsu <
masami.hiramatsu@linaro.org>
wrote:
Hi Sughosh,
2021年12月19日(日) 16:06 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 V1:
- Move all function declarations to a separate header fwu.h
- Rename metadata with mdata for all symbols
- Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne
include/fwu.h | 28 +++++ include/fwu_mdata.h | 102 ++++++++++++++++ lib/fwu_updates/fwu_mdata.c | 236
++++++++++++++++++++++++++++++++++++
3 files changed, 366 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..e6bc3e6b73 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <efi.h>
+#include <linux/types.h>
+#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_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); +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..11eb570012 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h> +#include <uuid.h>
+#include <linux/types.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;
u32 accepted;
u32 reserved;
+};
Could you explicitly pack these metadata data structures? Since these metadata will be shared among bootloaders (TF-A,
SCP-firmware),
it is better to ensure that those are packed and fixed offset for each field.
Okay. WIll do it.
+/**
- struct fwu_image_entry - information for a particular type of
image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is
located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of updatable
- firmware images. Each image type then contains an array of image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info
img_bank_info[CONFIG_FWU_NUM_BANKS];
+};
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting
images
- @previous_active_inde: Index of the bank used before the current
bank
being used for booting
- @img_entry: Array of information on various firmware images that
can
be updated
- This structure is used to store all the needed information for
performing
- multi bank updates on the platform. This contains info on the
bank
being
- used to boot along with the information needed for
identification of
- individual images
- */
+struct fwu_mdata {
u32 crc32;
u32 version;
u32 active_index;
u32 previous_active_index;
struct fwu_image_entry
img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+};
+/**
- @get_active_index: get the current active_index value
- @update_active_index: update the 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
- @revert_boot_index: set the active_index to previous_active_index
- @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
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*update_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 (*revert_boot_index)(void);
int (*set_accept_image)(efi_guid_t *img_type_id);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32 bank);
int (*get_mdata)(struct fwu_mdata **mdata);
+};
+int fwu_get_mdata(struct fwu_mdata **mdata); +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
Also, could you also move these function prototypes and operators to fwu? I would like to copy this header file to the boot loaders as is. In that case, I just need the definition of the metadata data
structure,
but no function prototypes.
I have moved the function declarations to fwu.h. The one function
prototype
that I have in fwu_mdata.h is the one which has the metadata structure as one of it's parameters. Same for the ops as well. The get_mdata function has the metadata structure as its parameter. Are you facing any issues
with
the current structure of the files.
struct fwu_mdata; int fwu_get_mdata(struct fwu_**mdata);
would be good enough?
Yes, I had considered putting this kind of declaration in fwu.h. But I decided against it thinking that any function declaration that involved the fwu metadata structure can be put in one file. But I just want to understand if there is some issue in putting these declarations in the fwu_mdata.h. The rest of the function declarations and symbols are put in the fwu.h header. If you see, I only include the fwu.h in the efi_firmware.c and efi_capsule.c.
I'm not sure whether it is a good idea that we re-use the *same* file in other software, but I would suggest you to use standard POSIX types like 'uint32_t' instead of 'u32' anyway.
Hmm, this is on the same lines to the types used in the capsule code. That was the primary reason that I stuck with u<size> types. Any issue with using the short type? The Linux kernel seems to be using it.
That is my point. Why should we use linux-specific types in other software, especially when we want to import a generic header, which is essentially platform agnostic?
-Takahiro Akashi
-sughosh
-Takahiro Akashi
-sughosh
Thank you,
+#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..348e9c85f7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <fwu_mdata.h>
+#include <linux/errno.h> +#include <linux/types.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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->update_active_index) {
log_err("update_active_index() method not defined for
the platform\n");
return -ENOSYS;
}
return ops->update_active_index(active_idx);
+}
+/**
- 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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->revert_boot_index) {
log_err("revert_boot_index() method not defined for
the
platform\n");
return -ENOSYS;
}
return ops->revert_boot_index();
+}
+/**
- 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
- 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) +{
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);
+}
+/**
- 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
- 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);
+}
2.17.1
-- Masami Hiramatsu

On Tue, 21 Dec 2021 at 11:46, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Tue, Dec 21, 2021 at 11:17:47AM +0530, Sughosh Ganu wrote:
On Tue, 21 Dec 2021 at 10:33, AKASHI Takahiro <
takahiro.akashi@linaro.org>
wrote:
On Tue, Dec 21, 2021 at 10:05:57AM +0530, Sughosh Ganu wrote:
hi Masami,
On Tue, 21 Dec 2021 at 05:40, Masami Hiramatsu <
masami.hiramatsu@linaro.org>
wrote:
Hi Sughosh,
2021年12月19日(日) 16:06 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 V1:
- Move all function declarations to a separate header fwu.h
- Rename metadata with mdata for all symbols
- Drop the parameter in the function fwu_revert_boot_index as suggested by Etienne
include/fwu.h | 28 +++++ include/fwu_mdata.h | 102 ++++++++++++++++ lib/fwu_updates/fwu_mdata.c | 236
++++++++++++++++++++++++++++++++++++
3 files changed, 366 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..e6bc3e6b73 --- /dev/null +++ b/include/fwu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_H_ +#define _FWU_H_
+#include <efi.h>
+#include <linux/types.h>
+#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_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); +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..11eb570012 --- /dev/null +++ b/include/fwu_mdata.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#if !defined _FWU_MDATA_H_ +#define _FWU_MDATA_H_
+#include <efi.h> +#include <uuid.h>
+#include <linux/types.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;
u32 accepted;
u32 reserved;
+};
Could you explicitly pack these metadata data structures? Since these metadata will be shared among bootloaders (TF-A,
SCP-firmware),
it is better to ensure that those are packed and fixed offset for
each
field.
Okay. WIll do it.
+/**
- struct fwu_image_entry - information for a particular type of
image
- @image_type_uuid: Guid value for identifying the image type
- @location_uuid: Guid of the storage volume where the image is
located
- @img_bank_info: Array containing properties of images
- This structure contains information on various types of
updatable
- firmware images. Each image type then contains an array of
image
- information per bank.
- */
+struct fwu_image_entry {
efi_guid_t image_type_uuid;
efi_guid_t location_uuid;
struct fwu_image_bank_info
img_bank_info[CONFIG_FWU_NUM_BANKS];
+};
+/**
- struct fwu_mdata - FWU metadata structure for multi-bank
updates
- @crc32: crc32 value for the FWU metadata
- @version: FWU metadata version
- @active_index: Index of the bank currently used for booting
images
- @previous_active_inde: Index of the bank used before the
current
bank
being used for booting
- @img_entry: Array of information on various firmware images
that
can
be updated
- This structure is used to store all the needed information
for
performing
- multi bank updates on the platform. This contains info on the
bank
being
- used to boot along with the information needed for
identification of
- individual images
- */
+struct fwu_mdata {
u32 crc32;
u32 version;
u32 active_index;
u32 previous_active_index;
struct fwu_image_entry
img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK];
+};
+/**
- @get_active_index: get the current active_index value
- @update_active_index: update the 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
- @revert_boot_index: set the active_index to
previous_active_index
- @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
- */
+struct fwu_mdata_ops {
int (*get_active_index)(u32 *active_idx);
int (*update_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 (*revert_boot_index)(void);
int (*set_accept_image)(efi_guid_t *img_type_id);
int (*clear_accept_image)(efi_guid_t *img_type_id, u32
bank);
int (*get_mdata)(struct fwu_mdata **mdata);
+};
+int fwu_get_mdata(struct fwu_mdata **mdata); +struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
Also, could you also move these function prototypes and operators
to
fwu? I would like to copy this header file to the boot loaders as
is.
In that case, I just need the definition of the metadata data
structure,
but no function prototypes.
I have moved the function declarations to fwu.h. The one function
prototype
that I have in fwu_mdata.h is the one which has the metadata
structure as
one of it's parameters. Same for the ops as well. The get_mdata
function
has the metadata structure as its parameter. Are you facing any
issues
with
the current structure of the files.
struct fwu_mdata; int fwu_get_mdata(struct fwu_**mdata);
would be good enough?
Yes, I had considered putting this kind of declaration in fwu.h. But I decided against it thinking that any function declaration that involved
the
fwu metadata structure can be put in one file. But I just want to understand if there is some issue in putting these declarations in the fwu_mdata.h. The rest of the function declarations and symbols are put in the fwu.h header. If you see, I only include the fwu.h in the efi_firmware.c and efi_capsule.c.
I'm not sure whether it is a good idea that we re-use the *same* file in other software, but I would suggest you to use standard POSIX types like 'uint32_t' instead of 'u32' anyway.
Hmm, this is on the same lines to the types used in the capsule code.
That
was the primary reason that I stuck with u<size> types. Any issue with using the short type? The Linux kernel seems to be using it.
That is my point. Why should we use linux-specific types in other software, especially when we want to import a generic header, which is essentially platform agnostic?
Well, I was not aware that the header was to be imported in other software, till Masami explained. I will change the types in the fwu_mdata.h header.
-sughosh
-Takahiro Akashi
-sughosh
-Takahiro Akashi
-sughosh
Thank you,
+#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..348e9c85f7 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2021, Linaro Limited
- */
+#include <fwu_mdata.h>
+#include <linux/errno.h> +#include <linux/types.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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->update_active_index) {
log_err("update_active_index() method not
defined for
the platform\n");
return -ENOSYS;
}
return ops->update_active_index(active_idx);
+}
+/**
- 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) +{
struct fwu_mdata_ops *ops;
ops = get_fwu_mdata_ops();
if (!ops)
return -EPROTONOSUPPORT;
if (!ops->revert_boot_index) {
log_err("revert_boot_index() method not defined
for
the
platform\n");
return -ENOSYS;
}
return ops->revert_boot_index();
+}
+/**
- 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
- 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) +{
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);
+}
+/**
- 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
- 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);
+}
2.17.1
-- Masami Hiramatsu

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 V1: * Rename metadata with mdata for all symbols * Use BIT for all macros * Use the logic suggested by Patrick to get the partition type guids and partition guid's instead of defining a new api * Call the platform function fwu_plat_get_alt_num for getting the alt_num for the image partition, instead of the earlier hard-coded approach. * Change the logic in gpt_check_mdata_validity as suggested by Ilias. * Other smaller code style changes suggested by Ilias
include/fwu_mdata.h | 2 + lib/fwu_updates/fwu_mdata_gpt_blk.c | 634 ++++++++++++++++++++++++++++ 2 files changed, 636 insertions(+) create mode 100644 lib/fwu_updates/fwu_mdata_gpt_blk.c
diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h index 11eb570012..9e24ab4047 100644 --- a/include/fwu_mdata.h +++ b/include/fwu_mdata.h @@ -99,4 +99,6 @@ struct fwu_mdata_ops { int fwu_get_mdata(struct fwu_mdata **mdata); struct fwu_mdata_ops *get_plat_fwu_mdata_ops(void);
+extern struct fwu_mdata_ops fwu_gpt_blk_ops; + #endif /* _FWU_MDATA_H_ */ 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..2dcac0c3d4 --- /dev/null +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -0,0 +1,634 @@ +// 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 <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_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; +} + +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 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 = gpt_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 = gpt_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 = gpt_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 = gpt_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(desc->devnum, &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_update_active_index(u32 active_idx) +{ + int ret; + void *buf; + struct fwu_mdata *mdata; + + if (active_idx > CONFIG_FWU_NUM_BANKS) { + printf("Active index value to be updated is incorrect\n"); + return -1; + } + + ret = gpt_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 = gpt_update_mdata(mdata); + if (ret < 0) { + log_err("Failed to update FWU metadata partitions\n"); + ret = -EIO; + } + +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); +} + +int fwu_gpt_revert_boot_index(void) +{ + int ret; + void *buf; + u32 cur_active_index; + struct fwu_mdata *mdata; + + ret = gpt_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 = gpt_update_mdata(mdata); + if (ret < 0) { + log_err("Failed to update FWU metadata partitions\n"); + ret = -EIO; + } + +out: + free(mdata); + + return ret; +} + +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; + } + + if (action == IMAGE_ACCEPT_SET) + bank = mdata->active_index; + + 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 = gpt_update_mdata(mdata); + goto out; + } + } + + /* Image not found */ + ret = -EINVAL; + +out: + free(mdata); + + return ret; +} + +int fwu_gpt_accept_image(efi_guid_t *img_type_id) +{ + return fwu_gpt_set_clear_image_accept(img_type_id, 0, + IMAGE_ACCEPT_SET); +} + +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, + .update_active_index = fwu_gpt_update_active_index, + .get_image_alt_num = fwu_gpt_get_image_alt_num, + .mdata_check = fwu_gpt_mdata_check, + .revert_boot_index = fwu_gpt_revert_boot_index, + .set_accept_image = fwu_gpt_accept_image, + .clear_accept_image = fwu_gpt_clear_accept_image, + .get_mdata = fwu_gpt_get_mdata, +};

Hi Sughosh,
2021年12月19日(日) 16:06 Sughosh Ganu sughosh.ganu@linaro.org:
+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(desc->devnum, &part);
This is still GPT depending interface. In my use case (no GPT but raw SPI flash) I don't have devnum. Moreover, this one is used only from the fwu_mdata_gpt_blk.c. Please ensure (and comment) that this is only for GPT user.
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_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata;
if (active_idx > CONFIG_FWU_NUM_BANKS) {
printf("Active index value to be updated is incorrect\n");
return -1;
}
ret = gpt_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 = gpt_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+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);
+}
+int fwu_gpt_revert_boot_index(void) +{
int ret;
void *buf;
u32 cur_active_index;
struct fwu_mdata *mdata;
ret = gpt_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 = gpt_update_mdata(mdata);
If we have the fwu_update_mdata(), you can make this fwu_gpt_revert_boot_index() and above fwu_gpt_update_boot_index() platform agnostic. (in that case "gpt" must be removed), because there is no dependency to GPT.
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+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;
}
if (action == IMAGE_ACCEPT_SET)
bank = mdata->active_index;
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 = gpt_update_mdata(mdata);
This function is also doing the generic things. Only gpt_update_mdata() is the barrier. I would like to suggest you to add ".update_mdata" member to the fwu_mdata_ops.
Thank you,
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+int fwu_gpt_accept_image(efi_guid_t *img_type_id) +{
return fwu_gpt_set_clear_image_accept(img_type_id, 0,
IMAGE_ACCEPT_SET);
+}
+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,
.update_active_index = fwu_gpt_update_active_index,
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.revert_boot_index = fwu_gpt_revert_boot_index,
.set_accept_image = fwu_gpt_accept_image,
.clear_accept_image = fwu_gpt_clear_accept_image,
.get_mdata = fwu_gpt_get_mdata,
+};
2.17.1

hi Masami,
On Fri, 24 Dec 2021 at 15:29, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2021年12月19日(日) 16:06 Sughosh Ganu sughosh.ganu@linaro.org:
+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(desc->devnum, &part);
This is still GPT depending interface. In my use case (no GPT but raw SPI flash) I don't have devnum. Moreover, this one is used only from the fwu_mdata_gpt_blk.c.
You are right. I will change this api to not have the first parameter. The function will then pass only the identifier which is a void *.
Please ensure (and comment) that this is only for GPT user.
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_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata;
if (active_idx > CONFIG_FWU_NUM_BANKS) {
printf("Active index value to be updated is incorrect\n");
return -1;
}
ret = gpt_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 = gpt_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+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);
+}
+int fwu_gpt_revert_boot_index(void) +{
int ret;
void *buf;
u32 cur_active_index;
struct fwu_mdata *mdata;
ret = gpt_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 = gpt_update_mdata(mdata);
If we have the fwu_update_mdata(), you can make this fwu_gpt_revert_boot_index() and above fwu_gpt_update_boot_index() platform agnostic. (in that case "gpt" must be removed), because there is no dependency to GPT.
Okay. I believe you are suggesting having a GPT specific implementation only for fwu_update_mdata, and move fwu_gpt_revert_boot_index and fwu_gpt_update_active_index as common functions with appropriate renaming. I can do that.
-sughosh
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+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;
}
if (action == IMAGE_ACCEPT_SET)
bank = mdata->active_index;
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 = gpt_update_mdata(mdata);
This function is also doing the generic things. Only gpt_update_mdata() is the barrier. I would like to suggest you to add ".update_mdata" member to the fwu_mdata_ops.
Thank you,
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+int fwu_gpt_accept_image(efi_guid_t *img_type_id) +{
return fwu_gpt_set_clear_image_accept(img_type_id, 0,
IMAGE_ACCEPT_SET);
+}
+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,
.update_active_index = fwu_gpt_update_active_index,
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.revert_boot_index = fwu_gpt_revert_boot_index,
.set_accept_image = fwu_gpt_accept_image,
.clear_accept_image = fwu_gpt_clear_accept_image,
.get_mdata = fwu_gpt_get_mdata,
+};
2.17.1
-- Masami Hiramatsu

Hi Sughosh,
2021年12月25日(土) 2:08 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Fri, 24 Dec 2021 at 15:29, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2021年12月19日(日) 16:06 Sughosh Ganu sughosh.ganu@linaro.org:
+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(desc->devnum, &part);
This is still GPT depending interface. In my use case (no GPT but raw SPI flash) I don't have devnum. Moreover, this one is used only from the fwu_mdata_gpt_blk.c.
You are right. I will change this api to not have the first parameter. The function will then pass only the identifier which is a void *.
What about passing image index and bank index ? :-)
Please ensure (and comment) that this is only for GPT user.
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_update_active_index(u32 active_idx) +{
int ret;
void *buf;
struct fwu_mdata *mdata;
if (active_idx > CONFIG_FWU_NUM_BANKS) {
printf("Active index value to be updated is incorrect\n");
return -1;
}
ret = gpt_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 = gpt_update_mdata(mdata);
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+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);
+}
+int fwu_gpt_revert_boot_index(void) +{
int ret;
void *buf;
u32 cur_active_index;
struct fwu_mdata *mdata;
ret = gpt_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 = gpt_update_mdata(mdata);
If we have the fwu_update_mdata(), you can make this fwu_gpt_revert_boot_index() and above fwu_gpt_update_boot_index() platform agnostic. (in that case "gpt" must be removed), because there is no dependency to GPT.
Okay. I believe you are suggesting having a GPT specific implementation only for fwu_update_mdata, and move fwu_gpt_revert_boot_index and fwu_gpt_update_active_index as common functions with appropriate renaming. I can do that.
Yes, that's right. Then I don't need to repeat the same code :-)
Thank you,
-sughosh
if (ret < 0) {
log_err("Failed to update FWU metadata partitions\n");
ret = -EIO;
}
+out:
free(mdata);
return ret;
+}
+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;
}
if (action == IMAGE_ACCEPT_SET)
bank = mdata->active_index;
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 = gpt_update_mdata(mdata);
This function is also doing the generic things. Only gpt_update_mdata() is the barrier. I would like to suggest you to add ".update_mdata" member to the fwu_mdata_ops.
Thank you,
goto out;
}
}
/* Image not found */
ret = -EINVAL;
+out:
free(mdata);
return ret;
+}
+int fwu_gpt_accept_image(efi_guid_t *img_type_id) +{
return fwu_gpt_set_clear_image_accept(img_type_id, 0,
IMAGE_ACCEPT_SET);
+}
+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,
.update_active_index = fwu_gpt_update_active_index,
.get_image_alt_num = fwu_gpt_get_image_alt_num,
.mdata_check = fwu_gpt_mdata_check,
.revert_boot_index = fwu_gpt_revert_boot_index,
.set_accept_image = fwu_gpt_accept_image,
.clear_accept_image = fwu_gpt_clear_accept_image,
.get_mdata = fwu_gpt_get_mdata,
+};
2.17.1
-- Masami Hiramatsu

Add helper functions needed for accessing the FWU metadata which contains information on the updatable images. These functions have been added for the STM32MP157C-DK2 board which has the updatable images on the uSD card, formatted as GPT partitions.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V1: * Define a new function fwu_plat_get_alt_num using logic suggested by Patrick for returning the alt_num for the partition * Define a new function plat_fill_gpt_partition_guids to fill the guid array with Partition Type guids
board/st/stm32mp1/stm32mp1.c | 162 ++++++++++++++++++++++++++++ include/fwu.h | 5 + lib/fwu_updates/fwu_mdata_gpt_blk.c | 11 +- 3 files changed, 173 insertions(+), 5 deletions(-)
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 84592677e4..28402fd127 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,160 @@ 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> + +int fwu_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; +} + +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 e6bc3e6b73..1e7a1eabff 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -25,4 +25,9 @@ int fwu_revert_boot_index(void); int fwu_accept_image(efi_guid_t *img_type_id); 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(int dev_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 2dcac0c3d4..6a2fa176f9 100644 --- a/lib/fwu_updates/fwu_mdata_gpt_blk.c +++ b/lib/fwu_updates/fwu_mdata_gpt_blk.c @@ -53,6 +53,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; @@ -340,7 +341,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) { @@ -371,7 +372,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; @@ -443,7 +444,7 @@ int fwu_gpt_update_active_index(u32 active_idx) { int ret; void *buf; - struct fwu_mdata *mdata; + struct fwu_mdata *mdata = NULL;
if (active_idx > CONFIG_FWU_NUM_BANKS) { printf("Active index value to be updated is incorrect\n"); @@ -523,7 +524,7 @@ int fwu_gpt_revert_boot_index(void) int ret; void *buf; u32 cur_active_index; - struct fwu_mdata *mdata; + struct fwu_mdata *mdata = NULL;
ret = gpt_get_mdata(&mdata); if (ret < 0) { @@ -569,7 +570,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;

() should Hi Sughosh and Ilias,
I would like to confirm that what the plat_fill_gpt_partition_guids() should return.
2021年12月19日(日) 16:07 Sughosh Ganu sughosh.ganu@linaro.org:
+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;
+}
So on this platform which uses GPT partition for each bank, it stores the GUID for each partition. I think this information will be shown in the ESRT, but not used for specifying capsule image_type_uuid.
This is strange. Without this FWU multi-bank update, the array will only have the image_type UUID. Thus, user can use ESRT to confirm what UUID should be specified for the capsule file. (it has image-type UUID) (of course that is fixed value on one platform anyway)
And when FWU multi-bank update is enabled, that changes to the partition GUIDs. But those GUIDs are NOT used when making the capsule file nor doing the update process, because we should not specify the bank index directly, right?
We will set a unique image-type UUID on each image entry, and use it for making a capsule file, but the capsule file itself doesn't specify the banks. And acceptance/revert capsule file also doesn't specify it. Acceptance file will also uses image_type UUID, but not the partition UUID for the bank.
Maybe I'm wrong, but I'm confusing. And this is important for the platform which doesn't use GPT.
Thank you,

hi Masami,
On Fri, 24 Dec 2021 at 11:19, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
() should Hi Sughosh and Ilias,
I would like to confirm that what the plat_fill_gpt_partition_guids() should return.
2021年12月19日(日) 16:07 Sughosh Ganu sughosh.ganu@linaro.org:
+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;
+}
So on this platform which uses GPT partition for each bank, it stores the GUID for each partition. I think this information will be shown in the ESRT, but not used for specifying capsule image_type_uuid.
This is strange. Without this FWU multi-bank update, the array will only have the image_type UUID. Thus, user can use ESRT to confirm what UUID should be specified for the capsule file. (it has image-type UUID) (of course that is fixed value on one platform anyway)
And when FWU multi-bank update is enabled, that changes to the partition GUIDs. But those GUIDs are NOT used when making the capsule file nor doing the update process, because we should not specify the bank index directly, right?
The partition GUIDs are the same as ImageTypeId field in the EFI_FIRMWARE_IMAGE_DESCRIPTOR and the UpdateImageTypeId field in the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER. This value is the same as the PartitionTypeGUID field in the GPT partition entry.
ImageTypeId = UpdateImageTypeId = PartitionTypeGUID
This is the GUID value that is used when generating the capsule.
We will set a unique image-type UUID on each image entry, and use it for making a capsule file,
Even with the FWU feature enabled, the PartitionTypeGUID/ImageTypeId is used for making the capsule. What changes for the FWU feature is that the value of UpdateImageIndex/ImageIndex that is passed to the capsule generation tool becomes irrelevant. When the FWU feature is not enabled, the ImageIndex value that is passed to the capsule generation tool is important, since this is supposed to correspond to the DFU alt number -- this ImageIndex value is then used to identify the partition/address to which the capsule payload is to be written. With the FWU feature enabled, this value is not obtained from the capsule, since the partition/address to write the image to is identified at runtime based on the value of the update bank.
but the capsule file itself doesn't specify the banks. And acceptance/revert capsule file also doesn't specify it. Acceptance file will also uses image_type UUID, but not the partition UUID for the bank.
The image acceptance capsule will also contain the ImageTypeId. The Accept bit will be set for the active bank image of the image type specified in the acceptance capsule.
-sughosh
Maybe I'm wrong, but I'm confusing. And this is important for the platform which doesn't use GPT.
Thank you,
-- Masami Hiramatsu

Hi Sughosh,
2021年12月24日(金) 19:08 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Fri, 24 Dec 2021 at 11:19, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
() should Hi Sughosh and Ilias,
I would like to confirm that what the plat_fill_gpt_partition_guids() should return.
2021年12月19日(日) 16:07 Sughosh Ganu sughosh.ganu@linaro.org:
+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;
+}
So on this platform which uses GPT partition for each bank, it stores the GUID for each partition. I think this information will be shown in the ESRT, but not used for specifying capsule image_type_uuid.
This is strange. Without this FWU multi-bank update, the array will only have the image_type UUID. Thus, user can use ESRT to confirm what UUID should be specified for the capsule file. (it has image-type UUID) (of course that is fixed value on one platform anyway)
And when FWU multi-bank update is enabled, that changes to the partition GUIDs. But those GUIDs are NOT used when making the capsule file nor doing the update process, because we should not specify the bank index directly, right?
The partition GUIDs are the same as ImageTypeId field in the EFI_FIRMWARE_IMAGE_DESCRIPTOR and the UpdateImageTypeId field in the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER. This value is the same as the PartitionTypeGUID field in the GPT partition entry.
ImageTypeId = UpdateImageTypeId = PartitionTypeGUID
This is the GUID value that is used when generating the capsule.
So you meant the above "plat_fill_gpt_partition_guids()" fills the array with ImageTypeId? Thus, if we have a single image type, the array will be filled with that single GUID?
We will set a unique image-type UUID on each image entry, and use it for making a capsule file,
Even with the FWU feature enabled, the PartitionTypeGUID/ImageTypeId is used for making the capsule. What changes for the FWU feature is that the value of UpdateImageIndex/ImageIndex that is passed to the capsule generation tool becomes irrelevant. When the FWU feature is not enabled, the ImageIndex value that is passed to the capsule generation tool is important, since this is supposed to correspond to the DFU alt number -- this ImageIndex value is then used to identify the partition/address to which the capsule payload is to be written. With the FWU feature enabled, this value is not obtained from the capsule, since the partition/address to write the image to is identified at runtime based on the value of the update bank.
OK.
but the capsule file itself doesn't specify the banks. And acceptance/revert capsule file also doesn't specify it. Acceptance file will also uses image_type UUID, but not the partition UUID for the bank.
The image acceptance capsule will also contain the ImageTypeId. The Accept bit will be set for the active bank image of the image type specified in the acceptance capsule.
OK, so the Image UUID(image slot for the banks) will not be used in the process, is that correct? I would like to confirm this, because this is important for the system which doesn't use GPT.
Thank you,
-sughosh
Maybe I'm wrong, but I'm confusing. And this is important for the platform which doesn't use GPT.
Thank you,
-- Masami Hiramatsu

hi Masami,
On Fri, 24 Dec 2021 at 15:49, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
2021年12月24日(金) 19:08 Sughosh Ganu sughosh.ganu@linaro.org:
hi Masami,
On Fri, 24 Dec 2021 at 11:19, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
() should Hi Sughosh and Ilias,
I would like to confirm that what the plat_fill_gpt_partition_guids() should return.
2021年12月19日(日) 16:07 Sughosh Ganu sughosh.ganu@linaro.org:
+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;
+}
So on this platform which uses GPT partition for each bank, it stores the GUID for each partition. I think this information will be shown in the ESRT, but not used for specifying capsule image_type_uuid.
This is strange. Without this FWU multi-bank update, the array will only have the image_type UUID. Thus, user can use ESRT to confirm what UUID should be specified for the capsule file. (it has image-type UUID) (of course that is fixed value on one platform anyway)
And when FWU multi-bank update is enabled, that changes to the partition GUIDs. But those GUIDs are NOT used when making the capsule file nor doing the update process, because we should not specify the bank index directly, right?
The partition GUIDs are the same as ImageTypeId field in the EFI_FIRMWARE_IMAGE_DESCRIPTOR and the UpdateImageTypeId field in the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER. This value is the same as the PartitionTypeGUID field in the GPT partition entry.
ImageTypeId = UpdateImageTypeId = PartitionTypeGUID
This is the GUID value that is used when generating the capsule.
So you meant the above "plat_fill_gpt_partition_guids()" fills the array with ImageTypeId?
Yes. Please note that the actual api is fwu_plat_fill_partition_guids. For the ST board, fwu_plat_fill_partition_guids calls plat_fill_gpt_partition_guids.
Thus, if we have a single image type, the array will be filled with that single GUID?
That will depend on the dfu_alt_info setting and the platform function fwu_plat_fill_partition_guids defined for the corresponding platform.
We will set a unique image-type UUID on each image entry, and use it for making a capsule file,
Even with the FWU feature enabled, the PartitionTypeGUID/ImageTypeId is used for making the capsule. What changes for the FWU feature is that the value of UpdateImageIndex/ImageIndex that is passed to the capsule generation tool becomes irrelevant. When the FWU feature is not enabled, the ImageIndex value that is passed to the capsule generation tool is important, since this is supposed to correspond to the DFU alt number -- this ImageIndex value is then used to identify the partition/address to which the capsule payload is to be written. With the FWU feature enabled, this value is not obtained from the capsule, since the partition/address to write the image to is identified at runtime based on the value of the update bank.
OK.
but the capsule file itself doesn't specify the banks. And acceptance/revert capsule file also doesn't specify it. Acceptance file will also uses image_type UUID, but not the partition UUID for the bank.
The image acceptance capsule will also contain the ImageTypeId. The Accept bit will be set for the active bank image of the image type specified in the acceptance capsule.
OK, so the Image UUID(image slot for the banks) will not be used in the process, is that correct? I would like to confirm this, because this is important for the system which doesn't use GPT.
Yes, only the ImageTypeId will be used. You can check the implementation for the GPT partitioned block devices in fwu_gpt_set_clear_image_accept.
-sughosh
Thank you,
-sughosh
Maybe I'm wrong, but I'm confusing. And this is important for the platform which doesn't use GPT.
Thank you,
-- Masami Hiramatsu
-- 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 V1: * Use the TAMP_BOOTCOUNT register as suggested by Yann Gautier instead of the earlier unused register 10
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 28402fd127..a8543c6410 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -1090,6 +1090,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 1e7a1eabff..5ba437798d 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -29,5 +29,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(int dev_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 V1: * Define a new function fwu_plat_get_alt_num for filling up all the dfu partitions with a preset ImageTypeId guid * Remove the distinction made in the earlier version for setting image_type_id as suggested by Heinrich
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); }

Sughosh,
On Sun, Dec 19, 2021 at 12:36:02PM +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 V1:
- Define a new function fwu_plat_get_alt_num for filling up all the dfu partitions with a preset ImageTypeId guid
- Remove the distinction made in the earlier version for setting image_type_id as suggested by Heinrich
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
If I understand your code correctly, a guid in descriptor for any image (I mean any part defined by dfu_alto_info) will have the same value even with this change. If so, why do we have to take an array of GUIDs as a parameter?
On your previous version, Heinrich made a comment like:
! The sequence of GUIDs in a capsule should not influence the update. The ! design lacks a configuration defining which GUID maps to which DFU part. ! ! Please, get rid of all DFU environment variables and describe the update ! in a configuration file that you add to the capsule.
Have you addressed this issue in this series? (To do that, we may have to introduce a new format of capsule file.)
-Takahiro Akashi
- 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);
}
-- 2.17.1

hi Takahiro,
On Tue, 21 Dec 2021 at 10:23, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Sun, Dec 19, 2021 at 12:36:02PM +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 V1:
- Define a new function fwu_plat_get_alt_num for filling up all the dfu partitions with a preset ImageTypeId guid
- Remove the distinction made in the earlier version for setting image_type_id as suggested by Heinrich
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
If I understand your code correctly, a guid in descriptor for any image (I mean any part defined by dfu_alto_info) will have the same value even with this change. If so, why do we have to take an array of GUIDs as a parameter?
One of Heinrich's comments in my previous version was not to distinguish between the FWU case and the normal case when setting the image_type_id. The existing code sets the same GUID value(image_type) for all images. I have kept this consistent. With the FWU feature enabled, fwu_plat_fill_partition_guids is called and this function fills in the array with the relevant values of partition GUIDs. fwu_plat_fill_partition_guids has been defined for the ST board in patch 3/8.
On your previous version, Heinrich made a comment like:
! The sequence of GUIDs in a capsule should not influence the update. The ! design lacks a configuration defining which GUID maps to which DFU part. ! ! Please, get rid of all DFU environment variables and describe the update ! in a configuration file that you add to the capsule.
Have you addressed this issue in this series? (To do that, we may have to introduce a new format of capsule file.)
No, Ilias and I had replied back that detaching capsule update from DFU is a separate effort, not related to the addition of the FWU functionality and should be taken up as a separate activity.
-sughosh
-Takahiro Akashi
- 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);
}
-- 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 V1: * Define a funtion fwu_update_checks_pass to do the checks before initiating the update * Log the status of the boottime checks using boottime_check variable and allow system to boot instead of hanging the platform(fwu_boottime_checks)
common/board_r.c | 6 ++ include/fwu.h | 3 + lib/fwu_updates/fwu.c | 163 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 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 5ba437798d..2d2e674d6a 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -16,6 +16,9 @@ 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_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, diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c new file mode 100644 index 0000000000..e964f9b0b1 --- /dev/null +++ b/lib/fwu_updates/fwu.c @@ -0,0 +1,163 @@ +// 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; + } + } + } + +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; +}

Sughosh,
On Sun, Dec 19, 2021 at 12:36:03PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update specification requires the Update Agent to carry out certain checks at the time of platform boot. The Update Agent is the component which is responsible for updating the firmware components and maintaining and keeping the metadata in sync.
The spec requires that the Update Agent perform the following checks at the time of boot
- Sanity check of both the metadata copies maintained by the platform.
- Get the boot index passed to U-Boot by the prior stage bootloader and use this value for metadata bookkeeping.
- Check if the system is booting in Trial State. If the system boots in the Trial State for more than a specified number of boot counts, change the Active Bank to be booting the platform from.
Add these checks in the board initialisation sequence, invoked after relocation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Define a funtion fwu_update_checks_pass to do the checks before initiating the update
- Log the status of the boottime checks using boottime_check variable and allow system to boot instead of hanging the platform(fwu_boottime_checks)
common/board_r.c | 6 ++ include/fwu.h | 3 + lib/fwu_updates/fwu.c | 163 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 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
Maybe I don't understand your code well. Why do you want to call fwu_boottime_checks() here? Why not in CONFIG_EFI_CAPSULE_UPDATE_EARLY (i.e. efi_launch_capsules() in main_loop())?
-Takahiro Akashi
run_main_loop, }; diff --git a/include/fwu.h b/include/fwu.h index 5ba437798d..2d2e674d6a 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -16,6 +16,9 @@ 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_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, diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c new file mode 100644 index 0000000000..e964f9b0b1 --- /dev/null +++ b/lib/fwu_updates/fwu.c @@ -0,0 +1,163 @@ +// 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;
}
}
- }
+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;
+}
2.17.1

hi Takahiro,
On Mon, 20 Dec 2021 at 11:39, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Sun, Dec 19, 2021 at 12:36:03PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update specification requires the Update Agent to carry out certain checks at the time of platform boot. The Update Agent is the component which is responsible for updating the firmware components and maintaining and keeping the metadata in sync.
The spec requires that the Update Agent perform the following checks at the time of boot
- Sanity check of both the metadata copies maintained by the platform.
- Get the boot index passed to U-Boot by the prior stage bootloader and use this value for metadata bookkeeping.
- Check if the system is booting in Trial State. If the system boots in the Trial State for more than a specified number of boot counts, change the Active Bank to be booting the platform from.
Add these checks in the board initialisation sequence, invoked after relocation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Define a funtion fwu_update_checks_pass to do the checks before initiating the update
- Log the status of the boottime checks using boottime_check variable and allow system to boot instead of hanging the platform(fwu_boottime_checks)
common/board_r.c | 6 ++ include/fwu.h | 3 + lib/fwu_updates/fwu.c | 163 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 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
Maybe I don't understand your code well. Why do you want to call fwu_boottime_checks() here? Why not in CONFIG_EFI_CAPSULE_UPDATE_EARLY (i.e. efi_launch_capsules() in main_loop())?
These are boot time checks which are to be carried out during platform boot. Do you see any issue if we place the call to fwu_boottime_checks in the init_sequence. I would like to avoid having the fwu boot time checks tied up with CONFIG_EFI_CAPSULE_ON_DISK_EARLY.
-sughosh
-Takahiro Akashi
run_main_loop,
}; diff --git a/include/fwu.h b/include/fwu.h index 5ba437798d..2d2e674d6a 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -16,6 +16,9 @@ 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_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, diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c new file mode 100644 index 0000000000..e964f9b0b1 --- /dev/null +++ b/lib/fwu_updates/fwu.c @@ -0,0 +1,163 @@ +// 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;
}
}
}
+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;
+}
2.17.1

Hi Sughosh,
On Mon, Dec 20, 2021 at 03:36:37PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Mon, 20 Dec 2021 at 11:39, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Sughosh,
On Sun, Dec 19, 2021 at 12:36:03PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update specification requires the Update Agent to carry out certain checks at the time of platform boot. The Update Agent is the component which is responsible for updating the firmware components and maintaining and keeping the metadata in sync.
The spec requires that the Update Agent perform the following checks at the time of boot
- Sanity check of both the metadata copies maintained by the platform.
- Get the boot index passed to U-Boot by the prior stage bootloader and use this value for metadata bookkeeping.
- Check if the system is booting in Trial State. If the system boots in the Trial State for more than a specified number of boot counts, change the Active Bank to be booting the platform from.
Add these checks in the board initialisation sequence, invoked after relocation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Define a funtion fwu_update_checks_pass to do the checks before initiating the update
- Log the status of the boottime checks using boottime_check variable and allow system to boot instead of hanging the platform(fwu_boottime_checks)
common/board_r.c | 6 ++ include/fwu.h | 3 + lib/fwu_updates/fwu.c | 163 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 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
Maybe I don't understand your code well. Why do you want to call fwu_boottime_checks() here? Why not in CONFIG_EFI_CAPSULE_UPDATE_EARLY (i.e. efi_launch_capsules() in main_loop())?
These are boot time checks which are to be carried out during platform boot. Do you see any issue if we place the call to fwu_boottime_checks in the init_sequence.
No, I don't see any specific issue right now.
I would like to avoid having the fwu boot time checks tied up with CONFIG_EFI_CAPSULE_ON_DISK_EARLY.
My question was why you want to avoid that. In main_loop(), update_tftp(), as well as efi capsule code, is put there. It would be a good practice to have similar functionality called in one place.
-Takahiro Akashi
-sughosh
-Takahiro Akashi
run_main_loop,
}; diff --git a/include/fwu.h b/include/fwu.h index 5ba437798d..2d2e674d6a 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -16,6 +16,9 @@ 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_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, diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c new file mode 100644 index 0000000000..e964f9b0b1 --- /dev/null +++ b/lib/fwu_updates/fwu.c @@ -0,0 +1,163 @@ +// 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;
}
}
}
+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;
+}
2.17.1

hi Takahiro,
On Mon, 20 Dec 2021 at 15:55, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Hi Sughosh,
On Mon, Dec 20, 2021 at 03:36:37PM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Mon, 20 Dec 2021 at 11:39, AKASHI Takahiro <
takahiro.akashi@linaro.org>
wrote:
Sughosh,
On Sun, Dec 19, 2021 at 12:36:03PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update specification requires the Update Agent to carry out certain checks at the time of platform boot. The Update Agent is the component which is responsible for updating the firmware components and maintaining and keeping the metadata in sync.
The spec requires that the Update Agent perform the following checks at the time of boot
- Sanity check of both the metadata copies maintained by the
platform.
- Get the boot index passed to U-Boot by the prior stage bootloader and use this value for metadata bookkeeping.
- Check if the system is booting in Trial State. If the system boots in the Trial State for more than a specified number of boot counts, change the Active Bank to be booting the platform from.
Add these checks in the board initialisation sequence, invoked after relocation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Define a funtion fwu_update_checks_pass to do the checks before initiating the update
- Log the status of the boottime checks using boottime_check variable and allow system to boot instead of hanging the platform(fwu_boottime_checks)
common/board_r.c | 6 ++ include/fwu.h | 3 + lib/fwu_updates/fwu.c | 163
++++++++++++++++++++++++++++++++++++++++++
3 files changed, 172 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
Maybe I don't understand your code well. Why do you want to call fwu_boottime_checks() here? Why not in CONFIG_EFI_CAPSULE_UPDATE_EARLY (i.e. efi_launch_capsules() in main_loop())?
These are boot time checks which are to be carried out during platform boot. Do you see any issue if we place the call to fwu_boottime_checks in the init_sequence.
No, I don't see any specific issue right now.
I would like to avoid having the fwu boot time checks tied up with CONFIG_EFI_CAPSULE_ON_DISK_EARLY.
My question was why you want to avoid that. In main_loop(), update_tftp(), as well as efi capsule code, is put there. It would be a good practice to have similar functionality called in one place.
Keeping the call to fwu_boottime_checks separate allows one to try it out separately from the u-boot shell, by not enabling CONFIG_EFI_CAPSULE_ON_DISK_EARLY. Also, currently, the FWU code is closely tied up with the capsule update code. But in the future, if someone wants to use the fwu metadata without using the capsule format for the update, that would be possible with the call being separate. But I agree that this is a hypothetical case which may or may not happen. If you don't have a strong opinion on this, I would prefer it be kept separate. Let me know.
-sughosh
-Takahiro Akashi
-sughosh
-Takahiro Akashi
run_main_loop,
}; diff --git a/include/fwu.h b/include/fwu.h index 5ba437798d..2d2e674d6a 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -16,6 +16,9 @@ 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_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, diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c new file mode 100644 index 0000000000..e964f9b0b1 --- /dev/null +++ b/lib/fwu_updates/fwu.c @@ -0,0 +1,163 @@ +// 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;
}
}
}
+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;
+}
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 V1: * Call function fwu_update_checks_pass to check if the update can be initiated * Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
include/fwu.h | 18 +++- lib/Kconfig | 32 ++++++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 +++++ 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 2d2e674d6a..bf50fe9277 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -10,14 +10,28 @@
#include <linux/types.h>
-#define FWU_MDATA_VERSION 0x1 +#define FWU_MDATA_GUID \ + EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ + 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23) + +#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)
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1 + u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..7cb306317c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,35 @@ 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. + +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/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..6dfe56bb0f 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,13 @@ 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; + +__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -403,10 +411,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 +492,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 +532,24 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; } + + if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { + status = fwu_clear_accept_image(&image_type_id, + update_index); + if (status < 0) { + log_err("Unable to clear the accept bit for the image %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("Cleared out accepted bit for Image %pUl\n", &image_type_id); + } + }
out: @@ -527,6 +584,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 +598,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 +622,64 @@ 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; + } + } + 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 to %u. Recommend rebooting the system\n", + active_idx); + } + } 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_accept_image(image_guid); + if (status < 0) { + 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 +690,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 +1247,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 +1278,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 +1290,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 +1298,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 1aba71cd96..6601176a2d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -298,7 +298,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/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 e964f9b0b1..bb0e1961be 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -107,6 +107,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;

On Sun, Dec 19, 2021 at 12:36:04PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update feature supports updation of firmware images to one of multiple sets(also called banks) of images. The firmware images are clubbed together in banks, with the system booting images from the active bank. Information on the images such as which bank they belong to is stored as part of the metadata structure, which is stored on the same storage media as the firmware images on a dedicated partition.
At the time of update, the metadata is read to identify the bank to which the images need to be flashed(update bank). On a successful update, the metadata is modified to set the updated bank as active bank to subsequently boot from.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Call function fwu_update_checks_pass to check if the update can be initiated
- Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
include/fwu.h | 18 +++- lib/Kconfig | 32 ++++++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 +++++ 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 2d2e674d6a..bf50fe9277 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -10,14 +10,28 @@
#include <linux/types.h>
-#define FWU_MDATA_VERSION 0x1 +#define FWU_MDATA_GUID \
- EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+#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)
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1
u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..7cb306317c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,35 @@ 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.
+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/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..6dfe56bb0f 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,13 @@ 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;
+__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -403,10 +411,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 +492,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 +532,24 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; }
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
status = fwu_clear_accept_image(&image_type_id,
update_index);
if (status < 0) {
log_err("Unable to clear the accept bit for the image %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("Cleared out accepted bit for Image %pUl\n", &image_type_id);
}
- }
out: @@ -527,6 +584,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 +598,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 +622,64 @@ 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;
}
}
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 to %u. Recommend rebooting the system\n",
active_idx);
}
} 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_accept_image(image_guid);
if (status < 0) {
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 +690,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 +1247,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 +1278,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 +1290,7 @@ efi_status_t efi_launch_capsules(void) free(capsule); } else { log_err("Reading capsule %ls failed\n", files[i]);
} /* delete a capsule either in case of success or failure */ ret = efi_capsule_delete_file(files[i]);update_status = false;
@@ -1136,7 +1298,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 1aba71cd96..6601176a2d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -298,7 +298,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) &&
ret = efi_launch_capsules();IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) && !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
out: 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
If I understand correctly, any platform may have its own fwu_mdata_ops. So we should not unconditionally compile in fwu_mdata_gpt_blk.o even if CONFIG_EFI_PARTITION is enabled.
Masami must have something to say here :)
-Takahiro Akashi
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index e964f9b0b1..bb0e1961be 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -107,6 +107,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; -- 2.17.1

On Mon, 20 Dec 2021 at 11:44, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Sun, Dec 19, 2021 at 12:36:04PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update feature supports updation of firmware images to one of multiple sets(also called banks) of images. The firmware images are clubbed together in banks, with the system booting images from the active bank. Information on the images such as which bank they belong to is stored as part of the metadata structure, which is stored on the same storage media as the firmware images on a dedicated partition.
At the time of update, the metadata is read to identify the bank to which the images need to be flashed(update bank). On a successful update, the metadata is modified to set the updated bank as active bank to subsequently boot from.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Call function fwu_update_checks_pass to check if the update can be initiated
- Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
include/fwu.h | 18 +++- lib/Kconfig | 32 ++++++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 +++++ 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 2d2e674d6a..bf50fe9277 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -10,14 +10,28 @@
#include <linux/types.h>
-#define FWU_MDATA_VERSION 0x1 +#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+#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)
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1
u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..7cb306317c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,35 @@ 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.
+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/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..6dfe56bb0f 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,13 @@ 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;
+__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -403,10 +411,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 +492,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 +532,24 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; }
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
status = fwu_clear_accept_image(&image_type_id,
update_index);
if (status < 0) {
log_err("Unable to clear the accept bit
for the image %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("Cleared out accepted bit for Image
%pUl\n", &image_type_id);
}
}
out: @@ -527,6 +584,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 +598,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 +622,64 @@ 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;
}
}
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 to %u. Recommend rebooting the system\n",
active_idx);
}
} 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_accept_image(image_guid);
if (status < 0) {
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 +690,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 +1247,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 +1278,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 +1290,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 +1298,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 1aba71cd96..6601176a2d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -298,7 +298,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/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
If I understand correctly, any platform may have its own fwu_mdata_ops. So we should not unconditionally compile in fwu_mdata_gpt_blk.o even if CONFIG_EFI_PARTITION is enabled.
I can put in an additional guard of CONFIG_BLK for building the file. Not sure if there would be a requirement to have a platform specific set of operations for a GPT partitioned block device. Will wait for Masami to explain.
-sughosh
Masami must have something to say here :)
-Takahiro Akashi
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index e964f9b0b1..bb0e1961be 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -107,6 +107,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; -- 2.17.1

Hi Sughosh,
2021年12月20日(月) 18:48 Sughosh Ganu sughosh.ganu@linaro.org:
On Mon, 20 Dec 2021 at 11:44, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Sun, Dec 19, 2021 at 12:36:04PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update feature supports updation of firmware images to one of multiple sets(also called banks) of images. The firmware images are clubbed together in banks, with the system booting images from the active bank. Information on the images such as which bank they belong to is stored as part of the metadata structure, which is stored on the same storage media as the firmware images on a dedicated partition.
At the time of update, the metadata is read to identify the bank to which the images need to be flashed(update bank). On a successful update, the metadata is modified to set the updated bank as active bank to subsequently boot from.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Call function fwu_update_checks_pass to check if the update can be initiated
- Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
include/fwu.h | 18 +++- lib/Kconfig | 32 ++++++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 +++++ 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 2d2e674d6a..bf50fe9277 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -10,14 +10,28 @@
#include <linux/types.h>
-#define FWU_MDATA_VERSION 0x1 +#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+#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)
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1
u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..7cb306317c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,35 @@ 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.
+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/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..6dfe56bb0f 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,13 @@ 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;
+__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -403,10 +411,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 +492,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 +532,24 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; }
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
status = fwu_clear_accept_image(&image_type_id,
update_index);
if (status < 0) {
log_err("Unable to clear the accept bit for the image %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("Cleared out accepted bit for Image %pUl\n", &image_type_id);
}
}
out: @@ -527,6 +584,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 +598,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 +622,64 @@ 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;
}
}
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 to %u. Recommend rebooting the system\n",
active_idx);
}
} 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_accept_image(image_guid);
if (status < 0) {
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 +690,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 +1247,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 +1278,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 +1290,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 +1298,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 1aba71cd96..6601176a2d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -298,7 +298,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/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
If I understand correctly, any platform may have its own fwu_mdata_ops. So we should not unconditionally compile in fwu_mdata_gpt_blk.o even if CONFIG_EFI_PARTITION is enabled.
I can put in an additional guard of CONFIG_BLK for building the file. Not sure if there would be a requirement to have a platform specific set of operations for a GPT partitioned block device. Will wait for Masami to explain.
OK, I'm trying to implement the AB update on the developerbox platform, which doesn't have GPT, nor BLK since the firmware will be stored on the SPI NOR flash. So I will introduce a new fwu_mdata_sf.c. For this purpose, I introduced CONFIG_FWU_MULTI_BANK_UPDATE_SF, which depends on CONFIG_FWU_MULTI_BANK_UPDATE and CONFIG_DM_SPI_FLASH. Thus, I also recommend you to introduce CONFIG_FWU_MULTI_BANK_UPDATE_GPT_BLK and it should depends on CONFIG_BLK and selects CONFIG_EFI_PARTITION.
BTW, there are some code pieces which can shared with the fwu_mdata_gpt_blk.c, for example, comparing primary and seconday metadata and calculate the crc32.
Thank you,
-sughosh
Masami must have something to say here :)
-Takahiro Akashi
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index e964f9b0b1..bb0e1961be 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -107,6 +107,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; -- 2.17.1

On Mon, Dec 20, 2021 at 10:13:35PM +0900, Masami Hiramatsu wrote:
Hi Sughosh,
2021年12月20日(月) 18:48 Sughosh Ganu sughosh.ganu@linaro.org:
On Mon, 20 Dec 2021 at 11:44, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Sun, Dec 19, 2021 at 12:36:04PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update feature supports updation of firmware images to one of multiple sets(also called banks) of images. The firmware images are clubbed together in banks, with the system booting images from the active bank. Information on the images such as which bank they belong to is stored as part of the metadata structure, which is stored on the same storage media as the firmware images on a dedicated partition.
At the time of update, the metadata is read to identify the bank to which the images need to be flashed(update bank). On a successful update, the metadata is modified to set the updated bank as active bank to subsequently boot from.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Call function fwu_update_checks_pass to check if the update can be initiated
- Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
include/fwu.h | 18 +++- lib/Kconfig | 32 ++++++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 +++++ 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 2d2e674d6a..bf50fe9277 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -10,14 +10,28 @@
#include <linux/types.h>
-#define FWU_MDATA_VERSION 0x1 +#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+#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)
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1
u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..7cb306317c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,35 @@ 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.
+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/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..6dfe56bb0f 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,13 @@ 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;
+__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -403,10 +411,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 +492,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 +532,24 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; }
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
status = fwu_clear_accept_image(&image_type_id,
update_index);
if (status < 0) {
log_err("Unable to clear the accept bit for the image %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("Cleared out accepted bit for Image %pUl\n", &image_type_id);
}
}
out: @@ -527,6 +584,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 +598,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 +622,64 @@ 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;
}
}
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 to %u. Recommend rebooting the system\n",
active_idx);
}
} 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_accept_image(image_guid);
if (status < 0) {
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 +690,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 +1247,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 +1278,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 +1290,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 +1298,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 1aba71cd96..6601176a2d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -298,7 +298,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/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
If I understand correctly, any platform may have its own fwu_mdata_ops. So we should not unconditionally compile in fwu_mdata_gpt_blk.o even if CONFIG_EFI_PARTITION is enabled.
I can put in an additional guard of CONFIG_BLK for building the file. Not sure if there would be a requirement to have a platform specific set of operations for a GPT partitioned block device. Will wait for Masami to explain.
OK, I'm trying to implement the AB update on the developerbox platform, which doesn't have GPT, nor BLK since the firmware will be stored on the SPI NOR flash. So I will introduce a new fwu_mdata_sf.c. For this purpose, I introduced CONFIG_FWU_MULTI_BANK_UPDATE_SF, which depends on CONFIG_FWU_MULTI_BANK_UPDATE and CONFIG_DM_SPI_FLASH. Thus, I also recommend you to introduce CONFIG_FWU_MULTI_BANK_UPDATE_GPT_BLK and it should depends on CONFIG_BLK and selects CONFIG_EFI_PARTITION.
BTW, there are some code pieces which can shared with the fwu_mdata_gpt_blk.c, for example, comparing primary and seconday metadata and calculate the crc32.
Here's my concern / question. At what level is this abstraction being used? I want to be sure that other SoCs, such as say a Rockchip platform (I have a SystemReady IR certified one on the way) can re-use this code as well but I'm sure it will need things written to different offsets within the SPI/eMMC. Thanks!

Hi Tom,
2021年12月21日(火) 1:36 Tom Rini trini@konsulko.com:
On Mon, Dec 20, 2021 at 10:13:35PM +0900, Masami Hiramatsu wrote:
Hi Sughosh,
2021年12月20日(月) 18:48 Sughosh Ganu sughosh.ganu@linaro.org:
On Mon, 20 Dec 2021 at 11:44, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Sun, Dec 19, 2021 at 12:36:04PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update feature supports updation of firmware images to one of multiple sets(also called banks) of images. The firmware images are clubbed together in banks, with the system booting images from the active bank. Information on the images such as which bank they belong to is stored as part of the metadata structure, which is stored on the same storage media as the firmware images on a dedicated partition.
At the time of update, the metadata is read to identify the bank to which the images need to be flashed(update bank). On a successful update, the metadata is modified to set the updated bank as active bank to subsequently boot from.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Call function fwu_update_checks_pass to check if the update can be initiated
- Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
include/fwu.h | 18 +++- lib/Kconfig | 32 ++++++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 +++++ 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 2d2e674d6a..bf50fe9277 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -10,14 +10,28 @@
#include <linux/types.h>
-#define FWU_MDATA_VERSION 0x1 +#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+#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)
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1
u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..7cb306317c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,35 @@ 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.
+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/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..6dfe56bb0f 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,13 @@ 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;
+__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -403,10 +411,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 +492,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 +532,24 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; }
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
status = fwu_clear_accept_image(&image_type_id,
update_index);
if (status < 0) {
log_err("Unable to clear the accept bit for the image %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("Cleared out accepted bit for Image %pUl\n", &image_type_id);
}
}
out: @@ -527,6 +584,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 +598,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 +622,64 @@ 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;
}
}
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 to %u. Recommend rebooting the system\n",
active_idx);
}
} 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_accept_image(image_guid);
if (status < 0) {
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 +690,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 +1247,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 +1278,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 +1290,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 +1298,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 1aba71cd96..6601176a2d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -298,7 +298,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/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
If I understand correctly, any platform may have its own fwu_mdata_ops. So we should not unconditionally compile in fwu_mdata_gpt_blk.o even if CONFIG_EFI_PARTITION is enabled.
I can put in an additional guard of CONFIG_BLK for building the file. Not sure if there would be a requirement to have a platform specific set of operations for a GPT partitioned block device. Will wait for Masami to explain.
OK, I'm trying to implement the AB update on the developerbox platform, which doesn't have GPT, nor BLK since the firmware will be stored on the SPI NOR flash. So I will introduce a new fwu_mdata_sf.c. For this purpose, I introduced CONFIG_FWU_MULTI_BANK_UPDATE_SF, which depends on CONFIG_FWU_MULTI_BANK_UPDATE and CONFIG_DM_SPI_FLASH. Thus, I also recommend you to introduce CONFIG_FWU_MULTI_BANK_UPDATE_GPT_BLK and it should depends on CONFIG_BLK and selects CONFIG_EFI_PARTITION.
BTW, there are some code pieces which can shared with the fwu_mdata_gpt_blk.c, for example, comparing primary and seconday metadata and calculate the crc32.
Here's my concern / question. At what level is this abstraction being used? I want to be sure that other SoCs, such as say a Rockchip platform (I have a SystemReady IR certified one on the way) can re-use this code as well but I'm sure it will need things written to different offsets within the SPI/eMMC. Thanks!
For the metadata, I introduced CONFIG_FWU_SF_PRIMARY_METADATA_OFFSET and CONFIG_FWU_SF_PRIMARY_METADATA_OFFSET for configuring offset of the metadata on SPI Flash for my prototype code. I think it might be better to introduce accessors for the metadata, e.g. fwu_load_pri_mdata()/fwu_save_sec_mdata() etc. so that the platform can choose the media which stores metadata independent from the firmware storage.
For the firmware offset, it is defined in the dfu_alt_info, so you can use (or even mix) any storage media like SPI nor or MTD or eMMC.
Thank you,
-- Tom

On Tue, Dec 21, 2021 at 08:30:02AM +0900, Masami Hiramatsu wrote:
Hi Tom,
2021年12月21日(火) 1:36 Tom Rini trini@konsulko.com:
On Mon, Dec 20, 2021 at 10:13:35PM +0900, Masami Hiramatsu wrote:
Hi Sughosh,
2021年12月20日(月) 18:48 Sughosh Ganu sughosh.ganu@linaro.org:
On Mon, 20 Dec 2021 at 11:44, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
On Sun, Dec 19, 2021 at 12:36:04PM +0530, Sughosh Ganu wrote:
The FWU Multi Bank Update feature supports updation of firmware images to one of multiple sets(also called banks) of images. The firmware images are clubbed together in banks, with the system booting images from the active bank. Information on the images such as which bank they belong to is stored as part of the metadata structure, which is stored on the same storage media as the firmware images on a dedicated partition.
At the time of update, the metadata is read to identify the bank to which the images need to be flashed(update bank). On a successful update, the metadata is modified to set the updated bank as active bank to subsequently boot from.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V1:
- Call function fwu_update_checks_pass to check if the update can be initiated
- Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
include/fwu.h | 18 +++- lib/Kconfig | 32 ++++++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 +++++ 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 2d2e674d6a..bf50fe9277 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -10,14 +10,28 @@
#include <linux/types.h>
-#define FWU_MDATA_VERSION 0x1 +#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+#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)
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1
u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..7cb306317c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,35 @@ 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.
+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/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..6dfe56bb0f 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,13 @@ 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;
+__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -403,10 +411,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 +492,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 +532,24 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; }
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
status = fwu_clear_accept_image(&image_type_id,
update_index);
if (status < 0) {
log_err("Unable to clear the accept bit for the image %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("Cleared out accepted bit for Image %pUl\n", &image_type_id);
}
}
out: @@ -527,6 +584,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 +598,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 +622,64 @@ 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;
}
}
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 to %u. Recommend rebooting the system\n",
active_idx);
}
} 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_accept_image(image_guid);
if (status < 0) {
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 +690,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 +1247,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 +1278,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 +1290,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 +1298,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 1aba71cd96..6601176a2d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -298,7 +298,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/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
If I understand correctly, any platform may have its own fwu_mdata_ops. So we should not unconditionally compile in fwu_mdata_gpt_blk.o even if CONFIG_EFI_PARTITION is enabled.
I can put in an additional guard of CONFIG_BLK for building the file. Not sure if there would be a requirement to have a platform specific set of operations for a GPT partitioned block device. Will wait for Masami to explain.
OK, I'm trying to implement the AB update on the developerbox platform, which doesn't have GPT, nor BLK since the firmware will be stored on the SPI NOR flash. So I will introduce a new fwu_mdata_sf.c. For this purpose, I introduced CONFIG_FWU_MULTI_BANK_UPDATE_SF, which depends on CONFIG_FWU_MULTI_BANK_UPDATE and CONFIG_DM_SPI_FLASH. Thus, I also recommend you to introduce CONFIG_FWU_MULTI_BANK_UPDATE_GPT_BLK and it should depends on CONFIG_BLK and selects CONFIG_EFI_PARTITION.
BTW, there are some code pieces which can shared with the fwu_mdata_gpt_blk.c, for example, comparing primary and seconday metadata and calculate the crc32.
Here's my concern / question. At what level is this abstraction being used? I want to be sure that other SoCs, such as say a Rockchip platform (I have a SystemReady IR certified one on the way) can re-use this code as well but I'm sure it will need things written to different offsets within the SPI/eMMC. Thanks!
For the metadata, I introduced CONFIG_FWU_SF_PRIMARY_METADATA_OFFSET and CONFIG_FWU_SF_PRIMARY_METADATA_OFFSET for configuring offset of the metadata on SPI Flash for my prototype code. I think it might be better to introduce accessors for the metadata, e.g. fwu_load_pri_mdata()/fwu_save_sec_mdata() etc. so that the platform can choose the media which stores metadata independent from the firmware storage.
For the firmware offset, it is defined in the dfu_alt_info, so you can use (or even mix) any storage media like SPI nor or MTD or eMMC.
OK, good so you're keeping it in mind. Is there any chance we can get a second platform supported as part of the series itself, to confirm it's sufficient? I always worry a bit about things that are supposed to be abstract enough to support anything but only implemented once. Thanks!

Hi Sughosh,
Can you move the FWU related configs to lib/fwu_updates/Kconfig ? FWU multi bank update is an independent feature, thus I think it is better to have its own Kconfig file and the lib/Kconfig only includes it. (I did it on my development series)
Thank you,
2021年12月19日(日) 16:07 Sughosh Ganu sughosh.ganu@linaro.org:
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 V1:
- Call function fwu_update_checks_pass to check if the update can be initiated
- Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
include/fwu.h | 18 +++- lib/Kconfig | 32 ++++++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 +++++ 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 2d2e674d6a..bf50fe9277 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -10,14 +10,28 @@
#include <linux/types.h>
-#define FWU_MDATA_VERSION 0x1 +#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+#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)
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1
u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..7cb306317c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,35 @@ 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.
+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/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..6dfe56bb0f 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,13 @@ 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;
+__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -403,10 +411,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 +492,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 +532,24 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; }
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
status = fwu_clear_accept_image(&image_type_id,
update_index);
if (status < 0) {
log_err("Unable to clear the accept bit for the image %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("Cleared out accepted bit for Image %pUl\n", &image_type_id);
}
}
out: @@ -527,6 +584,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 +598,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 +622,64 @@ 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;
}
}
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 to %u. Recommend rebooting the system\n",
active_idx);
}
} 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_accept_image(image_guid);
if (status < 0) {
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 +690,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 +1247,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 +1278,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 +1290,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 +1298,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 1aba71cd96..6601176a2d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -298,7 +298,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/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 e964f9b0b1..bb0e1961be 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -107,6 +107,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; -- 2.17.1

hi Masami,
On Thu, 23 Dec 2021 at 06:23, Masami Hiramatsu masami.hiramatsu@linaro.org wrote:
Hi Sughosh,
Can you move the FWU related configs to lib/fwu_updates/Kconfig ? FWU multi bank update is an independent feature, thus I think it is better to have its own Kconfig file and the lib/Kconfig only includes it. (I did it on my development series)
Okay, I have moved the FWU config options in a Kconfig file under lib/fwu_updates/. This gets sourced from lib/Kconfig.
-sughosh
Thank you,
2021年12月19日(日) 16:07 Sughosh Ganu sughosh.ganu@linaro.org:
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 V1:
- Call function fwu_update_checks_pass to check if the update can be initiated
- Do not allow firmware update from efi_init_obj_list as the fwu boot-time checks need to be run
include/fwu.h | 18 +++- lib/Kconfig | 32 ++++++ lib/Makefile | 1 + lib/efi_loader/efi_capsule.c | 198 ++++++++++++++++++++++++++++++++++- lib/efi_loader/efi_setup.c | 3 +- lib/fwu_updates/Makefile | 11 ++ lib/fwu_updates/fwu.c | 27 +++++ 7 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 lib/fwu_updates/Makefile
diff --git a/include/fwu.h b/include/fwu.h index 2d2e674d6a..bf50fe9277 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -10,14 +10,28 @@
#include <linux/types.h>
-#define FWU_MDATA_VERSION 0x1 +#define FWU_MDATA_GUID \
EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \
0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
+#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)
#define FWU_MDATA_GUID \ EFI_GUID(0x8a7a84a0, 0x8387, 0x40f6, 0xab, 0x41, \ 0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23)
-int fwu_boottime_checks(void); +#define FWU_MDATA_VERSION 0x1 +#define FWU_IMAGE_ACCEPTED 0x1
u8 fwu_update_checks_pass(void); +int fwu_boottime_checks(void); +int fwu_trial_state_ctr_start(void);
int fwu_get_active_index(u32 *active_idx); int fwu_update_active_index(u32 active_idx); diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade..7cb306317c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -835,3 +835,35 @@ 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.
+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/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..6dfe56bb0f 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,13 @@ 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;
+__maybe_unused static u32 update_index; +__maybe_unused static bool capsule_update;
#ifdef CONFIG_EFI_CAPSULE_ON_DISK /* for file system access */ @@ -403,10 +411,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 +492,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 +532,24 @@ static efi_status_t efi_capsule_update_firmware( efi_free_pool(abort_reason); goto out; }
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
status = fwu_clear_accept_image(&image_type_id,
update_index);
if (status < 0) {
log_err("Unable to clear the accept bit
for the image %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("Cleared out accepted bit for Image
%pUl\n", &image_type_id);
}
}
out: @@ -527,6 +584,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 +598,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 +622,64 @@ 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;
}
}
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 to %u. Recommend rebooting the system\n",
active_idx);
}
} 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_accept_image(image_guid);
if (status < 0) {
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 +690,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 +1247,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 +1278,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 +1290,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 +1298,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 1aba71cd96..6601176a2d 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -298,7 +298,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/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 e964f9b0b1..bb0e1961be 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -107,6 +107,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; -- 2.17.1
-- 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 V1: * None
cmd/Kconfig | 7 ++++++ cmd/Makefile | 1 + cmd/fwu_mdata.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 cmd/fwu_mdata.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 5b30b13e43..ee8a976b46 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 891819ae0f..32958cba43 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..4049fb186d --- /dev/null +++ b/cmd/fwu_mdata.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021, Linaro Limited + */ + +#include <command.h> +#include <fwu_mdata.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", + "" +);
participants (4)
-
AKASHI Takahiro
-
Masami Hiramatsu
-
Sughosh Ganu
-
Tom Rini