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
This commit is contained in:
Tom Rini
2024-09-19 11:25:26 -06:00
6 changed files with 108 additions and 45 deletions

View File

@@ -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_ */

View File

@@ -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");

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;