Rework handover interface between BL stages
authorVikram Kanigiri <vikram.kanigiri@arm.com>
Thu, 15 May 2014 17:27:15 +0000 (18:27 +0100)
committerVikram Kanigiri <vikram.kanigiri@arm.com>
Thu, 22 May 2014 14:43:23 +0000 (15:43 +0100)
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
bl1/bl1_main.c
bl2/aarch64/bl2_entrypoint.S
bl2/bl2_main.c
bl31/aarch64/bl31_entrypoint.S
common/bl_common.c
include/common/bl_common.h
plat/fvp/bl2_plat_setup.c

index a87b20f5c8d3e57f48a79a24132eb1c2a0b8e056..3613b9f4306fe2ec078b1384c9f4cce658e1312d 100644 (file)
@@ -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
index ecf255063887de135ccfe57298691521a09c8497..80e52ca13e9b82a1ced911ec096e6577351ed0d7 100644 (file)
 #include <stdio.h>
 #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;
 }
index 4f7565f41e5589a9de4e671dc622fd80b4b79bde..09eadff2e08eeea6b3e886352a11460ec53e847f 100644 (file)
@@ -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
 
index 4a54bf1d2d0dd63e9f8eb07eb19574df0f32cc26..6da5c8321d51e154ed62da063c4ff282594914b1 100644 (file)
 #include <stdio.h>
 #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);
 }
index 763303b3893bfec86efccf007bee6c0a3e6cc383..701bca38c38adbeea9f5a36350665de855b2fccf 100644 (file)
 
 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).
index 037d0ff27ea02533d593b9c25be08eff37ad748d..4144ae5014bfef25f5e5b96e76c32517cfc6aeac 100644 (file)
@@ -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);
-}
index 1569962584262f039babb70293482fda668e0938..72e2f6fde2997ccdd1a78b43ff238f666ed5d589 100644 (file)
  *****************************************************************************/
 #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 <cdefs.h> /* For __dead2 */
+#include <cassert.h>
 
 /*******************************************************************************
  * 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[];
 
index 80bb52e5a83c4b8ae027738ca8704b5f8f54b3d1..ddd3b01b74cbac5f81e25ab00bf4c37991c0f237 100644 (file)
@@ -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);