From 29fb905d5f36a415a170a4bffeadf13b5f084345 Mon Sep 17 00:00:00 2001 From: Vikram Kanigiri Date: Thu, 15 May 2014 18:27:15 +0100 Subject: [PATCH] Rework handover interface between BL stages This patch reworks the handover interface from: BL1 to BL2 and BL2 to BL3-1. It removes the raise_el(), change_el(), drop_el() and run_image() functions as they catered for code paths that were never exercised. BL1 calls bl1_run_bl2() to jump into BL2 instead of doing the same by calling run_image(). Similarly, BL2 issues the SMC to transfer execution to BL3-1 through BL1 directly. Only x0 and x1 are used to pass arguments to BL31. These arguments and parameters for running BL3-1 are passed through a reference to a 'el_change_info_t' structure. They were being passed value in general purpose registers earlier. Change-Id: Id4fd019a19a9595de063766d4a66295a2c9307e1 --- bl1/aarch64/bl1_exceptions.S | 97 ++++++++++++++-------------------- bl1/bl1_main.c | 61 +++++++++++++++------ bl2/aarch64/bl2_entrypoint.S | 2 - bl2/bl2_main.c | 61 +++++++++++++-------- bl31/aarch64/bl31_entrypoint.S | 17 ++---- common/bl_common.c | 90 ------------------------------- include/common/bl_common.h | 36 ++++++++++--- plat/fvp/bl2_plat_setup.c | 3 +- 8 files changed, 157 insertions(+), 210 deletions(-) diff --git a/bl1/aarch64/bl1_exceptions.S b/bl1/aarch64/bl1_exceptions.S index a87b20f5..3613b9f4 100644 --- a/bl1/aarch64/bl1_exceptions.S +++ b/bl1/aarch64/bl1_exceptions.S @@ -112,13 +112,51 @@ SErrorSPx: */ .align 7 SynchronousExceptionA64: - /* --------------------------------------------- + /* ------------------------------------------------ * Only a single SMC exception from BL2 to ask * BL1 to pass EL3 control to BL31 is expected * here. - * --------------------------------------------- + * It expects X0 with RUN_IMAGE SMC function id + * X1 with address of a el_change_info_t structure + * describing the BL3-1 entrypoint + * ------------------------------------------------ */ - b process_exception + mov x19, x0 + mov x20, x1 + + mrs x0, esr_el3 + ubfx x1, x0, #ESR_EC_SHIFT, #ESR_EC_LENGTH + cmp x1, #EC_AARCH64_SMC + b.ne panic + + mov x0, #RUN_IMAGE + cmp x19, x0 + b.ne panic + + mov x0, x20 + bl display_boot_progress + + ldp x0, x1, [x20, #EL_CHANGE_INFO_PC_OFFSET] + msr elr_el3, x0 + msr spsr_el3, x1 + ubfx x0, x1, #MODE_EL_SHIFT, #2 + cmp x0, #MODE_EL3 + b.ne panic + + bl disable_mmu_icache_el3 + tlbi alle3 + + ldp x6, x7, [x20, #(EL_CHANGE_INFO_ARGS_OFFSET + 0x30)] + ldp x4, x5, [x20, #(EL_CHANGE_INFO_ARGS_OFFSET + 0x20)] + ldp x2, x3, [x20, #(EL_CHANGE_INFO_ARGS_OFFSET + 0x10)] + ldp x0, x1, [x20, #(EL_CHANGE_INFO_ARGS_OFFSET + 0x0)] + eret +panic: + mov x0, #SYNC_EXCEPTION_AARCH64 + bl plat_report_exception + + wfi + b panic check_vector_size SynchronousExceptionA64 .align 7 @@ -173,56 +211,3 @@ SErrorA32: bl plat_report_exception b SErrorA32 check_vector_size SErrorA32 - - .align 7 - -func process_exception - sub sp, sp, #0x40 - stp x0, x1, [sp, #0x0] - stp x2, x3, [sp, #0x10] - stp x4, x5, [sp, #0x20] - stp x6, x7, [sp, #0x30] - - mov x19, x0 - mov x20, x1 - mov x21, x2 - mov x0, #SYNC_EXCEPTION_AARCH64 - bl plat_report_exception - - mrs x0, esr_el3 - ubfx x1, x0, #ESR_EC_SHIFT, #ESR_EC_LENGTH - cmp x1, #EC_AARCH64_SMC - b.ne panic - mov x1, #RUN_IMAGE - cmp x19, x1 - b.ne panic - mov x0, x20 - mov x1, x21 - mov x2, x3 - mov x3, x4 - bl display_boot_progress - msr elr_el3, x20 - msr spsr_el3, x21 - ubfx x0, x21, #MODE_EL_SHIFT, #2 - cmp x0, #MODE_EL3 - b.ne skip_mmu_teardown - - /* --------------------------------------------- - * If BL31 is to be executed in EL3 as well - * then turn off the MMU so that it can perform - * its own setup. - * --------------------------------------------- - */ - bl disable_mmu_icache_el3 - tlbi alle3 -skip_mmu_teardown: - ldp x6, x7, [sp, #0x30] - ldp x4, x5, [sp, #0x20] - ldp x2, x3, [sp, #0x10] - ldp x0, x1, [sp, #0x0] - add sp, sp, #0x40 - eret - -panic: - wfi - b panic diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c index ecf25506..80e52ca1 100644 --- a/bl1/bl1_main.c +++ b/bl1/bl1_main.c @@ -37,6 +37,34 @@ #include #include "bl1_private.h" +/******************************************************************************* + * Runs BL2 from the given entry point. It results in dropping the + * exception level + ******************************************************************************/ +static void __dead2 bl1_run_bl2(el_change_info_t *bl2_ep) +{ + bl1_arch_next_el_setup(); + + /* Tell next EL what we want done */ + bl2_ep->args.arg0 = RUN_IMAGE; + + if (bl2_ep->security_state == NON_SECURE) + change_security_state(bl2_ep->security_state); + + write_spsr_el3(bl2_ep->spsr); + write_elr_el3(bl2_ep->entrypoint); + + eret(bl2_ep->args.arg0, + bl2_ep->args.arg1, + bl2_ep->args.arg2, + bl2_ep->args.arg3, + bl2_ep->args.arg4, + bl2_ep->args.arg5, + bl2_ep->args.arg6, + bl2_ep->args.arg7); +} + + /******************************************************************************* * Function to perform late architectural and platform specific initialization. * It also locates and loads the BL2 raw binary image in the trusted DRAM. Only @@ -50,9 +78,10 @@ void bl1_main(void) unsigned long sctlr_el3 = read_sctlr_el3(); #endif unsigned long bl2_base; - unsigned int load_type = TOP_LOAD, spsr; + unsigned int load_type = TOP_LOAD; meminfo_t *bl1_tzram_layout; meminfo_t *bl2_tzram_layout = 0x0; + el_change_info_t bl2_ep = {0}; /* * Ensure that MMU/Caches and coherency are turned on @@ -94,20 +123,19 @@ void bl1_main(void) bl2_base); if (bl2_base) { - bl1_arch_next_el_setup(); - spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); + bl2_ep.spsr = + SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); + bl2_ep.entrypoint = bl2_base; + bl2_ep.security_state = SECURE; + bl2_ep.args.arg1 = (unsigned long)bl2_tzram_layout; printf("Booting trusted firmware boot loader stage 2\n\r"); #if DEBUG printf("BL2 address = 0x%llx \n\r", (unsigned long long) bl2_base); - printf("BL2 cpsr = 0x%x \n\r", spsr); + printf("BL2 cpsr = 0x%x \n\r", bl2_ep.spsr); printf("BL2 memory layout address = 0x%llx \n\r", (unsigned long long) bl2_tzram_layout); #endif - run_image(bl2_base, - spsr, - SECURE, - (void *) bl2_tzram_layout, - NULL); + bl1_run_bl2(&bl2_ep); } /* @@ -122,17 +150,16 @@ void bl1_main(void) * Temporary function to print the fact that BL2 has done its job and BL31 is * about to be loaded. This is needed as long as printfs cannot be used ******************************************************************************/ -void display_boot_progress(unsigned long entrypoint, - unsigned long spsr, - unsigned long mem_layout, - unsigned long ns_image_info) +void display_boot_progress(el_change_info_t *bl31_ep_info) { printf("Booting trusted firmware boot loader stage 3\n\r"); #if DEBUG - printf("BL31 address = 0x%llx \n\r", (unsigned long long) entrypoint); - printf("BL31 cpsr = 0x%llx \n\r", (unsigned long long)spsr); - printf("BL31 memory layout address = 0x%llx \n\r", (unsigned long long)mem_layout); - printf("BL31 non-trusted image info address = 0x%llx\n\r", (unsigned long long)ns_image_info); + printf("BL31 address = 0x%llx\n", + (unsigned long long)bl31_ep_info->entrypoint); + printf("BL31 cpsr = 0x%llx\n", + (unsigned long long)bl31_ep_info->spsr); + printf("BL31 args address = 0x%llx\n", + (unsigned long long)bl31_ep_info->args.arg0); #endif return; } diff --git a/bl2/aarch64/bl2_entrypoint.S b/bl2/aarch64/bl2_entrypoint.S index 4f7565f4..09eadff2 100644 --- a/bl2/aarch64/bl2_entrypoint.S +++ b/bl2/aarch64/bl2_entrypoint.S @@ -46,7 +46,6 @@ func bl2_entrypoint */ mov x20, x0 mov x21, x1 - mov x22, x2 /* --------------------------------------------- * This is BL2 which is expected to be executed @@ -110,7 +109,6 @@ func bl2_entrypoint * --------------------------------------------- */ mov x0, x21 - mov x1, x22 bl bl2_early_platform_setup bl bl2_plat_arch_setup diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c index 4a54bf1d..6da5c832 100644 --- a/bl2/bl2_main.c +++ b/bl2/bl2_main.c @@ -38,6 +38,27 @@ #include #include "bl2_private.h" +/******************************************************************************* + * Runs BL31 from the given entry point. It jumps to a higher exception level + * through an SMC. + ******************************************************************************/ +static void __dead2 bl2_run_bl31(bl31_args_t *bl2_to_bl31_args, + unsigned long arg1, + unsigned long arg2) +{ + /* Set the args pointers for X0 and X1 to BL31 */ + bl2_to_bl31_args->bl31_image_info.args.arg0 = arg1; + bl2_to_bl31_args->bl31_image_info.args.arg1 = arg2; + + /* Flush the entire BL31 args buffer */ + flush_dcache_range((unsigned long) bl2_to_bl31_args, + sizeof(*bl2_to_bl31_args)); + + smc(RUN_IMAGE, (unsigned long)&bl2_to_bl31_args->bl31_image_info, + 0, 0, 0, 0, 0, 0); +} + + /******************************************************************************* * The only thing to do in BL2 is to load further images and pass control to * BL31. The memory occupied by BL2 will be reclaimed by BL3_x stages. BL2 runs @@ -86,19 +107,9 @@ void bl2_main(void) */ bl2_to_bl31_args = bl2_get_bl31_args_ptr(); - /* - * Load the BL32 image if there's one. It is upto to platform - * to specify where BL32 should be loaded if it exists. It - * could create space in the secure sram or point to a - * completely different memory. A zero size indicates that the - * platform does not want to load a BL32 image. - */ - if (bl2_to_bl31_args->bl32_meminfo.total_size) - bl32_base = load_image(&bl2_to_bl31_args->bl32_meminfo, - BL32_IMAGE_NAME, - bl2_to_bl31_args->bl32_meminfo.attr & - LOAD_MASK, - BL32_BASE); + bl2_to_bl31_args->bl31_image_info.entrypoint = bl31_base; + bl2_to_bl31_args->bl31_image_info.spsr = + SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); /* * Create a new layout of memory for BL31 as seen by BL2. This @@ -143,6 +154,20 @@ void bl2_main(void) SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); bl2_to_bl31_args->bl33_image_info.security_state = NON_SECURE; + /* + * Load the BL32 image if there's one. It is upto to platform + * to specify where BL32 should be loaded if it exists. It + * could create space in the secure sram or point to a + * completely different memory. A zero size indicates that the + * platform does not want to load a BL32 image. + */ + if (bl2_to_bl31_args->bl32_meminfo.total_size) + bl32_base = load_image(&bl2_to_bl31_args->bl32_meminfo, + BL32_IMAGE_NAME, + bl2_to_bl31_args->bl32_meminfo.attr & + LOAD_MASK, + BL32_BASE); + if (bl32_base) { /* Fill BL32 image info */ bl2_to_bl31_args->bl32_image_info.entrypoint = bl32_base; @@ -155,18 +180,10 @@ void bl2_main(void) bl2_to_bl31_args->bl32_image_info.spsr = 0; } - /* Flush the entire BL31 args buffer */ - flush_dcache_range((unsigned long) bl2_to_bl31_args, - sizeof(*bl2_to_bl31_args)); - /* * Run BL31 via an SMC to BL1. Information on how to pass control to * the BL32 (if present) and BL33 software images will be passed to * BL31 as an argument. */ - run_image(bl31_base, - SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), - SECURE, - (void *) bl2_to_bl31_args, - NULL); + bl2_run_bl31(bl2_to_bl31_args, (unsigned long)bl2_to_bl31_args, 0); } diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S index 763303b3..701bca38 100644 --- a/bl31/aarch64/bl31_entrypoint.S +++ b/bl31/aarch64/bl31_entrypoint.S @@ -45,12 +45,13 @@ func bl31_entrypoint /* --------------------------------------------- - * BL2 has populated x0 with the opcode - * indicating BL31 should be run, x3 with - * a pointer to a 'bl31_args' structure & x4 + * Preceding bootloader has populated x0 with a + * pointer to a 'bl31_args' structure & x1 * with any other optional information * --------------------------------------------- */ + mov x20, x0 + mov x21, x1 /* --------------------------------------------- * Set the exception vector to something sane. @@ -91,16 +92,6 @@ func bl31_entrypoint msr sctlr_el3, x1 isb - /* --------------------------------------------- - * Check the opcodes out of paranoia. - * --------------------------------------------- - */ - mov x19, #RUN_IMAGE - cmp x0, x19 - b.ne _panic - mov x20, x3 - mov x21, x4 - /* --------------------------------------------- * This is BL31 which is expected to be executed * only by the primary cpu (at least for now). diff --git a/common/bl_common.c b/common/bl_common.c index 037d0ff2..4144ae50 100644 --- a/common/bl_common.c +++ b/common/bl_common.c @@ -71,57 +71,6 @@ void change_security_state(unsigned int target_security_state) write_scr(scr); } -void __dead2 drop_el(aapcs64_params_t *args, - unsigned long spsr, - unsigned long entrypoint) -{ - write_spsr_el3(spsr); - write_elr_el3(entrypoint); - eret(args->arg0, - args->arg1, - args->arg2, - args->arg3, - args->arg4, - args->arg5, - args->arg6, - args->arg7); -} - -void __dead2 raise_el(aapcs64_params_t *args) -{ - smc(args->arg0, - args->arg1, - args->arg2, - args->arg3, - args->arg4, - args->arg5, - args->arg6, - args->arg7); -} - -/* - * TODO: If we are not EL3 then currently we only issue an SMC. - * Add support for dropping into EL0 etc. Consider adding support - * for switching from S-EL1 to S-EL0/1 etc. - */ -void __dead2 change_el(el_change_info_t *info) -{ - if (IS_IN_EL3()) { - /* - * We can go anywhere from EL3. So find where. - * TODO: Lots to do if we are going non-secure. - * Flip the NS bit. Restore NS registers etc. - * Just doing the bare minimal for now. - */ - - if (info->security_state == NON_SECURE) - change_security_state(info->security_state); - - drop_el(&info->args, info->spsr, info->entrypoint); - } else - raise_el(&info->args); -} - /******************************************************************************* * The next two functions are the weak definitions. Platform specific @@ -521,42 +470,3 @@ exit: fail: image_base = 0; goto exit; } - -/******************************************************************************* - * Run a loaded image from the given entry point. This could result in either - * dropping into a lower exception level or jumping to a higher exception level. - * The only way of doing the latter is through an SMC. In either case, setup the - * parameters for the EL change request correctly. - ******************************************************************************/ -void __dead2 run_image(unsigned long entrypoint, - unsigned long spsr, - unsigned long target_security_state, - void *first_arg, - void *second_arg) -{ - el_change_info_t run_image_info; - - /* Tell next EL what we want done */ - run_image_info.args.arg0 = RUN_IMAGE; - run_image_info.entrypoint = entrypoint; - run_image_info.spsr = spsr; - run_image_info.security_state = target_security_state; - - /* - * If we are EL3 then only an eret can take us to the desired - * exception level. Else for the time being assume that we have - * to jump to a higher EL and issue an SMC. Contents of argY - * will go into the general purpose register xY e.g. arg0->x0 - */ - if (IS_IN_EL3()) { - run_image_info.args.arg1 = (unsigned long) first_arg; - run_image_info.args.arg2 = (unsigned long) second_arg; - } else { - run_image_info.args.arg1 = entrypoint; - run_image_info.args.arg2 = spsr; - run_image_info.args.arg3 = (unsigned long) first_arg; - run_image_info.args.arg4 = (unsigned long) second_arg; - } - - change_el(&run_image_info); -} diff --git a/include/common/bl_common.h b/include/common/bl_common.h index 15699625..72e2f6fd 100644 --- a/include/common/bl_common.h +++ b/include/common/bl_common.h @@ -56,10 +56,17 @@ *****************************************************************************/ #define RUN_IMAGE 0xC0000000 +/******************************************************************************* + * Constants that allow assembler code to access members of and the + * 'el_change_info' structure at their correct offsets. + ******************************************************************************/ +#define EL_CHANGE_INFO_PC_OFFSET 0x0 +#define EL_CHANGE_INFO_ARGS_OFFSET 0x18 #ifndef __ASSEMBLY__ #include /* For __dead2 */ +#include /******************************************************************************* * Structure used for telling the next BL how much of a particular type of @@ -89,6 +96,8 @@ typedef struct aapcs64_params { * This structure represents the superset of information needed while switching * exception levels. The only two mechanisms to do so are ERET & SMC. In case of * SMC all members apart from 'aapcs64_params' will be ignored. + * NOTE: BL1 expects entrypoint followed by spsr while processing SMC to jump + * to BL31 from the start of el_change_info ******************************************************************************/ typedef struct el_change_info { unsigned long entrypoint; @@ -103,6 +112,7 @@ typedef struct el_change_info { * populated only if BL2 detects its presence. ******************************************************************************/ typedef struct bl31_args { + el_change_info_t bl31_image_info; meminfo_t bl31_meminfo; el_change_info_t bl32_image_info; meminfo_t bl32_meminfo; @@ -110,14 +120,29 @@ typedef struct bl31_args { meminfo_t bl33_meminfo; } bl31_args_t; + +/* + * Compile time assertions related to the 'el_change_info' structure to + * ensure that the assembler and the compiler view of the offsets of + * the structure members is the same. + */ +CASSERT(EL_CHANGE_INFO_PC_OFFSET == \ + __builtin_offsetof(el_change_info_t, entrypoint), \ + assert_BL31_pc_offset_mismatch); + +CASSERT(EL_CHANGE_INFO_ARGS_OFFSET == \ + __builtin_offsetof(el_change_info_t, args), \ + assert_BL31_args_offset_mismatch); + +CASSERT(sizeof(unsigned long) == __builtin_offsetof(el_change_info_t, spsr) - \ + __builtin_offsetof(el_change_info_t, entrypoint), \ + assert_entrypoint_and_spsr_should_be_adjacent); + /******************************************************************************* * Function & variable prototypes ******************************************************************************/ extern unsigned long page_align(unsigned long, unsigned); extern void change_security_state(unsigned int); -extern void __dead2 drop_el(aapcs64_params_t *, unsigned long, unsigned long); -extern void __dead2 raise_el(aapcs64_params_t *); -extern void __dead2 change_el(el_change_info_t *); extern void init_bl2_mem_layout(meminfo_t *, meminfo_t *, unsigned int, @@ -130,11 +155,6 @@ extern unsigned long load_image(meminfo_t *, const char *, unsigned int, unsigned long); -extern void __dead2 run_image(unsigned long entrypoint, - unsigned long spsr, - unsigned long security_state, - void *first_arg, - void *second_arg); extern unsigned long *get_el_change_mem_ptr(void); extern const char build_message[]; diff --git a/plat/fvp/bl2_plat_setup.c b/plat/fvp/bl2_plat_setup.c index 80bb52e5..ddd3b01b 100644 --- a/plat/fvp/bl2_plat_setup.c +++ b/plat/fvp/bl2_plat_setup.c @@ -97,8 +97,7 @@ bl31_args_t *bl2_get_bl31_args_ptr(void) * in x0. This memory layout is sitting at the base of the free trusted SRAM. * Copy it to a safe loaction before its reclaimed by later BL2 functionality. ******************************************************************************/ -void bl2_early_platform_setup(meminfo_t *mem_layout, - void *data) +void bl2_early_platform_setup(meminfo_t *mem_layout) { /* Initialize the console to provide early debug support */ console_init(PL011_UART0_BASE); -- 2.30.2