diff options
author | Tom Rini <trini@konsulko.com> | 2024-09-19 11:25:26 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2024-09-19 11:25:26 -0600 |
commit | 2ac0a302ada6b1d0d9a2a137fd790ccd4f8d2090 (patch) | |
tree | dc529cd1f3c14da2c028833bb501a4a6ddf1d9f1 | |
parent | c17805e19b9335e1fb5295c81b59eddf88d1b9ec (diff) | |
parent | 6f933aa963bb971d848ff6bd1c743035bbc98ead (diff) |
Merge tag 'fwu-next-19092024' of https://source.denx.de/u-boot/custodians/u-boot-tpm into next
This PR contains various improvements in the A/B update logic for EFI
- Read both copies of metadata, in case one of the is corrupted
- Check the metadata version against the running firmware to make sure it's
allowed
- Limit the use of a revert capsule if the board is on a trial state and
make sure it's not applied if the max counter has expired
-rw-r--r-- | include/fwu.h | 11 | ||||
-rw-r--r-- | lib/efi_loader/efi_capsule.c | 11 | ||||
-rw-r--r-- | lib/fwu_updates/Kconfig | 1 | ||||
-rw-r--r-- | lib/fwu_updates/fwu.c | 31 | ||||
-rw-r--r-- | lib/fwu_updates/fwu_v1.c | 18 | ||||
-rw-r--r-- | lib/fwu_updates/fwu_v2.c | 81 |
6 files changed, 108 insertions, 45 deletions
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/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"); 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 diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index c7fc8987beb..7f085a0211f 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; @@ -88,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", @@ -737,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; diff --git a/lib/fwu_updates/fwu_v1.c b/lib/fwu_updates/fwu_v1.c index efb8d515008..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); } /** @@ -146,6 +149,7 @@ int fwu_init(void) { int ret; uint32_t mdata_size; + struct fwu_mdata mdata = {0}; fwu_get_mdata_size(&mdata_size); @@ -157,10 +161,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; diff --git a/lib/fwu_updates/fwu_v2.c b/lib/fwu_updates/fwu_v2.c index 108bc9bb4ac..ce46904ff2e 100644 --- a/lib/fwu_updates/fwu_v2.c +++ b/lib/fwu_updates/fwu_v2.c @@ -10,6 +10,9 @@ #include <linux/types.h> #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; @@ -100,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; @@ -127,6 +115,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 +204,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 +231,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; |