diff --git a/common/bl_common.c b/common/bl_common.c index fe4de0ae7..2a9f32fe2 100644 --- a/common/bl_common.c +++ b/common/bl_common.c @@ -211,18 +211,18 @@ int load_auth_image(unsigned int image_id, image_info_t *image_data) { int err; -/* - * All firmware banks should be part of the same non-volatile storage as per - * PSA FWU specification, hence don't check for any alternate boot source - * when PSA FWU is enabled. - */ -#if PSA_FWU_SUPPORT - err = load_auth_image_internal(image_id, image_data); -#else - do { + if ((plat_try_img_ops == NULL) || (plat_try_img_ops->next_instance == NULL)) { err = load_auth_image_internal(image_id, image_data); - } while ((err != 0) && (plat_try_next_boot_source() != 0)); -#endif /* PSA_FWU_SUPPORT */ + } else { + do { + err = load_auth_image_internal(image_id, image_data); + if (err != 0) { + if (plat_try_img_ops->next_instance(image_id) != 0) { + return err; + } + } + } while (err != 0); + } if (err == 0) { /* diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index a7600ec51..5643ea1fb 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -1518,6 +1518,40 @@ When CONDITIONAL_CMO flag is enabled: - The function must not clobber x1, x2 and x3. It's also not safe to rely on stack. Otherwise obey AAPCS. +Struct: plat_try_images_ops [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This optional structure holds platform hooks for alternative images load. +It has to be defined in platform code and registered by calling +plat_setup_try_img_ops() function, passing it the address of the +plat_try_images_ops struct. + +Function : plat_setup_try_img_ops [optional] +............................................ + +:: + + Argument : const struct plat_try_images_ops * + Return : void + +This optional function is called to register platform try images ops, given +as argument. + +Function : plat_try_images_ops.next_instance [optional] +....................................................... + +:: + + Argument : unsigned int image_id + Return : int + +This optional function tries to load images from alternative places. +In case PSA FWU is not used, it can be any instance or media. If PSA FWU is +used, it is mandatory that the backup image is on the same media. +This is required for MTD devices like NAND. +The argument is the ID of the image for which we are looking for an alternative +place. It returns 0 in case of success and a negative errno value otherwise. + Modifications specific to a Boot Loader stage --------------------------------------------- @@ -1607,9 +1641,6 @@ This function executes with the MMU and data caches enabled. It is responsible for performing any remaining platform-specific setup that can occur after the MMU and data cache have been enabled. -if support for multiple boot sources is required, it initializes the boot -sequence used by plat_try_next_boot_source(). - In Arm standard platforms, this function initializes the storage abstraction layer used to load the next bootloader image. @@ -1892,25 +1923,7 @@ Function : bl2_plat_preload_setup [optional] This optional function performs any BL2 platform initialization required before image loading, that is not done later in -bl2_platform_setup(). Specifically, if support for multiple -boot sources is required, it initializes the boot sequence used by -plat_try_next_boot_source(). - -Function : plat_try_next_boot_source() [optional] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - Argument : void - Return : int - -This optional function passes to the next boot source in the redundancy -sequence. - -This function moves the current boot redundancy source to the next -element in the boot sequence. If there are no more boot sources then it -must return 0, otherwise it must return 1. The default implementation -of this always returns 0. +bl2_platform_setup(). Boot Loader Stage 2 (BL2) at EL3 -------------------------------- diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index ce5e8e0d9..1015fca1b 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -40,6 +40,16 @@ struct sp_res_desc; struct rmm_manifest; enum fw_enc_status_t; +/******************************************************************************* + * Structure populated by platform specific code to export routines which + * perform load images functions, and associated pointer to platform ops + ******************************************************************************/ +struct plat_try_images_ops { + int (*next_instance)(unsigned int image_id); +}; + +extern const struct plat_try_images_ops *plat_try_img_ops; + /******************************************************************************* * plat_get_rotpk_info() flags ******************************************************************************/ @@ -154,7 +164,7 @@ void plat_panic_handler(void) __dead2; void plat_system_reset(void) __dead2; const char *plat_log_get_prefix(unsigned int log_level); void bl2_plat_preload_setup(void); -int plat_try_next_boot_source(void); +void plat_setup_try_img_ops(const struct plat_try_images_ops *plat_try_ops); #if MEASURED_BOOT int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data); diff --git a/plat/common/aarch32/plat_common.c b/plat/common/aarch32/plat_common.c index 2c1a8fa09..89791712f 100644 --- a/plat/common/aarch32/plat_common.c +++ b/plat/common/aarch32/plat_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2024, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -7,6 +7,14 @@ #include #include +/* Pointer and function to register platform function to load alernate images */ +const struct plat_try_images_ops *plat_try_img_ops; + +void plat_setup_try_img_ops(const struct plat_try_images_ops *plat_try_ops) +{ + plat_try_img_ops = plat_try_ops; +} + /* * The following platform setup functions are weakly defined. They * provide typical implementations that may be re-used by multiple @@ -14,7 +22,6 @@ */ #pragma weak bl32_plat_enable_mmu - void bl32_plat_enable_mmu(uint32_t flags) { enable_mmu_svc_mon(flags); diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c index 54f2a034d..7a228b976 100644 --- a/plat/common/aarch64/plat_common.c +++ b/plat/common/aarch64/plat_common.c @@ -17,6 +17,14 @@ #include #include +/* Pointer and function to register platform function to load alernate images */ +const struct plat_try_images_ops *plat_try_img_ops; + +void plat_setup_try_img_ops(const struct plat_try_images_ops *plat_try_ops) +{ + plat_try_img_ops = plat_try_ops; +} + /* * The following platform setup functions are weakly defined. They * provide typical implementations that may be re-used by multiple diff --git a/plat/common/plat_bl_common.c b/plat/common/plat_bl_common.c index 89b77ba6c..a603f2b10 100644 --- a/plat/common/plat_bl_common.c +++ b/plat/common/plat_bl_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -24,7 +24,6 @@ #pragma weak bl2_plat_preload_setup #pragma weak bl2_plat_handle_pre_image_load #pragma weak bl2_plat_handle_post_image_load -#pragma weak plat_try_next_boot_source #pragma weak plat_get_enc_key_info #pragma weak plat_is_smccc_feature_available #pragma weak plat_get_soc_version @@ -69,11 +68,6 @@ int bl2_plat_handle_post_image_load(unsigned int image_id) return 0; } -int plat_try_next_boot_source(void) -{ - return 0; -} - /* * Weak implementation to provide dummy decryption key only for test purposes, * platforms must override this API for any real world firmware encryption diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c index f8a0c1879..c17ac7eb8 100644 --- a/plat/st/common/bl2_io_storage.c +++ b/plat/st/common/bl2_io_storage.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -47,6 +47,7 @@ uintptr_t fip_dev_handle; uintptr_t storage_dev_handle; static const io_dev_connector_t *fip_dev_con; +static uint32_t nand_block_sz __maybe_unused; #ifndef DECRYPTION_SUPPORT_none static const io_dev_connector_t *enc_dev_con; @@ -310,11 +311,55 @@ static void boot_spi_nor(boot_api_context_t *boot_context) } #endif /* STM32MP_SPI_NOR */ +#if STM32MP_RAW_NAND || STM32MP_SPI_NAND +/* + * This function returns 0 if it can find an alternate + * image to be loaded or a negative errno otherwise. + */ +static int try_nand_backup_partitions(unsigned int image_id) +{ + static unsigned int backup_id; + static unsigned int backup_block_nb; + + /* Check if NAND storage used */ + if (nand_block_sz == 0U) { + return -ENODEV; + } + + if (backup_id != image_id) { + backup_block_nb = PLATFORM_MTD_MAX_PART_SIZE / nand_block_sz; + backup_id = image_id; + } + + if (backup_block_nb-- == 0U) { + return -ENOSPC; + } + +#if PSA_FWU_SUPPORT + if (((image_block_spec.offset < STM32MP_NAND_FIP_B_OFFSET) && + ((image_block_spec.offset + nand_block_sz) >= STM32MP_NAND_FIP_B_OFFSET)) || + (image_block_spec.offset + nand_block_sz >= STM32MP_NAND_FIP_B_MAX_OFFSET)) { + return 0; + } +#endif + + image_block_spec.offset += nand_block_sz; + + return 0; +} + +static const struct plat_try_images_ops try_img_ops = { + .next_instance = try_nand_backup_partitions, +}; +#endif /* STM32MP_RAW_NAND || STM32MP_SPI_NAND */ + #if STM32MP_RAW_NAND static void boot_fmc2_nand(boot_api_context_t *boot_context) { int io_result __maybe_unused; + plat_setup_try_img_ops(&try_img_ops); + io_result = stm32_fmc2_init(); assert(io_result == 0); @@ -326,6 +371,8 @@ static void boot_fmc2_nand(boot_api_context_t *boot_context) io_result = io_dev_open(nand_dev_con, (uintptr_t)&nand_dev_spec, &storage_dev_handle); assert(io_result == 0); + + nand_block_sz = nand_dev_spec.erase_size; } #endif /* STM32MP_RAW_NAND */ @@ -334,6 +381,8 @@ static void boot_spi_nand(boot_api_context_t *boot_context) { int io_result __maybe_unused; + plat_setup_try_img_ops(&try_img_ops); + io_result = stm32_qspi_init(); assert(io_result == 0); @@ -345,6 +394,8 @@ static void boot_spi_nand(boot_api_context_t *boot_context) (uintptr_t)&spi_nand_dev_spec, &storage_dev_handle); assert(io_result == 0); + + nand_block_sz = spi_nand_dev_spec.erase_size; } #endif /* STM32MP_SPI_NAND */ @@ -530,7 +581,14 @@ int bl2_plat_handle_pre_image_load(unsigned int image_id) #if STM32MP_SPI_NAND case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_SPI: #endif +/* + * With FWU Multi Bank feature enabled, the selection of + * the image to boot will be done by fwu_init calling the + * platform hook, plat_fwu_set_images_source. + */ +#if !PSA_FWU_SUPPORT image_block_spec.offset = STM32MP_NAND_FIP_OFFSET; +#endif break; #endif @@ -596,7 +654,7 @@ int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, return rc; } -#if (STM32MP_SDMMC || STM32MP_EMMC || STM32MP_SPI_NOR) && PSA_FWU_SUPPORT +#if PSA_FWU_SUPPORT /* * In each boot in non-trial mode, we set the BKP register to * FWU_MAX_TRIAL_REBOOT, and return the active_index from metadata. @@ -709,6 +767,19 @@ void plat_fwu_set_images_source(const struct fwu_metadata *metadata) panic(); } break; +#endif +#if (STM32MP_RAW_NAND || STM32MP_SPI_NAND) + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_SPI: + if (guidcmp(img_guid, &STM32MP_NAND_FIP_A_GUID) == 0) { + image_spec->offset = STM32MP_NAND_FIP_A_OFFSET; + } else if (guidcmp(img_guid, &STM32MP_NAND_FIP_B_GUID) == 0) { + image_spec->offset = STM32MP_NAND_FIP_B_OFFSET; + } else { + ERROR("Invalid uuid mentioned in metadata\n"); + panic(); + } + break; #endif default: panic(); @@ -717,9 +788,9 @@ void plat_fwu_set_images_source(const struct fwu_metadata *metadata) } } -static int plat_set_image_source(unsigned int image_id, - uintptr_t *handle, - uintptr_t *image_spec) +static int set_metadata_image_source(unsigned int image_id, + uintptr_t *handle, + uintptr_t *image_spec) { struct plat_io_policy *policy; io_block_spec_t *spec __maybe_unused; @@ -762,6 +833,19 @@ static int plat_set_image_source(unsigned int image_id, spec->length = sizeof(struct fwu_metadata); break; #endif + +#if (STM32MP_RAW_NAND || STM32MP_SPI_NAND) + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_SPI: + if (image_id == FWU_METADATA_IMAGE_ID) { + spec->offset = STM32MP_NAND_METADATA1_OFFSET; + } else { + spec->offset = STM32MP_NAND_METADATA2_OFFSET; + } + + spec->length = sizeof(struct fwu_metadata); + break; +#endif default: panic(); break; @@ -780,6 +864,6 @@ int plat_fwu_set_metadata_image_source(unsigned int image_id, assert((image_id == FWU_METADATA_IMAGE_ID) || (image_id == BKUP_FWU_METADATA_IMAGE_ID)); - return plat_set_image_source(image_id, handle, image_spec); + return set_metadata_image_source(image_id, handle, image_spec); } -#endif /* (STM32MP_SDMMC || STM32MP_EMMC || STM32MP_SPI_NOR) && PSA_FWU_SUPPORT */ +#endif /* PSA_FWU_SUPPORT */ diff --git a/plat/st/common/stm32mp_fconf_io.c b/plat/st/common/stm32mp_fconf_io.c index 5514c09c1..6ed09d9c0 100644 --- a/plat/st/common/stm32mp_fconf_io.c +++ b/plat/st/common/stm32mp_fconf_io.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2023, STMicroelectronics - All Rights Reserved + * Copyright (c) 2021-2024, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -27,12 +27,12 @@ static io_block_spec_t gpt_block_spec = { }; #endif -#if (STM32MP_SDMMC || STM32MP_EMMC || STM32MP_SPI_NOR) && PSA_FWU_SUPPORT +#if PSA_FWU_SUPPORT static io_block_spec_t metadata_block_spec = { .offset = 0, /* To be filled at runtime */ .length = 0, /* To be filled at runtime */ }; -#endif /* (STM32MP_SDMMC || STM32MP_EMMC || STM32MP_SPI_NOR) && PSA_FWU_SUPPORT */ +#endif /* PSA_FWU_SUPPORT */ /* By default, STM32 platforms load images from the FIP */ struct plat_io_policy policies[MAX_NUMBER_IDS] = { @@ -58,7 +58,7 @@ struct plat_io_policy policies[MAX_NUMBER_IDS] = { .check = open_storage }, #endif -#if (STM32MP_SDMMC || STM32MP_EMMC || STM32MP_SPI_NOR) && PSA_FWU_SUPPORT +#if PSA_FWU_SUPPORT [FWU_METADATA_IMAGE_ID] = { .dev_handle = &storage_dev_handle, .image_spec = (uintptr_t)&metadata_block_spec, @@ -71,7 +71,7 @@ struct plat_io_policy policies[MAX_NUMBER_IDS] = { .img_type_guid = NULL_GUID, .check = open_storage }, -#endif /* (STM32MP_SDMMC || STM32MP_EMMC || STM32MP_SPI_NOR) && PSA_FWU_SUPPORT */ +#endif /* PSA_FWU_SUPPORT */ }; #define DEFAULT_UUID_NUMBER U(7)