Merge changes from topic "topics/fwu_metadata_v2_migration" into integration

* changes:
  style(fwu): change the metadata fields to align with specification
  style(partition): use GUID values for GPT partition fields
  feat(st): add logic to boot the platform from an alternate bank
  feat(st): add a function to clear the FWU trial state counter
  feat(fwu): add a function to obtain an alternate FWU bank to boot
  feat(fwu): add some sanity checks for the FWU metadata
  feat(fwu): modify the check for getting the FWU bank's state
  feat(st): get the state of the active bank directly
  feat(fwu): add a config flag for including image info in the FWU metadata
  feat(fwu): migrate FWU metadata structure to version 2
  feat(fwu): document the config flag for including image info in the FWU metadata
  feat(fwu): update the URL links for the FWU specification
This commit is contained in:
Manish V Badarkhe 2024-03-04 15:53:31 +01:00 committed by TrustedFirmware Code Review
commit bd435c525e
14 changed files with 260 additions and 68 deletions

View file

@ -1185,6 +1185,7 @@ $(eval $(call assert_booleans,\
COT_DESC_IN_DTB \
USE_SP804_TIMER \
PSA_FWU_SUPPORT \
PSA_FWU_METADATA_FW_STORE_DESC \
ENABLE_MPMM \
ENABLE_MPMM_FCONF \
FEATURE_DETECTION \
@ -1360,6 +1361,7 @@ $(eval $(call add_defines,\
NR_OF_FW_BANKS \
NR_OF_IMAGES_IN_FW_BANK \
PSA_FWU_SUPPORT \
PSA_FWU_METADATA_FW_STORE_DESC \
ENABLE_BRBE_FOR_NS \
ENABLE_TRBE_FOR_NS \
ENABLE_SYS_REG_TRACE_FOR_NS \

View file

@ -494,4 +494,4 @@ This is only allowed if the image is not being executed.
.. _Universally Unique Identifier: https://tools.ietf.org/rfc/rfc4122.txt
.. |Flow Diagram| image:: ../resources/diagrams/fwu_flow.png
.. |FWU state machine| image:: ../resources/diagrams/fwu_states.png
.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/latest/

View file

@ -1340,12 +1340,21 @@ Firmware update options
This flag is used in defining the firmware update metadata structure. This
flag is by default set to '1'.
- ``PSA_FWU_METADATA_FW_STORE_DESC``: To be enabled when the FWU
metadata contains image description. The default value is 1.
The version 2 of the FWU metadata allows for an opaque metadata
structure where a platform can choose to not include the firmware
store description in the metadata structure. This option indicates
if the firmware store description, which provides information on
the updatable images is part of the structure.
--------------
*Copyright (c) 2019-2024, Arm Limited. All rights reserved.*
.. _DEN0115: https://developer.arm.com/docs/den0115/latest
.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/latest/
.. _PSA DRTM specification: https://developer.arm.com/documentation/den0113/a
.. _GCC: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
.. _Clang: https://clang.llvm.org/docs/DiagnosticsReference.html

View file

@ -95,4 +95,4 @@ have previously been raised against the software.
.. _System Control and Management Interface (SCMI): http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/DEN0056A_System_Control_and_Management_Interface.pdf
.. _Software Delegated Exception Interface (SDEI): http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
.. _SMC Calling Convention: https://developer.arm.com/docs/den0028/latest
.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/a/
.. _PSA FW update specification: https://developer.arm.com/documentation/den0118/latest/

View file

@ -328,7 +328,6 @@ static int auth_nvctr(const auth_method_param_nv_ctr_t *param,
unsigned int data_len, len, i;
unsigned int plat_nv_ctr;
int rc;
bool is_trial_run = false;
/* Get the counter value from current image. The AM expects the IPM
* to return the counter value as a DER encoded integer */
@ -388,9 +387,14 @@ static int auth_nvctr(const auth_method_param_nv_ctr_t *param,
return 1;
} else if (*cert_nv_ctr > plat_nv_ctr) {
#if PSA_FWU_SUPPORT && IMAGE_BL2
is_trial_run = fwu_is_trial_run_state();
if (fwu_get_active_bank_state() == FWU_BANK_STATE_ACCEPTED) {
*need_nv_ctr_upgrade = true;
} else {
*need_nv_ctr_upgrade = false;
}
#else
*need_nv_ctr_upgrade = true;
#endif /* PSA_FWU_SUPPORT && IMAGE_BL2 */
*need_nv_ctr_upgrade = !is_trial_run;
}
return 0;

View file

@ -24,6 +24,17 @@
CASSERT((offsetof(struct fwu_metadata, crc_32) == 0),
crc_32_must_be_first_member_of_structure);
/*
* Ensure that the NR_OF_FW_BANKS selected by the platform is not
* zero and not greater than the maximum number of banks allowed
* by the specification.
*/
CASSERT((NR_OF_FW_BANKS > 0) && (NR_OF_FW_BANKS <= NR_OF_MAX_FW_BANKS),
assert_fwu_num_banks_invalid_value);
#define FWU_METADATA_VERSION 2U
#define FWU_FW_STORE_DESC_OFFSET 0x20U
static struct fwu_metadata metadata;
static bool is_metadata_initialized __unused;
@ -51,16 +62,54 @@ static int fwu_metadata_crc_check(void)
/*******************************************************************************
* Check the sanity of FWU metadata.
*
* return -1 on error, otherwise 0
* return -EINVAL on error, otherwise 0
******************************************************************************/
static int fwu_metadata_sanity_check(void)
{
/* ToDo: add more conditions for sanity check */
if ((metadata.active_index >= NR_OF_FW_BANKS) ||
(metadata.previous_active_index >= NR_OF_FW_BANKS)) {
return -1;
if (metadata.version != FWU_METADATA_VERSION) {
WARN("Incorrect FWU Metadata version of %u\n",
metadata.version);
return -EINVAL;
}
if (metadata.active_index >= NR_OF_FW_BANKS) {
WARN("Active Index value(%u) greater than the configured value(%d)",
metadata.active_index, NR_OF_FW_BANKS);
return -EINVAL;
}
if (metadata.previous_active_index >= NR_OF_FW_BANKS) {
WARN("Previous Active Index value(%u) greater than the configured value(%d)",
metadata.previous_active_index, NR_OF_FW_BANKS);
return -EINVAL;
}
#if PSA_FWU_METADATA_FW_STORE_DESC
if (metadata.fw_desc.num_banks != NR_OF_FW_BANKS) {
WARN("Number of Banks(%u) in FWU Metadata different from the configured value(%d)",
metadata.fw_desc.num_banks, NR_OF_FW_BANKS);
return -EINVAL;
}
if (metadata.fw_desc.num_images != NR_OF_IMAGES_IN_FW_BANK) {
WARN("Number of Images(%u) in FWU Metadata different from the configured value(%d)",
metadata.fw_desc.num_images, NR_OF_IMAGES_IN_FW_BANK);
return -EINVAL;
}
if (metadata.desc_offset != FWU_FW_STORE_DESC_OFFSET) {
WARN("Descriptor Offset(0x%x) in the FWU Metadata not equal to 0x20\n",
metadata.desc_offset);
return -EINVAL;
}
#else
if (metadata.desc_offset != 0U) {
WARN("Descriptor offset has non zero value of 0x%x\n",
metadata.desc_offset);
return -EINVAL;
}
#endif
return 0;
}
@ -133,28 +182,80 @@ exit:
}
/*******************************************************************************
* The system runs in the trial run state if any of the images in the active
* firmware bank has not been accepted yet.
* Check for an alternate bank for the platform to boot from. This function will
* mostly be called whenever the count of the number of times a platform boots
* in the Trial State exceeds a pre-set limit.
* The function first checks if the platform can boot from the previously active
* bank. If not, it tries to find another bank in the accepted state.
* And finally, if both the checks fail, as a last resort, it tries to find
* a valid bank.
*
* Returns true if the system is running in the trial state.
* Returns the index of a bank to boot, else returns invalid index
* INVALID_BOOT_IDX.
******************************************************************************/
bool fwu_is_trial_run_state(void)
uint32_t fwu_get_alternate_boot_bank(void)
{
bool trial_run = false;
uint32_t i;
assert(is_metadata_initialized);
/* First check if the previously active bank can be used */
if (metadata.bank_state[metadata.previous_active_index] ==
FWU_BANK_STATE_ACCEPTED) {
return metadata.previous_active_index;
}
for (unsigned int i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
struct fwu_image_entry *entry = &metadata.img_entry[i];
struct fwu_image_properties *img_props =
&entry->img_props[metadata.active_index];
if (img_props->accepted == 0) {
trial_run = true;
break;
/* Now check for any other bank in the accepted state */
for (i = 0U; i < NR_OF_FW_BANKS; i++) {
if (i == metadata.active_index ||
i == metadata.previous_active_index) {
continue;
}
if (metadata.bank_state[i] == FWU_BANK_STATE_ACCEPTED) {
return i;
}
}
return trial_run;
/*
* No accepted bank found. Now try booting from a valid bank.
* Give priority to the previous active bank.
*/
if (metadata.bank_state[metadata.previous_active_index] ==
FWU_BANK_STATE_VALID) {
return metadata.previous_active_index;
}
for (i = 0U; i < NR_OF_FW_BANKS; i++) {
if (i == metadata.active_index ||
i == metadata.previous_active_index) {
continue;
}
if (metadata.bank_state[i] == FWU_BANK_STATE_VALID) {
return i;
}
}
return INVALID_BOOT_IDX;
}
/*******************************************************************************
* The platform can be in one of Valid, Invalid or Accepted states.
*
* Invalid - One or more images in the bank are corrupted, or partially
* overwritten. The bank is not to be used for booting.
*
* Valid - All images of the bank are valid but at least one image has not
* been accepted. This implies that the platform is in Trial State.
*
* Accepted - All images of the bank are valid and accepted.
*
* Returns the state of the current active bank
******************************************************************************/
uint32_t fwu_get_active_bank_state(void)
{
assert(is_metadata_initialized);
return metadata.bank_state[metadata.active_index];
}
const struct fwu_metadata *fwu_get_metadata(void)

View file

@ -452,14 +452,15 @@ const partition_entry_t *get_partition_entry(const char *name)
}
/*
* Try retrieving a partition table entry based on the GUID.
* Try retrieving a partition table entry based on the partition type GUID.
*/
const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_uuid)
const partition_entry_t *get_partition_entry_by_type(
const struct efi_guid *type_guid)
{
int i;
for (i = 0; i < list.entry_count; i++) {
if (guidcmp(type_uuid, &list.list[i].type_guid) == 0) {
if (guidcmp(type_guid, &list.list[i].type_guid) == 0) {
return &list.list[i];
}
}
@ -468,14 +469,15 @@ const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_uuid)
}
/*
* Try retrieving a partition table entry based on the UUID.
* Try retrieving a partition table entry based on the unique partition GUID.
*/
const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid)
const partition_entry_t *get_partition_entry_by_guid(
const struct efi_guid *part_guid)
{
int i;
for (i = 0; i < list.entry_count; i++) {
if (guidcmp(part_uuid, &list.list[i].part_guid) == 0) {
if (guidcmp(part_guid, &list.list[i].part_guid) == 0) {
return &list.list[i];
}
}

View file

@ -9,8 +9,15 @@
#include <stdbool.h>
#define FWU_BANK_STATE_ACCEPTED 0xFCU
#define FWU_BANK_STATE_VALID 0xFEU
#define FWU_BANK_STATE_INVALID 0xFFU
#define INVALID_BOOT_IDX 0xFFFFFFFFU
void fwu_init(void);
bool fwu_is_trial_run_state(void);
uint32_t fwu_get_active_bank_state(void);
uint32_t fwu_get_alternate_boot_bank(void);
const struct fwu_metadata *fwu_get_metadata(void);
#endif /* FWU_H */

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-3-Clause
*
* FWU metadata information as per the specification section 4.1:
* https://developer.arm.com/documentation/den0118/a/
* https://developer.arm.com/documentation/den0118/latest/
*
*/
@ -14,11 +14,13 @@
#include <stdint.h>
#include <tools_share/uuid.h>
/* Properties of image in a bank */
struct fwu_image_properties {
#define NR_OF_MAX_FW_BANKS 4
/* UUID of the image in this bank */
uuid_t img_uuid;
/* Properties of image in a bank */
struct fwu_image_bank_info {
/* GUID of the image in this bank */
struct efi_guid img_guid;
/* [0]: bit describing the image acceptance status
* 1 means the image is accepted
@ -34,14 +36,37 @@ struct fwu_image_properties {
/* Image entry information */
struct fwu_image_entry {
/* UUID identifying the image type */
uuid_t img_type_uuid;
/* GUID identifying the image type */
struct efi_guid img_type_guid;
/* UUID of the storage volume where the image is located */
uuid_t location_uuid;
/* GUID of the storage volume where the image is located */
struct efi_guid location_guid;
/* Properties of images with img_type_uuid in the different FW banks */
struct fwu_image_properties img_props[NR_OF_FW_BANKS];
/* Properties of images with img_type_guid in the different FW banks */
struct fwu_image_bank_info img_bank_info[NR_OF_FW_BANKS];
} __packed;
/* Firmware Image descriptor */
struct fwu_fw_store_descriptor {
/* Number of Banks */
uint8_t num_banks;
/* Reserved */
uint8_t reserved;
/* Number of images per bank */
uint16_t num_images;
/* Size of image_entry(all banks) in bytes */
uint16_t img_entry_size;
/* Size of image bank info structure in bytes */
uint16_t bank_info_entry_size;
/* Array of fwu_image_entry structs */
struct fwu_image_entry img_entry[NR_OF_IMAGES_IN_FW_BANK];
} __packed;
@ -66,8 +91,25 @@ struct fwu_metadata {
/* Previous bank index with which device booted successfully */
uint32_t previous_active_index;
/* Size of the entire metadata in bytes */
uint32_t metadata_size;
/* Offset of the image descriptor structure */
uint16_t desc_offset;
/* Reserved */
uint16_t reserved1;
/* Bank state */
uint8_t bank_state[NR_OF_MAX_FW_BANKS];
/* Reserved */
uint32_t reserved2;
#if PSA_FWU_METADATA_FW_STORE_DESC
/* Image entry information */
struct fwu_image_entry img_entry[NR_OF_IMAGES_IN_FW_BANK];
struct fwu_fw_store_descriptor fw_desc;
#endif
} __packed;

View file

@ -46,8 +46,10 @@ typedef struct partition_entry_list {
int load_partition_table(unsigned int image_id);
const partition_entry_t *get_partition_entry(const char *name);
const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_guid);
const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid);
const partition_entry_t *get_partition_entry_by_type(
const struct efi_guid *type_guid);
const partition_entry_t *get_partition_entry_by_guid(
const struct efi_guid *part_guid);
const partition_entry_list_t *get_partition_entry_list(void);
void partition_init(unsigned int image_id);
int gpt_partition_init(void);

View file

@ -351,6 +351,14 @@ NR_OF_IMAGES_IN_FW_BANK := 1
# Disable Firmware update support by default
PSA_FWU_SUPPORT := 0
# Enable image description in FWU metadata by default when PSA_FWU_SUPPORT
# is enabled.
ifeq ($(PSA_FWU_SUPPORT),1)
PSA_FWU_METADATA_FW_STORE_DESC := 1
else
PSA_FWU_METADATA_FW_STORE_DESC := 0
endif
# Dynamic Root of Trust for Measurement support
DRTM_SUPPORT := 0

View file

@ -493,12 +493,10 @@ int bl2_plat_handle_pre_image_load(unsigned int image_id)
*/
#if !PSA_FWU_SUPPORT
const partition_entry_t *entry;
const struct efi_guid img_type_guid = STM32MP_FIP_GUID;
uuid_t img_type_uuid;
const struct efi_guid fip_guid = STM32MP_FIP_GUID;
guidcpy(&img_type_uuid, &img_type_guid);
partition_init(GPT_IMAGE_ID);
entry = get_partition_entry_by_type(&img_type_uuid);
entry = get_partition_entry_by_type(&fip_guid);
if (entry == NULL) {
entry = get_partition_entry(FIP_IMAGE_NAME);
if (entry == NULL) {
@ -613,8 +611,6 @@ int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
* - we already boot FWU_MAX_TRIAL_REBOOT times in trial mode.
* we select the previous_active_index.
*/
#define INVALID_BOOT_IDX 0xFFFFFFFFU
uint32_t plat_fwu_get_boot_idx(void)
{
/*
@ -622,32 +618,38 @@ uint32_t plat_fwu_get_boot_idx(void)
* even if this function is called several times.
*/
static uint32_t boot_idx = INVALID_BOOT_IDX;
const struct fwu_metadata *data;
data = fwu_get_metadata();
if (boot_idx == INVALID_BOOT_IDX) {
const struct fwu_metadata *data = fwu_get_metadata();
boot_idx = data->active_index;
if (fwu_is_trial_run_state()) {
if (data->bank_state[boot_idx] == FWU_BANK_STATE_VALID) {
if (stm32_get_and_dec_fwu_trial_boot_cnt() == 0U) {
WARN("Trial FWU fails %u times\n",
FWU_MAX_TRIAL_REBOOT);
boot_idx = data->previous_active_index;
boot_idx = fwu_get_alternate_boot_bank();
}
} else {
} else if (data->bank_state[boot_idx] ==
FWU_BANK_STATE_ACCEPTED) {
stm32_set_max_fwu_trial_boot_cnt();
} else {
ERROR("The active bank(%u) of the platform is in Invalid State.\n",
boot_idx);
boot_idx = fwu_get_alternate_boot_bank();
stm32_clear_fwu_trial_boot_cnt();
}
}
return boot_idx;
}
static void *stm32_get_image_spec(const uuid_t *img_type_uuid)
static void *stm32_get_image_spec(const struct efi_guid *img_type_guid)
{
unsigned int i;
for (i = 0U; i < MAX_NUMBER_IDS; i++) {
if ((guidcmp(&policies[i].img_type_guid, img_type_uuid)) == 0) {
if ((guidcmp(&policies[i].img_type_guid, img_type_guid)) == 0) {
return (void *)policies[i].image_spec;
}
}
@ -660,20 +662,23 @@ void plat_fwu_set_images_source(const struct fwu_metadata *metadata)
unsigned int i;
uint32_t boot_idx;
const partition_entry_t *entry __maybe_unused;
const uuid_t *img_type_uuid;
const uuid_t *img_uuid __maybe_unused;
const struct fwu_image_entry *img_entry;
const void *img_type_guid;
const void *img_guid;
io_block_spec_t *image_spec;
const uint16_t boot_itf = stm32mp_get_boot_itf_selected();
boot_idx = plat_fwu_get_boot_idx();
assert(boot_idx < NR_OF_FW_BANKS);
VERBOSE("Selecting to boot from bank %u\n", boot_idx);
img_entry = (void *)&metadata->fw_desc.img_entry;
for (i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
img_type_uuid = &metadata->img_entry[i].img_type_uuid;
img_type_guid = &img_entry[i].img_type_guid;
img_uuid = &metadata->img_entry[i].img_props[boot_idx].img_uuid;
img_guid = &img_entry[i].img_bank_info[boot_idx].img_guid;
image_spec = stm32_get_image_spec(img_type_uuid);
image_spec = stm32_get_image_spec(img_type_guid);
if (image_spec == NULL) {
ERROR("Unable to get image spec for the image in the metadata\n");
panic();
@ -683,7 +688,7 @@ void plat_fwu_set_images_source(const struct fwu_metadata *metadata)
#if (STM32MP_SDMMC || STM32MP_EMMC)
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
entry = get_partition_entry_by_uuid(img_uuid);
entry = get_partition_entry_by_guid(img_guid);
if (entry == NULL) {
ERROR("No partition with the uuid mentioned in metadata\n");
panic();
@ -695,9 +700,9 @@ void plat_fwu_set_images_source(const struct fwu_metadata *metadata)
#endif
#if STM32MP_SPI_NOR
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_SPI:
if (guidcmp(img_uuid, &STM32MP_NOR_FIP_A_GUID) == 0) {
if (guidcmp(img_guid, &STM32MP_NOR_FIP_A_GUID) == 0) {
image_spec->offset = STM32MP_NOR_FIP_A_OFFSET;
} else if (guidcmp(img_uuid, &STM32MP_NOR_FIP_B_GUID) == 0) {
} else if (guidcmp(img_guid, &STM32MP_NOR_FIP_B_GUID) == 0) {
image_spec->offset = STM32MP_NOR_FIP_B_OFFSET;
} else {
ERROR("Invalid uuid mentioned in metadata\n");

View file

@ -142,6 +142,7 @@ void stm32_display_board_info(uint32_t board_id);
void stm32mp1_fwu_set_boot_idx(void);
uint32_t stm32_get_and_dec_fwu_trial_boot_cnt(void);
void stm32_set_max_fwu_trial_boot_cnt(void);
void stm32_clear_fwu_trial_boot_cnt(void);
#endif /* PSA_FWU_SUPPORT */
#endif /* STM32MP_COMMON_H */

View file

@ -714,4 +714,13 @@ void stm32_set_max_fwu_trial_boot_cnt(void)
TAMP_BOOT_FWU_INFO_CNT_MSK);
clk_disable(RTCAPB);
}
void stm32_clear_fwu_trial_boot_cnt(void)
{
uintptr_t bkpr_fwu_cnt = tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID);
clk_enable(RTCAPB);
mmio_clrbits_32(bkpr_fwu_cnt, TAMP_BOOT_FWU_INFO_CNT_MSK);
clk_disable(RTCAPB);
}
#endif /* PSA_FWU_SUPPORT */