Commit d9ec0c14 authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #175 from vikramkanigiri/vk/spd-init-by-stack-unwinding

Vk/spd init by stack unwinding
parents dd2bdee6 faaa2e76
...@@ -51,7 +51,7 @@ static int32_t (*bl32_init)(void); ...@@ -51,7 +51,7 @@ static int32_t (*bl32_init)(void);
* Variable to indicate whether next image to execute after BL31 is BL33 * Variable to indicate whether next image to execute after BL31 is BL33
* (non-secure & default) or BL32 (secure). * (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. * Simple function to initialise all BL31 helper libraries.
...@@ -89,9 +89,6 @@ void bl31_main(void) ...@@ -89,9 +89,6 @@ void bl31_main(void)
/* Clean caches before re-entering normal world */ /* Clean caches before re-entering normal world */
dcsw_op_all(DCCSW); 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 * 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. * decide which is the next image (BL32 or BL33) and how to execute it.
......
...@@ -39,6 +39,14 @@ BL32_SOURCES += bl32/tsp/tsp_main.c \ ...@@ -39,6 +39,14 @@ BL32_SOURCES += bl32/tsp/tsp_main.c \
BL32_LINKERFILE := bl32/tsp/tsp.ld.S 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 # Include the platform-specific TSP Makefile
# If no platform-specific TSP Makefile exists, it means TSP is not supported # If no platform-specific TSP Makefile exists, it means TSP is not supported
# on this platform. # on this platform.
......
...@@ -811,10 +811,10 @@ and is registered using the `bl31_register_bl32_init()` function. ...@@ -811,10 +811,10 @@ and is registered using the `bl31_register_bl32_init()` function.
Trusted Firmware supports two approaches for the SPD to pass control to BL3-2 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): 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 1. In the BL3-2 setup function, use `bl31_set_next_image_type()` to
for more details of CPU context support) for this CPU and use request that the exit from `bl31_main()` is to the BL3-2 entrypoint in
`bl31_set_next_image_type()` to request that the exit from `bl31_main()` is Secure-EL1. BL3-1 will exit to BL3-2 using the asynchronous method by
to the BL3-2 entrypoint in Secure-EL1. calling bl31_prepare_next_image_entry() and el3_exit().
When the BL3-2 has completed initialization at Secure-EL1, it returns to 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 BL3-1 by issuing an SMC, using a Function ID allocated to the SPD. On
...@@ -824,7 +824,8 @@ before returning through EL3 and running the non-trusted firmware (BL3-3): ...@@ -824,7 +824,8 @@ before returning through EL3 and running the non-trusted firmware (BL3-3):
the normal world firmware BL3-3. On return from the handler the framework the normal world firmware BL3-3. On return from the handler the framework
will exit to EL2 and run BL3-3. 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 invoke a 'world-switch synchronous call' to Secure-EL1 to run the BL3-2
entrypoint. entrypoint.
NOTE: The Test SPD service included with the Trusted Firmware provides one NOTE: The Test SPD service included with the Trusted Firmware provides one
......
...@@ -186,6 +186,13 @@ performed. ...@@ -186,6 +186,13 @@ performed.
value of `DEBUG` - i.e. by default this is only enabled for a debug value of `DEBUG` - i.e. by default this is only enabled for a debug
build of the firmware. 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 ### Creating a Firmware Image Package
FIPs are automatically created as part of the build instructions described in FIPs are automatically created as part of the build instructions described in
......
...@@ -73,7 +73,8 @@ extern unsigned long __COHERENT_RAM_END__; ...@@ -73,7 +73,8 @@ extern unsigned long __COHERENT_RAM_END__;
#if RESET_TO_BL31 #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 #else
/******************************************************************************* /*******************************************************************************
* Reference to structure which holds the arguments that have been passed to * Reference to structure which holds the arguments that have been passed to
...@@ -91,28 +92,12 @@ static bl31_params_t *bl2_to_bl31_params; ...@@ -91,28 +92,12 @@ static bl31_params_t *bl2_to_bl31_params;
entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
{ {
#if RESET_TO_BL31 #if RESET_TO_BL31
assert(sec_state_is_valid(type)); 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)
return &bl33_image_ep_info;
if (type == NON_SECURE) { else
/* return &bl32_image_ep_info;
* 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;
#else #else
entry_point_info_t *next_image_info; entry_point_info_t *next_image_info;
...@@ -155,7 +140,6 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, ...@@ -155,7 +140,6 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2,
assert(from_bl2 == NULL); assert(from_bl2 == NULL);
assert(plat_params_from_bl2 == NULL); assert(plat_params_from_bl2 == NULL);
/* /*
* Do initial security configuration to allow DRAM/device access. On * Do initial security configuration to allow DRAM/device access. On
* Base FVP only DRAM security is programmable (via TrustZone), but * Base FVP only DRAM security is programmable (via TrustZone), but
...@@ -163,6 +147,28 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, ...@@ -163,6 +147,28 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2,
* present. * present.
*/ */
fvp_security_setup(); 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 #else
/* Check params passed from BL2 should not be NULL, /* Check params passed from BL2 should not be NULL,
* We are not checking plat_params_from_bl2 as NULL as we are not * We are not checking plat_params_from_bl2 as NULL as we are not
......
...@@ -36,20 +36,21 @@ ...@@ -36,20 +36,21 @@
#include "tspd_private.h" #include "tspd_private.h"
/******************************************************************************* /*******************************************************************************
* Given a secure payload entrypoint, register width, cpu id & pointer to a * Given a secure payload entrypoint info pointer, entry point PC, register
* context data structure, this function will create a secure context ready for * width, cpu id & pointer to a context data structure, this function will
* programming an entry into the secure payload. * initialize tsp context and entry point info for the secure payload
******************************************************************************/ ******************************************************************************/
int32_t tspd_init_secure_context(uint64_t entrypoint, void tspd_init_tsp_ep_state(struct entry_point_info *tsp_entry_point,
uint32_t rw, uint32_t rw,
uint64_t mpidr, uint64_t pc,
tsp_context_t *tsp_ctx) tsp_context_t *tsp_ctx)
{ {
entry_point_info_t ep;
uint32_t ep_attr; uint32_t ep_attr;
/* Passing a NULL context is a critical programming error */ /* Passing a NULL context is a critical programming error */
assert(tsp_ctx); assert(tsp_ctx);
assert(tsp_entry_point);
assert(pc);
/* /*
* We support AArch64 TSP for now. * We support AArch64 TSP for now.
...@@ -58,25 +59,24 @@ int32_t tspd_init_secure_context(uint64_t entrypoint, ...@@ -58,25 +59,24 @@ int32_t tspd_init_secure_context(uint64_t entrypoint,
assert(rw == TSP_AARCH64); assert(rw == TSP_AARCH64);
/* Associate this context with the cpu specified */ /* Associate this context with the cpu specified */
tsp_ctx->mpidr = mpidr; tsp_ctx->mpidr = read_mpidr_el1();
tsp_ctx->state = 0; tsp_ctx->state = 0;
set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF); set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF);
clr_std_smc_active_flag(tsp_ctx->state); 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 */ /* initialise an entrypoint to set up the CPU context */
ep_attr = SECURE | EP_ST_ENABLE; ep_attr = SECURE | EP_ST_ENABLE;
if (read_sctlr_el3() & SCTLR_EE_BIT) if (read_sctlr_el3() & SCTLR_EE_BIT)
ep_attr |= EP_EE_BIG; ep_attr |= EP_EE_BIG;
SET_PARAM_HEAD(&ep, PARAM_EP, VERSION_1, ep_attr); SET_PARAM_HEAD(tsp_entry_point, 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); tsp_entry_point->pc = pc;
tsp_entry_point->spsr = SPSR_64(MODE_EL1,
return 0; MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS);
memset(&tsp_entry_point->args, 0, sizeof(tsp_entry_point->args));
} }
/******************************************************************************* /*******************************************************************************
......
...@@ -144,8 +144,7 @@ static uint64_t tspd_sel1_interrupt_handler(uint32_t id, ...@@ -144,8 +144,7 @@ static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
******************************************************************************/ ******************************************************************************/
int32_t tspd_setup(void) int32_t tspd_setup(void)
{ {
entry_point_info_t *image_info; entry_point_info_t *tsp_ep_info;
int32_t rc;
uint64_t mpidr = read_mpidr(); uint64_t mpidr = read_mpidr();
uint32_t linear_id; uint32_t linear_id;
...@@ -156,15 +155,20 @@ int32_t tspd_setup(void) ...@@ -156,15 +155,20 @@ int32_t tspd_setup(void)
* absence is a critical failure. TODO: Add support to * absence is a critical failure. TODO: Add support to
* conditionally include the SPD service * conditionally include the SPD service
*/ */
image_info = bl31_plat_get_next_image_ep_info(SECURE); tsp_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
assert(image_info); 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 * If there's no valid entry point for SP, we return a non-zero value
* signalling failure initializing the service. We bail out without * signalling failure initializing the service. We bail out without
* registering any handlers * registering any handlers
*/ */
if (!image_info->pc) if (!tsp_ep_info->pc)
return 1; return 1;
/* /*
...@@ -172,19 +176,21 @@ int32_t tspd_setup(void) ...@@ -172,19 +176,21 @@ int32_t tspd_setup(void)
* state i.e whether AArch32 or AArch64. Assuming it's AArch64 * state i.e whether AArch32 or AArch64. Assuming it's AArch64
* for the time being. * for the time being.
*/ */
rc = tspd_init_secure_context(image_info->pc, tspd_init_tsp_ep_state(tsp_ep_info,
TSP_AARCH64, TSP_AARCH64,
mpidr, tsp_ep_info->pc,
&tspd_sp_context[linear_id]); &tspd_sp_context[linear_id]);
assert(rc == 0);
#if TSP_INIT_ASYNC
bl31_set_next_image_type(SECURE);
#else
/* /*
* All TSPD initialization done. Now register our init function with * All TSPD initialization done. Now register our init function with
* BL31 for deferred invocation * BL31 for deferred invocation
*/ */
bl31_register_bl32_init(&tspd_init); bl31_register_bl32_init(&tspd_init);
#endif
return rc; return 0;
} }
/******************************************************************************* /*******************************************************************************
...@@ -199,37 +205,26 @@ int32_t tspd_setup(void) ...@@ -199,37 +205,26 @@ int32_t tspd_setup(void)
int32_t tspd_init(void) int32_t tspd_init(void)
{ {
uint64_t mpidr = read_mpidr(); uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr), flags; uint32_t linear_id = platform_get_core_pos(mpidr);
uint64_t rc;
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 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 * Get information about the Secure Payload (BL32) image. Its
* of vectors in return * absence is a critical failure.
*/ */
rc = tspd_synchronous_sp_entry(tsp_ctx); tsp_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
assert(rc != 0); assert(tsp_entry_point);
if (rc) {
set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
/* cm_init_context(mpidr, tsp_entry_point);
* 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 * Arrange for an entry into the test secure payload. It will be
* during code executing in the non-secure state. * returned via TSP_ENTRY_DONE case
*/ */
flags = 0; rc = tspd_synchronous_sp_entry(tsp_ctx);
set_interrupt_rm_flag(flags, NON_SECURE); assert(rc != 0);
rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
tspd_sel1_interrupt_handler,
flags);
if (rc)
panic();
return rc; return rc;
} }
...@@ -256,6 +251,10 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -256,6 +251,10 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
unsigned long mpidr = read_mpidr(); unsigned long mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr), ns; uint32_t linear_id = platform_get_core_pos(mpidr), ns;
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 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 */ /* Determine which security state this SMC originated from */
ns = is_caller_non_secure(flags); ns = is_caller_non_secure(flags);
...@@ -369,6 +368,45 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -369,6 +368,45 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
assert(tsp_vectors == NULL); assert(tsp_vectors == NULL);
tsp_vectors = (tsp_vectors_t *) x1; 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 * SP reports completion. The SPD must have initiated
* the original request through a synchronous entry * the original request through a synchronous entry
...@@ -376,6 +414,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -376,6 +414,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
* context. * context.
*/ */
tspd_synchronous_sp_exit(tsp_ctx, x1); tspd_synchronous_sp_exit(tsp_ctx, x1);
#endif
/* /*
* These function IDs is used only by the SP to indicate it has * These function IDs is used only by the SP to indicate it has
......
...@@ -123,16 +123,19 @@ static void tspd_cpu_on_finish_handler(uint64_t cookie) ...@@ -123,16 +123,19 @@ static void tspd_cpu_on_finish_handler(uint64_t cookie)
uint64_t mpidr = read_mpidr(); uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr); uint32_t linear_id = platform_get_core_pos(mpidr);
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
entry_point_info_t tsp_on_entrypoint;
assert(tsp_vectors); assert(tsp_vectors);
assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF);
/* Initialise this cpu's secure context */ tspd_init_tsp_ep_state(&tsp_on_entrypoint,
tspd_init_secure_context((uint64_t) &tsp_vectors->cpu_on_entry,
TSP_AARCH64, TSP_AARCH64,
mpidr, (uint64_t) &tsp_vectors->cpu_on_entry,
tsp_ctx); tsp_ctx);
/* Initialise this cpu's secure context */
cm_init_context(mpidr, &tsp_on_entrypoint);
/* Enter the TSP */ /* Enter the TSP */
rc = tspd_synchronous_sp_entry(tsp_ctx); rc = tspd_synchronous_sp_entry(tsp_ctx);
......
...@@ -192,10 +192,11 @@ uint64_t tspd_enter_sp(uint64_t *c_rt_ctx); ...@@ -192,10 +192,11 @@ uint64_t tspd_enter_sp(uint64_t *c_rt_ctx);
void __dead2 tspd_exit_sp(uint64_t c_rt_ctx, uint64_t ret); void __dead2 tspd_exit_sp(uint64_t c_rt_ctx, uint64_t ret);
uint64_t tspd_synchronous_sp_entry(tsp_context_t *tsp_ctx); 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); void __dead2 tspd_synchronous_sp_exit(tsp_context_t *tsp_ctx, uint64_t ret);
int32_t tspd_init_secure_context(uint64_t entrypoint, void tspd_init_tsp_ep_state(struct entry_point_info *tsp_ep,
uint32_t rw, uint32_t rw,
uint64_t mpidr, uint64_t pc,
tsp_context_t *tsp_ctx); tsp_context_t *tsp_ctx);
extern tsp_context_t tspd_sp_context[TSPD_CORE_COUNT]; extern tsp_context_t tspd_sp_context[TSPD_CORE_COUNT];
extern struct tsp_vectors *tsp_vectors; extern struct tsp_vectors *tsp_vectors;
#endif /*__ASSEMBLY__*/ #endif /*__ASSEMBLY__*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment