mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
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:
@@ -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_ */
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user