diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c index ff3c53b..68bdd36 100644 --- a/bl31/bl31_main.c +++ b/bl31/bl31_main.c @@ -51,7 +51,7 @@ * Variable to indicate whether next image to execute after BL31 is BL33 * (non-secure & default) or BL32 (secure). ******************************************************************************/ -static uint32_t next_image_type; +static uint32_t next_image_type = NON_SECURE; /******************************************************************************* * Simple function to initialise all BL31 helper libraries. @@ -89,9 +89,6 @@ /* Clean caches before re-entering normal world */ dcsw_op_all(DCCSW); - /* By default run the non-secure BL3-3 image next */ - next_image_type = NON_SECURE; - /* * 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. diff --git a/bl32/tsp/tsp.mk b/bl32/tsp/tsp.mk index b9084d5..02cc13d 100644 --- a/bl32/tsp/tsp.mk +++ b/bl32/tsp/tsp.mk @@ -39,6 +39,14 @@ BL32_LINKERFILE := bl32/tsp/tsp.ld.S +# This flag determines if the TSPD initializes BL3-2 in tspd_init() (synchronous +# method) or configures BL3-1 to pass control to BL3-2 instead of BL3-3 +# (asynchronous method). +TSP_INIT_ASYNC := 0 + +$(eval $(call assert_boolean,TSP_INIT_ASYNC)) +$(eval $(call add_define,TSP_INIT_ASYNC)) + # Include the platform-specific TSP Makefile # If no platform-specific TSP Makefile exists, it means TSP is not supported # on this platform. diff --git a/docs/firmware-design.md b/docs/firmware-design.md index 9bdfefb..3203a52 100644 --- a/docs/firmware-design.md +++ b/docs/firmware-design.md @@ -811,10 +811,10 @@ Trusted Firmware supports two approaches for the SPD to pass control to BL3-2 before returning through EL3 and running the non-trusted firmware (BL3-3): -1. In the BL3-2 initialization function, set up a secure context (see below - for more details of CPU context support) for this CPU and use - `bl31_set_next_image_type()` to request that the exit from `bl31_main()` is - to the BL3-2 entrypoint in Secure-EL1. +1. In the BL3-2 setup function, use `bl31_set_next_image_type()` to + request that the exit from `bl31_main()` is to the BL3-2 entrypoint in + Secure-EL1. BL3-1 will exit to BL3-2 using the asynchronous method by + calling bl31_prepare_next_image_entry() and el3_exit(). When the BL3-2 has completed initialization at Secure-EL1, it returns to BL3-1 by issuing an SMC, using a Function ID allocated to the SPD. On @@ -824,7 +824,8 @@ the normal world firmware BL3-3. On return from the handler the framework will exit to EL2 and run BL3-3. -2. In the BL3-2 initialization function, use an SPD-defined mechanism to +2. The BL3-2 setup function registers a initialization function using + `bl31_register_bl32_init()` which provides a SPD-defined mechanism to invoke a 'world-switch synchronous call' to Secure-EL1 to run the BL3-2 entrypoint. NOTE: The Test SPD service included with the Trusted Firmware provides one diff --git a/docs/user-guide.md b/docs/user-guide.md index 41e7606..ef5de71 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -186,6 +186,13 @@ value of `DEBUG` - i.e. by default this is only enabled for a debug build of the firmware. +* `TSP_INIT_ASYNC`: Choose BL3-2 initialization method as asynchronous or + synchronous, e.g. "(see "Initializing a BL3-2 Image" section in [Firmware + Design])". It can take the value 0 (BL3-2 is initialized using + synchronous method) or 1 (BL3-2 is initialized using asynchronous method). + Default is 0. + + ### Creating a Firmware Image Package FIPs are automatically created as part of the build instructions described in diff --git a/plat/fvp/bl31_fvp_setup.c b/plat/fvp/bl31_fvp_setup.c index 21fca70..0693a12 100644 --- a/plat/fvp/bl31_fvp_setup.c +++ b/plat/fvp/bl31_fvp_setup.c @@ -73,7 +73,8 @@ #if RESET_TO_BL31 -static entry_point_info_t next_image_ep_info; +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; #else /******************************************************************************* * Reference to structure which holds the arguments that have been passed to @@ -91,28 +92,12 @@ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { #if RESET_TO_BL31 - assert(sec_state_is_valid(type)); - SET_PARAM_HEAD(&next_image_ep_info, - PARAM_EP, - VERSION_1, - 0); - SET_SECURITY_STATE(next_image_ep_info.h.attr, type); - - if (type == NON_SECURE) { - /* - * Tell BL31 where the non-trusted software image - * is located and the entry state information - */ - next_image_ep_info.pc = plat_get_ns_image_entrypoint(); - next_image_ep_info.spsr = fvp_get_spsr_for_bl33_entry(); - } else { - next_image_ep_info.pc = BL32_BASE; - next_image_ep_info.spsr = fvp_get_spsr_for_bl32_entry(); - } - - return &next_image_ep_info; + if (type == NON_SECURE) + return &bl33_image_ep_info; + else + return &bl32_image_ep_info; #else entry_point_info_t *next_image_info; @@ -155,7 +140,6 @@ assert(from_bl2 == NULL); assert(plat_params_from_bl2 == NULL); - /* * Do initial security configuration to allow DRAM/device access. On * Base FVP only DRAM security is programmable (via TrustZone), but @@ -163,6 +147,28 @@ * present. */ fvp_security_setup(); + + /* Populate entry point information for BL3-2 and BL3-3 */ + SET_PARAM_HEAD(&bl32_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); + bl32_image_ep_info.pc = BL32_BASE; + bl32_image_ep_info.spsr = fvp_get_spsr_for_bl32_entry(); + + SET_PARAM_HEAD(&bl33_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + /* + * Tell BL31 where the non-trusted software image + * is located and the entry state information + */ + bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); + bl33_image_ep_info.spsr = fvp_get_spsr_for_bl33_entry(); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + #else /* Check params passed from BL2 should not be NULL, * We are not checking plat_params_from_bl2 as NULL as we are not diff --git a/services/spd/tspd/tspd_common.c b/services/spd/tspd/tspd_common.c index 1b9609f..322413c 100644 --- a/services/spd/tspd/tspd_common.c +++ b/services/spd/tspd/tspd_common.c @@ -36,20 +36,21 @@ #include "tspd_private.h" /******************************************************************************* - * Given a secure payload entrypoint, register width, cpu id & pointer to a - * context data structure, this function will create a secure context ready for - * programming an entry into the secure payload. + * Given a secure payload entrypoint info pointer, entry point PC, register + * width, cpu id & pointer to a context data structure, this function will + * initialize tsp context and entry point info for the secure payload ******************************************************************************/ -int32_t tspd_init_secure_context(uint64_t entrypoint, - uint32_t rw, - uint64_t mpidr, - tsp_context_t *tsp_ctx) +void tspd_init_tsp_ep_state(struct entry_point_info *tsp_entry_point, + uint32_t rw, + uint64_t pc, + tsp_context_t *tsp_ctx) { - entry_point_info_t ep; uint32_t ep_attr; /* Passing a NULL context is a critical programming error */ assert(tsp_ctx); + assert(tsp_entry_point); + assert(pc); /* * We support AArch64 TSP for now. @@ -58,25 +59,24 @@ assert(rw == TSP_AARCH64); /* Associate this context with the cpu specified */ - tsp_ctx->mpidr = mpidr; + tsp_ctx->mpidr = read_mpidr_el1(); tsp_ctx->state = 0; set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF); clr_std_smc_active_flag(tsp_ctx->state); - cm_set_context_by_mpidr(mpidr, &tsp_ctx->cpu_ctx, SECURE); + cm_set_context(&tsp_ctx->cpu_ctx, SECURE); /* initialise an entrypoint to set up the CPU context */ ep_attr = SECURE | EP_ST_ENABLE; if (read_sctlr_el3() & SCTLR_EE_BIT) ep_attr |= EP_EE_BIG; - SET_PARAM_HEAD(&ep, PARAM_EP, VERSION_1, ep_attr); - ep.pc = entrypoint; - ep.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); - memset(&ep.args, 0, sizeof(ep.args)); + SET_PARAM_HEAD(tsp_entry_point, PARAM_EP, VERSION_1, ep_attr); - cm_init_context(mpidr, &ep); - - return 0; + tsp_entry_point->pc = pc; + tsp_entry_point->spsr = SPSR_64(MODE_EL1, + MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + memset(&tsp_entry_point->args, 0, sizeof(tsp_entry_point->args)); } /******************************************************************************* diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c index f1dbe68..22f302a 100644 --- a/services/spd/tspd/tspd_main.c +++ b/services/spd/tspd/tspd_main.c @@ -144,8 +144,7 @@ ******************************************************************************/ int32_t tspd_setup(void) { - entry_point_info_t *image_info; - int32_t rc; + entry_point_info_t *tsp_ep_info; uint64_t mpidr = read_mpidr(); uint32_t linear_id; @@ -156,15 +155,20 @@ * absence is a critical failure. TODO: Add support to * conditionally include the SPD service */ - image_info = bl31_plat_get_next_image_ep_info(SECURE); - assert(image_info); + tsp_ep_info = bl31_plat_get_next_image_ep_info(SECURE); + if (!tsp_ep_info) { + WARN("No TSP provided by BL2 boot loader, Booting device" + " without TSP initialization. SMC`s destined for TSP" + " will return SMC_UNK\n"); + return 1; + } /* * If there's no valid entry point for SP, we return a non-zero value * signalling failure initializing the service. We bail out without * registering any handlers */ - if (!image_info->pc) + if (!tsp_ep_info->pc) return 1; /* @@ -172,19 +176,21 @@ * state i.e whether AArch32 or AArch64. Assuming it's AArch64 * for the time being. */ - rc = tspd_init_secure_context(image_info->pc, - TSP_AARCH64, - mpidr, - &tspd_sp_context[linear_id]); - assert(rc == 0); + tspd_init_tsp_ep_state(tsp_ep_info, + TSP_AARCH64, + tsp_ep_info->pc, + &tspd_sp_context[linear_id]); +#if TSP_INIT_ASYNC + bl31_set_next_image_type(SECURE); +#else /* * All TSPD initialization done. Now register our init function with * BL31 for deferred invocation */ bl31_register_bl32_init(&tspd_init); - - return rc; +#endif + return 0; } /******************************************************************************* @@ -199,37 +205,26 @@ int32_t tspd_init(void) { uint64_t mpidr = read_mpidr(); - uint32_t linear_id = platform_get_core_pos(mpidr), flags; - uint64_t rc; + uint32_t linear_id = platform_get_core_pos(mpidr); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; + entry_point_info_t *tsp_entry_point; + uint64_t rc; /* - * Arrange for an entry into the test secure payload. We expect an array - * of vectors in return + * Get information about the Secure Payload (BL32) image. Its + * absence is a critical failure. + */ + tsp_entry_point = bl31_plat_get_next_image_ep_info(SECURE); + assert(tsp_entry_point); + + cm_init_context(mpidr, tsp_entry_point); + + /* + * Arrange for an entry into the test secure payload. It will be + * returned via TSP_ENTRY_DONE case */ rc = tspd_synchronous_sp_entry(tsp_ctx); assert(rc != 0); - if (rc) { - set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); - - /* - * TSP has been successfully initialized. Register power - * managemnt hooks with PSCI - */ - psci_register_spd_pm_hook(&tspd_pm); - } - - /* - * Register an interrupt handler for S-EL1 interrupts when generated - * during code executing in the non-secure state. - */ - flags = 0; - set_interrupt_rm_flag(flags, NON_SECURE); - rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, - tspd_sel1_interrupt_handler, - flags); - if (rc) - panic(); return rc; } @@ -256,6 +251,10 @@ unsigned long mpidr = read_mpidr(); uint32_t linear_id = platform_get_core_pos(mpidr), ns; tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; + uint64_t rc; +#if TSP_INIT_ASYNC + entry_point_info_t *next_image_info; +#endif /* Determine which security state this SMC originated from */ ns = is_caller_non_secure(flags); @@ -369,6 +368,45 @@ assert(tsp_vectors == NULL); tsp_vectors = (tsp_vectors_t *) x1; + if (tsp_vectors) { + set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); + + /* + * TSP has been successfully initialized. Register power + * managemnt hooks with PSCI + */ + psci_register_spd_pm_hook(&tspd_pm); + + /* + * Register an interrupt handler for S-EL1 interrupts + * when generated during code executing in the + * non-secure state. + */ + flags = 0; + set_interrupt_rm_flag(flags, NON_SECURE); + rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, + tspd_sel1_interrupt_handler, + flags); + if (rc) + panic(); + } + + +#if TSP_INIT_ASYNC + /* Save the Secure EL1 system register context */ + assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx); + cm_el1_sysregs_context_save(SECURE); + + /* Program EL3 registers to enable entry into the next EL */ + next_image_info = bl31_plat_get_next_image_ep_info(NON_SECURE); + assert(next_image_info); + assert(NON_SECURE == + GET_SECURITY_STATE(next_image_info->h.attr)); + + cm_init_context(read_mpidr_el1(), next_image_info); + cm_prepare_el3_exit(NON_SECURE); + SMC_RET0(cm_get_context(NON_SECURE)); +#else /* * SP reports completion. The SPD must have initiated * the original request through a synchronous entry @@ -376,6 +414,7 @@ * context. */ tspd_synchronous_sp_exit(tsp_ctx, x1); +#endif /* * These function IDs is used only by the SP to indicate it has diff --git a/services/spd/tspd/tspd_pm.c b/services/spd/tspd/tspd_pm.c index ec4989d..e9e037a 100644 --- a/services/spd/tspd/tspd_pm.c +++ b/services/spd/tspd/tspd_pm.c @@ -123,16 +123,19 @@ uint64_t mpidr = read_mpidr(); uint32_t linear_id = platform_get_core_pos(mpidr); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; + entry_point_info_t tsp_on_entrypoint; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF); - /* Initialise this cpu's secure context */ - tspd_init_secure_context((uint64_t) &tsp_vectors->cpu_on_entry, + tspd_init_tsp_ep_state(&tsp_on_entrypoint, TSP_AARCH64, - mpidr, + (uint64_t) &tsp_vectors->cpu_on_entry, tsp_ctx); + /* Initialise this cpu's secure context */ + cm_init_context(mpidr, &tsp_on_entrypoint); + /* Enter the TSP */ rc = tspd_synchronous_sp_entry(tsp_ctx); diff --git a/services/spd/tspd/tspd_private.h b/services/spd/tspd/tspd_private.h index 5d7bf4b..4d48dbd 100644 --- a/services/spd/tspd/tspd_private.h +++ b/services/spd/tspd/tspd_private.h @@ -192,10 +192,11 @@ void __dead2 tspd_exit_sp(uint64_t c_rt_ctx, uint64_t ret); uint64_t tspd_synchronous_sp_entry(tsp_context_t *tsp_ctx); void __dead2 tspd_synchronous_sp_exit(tsp_context_t *tsp_ctx, uint64_t ret); -int32_t tspd_init_secure_context(uint64_t entrypoint, - uint32_t rw, - uint64_t mpidr, - tsp_context_t *tsp_ctx); +void tspd_init_tsp_ep_state(struct entry_point_info *tsp_ep, + uint32_t rw, + uint64_t pc, + tsp_context_t *tsp_ctx); + extern tsp_context_t tspd_sp_context[TSPD_CORE_COUNT]; extern struct tsp_vectors *tsp_vectors; #endif /*__ASSEMBLY__*/