diff --git a/Makefile b/Makefile index c3252c23b..80e05fa63 100644 --- a/Makefile +++ b/Makefile @@ -235,6 +235,10 @@ INCLUDE_TBBR_MK := 1 ################################################################################ ifneq (${SPD},none) +ifdef EL3_PAYLOAD_BASE + $(warning "SPD and EL3_PAYLOAD_BASE are incompatible build options.") + $(warning "The SPD and its BL32 companion will be present but ignored.") +endif # We expect to locate an spd.mk under the specified SPD directory SPD_MAKE := $(shell m="services/spd/${SPD}/${SPD}.mk"; [ -f "$$m" ] && echo "$$m") @@ -300,7 +304,12 @@ endif # supplied for the FIP and Certificate generation tools. This flag can be # overridden by the platform. ifdef BL2_SOURCES +ifndef EL3_PAYLOAD_BASE NEED_BL33 ?= yes +else +# The BL33 image is not needed when booting an EL3 payload. +NEED_BL33 := no +endif endif # Process TBB related flags @@ -375,6 +384,10 @@ $(eval $(call add_define,PSCI_EXTENDED_STATE_ID)) $(eval $(call add_define,ERROR_DEPRECATED)) $(eval $(call add_define,ENABLE_PLAT_COMPAT)) $(eval $(call add_define,SPIN_ON_BL1_EXIT)) +# Define the EL3_PAYLOAD_BASE flag only if it is provided. +ifdef EL3_PAYLOAD_BASE +$(eval $(call add_define,EL3_PAYLOAD_BASE)) +endif ################################################################################ @@ -392,9 +405,13 @@ include bl2/bl2.mk endif ifdef BL31_SOURCES +# When booting an EL3 payload, there is no need to compile the BL31 image nor +# put it in the FIP. +ifndef EL3_PAYLOAD_BASE NEED_BL31 := yes include bl31/bl31.mk endif +endif ################################################################################ diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c index f8a2372fe..a3f016f9c 100644 --- a/bl2/bl2_main.c +++ b/bl2/bl2_main.c @@ -83,6 +83,7 @@ static int load_bl30(void) return e; } +#ifndef EL3_PAYLOAD_BASE /******************************************************************************* * Load the BL3-1 image. * The bl2_to_bl31_params and bl31_ep_info params will be updated with the @@ -190,6 +191,7 @@ static int load_bl33(bl31_params_t *bl2_to_bl31_params) return e; } +#endif /* EL3_PAYLOAD_BASE */ /******************************************************************************* * The only thing to do in BL2 is to load further images and pass control to @@ -232,6 +234,22 @@ void bl2_main(void) bl2_to_bl31_params = bl2_plat_get_bl31_params(); bl31_ep_info = bl2_plat_get_bl31_ep_info(); +#ifdef EL3_PAYLOAD_BASE + /* + * In the case of an EL3 payload, we don't need to load any further + * images. Just update the BL31 entrypoint info structure to make BL1 + * jump to the EL3 payload. + * The pointer to the memory the platform has set aside to pass + * information to BL3-1 in the normal boot flow is reused here, even + * though only a fraction of the information contained in the + * bl31_params_t structure makes sense in the context of EL3 payloads. + * This will be refined in the future. + */ + VERBOSE("BL2: Populating the entrypoint info for the EL3 payload\n"); + bl31_ep_info->pc = EL3_PAYLOAD_BASE; + bl31_ep_info->args.arg0 = (unsigned long) bl2_to_bl31_params; + bl2_plat_set_bl31_ep_info(NULL, bl31_ep_info); +#else e = load_bl31(bl2_to_bl31_params, bl31_ep_info); if (e) { ERROR("Failed to load BL3-1 (%i)\n", e); @@ -253,6 +271,7 @@ void bl2_main(void) ERROR("Failed to load BL3-3 (%i)\n", e); plat_error_handler(e); } +#endif /* EL3_PAYLOAD_BASE */ /* Flush the params to be passed to memory */ bl2_plat_flush_bl31_params(); diff --git a/docs/porting-guide.md b/docs/porting-guide.md index 2c828c271..5e823e815 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -1001,10 +1001,13 @@ structure in BL2 memory. Argument : image_info *, entry_point_info * Return : void -This function is called after loading BL3-1 image and it can be used to -overwrite the entry point set by loader and also set the security state -and SPSR which represents the entry point system state for BL3-1. +In the normal boot flow, this function is called after loading BL3-1 image and +it can be used to overwrite the entry point set by loader and also set the +security state and SPSR which represents the entry point system state for BL3-1. +When booting an EL3 payload instead, this function is called after populating +its entry point address and can be used for the same purpose for the payload +image. It receives a null pointer as its first argument in this case. ### Function : bl2_plat_set_bl32_ep_info() [mandatory] diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index 044e18ef7..aadf58d83 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -149,6 +149,7 @@ int arm_validate_power_state(unsigned int power_state, psci_power_state_t *req_state); int arm_validate_ns_entrypoint(uintptr_t entrypoint); void arm_system_pwr_domain_resume(void); +void arm_program_trusted_mailbox(uintptr_t address); /* Topology utility function */ int arm_check_mpidr(u_register_t mpidr); diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c index ddf383fe2..887223cf4 100644 --- a/plat/arm/common/arm_bl1_setup.c +++ b/plat/arm/common/arm_bl1_setup.c @@ -145,6 +145,20 @@ void bl1_platform_setup(void) arm_bl1_platform_setup(); } +void bl1_plat_prepare_exit(entry_point_info_t *ep_info) +{ +#ifdef EL3_PAYLOAD_BASE + /* + * Program the EL3 payload's entry point address into the CPUs mailbox + * in order to release secondary CPUs from their holding pen and make + * them jump there. + */ + arm_program_trusted_mailbox(ep_info->pc); + dsbsy(); + sev(); +#endif +} + /******************************************************************************* * Before calling this function BL2 is loaded in memory and its entrypoint * is set by load_image. This is a placeholder for the platform to change diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk index eb5ae1116..7b2352759 100644 --- a/plat/arm/common/arm_common.mk +++ b/plat/arm/common/arm_common.mk @@ -81,6 +81,11 @@ BL1_SOURCES += drivers/arm/cci/cci.c \ plat/arm/common/arm_bl1_setup.c \ plat/arm/common/arm_io_storage.c \ plat/common/aarch64/platform_up_stack.S +ifdef EL3_PAYLOAD_BASE +# Need the arm_program_trusted_mailbox() function to release secondary CPUs from +# their holding pen +BL1_SOURCES += plat/arm/common/arm_pm.c +endif BL2_SOURCES += drivers/arm/tzc400/tzc400.c \ drivers/io/io_fip.c \ diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c index d13d2683c..cae65970f 100644 --- a/plat/arm/common/arm_pm.c +++ b/plat/arm/common/arm_pm.c @@ -175,7 +175,7 @@ void arm_system_pwr_domain_resume(void) * from reset. This function assumes that the Trusted mail box base is within * the ARM_SHARED_RAM region ******************************************************************************/ -static void arm_program_trusted_mailbox(uintptr_t address) +void arm_program_trusted_mailbox(uintptr_t address) { uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE; diff --git a/plat/arm/common/arm_security.c b/plat/arm/common/arm_security.c index 990d8d4a6..8b46aaedd 100644 --- a/plat/arm/common/arm_security.c +++ b/plat/arm/common/arm_security.c @@ -40,8 +40,13 @@ /******************************************************************************* * Initialize the TrustZone Controller for ARM standard platforms. - * Configure Region 0 with no access, Region 1 with secure access only, and - * the remaining DRAM regions access from the given Non-Secure masters. + * Configure: + * - Region 0 with no access; + * - Region 1 with secure access only; + * - the remaining DRAM regions access from the given Non-Secure masters. + * + * When booting an EL3 payload, this is simplified: we configure region 0 with + * secure access only and do not enable any other region. ******************************************************************************/ void arm_tzc_setup(void) { @@ -52,6 +57,7 @@ void arm_tzc_setup(void) /* Disable filters. */ tzc_disable_filters(); +#ifndef EL3_PAYLOAD_BASE /* Region 0 set to no access by default */ tzc_configure_region0(TZC_REGION_S_NONE, 0); @@ -73,6 +79,10 @@ void arm_tzc_setup(void) ARM_DRAM2_BASE, ARM_DRAM2_END, TZC_REGION_S_NONE, PLAT_ARM_TZC_NS_DEV_ACCESS); +#else + /* Allow secure access only to DRAM for EL3 payloads. */ + tzc_configure_region0(TZC_REGION_S_RDWR, 0); +#endif /* EL3_PAYLOAD_BASE */ /* * Raise an exception if a NS device tries to access secure memory diff --git a/plat/arm/css/common/css_bl2_setup.c b/plat/arm/css/common/css_bl2_setup.c index 2e423d962..6054f7a56 100644 --- a/plat/arm/css/common/css_bl2_setup.c +++ b/plat/arm/css/common/css_bl2_setup.c @@ -29,7 +29,11 @@ */ #include +#include #include +#include +#include +#include #include "css_scp_bootloader.h" /* Weak definition may be overridden in specific CSS based platform */ @@ -55,3 +59,38 @@ int bl2_plat_handle_bl30(image_info_t *bl30_image_info) return ret; } + +#ifdef EL3_PAYLOAD_BASE +/* + * We need to override some of the platform functions when booting an EL3 + * payload. + */ + +static unsigned int scp_boot_config; + +void bl2_early_platform_setup(meminfo_t *mem_layout) +{ + arm_bl2_early_platform_setup(mem_layout); + + /* Save SCP Boot config before it gets overwritten by BL30 loading */ + scp_boot_config = mmio_read_32(SCP_BOOT_CFG_ADDR); + VERBOSE("BL2: Saved SCP Boot config = 0x%x\n", scp_boot_config); +} + +void bl2_platform_setup(void) +{ + arm_bl2_platform_setup(); + + /* + * Before releasing the AP cores out of reset, the SCP writes some data + * at the beginning of the Trusted SRAM. It is is overwritten before + * reaching this function. We need to restore this data, as if the + * target had just come out of reset. This implies: + * - zeroing the first 128 bytes of Trusted SRAM; + * - restoring the SCP boot configuration. + */ + VERBOSE("BL2: Restoring SCP reset data in Trusted SRAM\n"); + memset((void *) ARM_TRUSTED_SRAM_BASE, 0, 128); + mmio_write_32(SCP_BOOT_CFG_ADDR, scp_boot_config); +} +#endif /* EL3_PAYLOAD_BASE */