From f42a61f57f69c9fac1e21cbfde3f40ebdadc518b Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 22 Mar 2024 16:27:16 +0530 Subject: drivers: fwu: add the size parameter to the metadata access API's In version 2 of the metadata structure, the size of the structure cannot be determined statically at build time. The structure is now broken into the top level structure which contains a field indicating the total size of the structure. Add a size parameter to the metadata access API functions to indicate the number of bytes to be accessed. This is then used to either read the entire structure, or only the top level structure. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek --- include/fwu.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/fwu.h b/include/fwu.h index eb5638f4f3a..1815bd0064c 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -32,20 +32,24 @@ struct fwu_mdata_ops { * @dev: FWU metadata device * @mdata: Output FWU mdata read * @primary: If primary or secondary copy of metadata is to be read + * @size: Size in bytes of the metadata to be read * * Return: 0 if OK, -ve on error */ - int (*read_mdata)(struct udevice *dev, struct fwu_mdata *mdata, bool primary); + int (*read_mdata)(struct udevice *dev, struct fwu_mdata *mdata, + bool primary, uint32_t size); /** * write_mdata() - Write the given FWU metadata copy * @dev: FWU metadata device * @mdata: Copy of the FWU metadata to write * @primary: If primary or secondary copy of metadata is to be written + * @size: Size in bytes of the metadata to be written * * Return: 0 if OK, -ve on error */ - int (*write_mdata)(struct udevice *dev, struct fwu_mdata *mdata, bool primary); + int (*write_mdata)(struct udevice *dev, struct fwu_mdata *mdata, + bool primary, uint32_t size); }; #define FWU_MDATA_VERSION 0x1 @@ -80,12 +84,14 @@ struct fwu_mdata_ops { /** * fwu_read_mdata() - Wrapper around fwu_mdata_ops.read_mdata() */ -int fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary); +int fwu_read_mdata(struct udevice *dev, struct fwu_mdata *mdata, + bool primary, uint32_t size); /** * fwu_write_mdata() - Wrapper around fwu_mdata_ops.write_mdata() */ -int fwu_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, bool primary); +int fwu_write_mdata(struct udevice *dev, struct fwu_mdata *mdata, + bool primary, uint32_t size); /** * fwu_get_mdata() - Read, verify and return the FWU metadata -- cgit v1.3.1 From e67c0b76d8e80856cd88256ef1d6ac5da904f503 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 22 Mar 2024 16:27:17 +0530 Subject: drivers: fwu: mtd: allocate buffer for image info dynamically The FWU metadata access driver for MTD partitioned devices currently uses a statically allocated array for storing the updatable image information. This array depends on the number of banks and images per bank. With migration of the FWU metadata to version 2, these parameters are now obtained at runtime from the metadata. Make changes to the FWU metadata access driver for MTD devices to allocate memory for the image information dynamically in the driver's probe function, after having obtained the number of banks and images per bank by reading the metadata. Move the image information as part of the driver's private structure, instead of using a global variable. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek --- drivers/fwu-mdata/raw_mtd.c | 68 ++++++++++++++++++++++++++++----------------- include/fwu.h | 9 ++++++ 2 files changed, 52 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/drivers/fwu-mdata/raw_mtd.c b/drivers/fwu-mdata/raw_mtd.c index 9f3f1dc2131..78a709f766c 100644 --- a/drivers/fwu-mdata/raw_mtd.c +++ b/drivers/fwu-mdata/raw_mtd.c @@ -12,22 +12,11 @@ #include #include -/* Internal helper structure to move data around */ -struct fwu_mdata_mtd_priv { - struct mtd_info *mtd; - char pri_label[50]; - char sec_label[50]; - u32 pri_offset; - u32 sec_offset; -}; - enum fwu_mtd_op { FWU_MTD_READ, FWU_MTD_WRITE, }; -extern struct fwu_mtd_image_info fwu_mtd_images[]; - static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size) { return !do_div(size, mtd->erasesize); @@ -134,7 +123,7 @@ static int flash_partition_offset(struct udevice *dev, const char *part_name, fd return (int)size; } -static int fwu_mdata_mtd_of_to_plat(struct udevice *dev) +static int get_fwu_mdata_dev(struct udevice *dev) { struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev); const fdt32_t *phandle_p = NULL; @@ -144,8 +133,6 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev) fdt_addr_t offset; int ret, size; u32 phandle; - ofnode bank; - int off_img; /* Find the FWU mdata storage device */ phandle_p = ofnode_get_property(dev_ofnode(dev), @@ -199,8 +186,28 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev) return ret; mtd_priv->sec_offset = offset; - off_img = 0; + return 0; +} + +static int fwu_mtd_image_info_populate(struct udevice *dev, u8 nbanks, + u16 nimages) +{ + struct fwu_mtd_image_info *mtd_images; + struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev); + struct udevice *mtd_dev = mtd_priv->mtd->dev; + fdt_addr_t offset; + ofnode bank; + int off_img; + u32 total_images; + total_images = nbanks * nimages; + mtd_priv->fwu_mtd_images = malloc(sizeof(struct fwu_mtd_image_info) * + total_images); + if (!mtd_priv->fwu_mtd_images) + return -ENOMEM; + + off_img = 0; + mtd_images = mtd_priv->fwu_mtd_images; ofnode_for_each_subnode(bank, dev_ofnode(dev)) { int bank_num, bank_offset, bank_size; const char *bank_name; @@ -219,8 +226,7 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev) int image_num, image_offset, image_size; const char *uuid; - if (off_img == CONFIG_FWU_NUM_BANKS * - CONFIG_FWU_NUM_IMAGES_PER_BANK) { + if (off_img == total_images) { log_err("DT provides more images than configured!\n"); break; } @@ -230,11 +236,11 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev) ofnode_read_u32(image, "offset", &image_offset); ofnode_read_u32(image, "size", &image_size); - fwu_mtd_images[off_img].start = bank_offset + image_offset; - fwu_mtd_images[off_img].size = image_size; - fwu_mtd_images[off_img].bank_num = bank_num; - fwu_mtd_images[off_img].image_num = image_num; - strcpy(fwu_mtd_images[off_img].uuidbuf, uuid); + mtd_images[off_img].start = bank_offset + image_offset; + mtd_images[off_img].size = image_size; + mtd_images[off_img].bank_num = bank_num; + mtd_images[off_img].image_num = image_num; + strcpy(mtd_images[off_img].uuidbuf, uuid); log_debug("\tImage%d: %s @0x%x\n\n", image_num, uuid, bank_offset + image_offset); off_img++; @@ -246,8 +252,21 @@ static int fwu_mdata_mtd_of_to_plat(struct udevice *dev) static int fwu_mdata_mtd_probe(struct udevice *dev) { - /* Ensure the metadata can be read. */ - return fwu_get_mdata(NULL); + u8 nbanks; + u16 nimages; + int ret; + + ret = get_fwu_mdata_dev(dev); + if (ret) + return ret; + + nbanks = CONFIG_FWU_NUM_BANKS; + nimages = CONFIG_FWU_NUM_IMAGES_PER_BANK; + ret = fwu_mtd_image_info_populate(dev, nbanks, nimages); + if (ret) + return ret; + + return 0; } static struct fwu_mdata_ops fwu_mtd_ops = { @@ -266,6 +285,5 @@ U_BOOT_DRIVER(fwu_mdata_mtd) = { .of_match = fwu_mdata_ids, .ops = &fwu_mtd_ops, .probe = fwu_mdata_mtd_probe, - .of_to_plat = fwu_mdata_mtd_of_to_plat, .priv_auto = sizeof(struct fwu_mdata_mtd_priv), }; diff --git a/include/fwu.h b/include/fwu.h index 1815bd0064c..6c4d218e13a 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -26,6 +26,15 @@ struct fwu_mtd_image_info { char uuidbuf[UUID_STR_LEN + 1]; }; +struct fwu_mdata_mtd_priv { + struct mtd_info *mtd; + char pri_label[50]; + char sec_label[50]; + u32 pri_offset; + u32 sec_offset; + struct fwu_mtd_image_info *fwu_mtd_images; +}; + struct fwu_mdata_ops { /** * read_mdata() - Populate the asked FWU metadata copy -- cgit v1.3.1 From 48d9325303d97751e47c6f8abed2cd59a0edc2a6 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 22 Mar 2024 16:27:18 +0530 Subject: fwu: metadata: add support for version 2 of the structure Add support for version 2 of the FWU metadata structure. The top level structure is kept separate through a config symbol. Most of the fields, primarily used for providing information on updatable images are common across the two versions. Also change a few existing structure members used for image identification to reflect the fact that these are GUIDs, and not UUIDs. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek --- include/fwu_mdata.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/fwu_mdata.h b/include/fwu_mdata.h index 56189e2f40a..d2521f39b42 100644 --- a/include/fwu_mdata.h +++ b/include/fwu_mdata.h @@ -11,7 +11,7 @@ /** * struct fwu_image_bank_info - firmware image information - * @image_uuid: Guid value of the image in this bank + * @image_guid: Guid value of the image in this bank * @accepted: Acceptance status of the image * @reserved: Reserved * @@ -20,15 +20,15 @@ * acceptance status */ struct fwu_image_bank_info { - efi_guid_t image_uuid; + efi_guid_t image_guid; uint32_t accepted; uint32_t reserved; } __packed; /** * struct fwu_image_entry - information for a particular type of image - * @image_type_uuid: Guid value for identifying the image type - * @location_uuid: Guid of the storage volume where the image is located + * @image_type_guid: Guid value for identifying the image type + * @location_guid: 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 @@ -36,11 +36,35 @@ struct fwu_image_bank_info { * information per bank. */ struct fwu_image_entry { - efi_guid_t image_type_uuid; - efi_guid_t location_uuid; + efi_guid_t image_type_guid; + efi_guid_t location_guid; struct fwu_image_bank_info img_bank_info[CONFIG_FWU_NUM_BANKS]; } __packed; +/** + * struct fwu_fw_store_desc - FWU updatable image information + * @num_banks: Number of firmware banks + * @num_images: Number of images per bank + * @img_entry_size: The size of the img_entry array + * @bank_info_entry_size: The size of the img_bank_info array + * @img_entry: Array of image entries each giving information on a image + * + * This image descriptor structure contains information on the number of + * updatable banks and images per bank. It also gives the total sizes of + * the fwu_image_entry and fwu_image_bank_info arrays. This structure is + * only present in version 2 of the metadata structure. + */ +struct fwu_fw_store_desc { + uint8_t num_banks; + uint8_t reserved; + uint16_t num_images; + uint16_t img_entry_size; + uint16_t bank_info_entry_size; + + struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK]; +} __packed; + +#if defined(CONFIG_FWU_MDATA_V1) /** * struct fwu_mdata - FWU metadata structure for multi-bank updates * @crc32: crc32 value for the FWU metadata @@ -65,4 +89,39 @@ struct fwu_mdata { struct fwu_image_entry img_entry[CONFIG_FWU_NUM_IMAGES_PER_BANK]; } __packed; +#else /* CONFIG_FWU_MDATA_V1 */ +/** + * 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 + * @metadata_size: Size of the entire metadata structure, including the + * image descriptors + * @desc_offset: The offset from the start of this structure where the + * image descriptor structure starts. 0 if absent + * @bank_state: State of each bank, valid, invalid or accepted + * @fw_desc: The structure describing the FWU updatable images + * + * This is the top level structure used to store all information for performing + * multi bank updates on the platform. This contains info on the bank being + * used to boot along with the information on state of individual banks. + */ +struct fwu_mdata { + uint32_t crc32; + uint32_t version; + uint32_t active_index; + uint32_t previous_active_index; + uint32_t metadata_size; + uint16_t desc_offset; + uint16_t reserved1; + uint8_t bank_state[4]; + uint32_t reserved2; + + // struct fwu_fw_store_desc fw_desc; +} __packed; + +#endif /* CONFIG_FWU_MDATA_V1 */ + #endif /* _FWU_MDATA_H_ */ -- cgit v1.3.1 From 1cafc2ab8d1e9da4d253442aa719895131c0901e Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 22 Mar 2024 16:27:19 +0530 Subject: fwu: metadata: add a version agnostic structure The FWU specification now has two versions of the FWU metadata structure, and both are to be supported. Introduce a version agnostic structure for storing information about the FWU updatable images. This allows for a split of common version agnostic FWU code and version specific code. The version specific code is then responsible for arranging the data as per the corresponding metadata structure before it gets written to the metadata partitions. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek --- include/fwu.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'include') diff --git a/include/fwu.h b/include/fwu.h index 6c4d218e13a..e681e910274 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -35,6 +36,23 @@ struct fwu_mdata_mtd_priv { struct fwu_mtd_image_info *fwu_mtd_images; }; +struct fwu_data { + uint32_t crc32; + uint32_t version; + uint32_t active_index; + uint32_t previous_active_index; + uint32_t metadata_size; + uint32_t boot_index; + uint32_t num_banks; + uint32_t num_images; + uint8_t bank_state[4]; + bool trial_state; + + struct fwu_mdata *fwu_mdata; + + struct fwu_image_entry fwu_images[CONFIG_FWU_NUM_IMAGES_PER_BANK]; +}; + struct fwu_mdata_ops { /** * read_mdata() - Populate the asked FWU metadata copy -- cgit v1.3.1 From fba5b3fa7c473fb356ce206ad2dbfe1c3917edfa Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 22 Mar 2024 16:27:20 +0530 Subject: fwu: metadata: add functions for handling version specific metadata fields Support is being added in U-Boot for version 2 of the FWU metadata. Support for this version is to co-exist with version 1 support. To achieve this, a common, version agnostic structure has been added to keep information provided by the FWU metadata structure. Add API's to handle the version specific FWU metadata fields. The version agnostic structure gets initialized at boot by reading the FWU metadata. Updates to the FWU metadata result in the API's getting called to populate the version specific fields of the strucure, before the metadata gets written to the storage media. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek --- include/fwu.h | 57 +++++++++++ lib/fwu_updates/fwu_v1.c | 167 ++++++++++++++++++++++++++++++ lib/fwu_updates/fwu_v2.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 484 insertions(+) create mode 100644 lib/fwu_updates/fwu_v1.c create mode 100644 lib/fwu_updates/fwu_v2.c (limited to 'include') diff --git a/include/fwu.h b/include/fwu.h index e681e910274..082b5481d1e 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -313,4 +313,61 @@ int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd); */ int fwu_mtd_get_alt_num(efi_guid_t *image_guid, u8 *alt_num, const char *mtd_dev); +/** + * fwu_populate_mdata_image_info() - Populate the image information + * of the metadata + * @data: Version agnostic FWU metadata information + * + * Populate the image information in the FWU metadata by copying it + * from the version agnostic structure. This is done before the + * metadata gets written to the storage media. + * + * Return: None + */ +void fwu_populate_mdata_image_info(struct fwu_data *data); + +/** + * fwu_get_mdata_size() - Get the FWU metadata size + * @mdata_size: Size of the metadata structure + * + * Get the size of the FWU metadata from the structure. This is later used + * to allocate memory for the structure. + * + * Return: 0 if OK, -ve on error + */ +int fwu_get_mdata_size(uint32_t *mdata_size); + +/** + * fwu_state_machine_updates() - Update FWU state of the platform + * @trial_state: Is platform transitioning into Trial State + * @update_index: Bank number to which images have been updated + * + * On successful completion of updates, transition the platform to + * either Trial State or Regular State. + * + * To transition the platform to Trial State, start the + * TrialStateCtr counter, followed by setting the value of bank_state + * field of the metadata to Valid state(applicable only in version 2 + * of metadata). + * + * In case, the platform is to transition directly to Regular State, + * update the bank_state field of the metadata to Accepted + * state(applicable only in version 2 of metadata). + * + * Return: 0 if OK, -ve on error + */ +int fwu_state_machine_updates(bool trial_state, uint32_t update_index); + +/** + * fwu_init() - FWU specific initialisations + * + * Carry out some FWU specific initialisations including allocation + * of memory for the metadata copies, and reading the FWU metadata + * copies into the allocated memory. The metadata fields are then + * copied into a version agnostic structure. + * + * Return: 0 if OK, -ve on error + */ +int fwu_init(void); + #endif /* _FWU_H_ */ diff --git a/lib/fwu_updates/fwu_v1.c b/lib/fwu_updates/fwu_v1.c new file mode 100644 index 00000000000..efb8d515008 --- /dev/null +++ b/lib/fwu_updates/fwu_v1.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024, Linaro Limited + */ + +#include +#include + +#include + +#define FWU_MDATA_VERSION 0x1U + +static uint32_t fwu_check_trial_state(struct fwu_mdata *mdata, uint32_t bank) +{ + u32 i; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_bank_info; + + img_entry = &mdata->img_entry[0]; + for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) { + img_bank_info = &img_entry[i].img_bank_info[bank]; + if (!img_bank_info->accepted) { + return 1; + } + } + + return 0; +} + +static void fwu_data_init(void) +{ + size_t image_info_size; + void *dst_img_info, *src_img_info; + struct fwu_data *data = fwu_get_data(); + struct fwu_mdata *mdata = data->fwu_mdata; + + data->crc32 = mdata->crc32; + data->version = mdata->version; + data->active_index = mdata->active_index; + data->previous_active_index = mdata->previous_active_index; + + data->metadata_size = sizeof(struct fwu_mdata); + data->num_banks = CONFIG_FWU_NUM_BANKS; + data->num_images = CONFIG_FWU_NUM_IMAGES_PER_BANK; + fwu_plat_get_bootidx(&data->boot_index); + data->trial_state = fwu_check_trial_state(mdata, data->boot_index); + + src_img_info = &mdata->img_entry[0]; + dst_img_info = &data->fwu_images[0]; + image_info_size = sizeof(data->fwu_images); + + memcpy(dst_img_info, src_img_info, image_info_size); +} + +static int fwu_trial_state_update(bool trial_state) +{ + int ret; + struct fwu_data *data = fwu_get_data(); + + if (trial_state) { + ret = fwu_trial_state_ctr_start(); + if (ret) + return ret; + } + + data->trial_state = trial_state; + + return 0; +} + +/** + * fwu_populate_mdata_image_info() - Populate the image information + * of the metadata + * @data: Version agnostic FWU metadata information + * + * Populate the image information in the FWU metadata by copying it + * from the version agnostic structure. This is done before the + * metadata gets written to the storage media. + * + * Return: None + */ +void fwu_populate_mdata_image_info(struct fwu_data *data) +{ + size_t image_info_size; + void *dst_img_info, *src_img_info; + struct fwu_mdata *mdata = data->fwu_mdata; + + image_info_size = sizeof(data->fwu_images); + dst_img_info = &mdata->img_entry[0]; + src_img_info = &data->fwu_images[0]; + + memcpy(dst_img_info, src_img_info, image_info_size); +} + +/** + * fwu_state_machine_updates() - Update FWU state of the platform + * @trial_state: Is platform transitioning into Trial State + * @update_index: Bank number to which images have been updated + * + * On successful completion of updates, transition the platform to + * either Trial State or Regular State. + * + * To transition the platform to Trial State, start the + * TrialStateCtr counter, followed by setting the value of bank_state + * field of the metadata to Valid state(applicable only in version 2 + * of metadata). + * + * In case, the platform is to transition directly to Regular State, + * update the bank_state field of the metadata to Accepted + * state(applicable only in version 2 of metadata). + * + * Return: 0 if OK, -ve on error + */ +int fwu_state_machine_updates(bool trial_state, + __maybe_unused uint32_t update_index) +{ + return fwu_trial_state_update(trial_state); +} + +/** + * fwu_get_mdata_size() - Get the FWU metadata size + * @mdata_size: Size of the metadata structure + * + * Get the size of the FWU metadata. + * + * Return: 0 if OK, -ve on error + */ +int fwu_get_mdata_size(uint32_t *mdata_size) +{ + *mdata_size = sizeof(struct fwu_mdata); + + return 0; +} + +/** + * fwu_init() - FWU specific initialisations + * + * Carry out some FWU specific initialisations including allocation + * of memory for the metadata copies, and reading the FWU metadata + * copies into the allocated memory. The metadata fields are then + * copied into a version agnostic structure. + * + * Return: 0 if OK, -ve on error + */ +int fwu_init(void) +{ + int ret; + uint32_t mdata_size; + + fwu_get_mdata_size(&mdata_size); + + ret = fwu_mdata_copies_allocate(mdata_size); + if (ret) + return ret; + + /* + * Now read the entire structure, both copies, and + * validate that the copies. + */ + ret = fwu_get_mdata(NULL); + if (ret) + return ret; + + fwu_data_init(); + + return 0; +} diff --git a/lib/fwu_updates/fwu_v2.c b/lib/fwu_updates/fwu_v2.c new file mode 100644 index 00000000000..108bc9bb4ac --- /dev/null +++ b/lib/fwu_updates/fwu_v2.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024, Linaro Limited + */ + +#include +#include +#include + +#include + +#define FWU_MDATA_VERSION 0x2U + +static inline struct fwu_fw_store_desc *fwu_get_fw_desc(struct fwu_mdata *mdata) +{ + return (struct fwu_fw_store_desc *)((u8 *)mdata + sizeof(*mdata)); +} + +static uint32_t fwu_check_trial_state(struct fwu_mdata *mdata, uint32_t bank) +{ + return mdata->bank_state[bank] == FWU_BANK_VALID ? 1 : 0; +} + +static void fwu_data_init(void) +{ + int i; + size_t image_info_size; + void *dst_img_info, *src_img_info; + struct fwu_data *data = fwu_get_data(); + struct fwu_mdata *mdata = data->fwu_mdata; + + data->crc32 = mdata->crc32; + data->version = mdata->version; + data->active_index = mdata->active_index; + data->previous_active_index = mdata->previous_active_index; + data->metadata_size = mdata->metadata_size; + fwu_plat_get_bootidx(&data->boot_index); + data->trial_state = fwu_check_trial_state(mdata, data->boot_index); + + data->num_banks = fwu_get_fw_desc(mdata)->num_banks; + data->num_images = fwu_get_fw_desc(mdata)->num_images; + + for (i = 0; i < 4; i++) { + data->bank_state[i] = mdata->bank_state[i]; + } + + image_info_size = sizeof(data->fwu_images); + src_img_info = &fwu_get_fw_desc(mdata)->img_entry[0]; + dst_img_info = &data->fwu_images[0]; + + memcpy(dst_img_info, src_img_info, image_info_size); +} + +static int fwu_mdata_sanity_checks(void) +{ + uint8_t num_banks; + uint16_t num_images; + struct fwu_data *data = fwu_get_data(); + struct fwu_mdata *mdata = data->fwu_mdata; + + if (mdata->version != FWU_MDATA_VERSION) { + log_err("FWU metadata version %u. Expected value of %u\n", + mdata->version, FWU_MDATA_VERSION); + return -EINVAL; + } + + if (!mdata->desc_offset) { + log_err("No image information provided with the Metadata. "); + log_err("Image information expected in the metadata\n"); + return -EINVAL; + } + + if (mdata->desc_offset != 0x20) { + log_err("Descriptor Offset(0x%x) in the FWU Metadata not equal to 0x20\n", + mdata->desc_offset); + return -EINVAL; + } + + num_banks = fwu_get_fw_desc(mdata)->num_banks; + num_images = fwu_get_fw_desc(mdata)->num_images; + + if (num_banks != CONFIG_FWU_NUM_BANKS) { + log_err("Number of Banks(%u) in FWU Metadata different from the configured value(%d)", + num_banks, CONFIG_FWU_NUM_BANKS); + return -EINVAL; + } + + if (num_images != CONFIG_FWU_NUM_IMAGES_PER_BANK) { + log_err("Number of Images(%u) in FWU Metadata different from the configured value(%d)", + num_images, CONFIG_FWU_NUM_IMAGES_PER_BANK); + return -EINVAL; + } + + return 0; +} + +static int fwu_bank_state_update(bool trial_state, uint32_t bank) +{ + int ret; + struct fwu_data *data = fwu_get_data(); + struct fwu_mdata *mdata = data->fwu_mdata; + + mdata->bank_state[bank] = data->bank_state[bank] = trial_state ? + FWU_BANK_VALID : FWU_BANK_ACCEPTED; + + ret = fwu_sync_mdata(mdata, BOTH_PARTS); + if (ret) + log_err("Unable to set bank_state for bank %u\n", bank); + else + data->trial_state = trial_state; + + return ret; +} + +static int fwu_trial_state_start(uint update_index) +{ + int ret; + + ret = fwu_trial_state_ctr_start(); + if (ret) + return ret; + + ret = fwu_bank_state_update(1, update_index); + if (ret) + return ret; + + return 0; +} + +/** + * fwu_populate_mdata_image_info() - Populate the image information + * of the metadata + * @data: Version agnostic FWU metadata information + * + * Populate the image information in the FWU metadata by copying it + * from the version agnostic structure. This is done before the + * metadata gets written to the storage media. + * + * Return: None + */ +void fwu_populate_mdata_image_info(struct fwu_data *data) +{ + size_t image_info_size; + struct fwu_mdata *mdata = data->fwu_mdata; + void *dst_img_info, *src_img_info; + + image_info_size = sizeof(data->fwu_images); + dst_img_info = &fwu_get_fw_desc(mdata)->img_entry[0]; + src_img_info = &data->fwu_images[0]; + + memcpy(dst_img_info, src_img_info, image_info_size); +} + +/** + * fwu_state_machine_updates() - Update FWU state of the platform + * @trial_state: Is platform transitioning into Trial State + * @update_index: Bank number to which images have been updated + * + * On successful completion of updates, transition the platform to + * either Trial State or Regular State. + * + * To transition the platform to Trial State, start the + * TrialStateCtr counter, followed by setting the value of bank_state + * field of the metadata to Valid state(applicable only in version 2 + * of metadata). + * + * In case, the platform is to transition directly to Regular State, + * update the bank_state field of the metadata to Accepted + * state(applicable only in version 2 of metadata). + * + * Return: 0 if OK, -ve on error + */ +int fwu_state_machine_updates(bool trial_state, uint32_t update_index) +{ + return trial_state ? fwu_trial_state_start(update_index) : + fwu_bank_state_update(0, update_index); +} + +/** + * fwu_get_mdata_size() - Get the FWU metadata size + * @mdata_size: Size of the metadata structure + * + * Get the size of the FWU metadata from the structure. This is later used + * to allocate memory for the structure. + * + * Return: 0 if OK, -ve on error + */ +int fwu_get_mdata_size(uint32_t *mdata_size) +{ + int ret = 0; + struct fwu_mdata mdata = { 0 }; + struct fwu_data *data = fwu_get_data(); + struct udevice *fwu_dev = fwu_get_dev(); + + if (data->metadata_size) { + *mdata_size = data->metadata_size; + return 0; + } + + ret = fwu_read_mdata(fwu_dev, &mdata, 1, + sizeof(struct fwu_mdata)); + if (ret) { + log_err("FWU metadata read failed\n"); + return ret; + } + + *mdata_size = mdata.metadata_size; + if (!*mdata_size) + return -EINVAL; + + return 0; +} + +/** + * fwu_init() - FWU specific initialisations + * + * Carry out some FWU specific initialisations including allocation + * of memory for the metadata copies, and reading the FWU metadata + * copies into the allocated memory. The metadata fields are then + * copied into a version agnostic structure. + * + * Return: 0 if OK, -ve on error + */ +int fwu_init(void) +{ + int ret; + struct fwu_mdata mdata = { 0 }; + struct udevice *fwu_dev = fwu_get_dev(); + + /* + * First we read only the top level structure + * and get the size of the complete structure. + */ + ret = fwu_read_mdata(fwu_dev, &mdata, 1, + sizeof(struct fwu_mdata)); + if (ret) { + log_err("FWU metadata read failed\n"); + return ret; + } + + ret = fwu_mdata_copies_allocate(mdata.metadata_size); + if (ret) + return ret; + + /* + * Now read the entire structure, both copies, and + * validate that the copies. + */ + ret = fwu_get_mdata(NULL); + if (ret) + return ret; + + ret = fwu_mdata_sanity_checks(); + if (ret) + return ret; + + fwu_data_init(); + + return 0; +} -- cgit v1.3.1 From ac62e0b62e02be0bb8c5f0d0dd49fa9bda91d5c5 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 22 Mar 2024 16:27:21 +0530 Subject: fwu: make changes to access version agnostic structure fields With addition of support for version 2 of the FWU metadata structure, the metadata information is collected into a version agnostic structure. Make changes to the FWU functions so that the information that was earlier obtained by reading the metadata structure is now obtained through this version agnostic structure. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek --- include/fwu.h | 49 +++++++++++- lib/fwu_updates/fwu.c | 204 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 186 insertions(+), 67 deletions(-) (limited to 'include') diff --git a/include/fwu.h b/include/fwu.h index 082b5481d1e..77ec65e6180 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -79,9 +79,18 @@ struct fwu_mdata_ops { bool primary, uint32_t size); }; -#define FWU_MDATA_VERSION 0x1 #define FWU_IMAGE_ACCEPTED 0x1 +#define FWU_BANK_INVALID (uint8_t)0xFF +#define FWU_BANK_VALID (uint8_t)0xFE +#define FWU_BANK_ACCEPTED (uint8_t)0xFC + +enum { + PRIMARY_PART = 1, + SECONDARY_PART, + BOTH_PARTS, +}; + /* * GUID value defined in the FWU specification for identification * of the FWU metadata partition. @@ -313,6 +322,44 @@ int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd); */ int fwu_mtd_get_alt_num(efi_guid_t *image_guid, u8 *alt_num, const char *mtd_dev); +/** + * fwu_mdata_copies_allocate() - Allocate memory for metadata + * @mdata_size: Size of the metadata structure + * + * Allocate memory for storing both the copies of the FWU metadata. The + * copies are then used as a cache for storing FWU metadata contents. + * + * Return: 0 if OK, -ve on error + */ +int fwu_mdata_copies_allocate(u32 mdata_size); + +/** + * fwu_get_dev() - Return the FWU metadata device + * + * Return the pointer to the FWU metadata device. + * + * Return: Pointer to the FWU metadata dev + */ +struct udevice *fwu_get_dev(void); + +/** + * fwu_get_data() - Return the version agnostic FWU structure + * + * Return the pointer to the version agnostic FWU structure. + * + * Return: Pointer to the FWU data structure + */ +struct fwu_data *fwu_get_data(void); + +/** + * fwu_sync_mdata() - Update given meta-data partition(s) with the copy provided + * @data: FWU Data structure + * @part: Bitmask of FWU metadata partitions to be written to + * + * Return: 0 if OK, -ve on error + */ +int fwu_sync_mdata(struct fwu_mdata *mdata, int part); + /** * fwu_populate_mdata_image_info() - Populate the image information * of the metadata diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index 86518108c2d..5dfea2a4d8d 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -17,7 +18,7 @@ #include -static struct fwu_mdata g_mdata; /* = {0} makes uninit crc32 always invalid */ +struct fwu_data g_fwu_data; static struct udevice *g_dev; static u8 in_trial; static u8 boottime_check; @@ -27,12 +28,6 @@ enum { IMAGE_ACCEPT_CLEAR, }; -enum { - PRIMARY_PART = 1, - SECONDARY_PART, - BOTH_PARTS, -}; - static int trial_counter_update(u16 *trial_state_ctr) { bool delete; @@ -106,23 +101,9 @@ out: return ret; } -static int in_trial_state(struct fwu_mdata *mdata) +static u32 in_trial_state(void) { - u32 i, active_bank; - struct fwu_image_entry *img_entry; - struct fwu_image_bank_info *img_bank_info; - - active_bank = mdata->active_index; - img_entry = &mdata->img_entry[0]; - for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) { - img_bank_info = &img_entry[i].img_bank_info[active_bank]; - if (!img_bank_info->accepted) { - log_info("System booting in Trial State\n"); - return 1; - } - } - - return 0; + return g_fwu_data.trial_state; } static int fwu_get_image_type_id(u8 image_index, efi_guid_t *image_type_id) @@ -141,17 +122,70 @@ static int fwu_get_image_type_id(u8 image_index, efi_guid_t *image_type_id) return -ENOENT; } +static int mdata_crc_check(struct fwu_mdata *mdata) +{ + int ret; + u32 calc_crc32; + uint32_t mdata_size; + void *buf = &mdata->version; + + ret = fwu_get_mdata_size(&mdata_size); + if (ret) + return ret; + + calc_crc32 = crc32(0, buf, mdata_size - sizeof(u32)); + return calc_crc32 == mdata->crc32 ? 0 : -EINVAL; +} + +static void fwu_data_crc_update(uint32_t crc32) +{ + g_fwu_data.crc32 = crc32; +} + +/** + * fwu_get_data() - Return the version agnostic FWU structure + * + * Return the pointer to the version agnostic FWU structure. + * + * Return: Pointer to the FWU data structure + */ +struct fwu_data *fwu_get_data(void) +{ + return &g_fwu_data; +} + +static void fwu_populate_mdata_bank_index(struct fwu_data *fwu_data) +{ + struct fwu_mdata *mdata = fwu_data->fwu_mdata; + + mdata->active_index = fwu_data->active_index; + mdata->previous_active_index = fwu_data->previous_active_index; +} + +/** + * fwu_get_dev() - Return the FWU metadata device + * + * Return the pointer to the FWU metadata device. + * + * Return: Pointer to the FWU metadata dev + */ +struct udevice *fwu_get_dev(void) +{ + return g_dev; +} + /** * fwu_sync_mdata() - Update given meta-data partition(s) with the copy provided - * @mdata: FWU metadata structure + * @data: FWU Data structure * @part: Bitmask of FWU metadata partitions to be written to * * Return: 0 if OK, -ve on error */ -static int fwu_sync_mdata(struct fwu_mdata *mdata, int part) +int fwu_sync_mdata(struct fwu_mdata *mdata, int part) { - void *buf = &mdata->version; int err; + uint mdata_size; + void *buf = &mdata->version; if (part == BOTH_PARTS) { err = fwu_sync_mdata(mdata, SECONDARY_PART); @@ -160,32 +194,53 @@ static int fwu_sync_mdata(struct fwu_mdata *mdata, int part) part = PRIMARY_PART; } + err = fwu_get_mdata_size(&mdata_size); + if (err) + return err; + /* * Calculate the crc32 for the updated FWU metadata * and put the updated value in the FWU metadata crc32 * field */ - mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); + mdata->crc32 = crc32(0, buf, mdata_size - sizeof(u32)); + fwu_data_crc_update(mdata->crc32); - err = fwu_write_mdata(g_dev, mdata, part == PRIMARY_PART); + err = fwu_write_mdata(g_dev, mdata, part == PRIMARY_PART, mdata_size); if (err) { log_err("Unable to write %s mdata\n", part == PRIMARY_PART ? "primary" : "secondary"); return err; } - /* update the cached copy of meta-data */ - memcpy(&g_mdata, mdata, sizeof(struct fwu_mdata)); - return 0; } -static inline int mdata_crc_check(struct fwu_mdata *mdata) +/** + * fwu_mdata_copies_allocate() - Allocate memory for metadata + * @mdata_size: Size of the metadata structure + * + * Allocate memory for storing both the copies of the FWU metadata. The + * copies are then used as a cache for storing FWU metadata contents. + * + * Return: 0 if OK, -ve on error + */ +int fwu_mdata_copies_allocate(u32 mdata_size) { - void *buf = &mdata->version; - u32 calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32)); + if (g_fwu_data.fwu_mdata) + return 0; - return calc_crc32 == mdata->crc32 ? 0 : -EINVAL; + /* + * Allocate the total memory that would be needed for both + * the copies. + */ + g_fwu_data.fwu_mdata = calloc(2, mdata_size); + if (!g_fwu_data.fwu_mdata) { + log_err("Unable to allocate space for FWU metadata\n"); + return -ENOMEM; + } + + return 0; } /** @@ -201,21 +256,33 @@ static inline int mdata_crc_check(struct fwu_mdata *mdata) int fwu_get_mdata(struct fwu_mdata *mdata) { int err; + uint32_t mdata_size; bool parts_ok[2] = { false }; - struct fwu_mdata s, *parts_mdata[2]; + struct fwu_mdata *parts_mdata[2]; - parts_mdata[0] = &g_mdata; - parts_mdata[1] = &s; + err = fwu_get_mdata_size(&mdata_size); + if (err) + return err; + + parts_mdata[0] = g_fwu_data.fwu_mdata; + if (!parts_mdata[0]) { + log_err("Memory not allocated for the FWU Metadata copies\n"); + return -ENOMEM; + } + + parts_mdata[1] = (struct fwu_mdata *)((char *)parts_mdata[0] + + mdata_size); /* if mdata already read and ready */ err = mdata_crc_check(parts_mdata[0]); if (!err) goto ret_mdata; - /* else read, verify and, if needed, fix mdata */ + + /* else read, verify and, if needed, fix mdata */ for (int i = 0; i < 2; i++) { parts_ok[i] = false; - err = fwu_read_mdata(g_dev, parts_mdata[i], !i); + err = fwu_read_mdata(g_dev, parts_mdata[i], !i, mdata_size); if (!err) { err = mdata_crc_check(parts_mdata[i]); if (!err) @@ -230,7 +297,7 @@ int fwu_get_mdata(struct fwu_mdata *mdata) * Before returning, check that both the * FWU metadata copies are the same. */ - err = memcmp(parts_mdata[0], parts_mdata[1], sizeof(struct fwu_mdata)); + err = memcmp(parts_mdata[0], parts_mdata[1], mdata_size); if (!err) goto ret_mdata; @@ -247,7 +314,7 @@ int fwu_get_mdata(struct fwu_mdata *mdata) if (parts_ok[i]) continue; - memcpy(parts_mdata[i], parts_mdata[1 - i], sizeof(struct fwu_mdata)); + memcpy(parts_mdata[i], parts_mdata[1 - i], mdata_size); err = fwu_sync_mdata(parts_mdata[i], i ? SECONDARY_PART : PRIMARY_PART); if (err) { log_debug("mdata : %s write failed\n", i ? "secondary" : "primary"); @@ -257,7 +324,7 @@ int fwu_get_mdata(struct fwu_mdata *mdata) ret_mdata: if (!err && mdata) - memcpy(mdata, parts_mdata[0], sizeof(struct fwu_mdata)); + memcpy(mdata, parts_mdata[0], mdata_size); return err; } @@ -275,13 +342,13 @@ ret_mdata: int fwu_get_active_index(uint *active_idx) { int ret = 0; - struct fwu_mdata *mdata = &g_mdata; + struct fwu_data *data = &g_fwu_data; /* * Found the FWU metadata partition, now read the active_index * value */ - *active_idx = mdata->active_index; + *active_idx = data->active_index; if (*active_idx >= CONFIG_FWU_NUM_BANKS) { log_debug("Active index value read is incorrect\n"); ret = -EINVAL; @@ -302,7 +369,7 @@ int fwu_get_active_index(uint *active_idx) int fwu_set_active_index(uint active_idx) { int ret; - struct fwu_mdata *mdata = &g_mdata; + struct fwu_data *data = &g_fwu_data; if (active_idx >= CONFIG_FWU_NUM_BANKS) { log_debug("Invalid active index value\n"); @@ -313,14 +380,16 @@ int fwu_set_active_index(uint active_idx) * 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; + data->previous_active_index = data->active_index; + data->active_index = active_idx; + + fwu_populate_mdata_bank_index(data); /* * Now write this updated FWU metadata to both the * FWU metadata partitions */ - ret = fwu_sync_mdata(mdata, BOTH_PARTS); + ret = fwu_sync_mdata(data->fwu_mdata, BOTH_PARTS); if (ret) { log_debug("Failed to update FWU metadata partitions\n"); ret = -EIO; @@ -346,7 +415,7 @@ int fwu_get_dfu_alt_num(u8 image_index, u8 *alt_num) int ret, i; uint update_bank; efi_guid_t *image_guid, image_type_id; - struct fwu_mdata *mdata = &g_mdata; + struct fwu_data *data = &g_fwu_data; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info; @@ -365,15 +434,15 @@ int fwu_get_dfu_alt_num(u8 image_index, u8 *alt_num) ret = -EINVAL; /* - * The FWU metadata has been read. Now get the image_uuid for the + * The FWU metadata has been read. Now get the image_guid 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]; + &data->fwu_images[i].image_type_guid)) { + img_entry = &data->fwu_images[i]; img_bank_info = &img_entry->img_bank_info[update_bank]; - image_guid = &img_bank_info->image_uuid; + image_guid = &img_bank_info->image_guid; ret = fwu_plat_get_alt_num(g_dev, image_guid, alt_num); if (ret) log_debug("alt_num not found for partition with GUID %pUs\n", @@ -407,21 +476,23 @@ int fwu_revert_boot_index(void) { int ret; u32 cur_active_index; - struct fwu_mdata *mdata = &g_mdata; + struct fwu_data *data = &g_fwu_data; /* * 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; + cur_active_index = data->active_index; + data->active_index = data->previous_active_index; + data->previous_active_index = cur_active_index; + + fwu_populate_mdata_bank_index(data); /* * Now write this updated FWU metadata to both the * FWU metadata partitions */ - ret = fwu_sync_mdata(mdata, BOTH_PARTS); + ret = fwu_sync_mdata(data->fwu_mdata, BOTH_PARTS); if (ret) { log_debug("Failed to update FWU metadata partitions\n"); ret = -EIO; @@ -448,20 +519,21 @@ int fwu_revert_boot_index(void) static int fwu_clrset_image_accept(efi_guid_t *img_type_id, u32 bank, u8 action) { int ret, i; - struct fwu_mdata *mdata = &g_mdata; + struct fwu_data *data = &g_fwu_data; struct fwu_image_entry *img_entry; struct fwu_image_bank_info *img_bank_info; - img_entry = &mdata->img_entry[0]; + img_entry = &data->fwu_images[0]; for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) { - if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) { + if (!guidcmp(&img_entry[i].image_type_guid, img_type_id)) { img_bank_info = &img_entry[i].img_bank_info[bank]; if (action == IMAGE_ACCEPT_SET) img_bank_info->accepted |= FWU_IMAGE_ACCEPTED; else img_bank_info->accepted = 0; - ret = fwu_sync_mdata(mdata, BOTH_PARTS); + fwu_populate_mdata_image_info(data); + ret = fwu_sync_mdata(data->fwu_mdata, BOTH_PARTS); goto out; } } @@ -627,9 +699,9 @@ static int fwu_boottime_checks(void) return 0; } - ret = fwu_get_mdata(NULL); + ret = fwu_init(); if (ret) { - log_debug("Unable to read meta-data\n"); + log_debug("fwu_init() failed\n"); return ret; } @@ -665,7 +737,7 @@ static int fwu_boottime_checks(void) if (efi_init_obj_list() != EFI_SUCCESS) return 0; - in_trial = in_trial_state(&g_mdata); + in_trial = in_trial_state(); if (!in_trial || (ret = fwu_trial_count_update()) > 0) ret = trial_counter_update(NULL); -- cgit v1.3.1