From e633f9c52f7a6f48a65a7b131f96dc2af0529464 Mon Sep 17 00:00:00 2001 From: Yann Gautier Date: Mon, 28 Mar 2022 17:49:38 +0200 Subject: [PATCH 1/2] refactor(stm32mp1): update backup reg for FWU Change the backup register used to store FWU parameters from 21 to 10. This is chosen to have a Read/Write secure and Read non-secure register. The mapping is also changed: only the first 4 bits will be used to store the FWU index. The 4 next bits will be used to store count info. The other bits are reserved. Signed-off-by: Yann Gautier Signed-off-by: Nicolas Toromanoff Change-Id: I9249768287ec5688ba2d8711ce04d429763543d7 --- plat/st/stm32mp1/stm32mp1_private.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c index a9b9f4c5a..0624d46cd 100644 --- a/plat/st/stm32mp1/stm32mp1_private.c +++ b/plat/st/stm32mp1/stm32mp1_private.c @@ -46,7 +46,16 @@ #define TAMP_BOOT_MODE_ITF_MASK U(0x0000FF00) #define TAMP_BOOT_MODE_ITF_SHIFT 8 -#define TAMP_BOOT_COUNTER_REG_ID U(21) +/* + * Backup register to store fwu update information. + * It should be writeable only by secure world, but also readable by non secure + * (so it should be in Zone 2). + */ +#define TAMP_BOOT_FWU_INFO_REG_ID U(10) +#define TAMP_BOOT_FWU_INFO_IDX_MSK U(0xF) +#define TAMP_BOOT_FWU_INFO_IDX_OFF U(0) +#define TAMP_BOOT_FWU_INFO_CNT_MSK U(0xF0) +#define TAMP_BOOT_FWU_INFO_CNT_OFF U(4) #if defined(IMAGE_BL2) #define MAP_SEC_SYSRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \ @@ -733,8 +742,10 @@ void stm32_get_boot_interface(uint32_t *interface, uint32_t *instance) void stm32mp1_fwu_set_boot_idx(void) { clk_enable(RTCAPB); - mmio_write_32(tamp_bkpr(TAMP_BOOT_COUNTER_REG_ID), - plat_fwu_get_boot_idx()); + mmio_clrsetbits_32(tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID), + TAMP_BOOT_FWU_INFO_IDX_MSK, + (plat_fwu_get_boot_idx() << TAMP_BOOT_FWU_INFO_IDX_OFF) & + TAMP_BOOT_FWU_INFO_IDX_MSK); clk_disable(RTCAPB); } #endif /* !STM32MP_USE_STM32IMAGE && PSA_FWU_SUPPORT */ From f87de907c87e5b2091592c131c4d3d2f737bef01 Mon Sep 17 00:00:00 2001 From: Nicolas Toromanoff Date: Mon, 7 Feb 2022 10:12:04 +0100 Subject: [PATCH 2/2] feat(stm32mp1): retry 3 times FWU trial boot If we reboot 3 times in trial mode, BL2 will select previous boot image. Signed-off-by: Nicolas Toromanoff Change-Id: I82b423cc84f0471fdb6fa7c393fc5fe411d25c06 --- plat/st/common/bl2_io_storage.c | 48 ++++++++++++++++++------- plat/st/common/include/stm32mp_common.h | 2 ++ plat/st/stm32mp1/stm32mp1_def.h | 3 ++ plat/st/stm32mp1/stm32mp1_private.c | 31 ++++++++++++++++ 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c index e129dfdb1..5cc339037 100644 --- a/plat/st/common/bl2_io_storage.c +++ b/plat/st/common/bl2_io_storage.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -485,22 +485,46 @@ int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, #if (STM32MP_SDMMC || STM32MP_EMMC) && PSA_FWU_SUPPORT /* - * Eventually, this function will return the - * boot index to be passed on to the Update - * Agent after performing certain checks like - * a watchdog timeout, or Auth failure while - * trying to load from a certain bank. - * For now, since we do not have that logic - * implemented, just pass the active_index - * read from the metadata. + * In each boot in non-trial mode, we set the BKP register to + * FWU_MAX_TRIAL_REBOOT, and return the active_index from metadata. + * + * As long as the update agent didn't update the "accepted" field in metadata + * (i.e. we are in trial mode), we select the new active_index. + * To avoid infinite boot loop at trial boot we decrement a BKP register. + * If this counter is 0: + * - an unexpected TAMPER event raised (that resets the BKP registers to 0) + * - a power-off occurs before the update agent was able to update the + * "accepted' field + * - we already boot FWU_MAX_TRIAL_REBOOT times in trial mode. + * we select the previous_active_index. */ +#define INVALID_BOOT_IDX 0xFFFFFFFF + uint32_t plat_fwu_get_boot_idx(void) { - const struct fwu_metadata *metadata; + /* + * Select boot index and update boot counter only once per boot + * even if this function is called several times. + */ + static uint32_t boot_idx = INVALID_BOOT_IDX; + const struct fwu_metadata *data; - metadata = fwu_get_metadata(); + data = fwu_get_metadata(); - return metadata->active_index; + if (boot_idx == INVALID_BOOT_IDX) { + boot_idx = data->active_index; + if (fwu_is_trial_run_state()) { + 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; + } + } else { + stm32_set_max_fwu_trial_boot_cnt(); + } + } + + return boot_idx; } static void *stm32_get_image_spec(const uuid_t *img_type_uuid) diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h index d8d1c13ba..0010cd8f3 100644 --- a/plat/st/common/include/stm32mp_common.h +++ b/plat/st/common/include/stm32mp_common.h @@ -129,6 +129,8 @@ void stm32_get_boot_interface(uint32_t *interface, uint32_t *instance); #if !STM32MP_USE_STM32IMAGE && PSA_FWU_SUPPORT 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); #endif /* !STM32MP_USE_STM32IMAGE && PSA_FWU_SUPPORT */ #endif /* STM32MP_COMMON_H */ diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h index d8699784f..3b711a3cd 100644 --- a/plat/st/stm32mp1/stm32mp1_def.h +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -511,6 +511,9 @@ enum ddr_type { /* UID OTP */ #define UID_WORD_NB U(3) +/* FWU configuration (max supported value is 15) */ +#define FWU_MAX_TRIAL_REBOOT U(3) + /******************************************************************************* * STM32MP1 TAMP ******************************************************************************/ diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c index 0624d46cd..1617afd04 100644 --- a/plat/st/stm32mp1/stm32mp1_private.c +++ b/plat/st/stm32mp1/stm32mp1_private.c @@ -748,4 +748,35 @@ void stm32mp1_fwu_set_boot_idx(void) TAMP_BOOT_FWU_INFO_IDX_MSK); clk_disable(RTCAPB); } + +uint32_t stm32_get_and_dec_fwu_trial_boot_cnt(void) +{ + uintptr_t bkpr_fwu_cnt = tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID); + uint32_t try_cnt; + + clk_enable(RTCAPB); + try_cnt = (mmio_read_32(bkpr_fwu_cnt) & TAMP_BOOT_FWU_INFO_CNT_MSK) >> + TAMP_BOOT_FWU_INFO_CNT_OFF; + + assert(try_cnt <= FWU_MAX_TRIAL_REBOOT); + + if (try_cnt != 0U) { + mmio_clrsetbits_32(bkpr_fwu_cnt, TAMP_BOOT_FWU_INFO_CNT_MSK, + (try_cnt - 1U) << TAMP_BOOT_FWU_INFO_CNT_OFF); + } + clk_disable(RTCAPB); + + return try_cnt; +} + +void stm32_set_max_fwu_trial_boot_cnt(void) +{ + uintptr_t bkpr_fwu_cnt = tamp_bkpr(TAMP_BOOT_FWU_INFO_REG_ID); + + clk_enable(RTCAPB); + mmio_clrsetbits_32(bkpr_fwu_cnt, TAMP_BOOT_FWU_INFO_CNT_MSK, + (FWU_MAX_TRIAL_REBOOT << TAMP_BOOT_FWU_INFO_CNT_OFF) & + TAMP_BOOT_FWU_INFO_CNT_MSK); + clk_disable(RTCAPB); +} #endif /* !STM32MP_USE_STM32IMAGE && PSA_FWU_SUPPORT */