diff --git a/bl31/aarch64/bl31_arch_setup.c b/bl31/aarch64/bl31_arch_setup.c index 492c45b..03b9623 100644 --- a/bl31/aarch64/bl31_arch_setup.c +++ b/bl31/aarch64/bl31_arch_setup.c @@ -73,10 +73,12 @@ } /******************************************************************************* - * Detect what is the next Non-Secure EL and setup the required architectural - * state + * Detect what the security state of the next EL is and setup the minimum + * required architectural state: program SCTRL to reflect the RES1 bits, and to + * have MMU and caches disabled ******************************************************************************/ -void bl31_arch_next_el_setup(void) { +void bl31_next_el_arch_setup(uint32_t security_state) +{ unsigned long id_aa64pfr0 = read_id_aa64pfr0_el1(); unsigned long current_sctlr, next_sctlr; unsigned long el_status; @@ -89,16 +91,20 @@ /* Find out which EL we are going to */ el_status = (id_aa64pfr0 >> ID_AA64PFR0_EL2_SHIFT) & ID_AA64PFR0_ELX_MASK; - /* Check what if EL2 is supported */ - if (el_status && (scr & SCR_HCE_BIT)) { - /* Set SCTLR EL2 */ - next_sctlr |= SCTLR_EL2_RES1; - - write_sctlr_el2(next_sctlr); - } else { - /* Set SCTLR Non-Secure EL1 */ - next_sctlr |= SCTLR_EL1_RES1; - - write_sctlr_el1(next_sctlr); + if (security_state == NON_SECURE) { + /* Check if EL2 is supported */ + if (el_status && (scr & SCR_HCE_BIT)) { + /* Set SCTLR EL2 */ + next_sctlr |= SCTLR_EL2_RES1; + write_sctlr_el2(next_sctlr); + return; + } } + + /* + * SCTLR_EL1 needs the same programming irrespective of the + * security state of EL1. + */ + next_sctlr |= SCTLR_EL1_RES1; + write_sctlr_el1(next_sctlr); } diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S index c72b363..97f59f3 100644 --- a/bl31/aarch64/bl31_entrypoint.S +++ b/bl31/aarch64/bl31_entrypoint.S @@ -166,18 +166,6 @@ */ bl bl31_main - /* --------------------------------------------- - * Use the more complex exception vectors now - * that context management is setup. SP_EL3 is - * pointing to a 'cpu_context' structure which - * has an exception stack allocated. Since - * we're just about to leave this EL with ERET, - * we don't need an ISB here - * --------------------------------------------- - */ - adr x1, runtime_exceptions - msr vbar_el3, x1 - zero_callee_saved_regs b el3_exit diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c index 9d2dc29..ea44871 100644 --- a/bl31/bl31_main.c +++ b/bl31/bl31_main.c @@ -41,6 +41,12 @@ #include /******************************************************************************* + * Variable to indicate whether next image to execute after BL31 is BL33 + * (non-secure & default) or BL32 (secure). + ******************************************************************************/ +static uint32_t next_image_type = NON_SECURE; + +/******************************************************************************* * Simple function to initialise all BL31 helper libraries. ******************************************************************************/ void bl31_lib_init() @@ -50,16 +56,17 @@ /******************************************************************************* * BL31 is responsible for setting up the runtime services for the primary cpu - * before passing control to the bootloader (UEFI) or Linux. This function calls - * runtime_svc_init() which initializes all registered runtime services. The run - * time services would setup enough context for the core to swtich to the next - * exception level. When this function returns, the core will switch to the - * programmed exception level via. an ERET. + * before passing control to the bootloader or an Operating System. This + * function calls runtime_svc_init() which initializes all registered runtime + * services. The run time services would setup enough context for the core to + * swtich to the next exception level. When this function returns, the core will + * switch to the programmed exception level via. an ERET. ******************************************************************************/ void bl31_main(void) { - el_change_info *next_image_info; - uint32_t scr; +#if DEBUG + unsigned long mpidr = read_mpidr(); +#endif /* Perform remaining generic architectural setup from EL3 */ bl31_arch_setup(); @@ -80,15 +87,80 @@ dcsw_op_all(DCCSW); /* + * Use the more complex exception vectors now that context + * management is setup. SP_EL3 should point to a 'cpu_context' + * structure which has an exception stack allocated. The PSCI + * service should have set the context. + */ + assert(cm_get_context(mpidr, NON_SECURE)); + cm_set_next_eret_context(NON_SECURE); + write_vbar_el3((uint64_t) runtime_exceptions); + + /* + * All the cold boot actions on the primary cpu are done. We + * now need to decide which is the next image (BL32 or BL33) + * and how to execute it. If the SPD runtime service is + * present, it would want to pass control to BL32 first in + * S-EL1. It will export the bl32_init() routine where it takes + * responsibility of entering S-EL1 and returning control back + * to bl31_main. Once this is done we can prepare entry into + * BL33 as normal. + */ + + /* Tell BL32 about it memory extents as well */ + if (bl32_init) + bl32_init(bl31_plat_get_bl32_mem_layout()); + + /* + * We are ready to enter the next EL. Prepare entry into the image + * corresponding to the desired security state after the next ERET. + */ + bl31_prepare_next_image_entry(); +} + +/******************************************************************************* + * Accessor functions to help runtime services decide which image should be + * executed after BL31. This is BL33 or the non-secure bootloader image by + * default but the Secure payload dispatcher could override this by requesting + * an entry into BL32 (Secure payload) first. If it does so then it should use + * the same API to program an entry into BL33 once BL32 initialisation is + * complete. + ******************************************************************************/ +void bl31_set_next_image_type(uint32_t security_state) +{ + assert(security_state == NON_SECURE || security_state == SECURE); + next_image_type = security_state; +} + +uint32_t bl31_get_next_image_type(void) +{ + return next_image_type; +} + +/******************************************************************************* + * This function programs EL3 registers and performs other setup to enable entry + * into the next image after BL31 at the next ERET. + ******************************************************************************/ +void bl31_prepare_next_image_entry() +{ + el_change_info *next_image_info; + uint32_t scr, image_type; + + /* Determine which image to execute next */ + image_type = bl31_get_next_image_type(); + + /* * Setup minimal architectural state of the next highest EL to * allow execution in it immediately upon entering it. */ - bl31_arch_next_el_setup(); + bl31_next_el_arch_setup(image_type); /* Program EL3 registers to enable entry into the next EL */ - next_image_info = bl31_get_next_image_info(); + next_image_info = bl31_get_next_image_info(image_type); + assert(next_image_info); + scr = read_scr(); - if (next_image_info->security_state == NON_SECURE) + if (image_type == NON_SECURE) scr |= SCR_NS_BIT; /* diff --git a/docs/porting-guide.md b/docs/porting-guide.md index 720c877..460dbcc 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -709,6 +709,12 @@ service. See Section 3.3 below for details of porting the PSCI implementation. +4. Optionally passing control to the BL3-2 image, pre-loaded at a platform- + specific address by BL2. BL3-1 exports a set of apis that allow runtime + services to specify the security state in which the next image should be + executed and run the corresponding image. BL3-1 uses the `el_change_info` + and `meminfo` structure populated by BL2 to do this. + The following functions must be implemented by the platform port to enable BL3-1 to perform the above tasks. @@ -771,16 +777,18 @@ ### Function : bl31_get_next_image_info() [mandatory] - Argument : unsigned long + Argument : unsigned int Return : el_change_info * This function may execute with the MMU and data caches enabled if the platform port does the necessary initializations in `bl31_plat_arch_setup()`. This function is called by `bl31_main()` to retrieve information provided by -BL2, so that BL3-1 can pass control to the normal world software image. This -function must return a pointer to the `el_change_info` structure (that was -copied during `bl31_early_platform_setup()`). +BL2 for the next image in the security state specified by the argument. BL3-1 +uses this information to pass control to that image in the specified security +state. This function must return a pointer to the `el_change_info` structure +(that was copied during `bl31_early_platform_setup()`) if the image exists. It +should return NULL otherwise. ### Function : bl31_plat_sec_mem_layout() [mandatory] @@ -798,6 +806,21 @@ `bl31_early_platform_setup()` above. +### Function : bl31_plat_get_bl32_mem_layout() [mandatory] + + Argument : void + Return : meminfo * + +This function should only be called on the cold boot path. This function may +execute with the MMU and data caches enabled if the platform port does the +necessary initializations in `bl31_plat_arch_setup()`. It is only called by the +primary CPU. + +The purpose of this function is to return a pointer to a `meminfo` structure +populated with the extents of memory available for BL3-2 to use. See +`bl31_early_platform_setup()` above. + + 3.3 Power State Coordination Interface (in BL3-1) ------------------------------------------------ diff --git a/docs/user-guide.md b/docs/user-guide.md index 589d0b1..ffad7f4 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -955,6 +955,13 @@ [SMCCC]. +### BL3-2 (Secure Payload) image initialization + +BL2 is responsible for loading a BL3-2 image in memory specified by the platform. +BL3-1 provides an api that uses the entrypoint and memory layout information for +the BL3-2 image provided by BL2 to initialise BL3-2 in S-EL1. + + ### Normal world software execution BL3-1 uses the entrypoint information provided by BL2 to jump to the normal diff --git a/include/aarch64/arch.h b/include/aarch64/arch.h index 69926a3..a590f27 100644 --- a/include/aarch64/arch.h +++ b/include/aarch64/arch.h @@ -320,7 +320,6 @@ extern void bl1_arch_setup(void); extern void bl2_arch_setup(void); extern void bl31_arch_setup(void); -extern void bl31_arch_next_el_setup(void); #endif /*__ASSEMBLY__*/ #endif /* __ARCH_H__ */ diff --git a/include/bl31.h b/include/bl31.h index d2ce201..8b2c787 100644 --- a/include/bl31.h +++ b/include/bl31.h @@ -41,7 +41,19 @@ /******************************************************************************* * Function prototypes ******************************************************************************/ +extern void bl31_next_el_arch_setup(uint32_t security_state); +extern void bl31_set_next_image_type(uint32_t type); +extern uint32_t bl31_get_next_image_type(void); +extern void bl31_prepare_next_image_entry(); +extern el_change_info *bl31_get_next_image_info(uint32_t type); extern void bl31_platform_setup(void); +extern meminfo *bl31_plat_get_bl32_mem_layout(void); extern meminfo *bl31_plat_sec_mem_layout(void); -extern el_change_info* bl31_get_next_image_info(void); + +/* + * This function is used to initialise the BL32 image. It is a weak + * declaration to cope with a system where the Secure Payload + * Dispatcher is absent. + */ +extern int32_t bl32_init(meminfo *) __attribute__ ((weak)); #endif /* __BL31_H__ */ diff --git a/plat/fvp/bl31_plat_setup.c b/plat/fvp/bl31_plat_setup.c index 019b8e1..01b0a45 100644 --- a/plat/fvp/bl31_plat_setup.c +++ b/plat/fvp/bl31_plat_setup.c @@ -72,15 +72,30 @@ return &bl2_to_bl31_args->bl31_meminfo; } -/******************************************************************************* - * Return information about passing control to the non-trusted software images - * to common code.TODO: In the initial architecture, the image after BL31 will - * always run in the non-secure state. In the final architecture there - * will be a series of images. This function will need enhancement then - ******************************************************************************/ -el_change_info *bl31_get_next_image_info(void) +meminfo *bl31_plat_get_bl32_mem_layout(void) { - return &bl2_to_bl31_args->bl33_image_info; + return &bl2_to_bl31_args->bl32_meminfo; +} + +/******************************************************************************* + * Return a pointer to the 'el_change_info' structure of the next image for the + * security state specified. BL33 corresponds to the non-secure image type + * while BL32 corresponds to the secure image type. A NULL pointer is returned + * if the image does not exist. + ******************************************************************************/ +el_change_info *bl31_get_next_image_info(uint32_t type) +{ + el_change_info *next_image_info; + + next_image_info = (type == NON_SECURE) ? + &bl2_to_bl31_args->bl33_image_info : + &bl2_to_bl31_args->bl32_image_info; + + /* None of the images on this platform can have 0x0 as the entrypoint */ + if (next_image_info->entrypoint) + return next_image_info; + else + return NULL; } /*******************************************************************************