Commit 4ca473db authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #456 from soby-mathew/sm/gicv3-tsp-plat-changes-v2

Modify TSP and ARM standard platforms for new GIC drivers v2
parents 8d297cc9 63b8440f
...@@ -55,7 +55,17 @@ NEED_BL32 := yes ...@@ -55,7 +55,17 @@ NEED_BL32 := yes
# Flag used to enable routing of non-secure interrupts to EL3 when they are # Flag used to enable routing of non-secure interrupts to EL3 when they are
# generated while the code is executing in S-EL1/0. # generated while the code is executing in S-EL1/0.
TSPD_ROUTE_IRQ_TO_EL3 := 0 TSP_NS_INTR_ASYNC_PREEMPT := 0
$(eval $(call assert_boolean,TSPD_ROUTE_IRQ_TO_EL3)) # If TSPD_ROUTE_IRQ_TO_EL3 build flag is defined, use it to define value for
$(eval $(call add_define,TSPD_ROUTE_IRQ_TO_EL3)) # TSP_NS_INTR_ASYNC_PREEMPT for backward compatibility.
ifdef TSPD_ROUTE_IRQ_TO_EL3
ifeq (${ERROR_DEPRECATED},1)
$(error "TSPD_ROUTE_IRQ_TO_EL3 is deprecated. Please use the new build flag TSP_NS_INTR_ASYNC_PREEMPT")
endif
$(warning "TSPD_ROUTE_IRQ_TO_EL3 is deprecated. Please use the new build flag TSP_NS_INTR_ASYNC_PREEMPT")
TSP_NS_INTR_ASYNC_PREEMPT := ${TSPD_ROUTE_IRQ_TO_EL3}
endif
$(eval $(call assert_boolean,TSP_NS_INTR_ASYNC_PREEMPT))
$(eval $(call add_define,TSP_NS_INTR_ASYNC_PREEMPT))
...@@ -72,9 +72,16 @@ DEFINE_SVC_UUID(tsp_uuid, ...@@ -72,9 +72,16 @@ DEFINE_SVC_UUID(tsp_uuid,
int32_t tspd_init(void); int32_t tspd_init(void);
/*
* This helper function handles Secure EL1 preemption. The preemption could be
* due Non Secure interrupts or EL3 interrupts. In both the cases we context
* switch to the normal world and in case of EL3 interrupts, it will again be
* routed to EL3 which will get handled at the exception vectors.
*/
uint64_t tspd_handle_sp_preemption(void *handle) uint64_t tspd_handle_sp_preemption(void *handle)
{ {
cpu_context_t *ns_cpu_context; cpu_context_t *ns_cpu_context;
assert(handle == cm_get_context(SECURE)); assert(handle == cm_get_context(SECURE));
cm_el1_sysregs_context_save(SECURE); cm_el1_sysregs_context_save(SECURE);
/* Get a reference to the non-secure context */ /* Get a reference to the non-secure context */
...@@ -82,18 +89,30 @@ uint64_t tspd_handle_sp_preemption(void *handle) ...@@ -82,18 +89,30 @@ uint64_t tspd_handle_sp_preemption(void *handle)
assert(ns_cpu_context); assert(ns_cpu_context);
/* /*
* Restore non-secure state. The secure system * To allow Secure EL1 interrupt handler to re-enter TSP while TSP
* register context will be saved when required. * is preempted, the secure system register context which will get
* overwritten must be additionally saved. This is currently done
* by the TSPD S-EL1 interrupt handler.
*/
/*
* Restore non-secure state.
*/ */
cm_el1_sysregs_context_restore(NON_SECURE); cm_el1_sysregs_context_restore(NON_SECURE);
cm_set_next_eret_context(NON_SECURE); cm_set_next_eret_context(NON_SECURE);
/*
* The TSP was preempted during STD SMC execution.
* Return back to the normal world with SMC_PREEMPTED as error
* code in x0.
*/
SMC_RET1(ns_cpu_context, SMC_PREEMPTED); SMC_RET1(ns_cpu_context, SMC_PREEMPTED);
} }
/******************************************************************************* /*******************************************************************************
* This function is the handler registered for S-EL1 interrupts by the TSPD. It * This function is the handler registered for S-EL1 interrupts by the TSPD. It
* validates the interrupt and upon success arranges entry into the TSP at * validates the interrupt and upon success arranges entry into the TSP at
* 'tsp_fiq_entry()' for handling the interrupt. * 'tsp_sel1_intr_entry()' for handling the interrupt.
******************************************************************************/ ******************************************************************************/
static uint64_t tspd_sel1_interrupt_handler(uint32_t id, static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
uint32_t flags, uint32_t flags,
...@@ -121,44 +140,44 @@ static uint64_t tspd_sel1_interrupt_handler(uint32_t id, ...@@ -121,44 +140,44 @@ static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
* Determine if the TSP was previously preempted. Its last known * Determine if the TSP was previously preempted. Its last known
* context has to be preserved in this case. * context has to be preserved in this case.
* The TSP should return control to the TSPD after handling this * The TSP should return control to the TSPD after handling this
* FIQ. Preserve essential EL3 context to allow entry into the * S-EL1 interrupt. Preserve essential EL3 context to allow entry into
* TSP at the FIQ entry point using the 'cpu_context' structure. * the TSP at the S-EL1 interrupt entry point using the 'cpu_context'
* There is no need to save the secure system register context * structure. There is no need to save the secure system register
* since the TSP is supposed to preserve it during S-EL1 interrupt * context since the TSP is supposed to preserve it during S-EL1
* handling. * interrupt handling.
*/ */
if (get_std_smc_active_flag(tsp_ctx->state)) { if (get_std_smc_active_flag(tsp_ctx->state)) {
tsp_ctx->saved_spsr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx, tsp_ctx->saved_spsr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
CTX_SPSR_EL3); CTX_SPSR_EL3);
tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx, tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
CTX_ELR_EL3); CTX_ELR_EL3);
#if TSPD_ROUTE_IRQ_TO_EL3 #if TSP_NS_INTR_ASYNC_PREEMPT
/*Need to save the previously interrupted secure context */ /*Need to save the previously interrupted secure context */
memcpy(&tsp_ctx->sp_ctx, &tsp_ctx->cpu_ctx, TSPD_SP_CTX_SIZE); memcpy(&tsp_ctx->sp_ctx, &tsp_ctx->cpu_ctx, TSPD_SP_CTX_SIZE);
#endif #endif
} }
cm_el1_sysregs_context_restore(SECURE); cm_el1_sysregs_context_restore(SECURE);
cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->fiq_entry, cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->sel1_intr_entry,
SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)); SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
cm_set_next_eret_context(SECURE); cm_set_next_eret_context(SECURE);
/* /*
* Tell the TSP that it has to handle an FIQ synchronously. Also the * Tell the TSP that it has to handle a S-EL1 interrupt synchronously.
* instruction in normal world where the interrupt was generated is * Also the instruction in normal world where the interrupt was
* passed for debugging purposes. It is safe to retrieve this address * generated is passed for debugging purposes. It is safe to retrieve
* from ELR_EL3 as the secure context will not take effect until * this address from ELR_EL3 as the secure context will not take effect
* el3_exit(). * until el3_exit().
*/ */
SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_FIQ_AND_RETURN, read_elr_el3()); SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_SEL1_INTR_AND_RETURN, read_elr_el3());
} }
#if TSPD_ROUTE_IRQ_TO_EL3 #if TSP_NS_INTR_ASYNC_PREEMPT
/******************************************************************************* /*******************************************************************************
* This function is the handler registered for S-EL1 interrupts by the TSPD. It * This function is the handler registered for Non secure interrupts by the
* validates the interrupt and upon success arranges entry into the TSP at * TSPD. It validates the interrupt and upon success arranges entry into the
* 'tsp_fiq_entry()' for handling the interrupt. * normal world for handling the interrupt.
******************************************************************************/ ******************************************************************************/
static uint64_t tspd_ns_interrupt_handler(uint32_t id, static uint64_t tspd_ns_interrupt_handler(uint32_t id,
uint32_t flags, uint32_t flags,
...@@ -312,10 +331,11 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -312,10 +331,11 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
/* /*
* This function ID is used only by the TSP to indicate that it has * This function ID is used only by the TSP to indicate that it has
* finished handling a S-EL1 FIQ interrupt. Execution should resume * finished handling a S-EL1 interrupt or was preempted by a higher
* priority pending EL3 interrupt. Execution should resume
* in the normal world. * in the normal world.
*/ */
case TSP_HANDLED_S_EL1_FIQ: case TSP_HANDLED_S_EL1_INTR:
if (ns) if (ns)
SMC_RET1(handle, SMC_UNK); SMC_RET1(handle, SMC_UNK);
...@@ -332,7 +352,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -332,7 +352,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
SMC_SET_EL3(&tsp_ctx->cpu_ctx, SMC_SET_EL3(&tsp_ctx->cpu_ctx,
CTX_ELR_EL3, CTX_ELR_EL3,
tsp_ctx->saved_elr_el3); tsp_ctx->saved_elr_el3);
#if TSPD_ROUTE_IRQ_TO_EL3 #if TSP_NS_INTR_ASYNC_PREEMPT
/* /*
* Need to restore the previously interrupted * Need to restore the previously interrupted
* secure context. * secure context.
...@@ -356,35 +376,6 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -356,35 +376,6 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
SMC_RET0((uint64_t) ns_cpu_context); SMC_RET0((uint64_t) ns_cpu_context);
/*
* This function ID is used only by the TSP to indicate that it was
* interrupted due to a EL3 FIQ interrupt. Execution should resume
* in the normal world.
*/
case TSP_EL3_FIQ:
if (ns)
SMC_RET1(handle, SMC_UNK);
assert(handle == cm_get_context(SECURE));
/* Assert that standard SMC execution has been preempted */
assert(get_std_smc_active_flag(tsp_ctx->state));
/* Save the secure system register state */
cm_el1_sysregs_context_save(SECURE);
/* Get a reference to the non-secure context */
ns_cpu_context = cm_get_context(NON_SECURE);
assert(ns_cpu_context);
/* Restore non-secure state */
cm_el1_sysregs_context_restore(NON_SECURE);
cm_set_next_eret_context(NON_SECURE);
SMC_RET1(ns_cpu_context, TSP_EL3_FIQ);
/* /*
* This function ID is used only by the SP to indicate it has * This function ID is used only by the SP to indicate it has
* finished initialising itself after a cold boot * finished initialising itself after a cold boot
...@@ -422,7 +413,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -422,7 +413,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
if (rc) if (rc)
panic(); panic();
#if TSPD_ROUTE_IRQ_TO_EL3 #if TSP_NS_INTR_ASYNC_PREEMPT
/* /*
* Register an interrupt handler for NS interrupts when * Register an interrupt handler for NS interrupts when
* generated during code executing in secure state are * generated during code executing in secure state are
...@@ -438,8 +429,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -438,8 +429,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
panic(); panic();
/* /*
* Disable the interrupt NS locally since it will be enabled globally * Disable the NS interrupt locally.
* within cm_init_my_context.
*/ */
disable_intr_rm_local(INTR_TYPE_NS, SECURE); disable_intr_rm_local(INTR_TYPE_NS, SECURE);
#endif #endif
...@@ -561,7 +551,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -561,7 +551,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
set_std_smc_active_flag(tsp_ctx->state); set_std_smc_active_flag(tsp_ctx->state);
cm_set_elr_el3(SECURE, (uint64_t) cm_set_elr_el3(SECURE, (uint64_t)
&tsp_vectors->std_smc_entry); &tsp_vectors->std_smc_entry);
#if TSPD_ROUTE_IRQ_TO_EL3 #if TSP_NS_INTR_ASYNC_PREEMPT
/* /*
* Enable the routing of NS interrupts to EL3 * Enable the routing of NS interrupts to EL3
* during STD SMC processing on this core. * during STD SMC processing on this core.
...@@ -592,7 +582,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -592,7 +582,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
cm_set_next_eret_context(NON_SECURE); cm_set_next_eret_context(NON_SECURE);
if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_STD) { if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_STD) {
clr_std_smc_active_flag(tsp_ctx->state); clr_std_smc_active_flag(tsp_ctx->state);
#if TSPD_ROUTE_IRQ_TO_EL3 #if TSP_NS_INTR_ASYNC_PREEMPT
/* /*
* Disable the routing of NS interrupts to EL3 * Disable the routing of NS interrupts to EL3
* after STD SMC processing is finished on this * after STD SMC processing is finished on this
...@@ -635,7 +625,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -635,7 +625,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
* We are done stashing the non-secure context. Ask the * We are done stashing the non-secure context. Ask the
* secure payload to do the work now. * secure payload to do the work now.
*/ */
#if TSPD_ROUTE_IRQ_TO_EL3 #if TSP_NS_INTR_ASYNC_PREEMPT
/* /*
* Enable the routing of NS interrupts to EL3 during resumption * Enable the routing of NS interrupts to EL3 during resumption
* of STD SMC call on this core. * of STD SMC call on this core.
......
...@@ -130,7 +130,7 @@ static void tspd_cpu_on_finish_handler(uint64_t unused) ...@@ -130,7 +130,7 @@ static void tspd_cpu_on_finish_handler(uint64_t unused)
/* Initialise this cpu's secure context */ /* Initialise this cpu's secure context */
cm_init_my_context(&tsp_on_entrypoint); cm_init_my_context(&tsp_on_entrypoint);
#if TSPD_ROUTE_IRQ_TO_EL3 #if TSP_NS_INTR_ASYNC_PREEMPT
/* /*
* Disable the NS interrupt locally since it will be enabled globally * Disable the NS interrupt locally since it will be enabled globally
* within cm_init_my_context. * within cm_init_my_context.
......
...@@ -183,10 +183,10 @@ CASSERT(TSPD_SP_CTX_SIZE == sizeof(sp_ctx_regs_t), \ ...@@ -183,10 +183,10 @@ CASSERT(TSPD_SP_CTX_SIZE == sizeof(sp_ctx_regs_t), \
/******************************************************************************* /*******************************************************************************
* Structure which helps the SPD to maintain the per-cpu state of the SP. * Structure which helps the SPD to maintain the per-cpu state of the SP.
* 'saved_spsr_el3' - temporary copy to allow FIQ handling when the TSP has been * 'saved_spsr_el3' - temporary copy to allow S-EL1 interrupt handling when
* preempted. * the TSP has been preempted.
* 'saved_elr_el3' - temporary copy to allow FIQ handling when the TSP has been * 'saved_elr_el3' - temporary copy to allow S-EL1 interrupt handling when
* preempted. * the TSP has been preempted.
* 'state' - collection of flags to track SP state e.g. on/off * 'state' - collection of flags to track SP state e.g. on/off
* 'mpidr' - mpidr to associate a context with a cpu * 'mpidr' - mpidr to associate a context with a cpu
* 'c_rt_ctx' - stack address to restore C runtime context from after * 'c_rt_ctx' - stack address to restore C runtime context from after
...@@ -207,7 +207,7 @@ typedef struct tsp_context { ...@@ -207,7 +207,7 @@ typedef struct tsp_context {
uint64_t c_rt_ctx; uint64_t c_rt_ctx;
cpu_context_t cpu_ctx; cpu_context_t cpu_ctx;
uint64_t saved_tsp_args[TSP_NUM_ARGS]; uint64_t saved_tsp_args[TSP_NUM_ARGS];
#if TSPD_ROUTE_IRQ_TO_EL3 #if TSP_NS_INTR_ASYNC_PREEMPT
sp_ctx_regs_t sp_ctx; sp_ctx_regs_t sp_ctx;
#endif #endif
} tsp_context_t; } tsp_context_t;
......
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