Merge pull request #178 from soby-mathew/sm/optmize_el3_context
Optimize EL3 register state stored in cpu_context structure
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));
-
- cm_init_context(mpidr, &ep);
+ SET_PARAM_HEAD(tsp_entry_point, PARAM_EP, VERSION_1, ep_attr);
- 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.
*/
- rc = tspd_synchronous_sp_entry(tsp_ctx);
- assert(rc != 0);
- if (rc) {
- set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
+ tsp_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
+ assert(tsp_entry_point);
- /*
- * TSP has been successfully initialized. Register power
- * managemnt hooks with PSCI
- */
- psci_register_spd_pm_hook(&tspd_pm);
- }
+ cm_init_context(mpidr, tsp_entry_point);
/*
- * Register an interrupt handler for S-EL1 interrupts when generated
- * during code executing in the non-secure state.
+ * Arrange for an entry into the test secure payload. It will be
+ * returned via TSP_ENTRY_DONE case
*/
- 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();
+ rc = tspd_synchronous_sp_entry(tsp_ctx);
+ assert(rc != 0);
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__*/