diff --git a/bl1/aarch64/bl1_exceptions.S b/bl1/aarch64/bl1_exceptions.S index 3613b9f..8ab9df8 100644 --- a/bl1/aarch64/bl1_exceptions.S +++ b/bl1/aarch64/bl1_exceptions.S @@ -117,7 +117,7 @@ * 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 + * X1 with address of a entry_point_info_t structure * describing the BL3-1 entrypoint * ------------------------------------------------ */ @@ -136,7 +136,7 @@ mov x0, x20 bl display_boot_progress - ldp x0, x1, [x20, #EL_CHANGE_INFO_PC_OFFSET] + ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET] msr elr_el3, x0 msr spsr_el3, x1 ubfx x0, x1, #MODE_EL_SHIFT, #2 @@ -146,10 +146,10 @@ 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)] + ldp x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)] + ldp x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)] + ldp x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)] + ldp x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)] eret panic: mov x0, #SYNC_EXCEPTION_AARCH64 diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c index 80e52ca..da81839 100644 --- a/bl1/bl1_main.c +++ b/bl1/bl1_main.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include "bl1_private.h" @@ -41,18 +42,18 @@ * 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) +static void __dead2 bl1_run_bl2(entry_point_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); + if (GET_SECURITY_STATE(bl2_ep->h.attr) == NON_SECURE) + change_security_state(GET_SECURITY_STATE(bl2_ep->h.attr)); write_spsr_el3(bl2_ep->spsr); - write_elr_el3(bl2_ep->entrypoint); + write_elr_el3(bl2_ep->pc); eret(bl2_ep->args.arg0, bl2_ep->args.arg1, @@ -77,11 +78,12 @@ #if DEBUG unsigned long sctlr_el3 = read_sctlr_el3(); #endif - unsigned long bl2_base; unsigned int load_type = TOP_LOAD; + image_info_t bl2_image_info = { {0} }; + entry_point_info_t bl2_ep = { {0} }; meminfo_t *bl1_tzram_layout; meminfo_t *bl2_tzram_layout = 0x0; - el_change_info_t bl2_ep = {0}; + int err; /* * Ensure that MMU/Caches and coherency are turned on @@ -100,15 +102,28 @@ printf(FIRMWARE_WELCOME_STR); printf("%s\n\r", build_message); + SET_PARAM_HEAD(&bl2_image_info, PARAM_IMAGE_BINARY, VERSION_1, 0); + SET_PARAM_HEAD(&bl2_ep, PARAM_EP, VERSION_1, 0); + /* * Find out how much free trusted ram remains after BL1 load * & load the BL2 image at its top */ bl1_tzram_layout = bl1_plat_sec_mem_layout(); - bl2_base = load_image(bl1_tzram_layout, + err = load_image(bl1_tzram_layout, (const char *) BL2_IMAGE_NAME, - load_type, BL2_BASE); - + load_type, + BL2_BASE, + &bl2_image_info, + &bl2_ep); + if (err) { + /* + * TODO: print failure to load BL2 but also add a tzwdog timer + * which will reset the system eventually. + */ + printf("Failed to load boot loader stage 2 (BL2) firmware.\n"); + panic(); + } /* * Create a new layout of memory for BL2 as seen by BL1 i.e. * tell it the amount of total and free memory available. @@ -120,29 +135,20 @@ init_bl2_mem_layout(bl1_tzram_layout, bl2_tzram_layout, load_type, - bl2_base); + bl2_image_info.image_base); - if (bl2_base) { - 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"); + bl1_plat_set_bl2_ep_info(&bl2_image_info, &bl2_ep); + bl2_ep.args.arg1 = (unsigned long)bl2_tzram_layout; + printf("Booting trusted firmware boot loader stage 2\n"); #if DEBUG - printf("BL2 address = 0x%llx \n\r", (unsigned long long) bl2_base); - 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); + printf("BL2 address = 0x%llx\n", + (unsigned long long) bl2_ep.pc); + printf("BL2 cpsr = 0x%x\n", bl2_ep.spsr); + printf("BL2 memory layout address = 0x%llx\n", + (unsigned long long) bl2_tzram_layout); #endif - bl1_run_bl2(&bl2_ep); - } + bl1_run_bl2(&bl2_ep); - /* - * TODO: print failure to load BL2 but also add a tzwdog timer - * which will reset the system eventually. - */ - printf("Failed to load boot loader stage 2 (BL2) firmware.\n\r"); return; } @@ -150,16 +156,16 @@ * 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(el_change_info_t *bl31_ep_info) +void display_boot_progress(entry_point_info_t *bl31_ep_info) { printf("Booting trusted firmware boot loader stage 3\n\r"); #if DEBUG - 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", + printf("BL31 address = 0x%llx\n", (unsigned long long)bl31_ep_info->pc); + printf("BL31 cpsr = 0x%llx\n", (unsigned long long)bl31_ep_info->spsr); + printf("BL31 params address = 0x%llx\n", (unsigned long long)bl31_ep_info->args.arg0); + printf("BL31 plat params address = 0x%llx\n", + (unsigned long long)bl31_ep_info->args.arg1); #endif return; } diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c index 6da5c83..1969981 100644 --- a/bl2/bl2_main.c +++ b/bl2/bl2_main.c @@ -42,20 +42,18 @@ * 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, +static void __dead2 bl2_run_bl31(entry_point_info_t *bl31_ep_info, 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; + /* Set the args pointer */ + bl31_ep_info->args.arg0 = arg1; + bl31_ep_info->args.arg1 = arg2; - /* Flush the entire BL31 args buffer */ - flush_dcache_range((unsigned long) bl2_to_bl31_args, - sizeof(*bl2_to_bl31_args)); + /* Flush the params to be passed to memory */ + bl2_plat_flush_bl31_params(); - smc(RUN_IMAGE, (unsigned long)&bl2_to_bl31_args->bl31_image_info, - 0, 0, 0, 0, 0, 0); + smc(RUN_IMAGE, (unsigned long)bl31_ep_info, 0, 0, 0, 0, 0, 0); } @@ -68,9 +66,11 @@ void bl2_main(void) { meminfo_t *bl2_tzram_layout; - bl31_args_t *bl2_to_bl31_args; - unsigned long bl31_base, bl32_base = 0, bl33_base, el_status; - unsigned int bl2_load, bl31_load, mode; + bl31_params_t *bl2_to_bl31_params; + bl31_plat_params_t *bl2_to_bl31_plat_params; + unsigned int bl2_load, bl31_load; + entry_point_info_t *bl31_ep_info; + int e; /* Perform remaining generic architectural setup in S-El1 */ bl2_arch_setup(); @@ -84,6 +84,14 @@ bl2_tzram_layout = bl2_plat_sec_mem_layout(); /* + * Get a pointer to the memory the platform has set aside to pass + * information to BL31. + */ + bl2_to_bl31_params = bl2_plat_get_bl31_params(); + bl2_to_bl31_plat_params = bl2_plat_get_bl31_plat_params(); + bl31_ep_info = bl2_plat_get_bl31_ep_info(); + + /* * Load BL31. BL1 tells BL2 whether it has been TOP or BOTTOM loaded. * To avoid fragmentation of trusted SRAM memory, BL31 is always * loaded opposite to BL2. This allows BL31 to reclaim BL2 memory @@ -92,67 +100,45 @@ bl2_load = bl2_tzram_layout->attr & LOAD_MASK; assert((bl2_load == TOP_LOAD) || (bl2_load == BOT_LOAD)); bl31_load = (bl2_load == TOP_LOAD) ? BOT_LOAD : TOP_LOAD; - bl31_base = load_image(bl2_tzram_layout, BL31_IMAGE_NAME, - bl31_load, BL31_BASE); + e = load_image(bl2_tzram_layout, + BL31_IMAGE_NAME, + bl31_load, + BL31_BASE, + bl2_to_bl31_params->bl31_image_info, + bl31_ep_info); /* Assert if it has not been possible to load BL31 */ - if (bl31_base == 0) { + if (e) { ERROR("Failed to load BL3-1.\n"); panic(); } - /* - * Get a pointer to the memory the platform has set aside to pass - * information to BL31. - */ - bl2_to_bl31_args = bl2_get_bl31_args_ptr(); - - 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); + bl2_plat_set_bl31_ep_info(bl2_to_bl31_params->bl31_image_info, + bl31_ep_info); /* * Create a new layout of memory for BL31 as seen by BL2. This * will gobble up all the BL2 memory. */ init_bl31_mem_layout(bl2_tzram_layout, - &bl2_to_bl31_args->bl31_meminfo, + &bl2_to_bl31_plat_params->bl31_meminfo, bl31_load); /* Load the BL33 image in non-secure memory provided by the platform */ - bl33_base = load_image(&bl2_to_bl31_args->bl33_meminfo, - BL33_IMAGE_NAME, - BOT_LOAD, - plat_get_ns_image_entrypoint()); + e = load_image(&bl2_to_bl31_plat_params->bl33_meminfo, + BL33_IMAGE_NAME, + BOT_LOAD, + plat_get_ns_image_entrypoint(), + bl2_to_bl31_params->bl33_image_info, + bl2_to_bl31_params->bl33_ep_info); + /* Halt if failed to load normal world firmware. */ - if (bl33_base == 0) { + if (e) { ERROR("Failed to load BL3-3.\n"); panic(); } - - /* - * BL2 also needs to tell BL31 where the non-trusted software image - * is located. - */ - bl2_to_bl31_args->bl33_image_info.entrypoint = bl33_base; - - /* Figure out what mode we enter the non-secure world in */ - el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; - el_status &= ID_AA64PFR0_ELX_MASK; - - if (el_status) - mode = MODE_EL2; - else - mode = MODE_EL1; - - /* - * TODO: Consider the possibility of specifying the SPSR in - * the FIP ToC and allowing the platform to have a say as - * well. - */ - bl2_to_bl31_args->bl33_image_info.spsr = - SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); - bl2_to_bl31_args->bl33_image_info.security_state = NON_SECURE; + bl2_plat_set_bl33_ep_info(bl2_to_bl31_params->bl33_image_info, + bl2_to_bl31_params->bl33_ep_info); /* * Load the BL32 image if there's one. It is upto to platform @@ -161,29 +147,31 @@ * 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 (bl2_to_bl31_plat_params->bl32_meminfo.total_size) { + e = load_image(&bl2_to_bl31_plat_params->bl32_meminfo, + BL32_IMAGE_NAME, + bl2_to_bl31_plat_params->bl32_meminfo.attr & + LOAD_MASK, + BL32_BASE, + bl2_to_bl31_params->bl32_image_info, + bl2_to_bl31_params->bl32_ep_info); - if (bl32_base) { - /* Fill BL32 image info */ - bl2_to_bl31_args->bl32_image_info.entrypoint = bl32_base; - bl2_to_bl31_args->bl32_image_info.security_state = SECURE; - - /* - * The Secure Payload Dispatcher service is responsible for - * setting the SPSR prior to entry into the BL32 image. - */ - bl2_to_bl31_args->bl32_image_info.spsr = 0; + /* Halt if failed to load normal world firmware. */ + if (e) { + WARN("Failed to load BL3-2.\n"); + } else { + bl2_plat_set_bl32_ep_info( + bl2_to_bl31_params->bl32_image_info, + bl2_to_bl31_params->bl32_ep_info); + } } + /* * 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. */ - bl2_run_bl31(bl2_to_bl31_args, (unsigned long)bl2_to_bl31_args, 0); + bl2_run_bl31(bl31_ep_info, (unsigned long)bl2_to_bl31_params, + (unsigned long)bl2_to_bl31_plat_params); } diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S index 701bca3..c67d029 100644 --- a/bl31/aarch64/bl31_entrypoint.S +++ b/bl31/aarch64/bl31_entrypoint.S @@ -44,11 +44,11 @@ */ func bl31_entrypoint - /* --------------------------------------------- - * Preceding bootloader has populated x0 with a - * pointer to a 'bl31_args' structure & x1 - * with any other optional information - * --------------------------------------------- + /* --------------------------------------------------------------- + * Preceding bootloader has populated x0 with a pointer to a + * 'bl31_params' structure & x1 with a pointer to platform + * specific structure + * --------------------------------------------------------------- */ mov x20, x0 mov x21, x1 diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c index 5a09829..d74b254 100644 --- a/bl31/bl31_main.c +++ b/bl31/bl31_main.c @@ -152,7 +152,7 @@ ******************************************************************************/ void bl31_prepare_next_image_entry() { - el_change_info_t *next_image_info; + entry_point_info_t *next_image_info; uint32_t scr, image_type; /* Determine which image to execute next */ @@ -176,13 +176,13 @@ * Tell the context mgmt. library to ensure that SP_EL3 points to * the right context to exit from EL3 correctly. */ - cm_set_el3_eret_context(next_image_info->security_state, - next_image_info->entrypoint, + cm_set_el3_eret_context(GET_SECURITY_STATE(next_image_info->h.attr), + next_image_info->pc, next_image_info->spsr, scr); /* Finally set the next context */ - cm_set_next_eret_context(next_image_info->security_state); + cm_set_next_eret_context(GET_SECURITY_STATE(next_image_info->h.attr)); } /******************************************************************************* diff --git a/common/bl_common.c b/common/bl_common.c index 4144ae5..a2fa2d6 100644 --- a/common/bl_common.c +++ b/common/bl_common.c @@ -35,6 +35,7 @@ #include #include #include +#include #include unsigned long page_align(unsigned long value, unsigned dir) @@ -229,12 +230,15 @@ * Generic function to load an image into the trusted RAM, * given a name, extents of free memory & whether the image should be loaded at * the bottom or top of the free memory. It updates the memory layout if the - * load is successful. + * load is successful. It also updates the image information and the entry point + * information in the params passed ******************************************************************************/ -unsigned long load_image(meminfo_t *mem_layout, +int load_image(meminfo_t *mem_layout, const char *image_name, unsigned int load_type, - unsigned long fixed_addr) + unsigned long fixed_addr, + image_info_t *image_data, + entry_point_info_t *entry_point_info) { uintptr_t dev_handle; uintptr_t image_handle; @@ -248,13 +252,14 @@ assert(mem_layout != NULL); assert(image_name != NULL); + assert(image_data->h.version >= VERSION_1); /* Obtain a reference to the image by querying the platform layer */ io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); if (io_result != IO_SUCCESS) { WARN("Failed to obtain reference to image '%s' (%i)\n", image_name, io_result); - return 0; + return io_result; } /* Attempt to access the image */ @@ -262,7 +267,7 @@ if (io_result != IO_SUCCESS) { WARN("Failed to access image '%s' (%i)\n", image_name, io_result); - return 0; + return io_result; } /* Find the size of the image */ @@ -270,7 +275,7 @@ if ((io_result != IO_SUCCESS) || (image_size == 0)) { WARN("Failed to determine the size of the image '%s' file (%i)\n", image_name, io_result); - goto fail; + goto exit; } /* See if we have enough space */ @@ -278,7 +283,7 @@ WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(0, image_size, mem_layout); - goto fail; + goto exit; } switch (load_type) { @@ -297,7 +302,8 @@ WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(image_base, image_size, mem_layout); - goto fail; + io_result = -ENOMEM; + goto exit; } /* Calculate the amount of extra memory used due to alignment */ @@ -315,10 +321,11 @@ /* Page align base address and check whether the image still fits */ if (image_base + image_size > mem_layout->free_base + mem_layout->free_size) { - WARN("Cannot load '%s' file: Not enough space.\n", - image_name); - dump_load_info(image_base, image_size, mem_layout); - goto fail; + WARN("Cannot load '%s' file: Not enough space.\n", + image_name); + dump_load_info(image_base, image_size, mem_layout); + io_result = -ENOMEM; + goto exit; } /* Calculate the amount of extra memory used due to alignment */ @@ -383,14 +390,16 @@ WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(image_base, image_size, mem_layout); - goto fail; + io_result = -ENOMEM; + goto exit; } /* Check whether the fixed load address is page-aligned. */ if (!is_page_aligned(image_base)) { WARN("Cannot load '%s' file at unaligned address 0x%lx\n", image_name, fixed_addr); - goto fail; + io_result = -ENOMEM; + goto exit; } /* @@ -440,9 +449,14 @@ io_result = io_read(image_handle, image_base, image_size, &bytes_read); if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) { WARN("Failed to load '%s' file (%i)\n", image_name, io_result); - goto fail; + goto exit; } + image_data->image_base = image_base; + image_data->image_size = image_size; + + entry_point_info->pc = image_base; + /* * File has been successfully loaded. Update the free memory * data structure & flush the contents of the TZRAM so that @@ -458,15 +472,12 @@ mem_layout->free_base += offset + image_size; exit: - io_result = io_close(image_handle); + io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this bootloader stage */ - io_result = io_dev_close(dev_handle); + io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ - return image_base; - -fail: image_base = 0; - goto exit; + return io_result; } diff --git a/include/bl2/bl2.h b/include/bl2/bl2.h index 25b6f9c..5936d84 100644 --- a/include/bl2/bl2.h +++ b/include/bl2/bl2.h @@ -47,6 +47,32 @@ *****************************************/ extern void bl2_platform_setup(void); extern struct meminfo *bl2_plat_sec_mem_layout(void); -extern struct bl31_args *bl2_get_bl31_args_ptr(void); + +/******************************************************************************* + * This function returns a pointer to the shared memory that the platform has + * kept aside to pass trusted firmware related information that BL3-1 + * could need + ******************************************************************************/ +extern struct bl31_params *bl2_plat_get_bl31_params(void); + +/******************************************************************************* + * This function returns a pointer to the shared memory that the platform has + * kept aside to pass platform related information that BL3-1 could need + ******************************************************************************/ +extern struct bl31_plat_params *bl2_plat_get_bl31_plat_params(void); + +/******************************************************************************* + * This function returns a pointer to the shared memory that the platform + * has kept to point to entry point information of BL31 to BL2 + ******************************************************************************/ +extern struct entry_point_info *bl2_plat_get_bl31_ep_info(void); + + +/************************************************************************ + * This function flushes to main memory all the params that are + * passed to BL3-1 + **************************************************************************/ +extern void bl2_plat_flush_bl31_params(void); + #endif /* __BL2_H__ */ diff --git a/include/bl31/bl31.h b/include/bl31/bl31.h index b60e32c..ad6e70e 100644 --- a/include/bl31/bl31.h +++ b/include/bl31/bl31.h @@ -42,7 +42,7 @@ * Forward declarations *****************************************/ struct meminfo; -struct el_change_info; +struct entry_point_info; /******************************************************************************* * Function prototypes @@ -52,7 +52,7 @@ 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 struct el_change_info *bl31_get_next_image_info(uint32_t type); +extern struct entry_point_info *bl31_get_next_image_info(uint32_t type); extern void bl31_platform_setup(void); extern struct meminfo *bl31_plat_get_bl32_mem_layout(void); extern struct meminfo *bl31_plat_sec_mem_layout(void); diff --git a/include/common/bl_common.h b/include/common/bl_common.h index 72e2f6f..e3e4a43 100644 --- a/include/common/bl_common.h +++ b/include/common/bl_common.h @@ -31,8 +31,9 @@ #ifndef __BL_COMMON_H__ #define __BL_COMMON_H__ -#define SECURE 0 -#define NON_SECURE 1 +#define SECURE 0x0 +#define NON_SECURE 0x1 +#define PARAM_EP_SECURITY_MASK 0x1 #define UP 1 #define DOWN 0 @@ -58,15 +59,32 @@ /******************************************************************************* * Constants that allow assembler code to access members of and the - * 'el_change_info' structure at their correct offsets. + * 'entry_point_info' structure at their correct offsets. ******************************************************************************/ -#define EL_CHANGE_INFO_PC_OFFSET 0x0 -#define EL_CHANGE_INFO_ARGS_OFFSET 0x18 +#define ENTRY_POINT_INFO_PC_OFFSET 0x08 +#define ENTRY_POINT_INFO_ARGS_OFFSET 0x18 + +#define GET_SECURITY_STATE(x) (x & PARAM_EP_SECURITY_MASK) +#define SET_SECURITY_STATE(x, security) \ + ((x) = ((x) & ~PARAM_EP_SECURITY_MASK) | (security)) + +#define PARAM_EP 0x01 +#define PARAM_IMAGE_BINARY 0x02 +#define PARAM_BL31 0x03 + +#define VERSION_1 0x01 + +#define SET_PARAM_HEAD(_p, _type, _ver, _attr) do { \ + (_p)->h.type = (uint8_t)(_type); \ + (_p)->h.version = (uint8_t)(_ver); \ + (_p)->h.size = (uint16_t)sizeof(*_p); \ + (_p)->h.attr = (uint32_t)(_attr) ; \ + } while (0) #ifndef __ASSEMBLY__ - #include /* For __dead2 */ #include +#include /******************************************************************************* * Structure used for telling the next BL how much of a particular type of @@ -92,50 +110,97 @@ unsigned long arg7; } aapcs64_params_t; -/******************************************************************************* - * 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; - unsigned long spsr; - unsigned long security_state; +/*************************************************************************** + * This structure provides version information and the size of the + * structure, attributes for the structure it represents + ***************************************************************************/ +typedef struct param_header { + uint8_t type; /* type of the structure */ + uint8_t version; /* version of this structure */ + uint16_t size; /* size of this structure in bytes */ + uint32_t attr; /* attributes: unused bits SBZ */ +} param_header_t; + +/***************************************************************************** + * This structure represents the superset of information needed while + * switching exception levels. The only two mechanisms to do so are + * ERET & SMC. Security state is indicated using bit zero of header + * attribute + * NOTE: BL1 expects entrypoint followed by spsr while processing + * SMC to jump to BL31 from the start of entry_point_info + *****************************************************************************/ +typedef struct entry_point_info { + param_header_t h; + uintptr_t pc; + uint32_t spsr; aapcs64_params_t args; -} el_change_info_t; +} entry_point_info_t; + +/***************************************************************************** + * Image info binary provides information from the image loader that + * can be used by the firmware to manage available trusted RAM. + * More advanced firmware image formats can provide additional + * information that enables optimization or greater flexibility in the + * common firmware code + *****************************************************************************/ +typedef struct image_info { + param_header_t h; + uintptr_t image_base; /* physical address of base of image */ + uint32_t image_size; /* bytes read from image file */ +} image_info_t; /******************************************************************************* * This structure represents the superset of information that can be passed to * BL31 e.g. while passing control to it from BL2. The BL32 parameters will be - * populated only if BL2 detects its presence. + * populated only if BL2 detects its presence. A pointer to a structure of this + * type should be passed in X3 to BL31's cold boot entrypoint + * + * Use of this structure and the X3 parameter is not mandatory: the BL3-1 + * platform code can use other mechanisms to provide the necessary information + * about BL3-2 and BL3-3 to the common and SPD code. + * + * BL3-1 image information is mandatory if this structure is used. If either of + * the optional BL3-2 and BL3-3 image information is not provided, this is + * indicated by the respective image_info pointers being zero. ******************************************************************************/ -typedef struct bl31_args { - el_change_info_t bl31_image_info; +typedef struct bl31_params { + param_header_t h; + image_info_t *bl31_image_info; + entry_point_info_t *bl32_ep_info; + image_info_t *bl32_image_info; + entry_point_info_t *bl33_ep_info; + image_info_t *bl33_image_info; +} bl31_params_t; + + +/*************************************************************************** + * This structure provides platform specific data that needs to be known to + * BL31. Currently, The loader updates the memory information available for + * each binary + ***************************************************************************/ +typedef struct bl31_plat_params { meminfo_t bl31_meminfo; - el_change_info_t bl32_image_info; meminfo_t bl32_meminfo; - el_change_info_t bl33_image_info; meminfo_t bl33_meminfo; -} bl31_args_t; +} bl31_plat_params_t; /* - * Compile time assertions related to the 'el_change_info' structure to + * Compile time assertions related to the 'entry_point_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(ENTRY_POINT_INFO_PC_OFFSET == + __builtin_offsetof(entry_point_info_t, pc), \ + assert_BL31_pc_offset_mismatch); -CASSERT(EL_CHANGE_INFO_ARGS_OFFSET == \ - __builtin_offsetof(el_change_info_t, args), \ +CASSERT(ENTRY_POINT_INFO_ARGS_OFFSET == \ + __builtin_offsetof(entry_point_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), \ +CASSERT(sizeof(unsigned long) == + __builtin_offsetof(entry_point_info_t, spsr) - \ + __builtin_offsetof(entry_point_info_t, pc), \ assert_entrypoint_and_spsr_should_be_adjacent); /******************************************************************************* @@ -151,10 +216,12 @@ meminfo_t *, unsigned int) __attribute__((weak)); extern unsigned long image_size(const char *); -extern unsigned long load_image(meminfo_t *, +extern int load_image(meminfo_t *, const char *, unsigned int, - unsigned long); + unsigned long, + image_info_t *, + entry_point_info_t *); extern unsigned long *get_el_change_mem_ptr(void); extern const char build_message[]; diff --git a/plat/fvp/bl1_plat_setup.c b/plat/fvp/bl1_plat_setup.c index edd3f7b..ac3b69a 100644 --- a/plat/fvp/bl1_plat_setup.c +++ b/plat/fvp/bl1_plat_setup.c @@ -144,3 +144,17 @@ BL1_COHERENT_RAM_BASE, BL1_COHERENT_RAM_LIMIT); } + + +/******************************************************************************* + * 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 + * the entrypoint of BL2 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl1_plat_set_bl2_ep_info(image_info_t *bl2_image, + entry_point_info_t *bl2_ep) +{ + SET_SECURITY_STATE(bl2_ep->h.attr, SECURE); + bl2_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); +} diff --git a/plat/fvp/bl2_plat_setup.c b/plat/fvp/bl2_plat_setup.c index ddd3b01..1eb8001 100644 --- a/plat/fvp/bl2_plat_setup.c +++ b/plat/fvp/bl2_plat_setup.c @@ -34,6 +34,7 @@ #include #include #include +#include /******************************************************************************* * Declarations of linker defined symbols which will help us find the layout @@ -73,10 +74,12 @@ section("tzfw_coherent_mem"))); /******************************************************************************* - * Reference to structure which holds the arguments which need to be passed + * Reference to structures which holds the arguments which need to be passed * to BL31 ******************************************************************************/ -static bl31_args_t *bl2_to_bl31_args; +static bl31_params_t *bl2_to_bl31_params; +static bl31_plat_params_t *bl2_to_bl31_plat_params; +static entry_point_info_t *bl31_ep_info; meminfo_t *bl2_plat_sec_mem_layout(void) { @@ -84,15 +87,105 @@ } /******************************************************************************* - * This function returns a pointer to the memory that the platform has kept - * aside to pass all the information that BL31 could need. + * This function assigns a pointer to the memory that the platform has kept + * aside to pass platform specific and trusted firmware related information + * to BL31. This memory is allocated by allocating memory to + * bl2_to_bl31_params_mem_t structure which is a superset of all the + * structure whose information is passed to BL31 + * NOTE: This function should be called only once and should be done + * before generating params to BL31 ******************************************************************************/ -bl31_args_t *bl2_get_bl31_args_ptr(void) +bl31_params_t *bl2_plat_get_bl31_params(void) { - return bl2_to_bl31_args; + bl2_to_bl31_params_mem_t *bl31_params_mem; + + /* + * Ensure that the secure DRAM memory used for passing BL31 arguments + * does not overlap with the BL32_BASE. + */ + assert(BL32_BASE > PARAMS_BASE + sizeof(bl2_to_bl31_params_mem_t)); + + /* + * Allocate the memory for all the arguments that needs to + * be passed to BL31 + */ + bl31_params_mem = (bl2_to_bl31_params_mem_t *)PARAMS_BASE; + memset((void *)PARAMS_BASE, 0, sizeof(bl2_to_bl31_params_mem_t)); + + /* Assign memory for TF related information */ + bl2_to_bl31_params = &bl31_params_mem->bl31_params; + SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0); + + /* Assign memory for platform specific information */ + bl2_to_bl31_plat_params = &bl31_params_mem->bl31_plat_params; + + /* Fill BL31 related information */ + bl31_ep_info = &bl31_params_mem->bl31_ep_info; + bl2_to_bl31_params->bl31_image_info = &bl31_params_mem->bl31_image_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY, + VERSION_1, 0); + + /* Fill BL32 related information if it exists */ + if (BL32_BASE) { + bl2_to_bl31_params->bl32_ep_info = + &bl31_params_mem->bl32_ep_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, + PARAM_EP, VERSION_1, 0); + bl2_to_bl31_params->bl32_image_info = + &bl31_params_mem->bl32_image_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, + PARAM_IMAGE_BINARY, + VERSION_1, 0); + /* + * Populate the extents of memory available for loading BL32. + * TODO: We are temporarily executing BL2 from TZDRAM; + * will eventually move to Trusted SRAM + */ + bl2_to_bl31_plat_params->bl32_meminfo.total_base = BL32_BASE; + bl2_to_bl31_plat_params->bl32_meminfo.free_base = BL32_BASE; + bl2_to_bl31_plat_params->bl32_meminfo.total_size = + (TZDRAM_BASE + TZDRAM_SIZE) - BL32_BASE; + bl2_to_bl31_plat_params->bl32_meminfo.free_size = + (TZDRAM_BASE + TZDRAM_SIZE) - BL32_BASE; + bl2_to_bl31_plat_params->bl32_meminfo.attr = BOT_LOAD; + } + + /* Fill BL33 related information */ + bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem->bl33_ep_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl33_ep_info, + PARAM_EP, VERSION_1, 0); + bl2_to_bl31_params->bl33_image_info = &bl31_params_mem->bl33_image_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY, + VERSION_1, 0); + /* Populate the extents of memory available for loading BL33 */ + bl2_to_bl31_plat_params->bl33_meminfo.total_base = DRAM_BASE; + bl2_to_bl31_plat_params->bl33_meminfo.total_size = DRAM_SIZE; + bl2_to_bl31_plat_params->bl33_meminfo.free_base = DRAM_BASE; + bl2_to_bl31_plat_params->bl33_meminfo.free_size = DRAM_SIZE; + + return bl2_to_bl31_params; } /******************************************************************************* + * This function returns a pointer to the memory that the platform has kept + * aside to pass platform related information that BL31 could need + ******************************************************************************/ +bl31_plat_params_t *bl2_plat_get_bl31_plat_params(void) +{ + return bl2_to_bl31_plat_params; +} + +/******************************************************************************* + * This function returns a pointer to the shared memory that the platform + * has kept to point to entry point information of BL31 to BL2 + ******************************************************************************/ +struct entry_point_info *bl2_plat_get_bl31_ep_info(void) +{ + return bl31_ep_info; +} + + +/******************************************************************************* * BL1 has passed the extents of the trusted SRAM that should be visible to BL2 * 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. @@ -118,7 +211,7 @@ * Perform platform specific setup. For now just initialize the memory location * to use for passing arguments to BL31. ******************************************************************************/ -void bl2_platform_setup() +void bl2_platform_setup(void) { /* * Do initial security configuration to allow DRAM/device access. On @@ -130,41 +223,16 @@ /* Initialise the IO layer and register platform IO devices */ io_setup(); - - /* - * Ensure that the secure DRAM memory used for passing BL31 arguments - * does not overlap with the BL32_BASE. - */ - assert (BL32_BASE > TZDRAM_BASE + sizeof(bl31_args_t)); - - /* Use the Trusted DRAM for passing args to BL31 */ - bl2_to_bl31_args = (bl31_args_t *) TZDRAM_BASE; - - /* Populate the extents of memory available for loading BL33 */ - bl2_to_bl31_args->bl33_meminfo.total_base = DRAM_BASE; - bl2_to_bl31_args->bl33_meminfo.total_size = DRAM_SIZE; - bl2_to_bl31_args->bl33_meminfo.free_base = DRAM_BASE; - bl2_to_bl31_args->bl33_meminfo.free_size = DRAM_SIZE; - bl2_to_bl31_args->bl33_meminfo.attr = 0; - bl2_to_bl31_args->bl33_meminfo.next = 0; - - /* - * Populate the extents of memory available for loading BL32. - * TODO: We are temporarily executing BL2 from TZDRAM; will eventually - * move to Trusted SRAM - */ - bl2_to_bl31_args->bl32_meminfo.total_base = BL32_BASE; - bl2_to_bl31_args->bl32_meminfo.free_base = BL32_BASE; - - bl2_to_bl31_args->bl32_meminfo.total_size = - (TZDRAM_BASE + TZDRAM_SIZE) - BL32_BASE; - bl2_to_bl31_args->bl32_meminfo.free_size = - (TZDRAM_BASE + TZDRAM_SIZE) - BL32_BASE; - - bl2_to_bl31_args->bl32_meminfo.attr = BOT_LOAD; - bl2_to_bl31_args->bl32_meminfo.next = 0; } +/* Flush the TF params and the TF plat params */ +void bl2_plat_flush_bl31_params(void) +{ + flush_dcache_range((unsigned long)PARAMS_BASE, \ + sizeof(bl2_to_bl31_params_mem_t)); +} + + /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the mmu in a quick and dirty way. @@ -177,3 +245,66 @@ BL2_COHERENT_RAM_BASE, BL2_COHERENT_RAM_LIMIT); } + +/******************************************************************************* + * Before calling this function BL31 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL31 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl2_plat_set_bl31_ep_info(image_info_t *bl31_image_info, + entry_point_info_t *bl31_ep_info) +{ + SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE); + bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); +} + + +/******************************************************************************* + * Before calling this function BL32 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL32 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl2_plat_set_bl32_ep_info(image_info_t *bl32_image_info, + entry_point_info_t *bl32_ep_info) +{ + SET_SECURITY_STATE(bl32_ep_info->h.attr, SECURE); + /* + * The Secure Payload Dispatcher service is responsible for + * setting the SPSR prior to entry into the BL32 image. + */ + bl32_ep_info->spsr = 0; +} + +/******************************************************************************* + * Before calling this function BL33 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL33 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl2_plat_set_bl33_ep_info(image_info_t *image, + entry_point_info_t *bl33_ep_info) +{ + unsigned long el_status; + unsigned int mode; + + /* Figure out what mode we enter the non-secure world in */ + el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; + el_status &= ID_AA64PFR0_ELX_MASK; + + if (el_status) + mode = MODE_EL2; + else + mode = MODE_EL1; + + /* + * TODO: Consider the possibility of specifying the SPSR in + * the FIP ToC and allowing the platform to have a say as + * well. + */ + bl33_ep_info->spsr = SPSR_64(mode, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + SET_SECURITY_STATE(bl33_ep_info->h.attr, NON_SECURE); +} diff --git a/plat/fvp/bl31_plat_setup.c b/plat/fvp/bl31_plat_setup.c index baf7df1..83072e4 100644 --- a/plat/fvp/bl31_plat_setup.c +++ b/plat/fvp/bl31_plat_setup.c @@ -29,6 +29,7 @@ */ #include +#include #include #include #include @@ -70,34 +71,35 @@ * Reference to structure which holds the arguments that have been passed to * BL31 from BL2. ******************************************************************************/ -static bl31_args_t *bl2_to_bl31_args; +static bl31_params_t *bl2_to_bl31_params; +static bl31_plat_params_t *bl2_to_bl31_plat_params; meminfo_t *bl31_plat_sec_mem_layout(void) { - return &bl2_to_bl31_args->bl31_meminfo; + return &bl2_to_bl31_plat_params->bl31_meminfo; } meminfo_t *bl31_plat_get_bl32_mem_layout(void) { - return &bl2_to_bl31_args->bl32_meminfo; + return &bl2_to_bl31_plat_params->bl32_meminfo; } /******************************************************************************* - * Return a pointer to the 'el_change_info' structure of the next image for the + * Return a pointer to the 'entry_point_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_t *bl31_get_next_image_info(uint32_t type) +entry_point_info_t *bl31_get_next_image_info(uint32_t type) { - el_change_info_t *next_image_info; + entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? - &bl2_to_bl31_args->bl33_image_info : - &bl2_to_bl31_args->bl32_image_info; + bl2_to_bl31_params->bl33_ep_info : + bl2_to_bl31_params->bl32_ep_info; /* None of the images on this platform can have 0x0 as the entrypoint */ - if (next_image_info->entrypoint) + if (next_image_info->pc) return next_image_info; else return NULL; @@ -114,10 +116,15 @@ * has flushed this information to memory, so we are guaranteed to pick up good * data ******************************************************************************/ -void bl31_early_platform_setup(bl31_args_t *from_bl2, - void *data) +void bl31_early_platform_setup(bl31_params_t *from_bl2, + bl31_plat_params_t *plat_info_from_bl2) { - bl2_to_bl31_args = from_bl2; + assert(from_bl2->h.type == PARAM_BL31); + assert(from_bl2->h.version >= VERSION_1); + + bl2_to_bl31_params = from_bl2; + bl2_to_bl31_plat_params = plat_info_from_bl2; + /* Initialize the console to provide early debug support */ console_init(PL011_UART0_BASE); @@ -172,7 +179,7 @@ ******************************************************************************/ void bl31_plat_arch_setup() { - configure_mmu_el3(&bl2_to_bl31_args->bl31_meminfo, + configure_mmu_el3(&bl2_to_bl31_plat_params->bl31_meminfo, BL31_RO_BASE, BL31_RO_LIMIT, BL31_COHERENT_RAM_BASE, diff --git a/plat/fvp/platform.h b/plat/fvp/platform.h index 40f780e..85a74bc 100644 --- a/plat/fvp/platform.h +++ b/plat/fvp/platform.h @@ -134,6 +134,10 @@ #define TZDRAM_SIZE 0x02000000 #define MBOX_OFF 0x1000 +/* Base address where parameters to BL31 are stored */ +#define PARAMS_BASE TZDRAM_BASE + + #define DRAM_BASE 0x80000000ull #define DRAM_SIZE 0x80000000ull @@ -339,7 +343,7 @@ #ifndef __ASSEMBLY__ #include - +#include typedef volatile struct mailbox { unsigned long value @@ -351,6 +355,28 @@ ******************************************************************************/ struct plat_pm_ops; struct meminfo; +struct bl31_params; +struct bl31_plat_params; +struct image_info; +struct entry_point_info; + + +/******************************************************************************* + * This structure represents the superset of information that is passed to + * BL31 e.g. while passing control to it from BL2 which is bl31_params + * and bl31_plat_params and its elements + ******************************************************************************/ +typedef struct bl2_to_bl31_params_mem { + struct bl31_params bl31_params; + struct bl31_plat_params bl31_plat_params; + struct image_info bl31_image_info; + struct image_info bl32_image_info; + struct image_info bl33_image_info; + struct entry_point_info bl33_ep_info; + struct entry_point_info bl32_ep_info; + struct entry_point_info bl31_ep_info; +} bl2_to_bl31_params_mem_t; + /******************************************************************************* * Function and variable prototypes @@ -412,6 +438,42 @@ /* Declarations for plat_security.c */ extern void plat_security_setup(void); +/* + * 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 + * the entrypoint of BL2 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + */ +extern void bl1_plat_set_bl2_ep_info(struct image_info *image, + struct entry_point_info *ep); + +/* + * Before calling this function BL31 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL31 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + */ +extern void bl2_plat_set_bl31_ep_info(struct image_info *image, + struct entry_point_info *ep); + +/* + * Before calling this function BL32 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL32 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + */ +extern void bl2_plat_set_bl32_ep_info(struct image_info *image, + struct entry_point_info *ep); + +/* + * Before calling this function BL33 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL33 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + */ +extern void bl2_plat_set_bl33_ep_info(struct image_info *image, + struct entry_point_info *ep); + #endif /*__ASSEMBLY__*/ diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c index 9fda307..15f7ffe 100644 --- a/services/spd/tspd/tspd_main.c +++ b/services/spd/tspd/tspd_main.c @@ -76,7 +76,7 @@ ******************************************************************************/ int32_t tspd_setup(void) { - el_change_info_t *image_info; + entry_point_info_t *image_info; int32_t rc; uint64_t mpidr = read_mpidr(); uint32_t linear_id; @@ -96,7 +96,7 @@ * signalling failure initializing the service. We bail out without * registering any handlers */ - if (!image_info->entrypoint) + if (!image_info->pc) return 1; /* @@ -104,7 +104,7 @@ * state i.e whether AArch32 or AArch64. Assuming it's AArch64 * for the time being. */ - rc = tspd_init_secure_context(image_info->entrypoint, + rc = tspd_init_secure_context(image_info->pc, TSP_AARCH64, mpidr, &tspd_sp_context[linear_id]);