diff --git a/bl32/tsp/aarch64/tsp_exceptions.S b/bl32/tsp/aarch64/tsp_exceptions.S index 4c0d436..272d94b 100644 --- a/bl32/tsp/aarch64/tsp_exceptions.S +++ b/bl32/tsp/aarch64/tsp_exceptions.S @@ -125,7 +125,7 @@ save_caller_regs_and_lr /* We just update some statistics in the handler */ - bl tsp_irq_received + bl tsp_handle_preemption /* Hand over control to the normal world to handle the IRQ */ smc #0 /* The resume std smc starts from here */ diff --git a/bl32/tsp/tsp_interrupt.c b/bl32/tsp/tsp_interrupt.c index 139642d..d5379cd 100644 --- a/bl32/tsp/tsp_interrupt.c +++ b/bl32/tsp/tsp_interrupt.c @@ -67,6 +67,25 @@ #endif } +/****************************************************************************** + * This function is invoked when a non S-EL1 interrupt is received and causes + * the preemption of TSP. This function returns TSP_PREEMPTED and results + * in the control being handed over to EL3 for handling the interrupt. + *****************************************************************************/ +int32_t tsp_handle_preemption(void) +{ + uint32_t linear_id = plat_my_core_pos(); + + tsp_stats[linear_id].preempt_intr_count++; +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + spin_lock(&console_lock); + VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n", + read_mpidr(), tsp_stats[linear_id].preempt_intr_count); + spin_unlock(&console_lock); +#endif + return TSP_PREEMPTED; +} + /******************************************************************************* * TSP FIQ handler called as a part of both synchronous and asynchronous * handling of FIQ interrupts. It returns 0 upon successfully handling a S-EL1 @@ -82,16 +101,21 @@ * Get the highest priority pending interrupt id and see if it is the * secure physical generic timer interrupt in which case, handle it. * Otherwise throw this interrupt at the EL3 firmware. + * + * There is a small time window between reading the highest priority + * pending interrupt and acknowledging it during which another + * interrupt of higher priority could become the highest pending + * interrupt. This is not expected to happen currently for TSP. */ id = plat_ic_get_pending_interrupt_id(); /* TSP can only handle the secure physical timer interrupt */ if (id != TSP_IRQ_SEC_PHY_TIMER) - return TSP_EL3_FIQ; + return tsp_handle_preemption(); /* - * Handle the interrupt. Also sanity check if it has been preempted by - * another secure interrupt through an assertion. + * Acknowledge and handle the secure timer interrupt. Also sanity check + * if it has been preempted by another interrupt through an assertion. */ id = plat_ic_acknowledge_interrupt(); assert(id == TSP_IRQ_SEC_PHY_TIMER); @@ -110,18 +134,3 @@ #endif return 0; } - -int32_t tsp_irq_received(void) -{ - uint32_t linear_id = plat_my_core_pos(); - - tsp_stats[linear_id].irq_count++; -#if LOG_LEVEL >= LOG_LEVEL_VERBOSE - spin_lock(&console_lock); - VERBOSE("TSP: cpu 0x%lx received irq\n", read_mpidr()); - VERBOSE("TSP: cpu 0x%lx: %d irq requests\n", - read_mpidr(), tsp_stats[linear_id].irq_count); - spin_unlock(&console_lock); -#endif - return TSP_PREEMPTED; -} diff --git a/bl32/tsp/tsp_private.h b/bl32/tsp/tsp_private.h index 39fb5f6..346351c 100644 --- a/bl32/tsp/tsp_private.h +++ b/bl32/tsp/tsp_private.h @@ -55,9 +55,10 @@ typedef struct work_statistics { uint32_t fiq_count; /* Number of FIQs on this cpu */ - uint32_t irq_count; /* Number of IRQs on this cpu */ uint32_t sync_fiq_count; /* Number of sync. fiqs on this cpu */ uint32_t sync_fiq_ret_count; /* Number of fiq returns on this cpu */ + /* Number of non s-el1 interrupts on this cpu which preempted TSP */ + uint32_t preempt_intr_count; uint32_t smc_count; /* Number of returns on this cpu */ uint32_t eret_count; /* Number of entries on this cpu */ uint32_t cpu_on_count; /* Number of cpu on requests */ diff --git a/include/bl32/tsp/tsp.h b/include/bl32/tsp/tsp.h index c6578b7..2286b3f 100644 --- a/include/bl32/tsp/tsp.h +++ b/include/bl32/tsp/tsp.h @@ -50,7 +50,6 @@ * the TSPD after handling the interrupt else execution can remain in the TSP. */ #define TSP_HANDLED_S_EL1_FIQ 0xf2000006 -#define TSP_EL3_FIQ 0xf2000007 /* SMC function ID that TSP uses to request service from secure monitor */ #define TSP_GET_ARGS 0xf2001000 diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c index 6223160..0d6e0d2 100644 --- a/services/spd/tspd/tspd_main.c +++ b/services/spd/tspd/tspd_main.c @@ -72,9 +72,16 @@ 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) { cpu_context_t *ns_cpu_context; + assert(handle == cm_get_context(SECURE)); cm_el1_sysregs_context_save(SECURE); /* Get a reference to the non-secure context */ @@ -88,8 +95,16 @@ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); + /* + * We need to restore non secure context according to + * the SEL1 context which got preempted and currently + * TSP can only be preempted when a STD SMC is ongoing. + * Return SMC_PREEMPTED in x0 and restore non secure + * context. + */ SMC_RET1(ns_cpu_context, SMC_PREEMPTED); } + /******************************************************************************* * 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 @@ -356,35 +371,6 @@ 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 * finished initialising itself after a cold boot @@ -438,8 +424,7 @@ panic(); /* - * Disable the interrupt NS locally since it will be enabled globally - * within cm_init_my_context. + * Disable the NS interrupt locally. */ disable_intr_rm_local(INTR_TYPE_NS, SECURE); #endif