From 5e9feeed8afa7ed4e26766bb15af3d2b04117f4a Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Mon, 9 Sep 2024 16:50:16 +0530 Subject: fwu: v2: try reading both copies of metadata In the version 2 of the FWU metadata, the metadata is broken into two parts, a top-level structure, which provides information on the total size of the structure among other things. Try reading the primary partition first, and if that fails, try reading the secondary partition. This will help in the scenario where the primary metadata partition has been corrupted, but the secondary partition is intact. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek Signed-off-by: Ilias Apalodimas --- lib/fwu_updates/fwu_v2.c | 78 ++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 36 deletions(-) (limited to 'lib') diff --git a/lib/fwu_updates/fwu_v2.c b/lib/fwu_updates/fwu_v2.c index 108bc9bb4ac..a055a207bf4 100644 --- a/lib/fwu_updates/fwu_v2.c +++ b/lib/fwu_updates/fwu_v2.c @@ -10,6 +10,9 @@ #include #define FWU_MDATA_VERSION 0x2U +#define FWU_IMG_DESC_OFFSET 0x20U + +static struct fwu_mdata g_mdata; static inline struct fwu_fw_store_desc *fwu_get_fw_desc(struct fwu_mdata *mdata) { @@ -58,24 +61,6 @@ static int fwu_mdata_sanity_checks(void) 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; @@ -127,6 +112,35 @@ static int fwu_trial_state_start(uint update_index) return 0; } +static bool fwu_get_mdata_mandatory(uint part) +{ + int ret = 0; + struct udevice *fwu_dev = fwu_get_dev(); + + memset(&g_mdata, 0, sizeof(struct fwu_mdata)); + + ret = fwu_read_mdata(fwu_dev, &g_mdata, + part == PRIMARY_PART ? true : false, + sizeof(struct fwu_mdata)); + if (ret) + return false; + + if (g_mdata.version != FWU_MDATA_VERSION) { + log_err("FWU partition %u has metadata version %u. Expected value of %u\n", + part, g_mdata.version, FWU_MDATA_VERSION); + return false; + } + + if (g_mdata.desc_offset != FWU_IMG_DESC_OFFSET) { + log_err("Descriptor Offset(0x%x) in the FWU Metadata partition %u not equal to 0x20\n", + g_mdata.desc_offset, part); + log_err("Image information expected in the metadata\n"); + return false; + } + + return true; +} + /** * fwu_populate_mdata_image_info() - Populate the image information * of the metadata @@ -187,24 +201,14 @@ int fwu_state_machine_updates(bool trial_state, uint32_t update_index) */ 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; + *mdata_size = g_mdata.metadata_size; if (!*mdata_size) return -EINVAL; @@ -224,21 +228,23 @@ int fwu_get_mdata_size(uint32_t *mdata_size) 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. + * Try reading the first partition first, if + * that does not work, try the secondary + * partition. The idea is, if one of the + * partitions is corrupted, it should be restored + * from the intact partition. */ - ret = fwu_read_mdata(fwu_dev, &mdata, 1, - sizeof(struct fwu_mdata)); - if (ret) { + if (!fwu_get_mdata_mandatory(PRIMARY_PART) && + !fwu_get_mdata_mandatory(SECONDARY_PART)) { log_err("FWU metadata read failed\n"); - return ret; + return -1; } - ret = fwu_mdata_copies_allocate(mdata.metadata_size); + ret = fwu_mdata_copies_allocate(g_mdata.metadata_size); if (ret) return ret; -- cgit v1.3.1 From 36811ff8275144a9fe78453023ce1b7e20bd0cf9 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Mon, 9 Sep 2024 16:50:17 +0530 Subject: fwu: v1: do a version check for the metadata Do a sanity check that the version of the FWU metadata that has been read aligns with the version enabled in the image. This allows to indicate an early failure as part of the FWU module initialisation. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek Signed-off-by: Ilias Apalodimas --- lib/fwu_updates/fwu_v1.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/fwu_updates/fwu_v1.c b/lib/fwu_updates/fwu_v1.c index efb8d515008..023e43728df 100644 --- a/lib/fwu_updates/fwu_v1.c +++ b/lib/fwu_updates/fwu_v1.c @@ -146,6 +146,7 @@ int fwu_init(void) { int ret; uint32_t mdata_size; + struct fwu_mdata mdata = {0}; fwu_get_mdata_size(&mdata_size); @@ -157,10 +158,16 @@ int fwu_init(void) * Now read the entire structure, both copies, and * validate that the copies. */ - ret = fwu_get_mdata(NULL); + ret = fwu_get_mdata(&mdata); if (ret) return ret; + if (mdata.version != 0x1) { + log_err("FWU metadata version %u. Expected value of %u\n", + mdata.version, FWU_MDATA_VERSION); + return -EINVAL; + } + fwu_data_init(); return 0; -- cgit v1.3.1 From 03392f1eb85655bf6397f6eafaeafa1f9571a77e Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Mon, 9 Sep 2024 16:50:18 +0530 Subject: fwu: check all images for transitioning out of Trial State The platform transitions out of Trial State into the Regular State only when all the images in the update bank have been accepted. Check for this condition before transitioning out of Trial State. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek Signed-off-by: Ilias Apalodimas --- include/fwu.h | 11 +++++++++++ lib/fwu_updates/fwu.c | 25 +++++++++++++++++++++++++ lib/fwu_updates/fwu_v1.c | 9 ++++++--- lib/fwu_updates/fwu_v2.c | 3 +++ 4 files changed, 45 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/include/fwu.h b/include/fwu.h index c317613eaaa..6441de370c9 100644 --- a/include/fwu.h +++ b/include/fwu.h @@ -417,4 +417,15 @@ int fwu_state_machine_updates(bool trial_state, uint32_t update_index); */ int fwu_init(void); +/** + * fwu_bank_accepted() - Has the bank been accepted + * @data: Version agnostic FWU metadata information + * @bank: Update bank to check + * + * Check in the given bank if all the images have been accepted. + * + * Return: true if all images accepted, false otherwise + */ +bool fwu_bank_accepted(struct fwu_data *data, uint32_t bank); + #endif /* _FWU_H_ */ diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index c7fc8987beb..a94a769a2b6 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -28,6 +28,31 @@ enum { IMAGE_ACCEPT_CLEAR, }; +/** + * fwu_bank_accepted() - Has the bank been accepted + * @data: Version agnostic FWU metadata information + * @bank: Update bank to check + * + * Check in the given bank if all the images have been accepted. + * + * Return: true if all images accepted, false otherwise + */ +bool fwu_bank_accepted(struct fwu_data *data, uint32_t bank) +{ + u32 i; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_bank_info; + + img_entry = &data->fwu_images[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 false; + } + + return true; +} + static int trial_counter_update(u16 *trial_state_ctr) { bool delete; diff --git a/lib/fwu_updates/fwu_v1.c b/lib/fwu_updates/fwu_v1.c index 023e43728df..c311a8857a6 100644 --- a/lib/fwu_updates/fwu_v1.c +++ b/lib/fwu_updates/fwu_v1.c @@ -52,11 +52,14 @@ static void fwu_data_init(void) memcpy(dst_img_info, src_img_info, image_info_size); } -static int fwu_trial_state_update(bool trial_state) +static int fwu_trial_state_update(bool trial_state, uint32_t bank) { int ret; struct fwu_data *data = fwu_get_data(); + if (!trial_state && !fwu_bank_accepted(data, bank)) + return 0; + if (trial_state) { ret = fwu_trial_state_ctr_start(); if (ret) @@ -112,9 +115,9 @@ void fwu_populate_mdata_image_info(struct fwu_data *data) * Return: 0 if OK, -ve on error */ int fwu_state_machine_updates(bool trial_state, - __maybe_unused uint32_t update_index) + uint32_t update_index) { - return fwu_trial_state_update(trial_state); + return fwu_trial_state_update(trial_state, update_index); } /** diff --git a/lib/fwu_updates/fwu_v2.c b/lib/fwu_updates/fwu_v2.c index a055a207bf4..ce46904ff2e 100644 --- a/lib/fwu_updates/fwu_v2.c +++ b/lib/fwu_updates/fwu_v2.c @@ -85,6 +85,9 @@ static int fwu_bank_state_update(bool trial_state, uint32_t bank) struct fwu_data *data = fwu_get_data(); struct fwu_mdata *mdata = data->fwu_mdata; + if (!trial_state && !fwu_bank_accepted(data, bank)) + return 0; + mdata->bank_state[bank] = data->bank_state[bank] = trial_state ? FWU_BANK_VALID : FWU_BANK_ACCEPTED; -- cgit v1.3.1 From 1049dc7e918af23fa05cae2af3cf271a6eb119b2 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Mon, 9 Sep 2024 16:50:19 +0530 Subject: fwu: add dependency checks for selecting FWU metadata version The FWU code supports both versions of the FWU metadata, i.e. v1 and v2. A platform can then select one of the two versions through a config symbol. Put a dependency in the FWU metadata version selection config symbol to ensure that both versions of the metadata cannot be enabled. Signed-off-by: Sughosh Ganu Reviewed-by: Michal Simek Tested-by: Michal Simek Signed-off-by: Ilias Apalodimas --- lib/fwu_updates/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig index 51b7fbbefd3..a722107c129 100644 --- a/lib/fwu_updates/Kconfig +++ b/lib/fwu_updates/Kconfig @@ -40,6 +40,7 @@ config FWU_MDATA_V1 config FWU_MDATA_V2 bool "Enable support FWU Metadata version 2" + depends on !FWU_MDATA_V1 help The FWU specification supports two versions of the metadata structure. This option enables support for FWU -- cgit v1.3.1 From be281eccb053c6d44bc8298024d5b7d637631c24 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Mon, 9 Sep 2024 16:50:20 +0530 Subject: fwu: do not allow capsule processing on exceeding Trial Counter threshold When in Trial State, the platform keeps a count of the number of times it has booted in the Trial State. Once the threshold of the maximum allowed count exceeds, the platform reverts to boot from a different bank on subsequent boot, thus coming out of the Trial State. It is expected that all the updated images would be accepted or rejected while the platform is in Trial State. Put in checks so that it is not possible to apply an empty capsule once the max Trial Count exceeds. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek Signed-off-by: Ilias Apalodimas --- lib/fwu_updates/fwu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index a94a769a2b6..7f085a0211f 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -113,6 +113,8 @@ static int fwu_trial_count_update(void) ret = fwu_revert_boot_index(); if (ret) log_err("Unable to revert active_index\n"); + + trial_counter_update(NULL); ret = 1; } else { log_info("Trial State count: attempt %d out of %d\n", @@ -762,8 +764,8 @@ static int fwu_boottime_checks(void) return 0; in_trial = in_trial_state(); - if (!in_trial || (ret = fwu_trial_count_update()) > 0) - ret = trial_counter_update(NULL); + + ret = in_trial ? fwu_trial_count_update() : trial_counter_update(NULL); if (!ret) boottime_check = 1; -- cgit v1.3.1 From 6f933aa963bb971d848ff6bd1c743035bbc98ead Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Mon, 9 Sep 2024 16:50:21 +0530 Subject: fwu: print a message if empty capsule checks fail When dealing with processing of the empty capsule, the capsule gets applied only when the checks for the empty capsule pass. Print a message to highlight if empty capsule checks fail, and return an error value, similar to the normal capsules. Signed-off-by: Sughosh Ganu Tested-by: Michal Simek Signed-off-by: Ilias Apalodimas --- lib/efi_loader/efi_capsule.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index a4ea2873038..f8a4a7c6ef4 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -564,9 +564,14 @@ static efi_status_t efi_capsule_update_firmware( bool fw_accept_os; if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) { - if (fwu_empty_capsule_checks_pass() && - fwu_empty_capsule(capsule_data)) - return fwu_empty_capsule_process(capsule_data); + if (fwu_empty_capsule(capsule_data)) { + if (fwu_empty_capsule_checks_pass()) { + return fwu_empty_capsule_process(capsule_data); + } else { + log_err("FWU empty capsule checks failed. Cannot start update\n"); + return EFI_INVALID_PARAMETER; + } + } if (!fwu_update_checks_pass()) { log_err("FWU checks failed. Cannot start update\n"); -- cgit v1.3.1