Add S-EL1 interrupt handling support in the TSPD
This patch adds support in the TSPD for registering a handler for S-EL1 interrupts. This handler ferries the interrupts generated in the non-secure state to the TSP at 'tsp_fiq_entry'. Support has been added to the smc handler to resume execution in the non-secure state once interrupt handling has been completed by the TSP. There is also support for resuming execution in the normal world if the TSP receives a EL3 interrupt. This code is currently unused. Change-Id: I816732595a2635e299572965179f11aa0bf93b69
This commit is contained in:
parent
757d591168
commit
843ff73369
|
@ -135,9 +135,12 @@
|
|||
typedef int32_t (*rt_svc_init_t)(void);
|
||||
|
||||
/* Convenience macros to return from SMC handler */
|
||||
#define SMC_RET0(_h) { \
|
||||
return (uint64_t) (_h); \
|
||||
}
|
||||
#define SMC_RET1(_h, _x0) { \
|
||||
write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X0, (_x0)); \
|
||||
return _x0; \
|
||||
SMC_RET0(_h); \
|
||||
}
|
||||
#define SMC_RET2(_h, _x0, _x1) { \
|
||||
write_ctx_reg(get_gpregs_ctx(_h), CTX_GPREG_X1, (_x1)); \
|
||||
|
|
|
@ -42,9 +42,9 @@
|
|||
* programming an entry into the secure payload.
|
||||
******************************************************************************/
|
||||
int32_t tspd_init_secure_context(uint64_t entrypoint,
|
||||
uint32_t rw,
|
||||
uint64_t mpidr,
|
||||
tsp_context_t *tsp_ctx)
|
||||
uint32_t rw,
|
||||
uint64_t mpidr,
|
||||
tsp_context_t *tsp_ctx)
|
||||
{
|
||||
uint32_t scr, sctlr;
|
||||
el1_sys_regs_t *el1_state;
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
#include <bl_common.h>
|
||||
#include <bl31.h>
|
||||
#include <context_mgmt.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <platform.h>
|
||||
#include <runtime_svc.h>
|
||||
#include <stddef.h>
|
||||
#include <tsp.h>
|
||||
|
@ -68,6 +71,75 @@ DEFINE_SVC_UUID(tsp_uuid,
|
|||
|
||||
int32_t tspd_init(meminfo_t *bl32_meminfo);
|
||||
|
||||
/*******************************************************************************
|
||||
* 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
|
||||
* 'tsp_fiq_entry()' for handling the interrupt.
|
||||
******************************************************************************/
|
||||
static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
|
||||
uint32_t flags,
|
||||
void *handle,
|
||||
void *cookie)
|
||||
{
|
||||
uint32_t linear_id;
|
||||
uint64_t mpidr;
|
||||
tsp_context_t *tsp_ctx;
|
||||
|
||||
/* Check the security state when the exception was generated */
|
||||
assert(get_interrupt_src_ss(flags) == NON_SECURE);
|
||||
|
||||
#if IMF_READ_INTERRUPT_ID
|
||||
/* Check the security status of the interrupt */
|
||||
assert(ic_get_interrupt_group(id) == SECURE);
|
||||
#endif
|
||||
|
||||
/* Sanity check the pointer to this cpu's context */
|
||||
mpidr = read_mpidr();
|
||||
assert(handle == cm_get_context(mpidr, NON_SECURE));
|
||||
|
||||
/* Save the non-secure context before entering the TSP */
|
||||
cm_el1_sysregs_context_save(NON_SECURE);
|
||||
|
||||
/* Get a reference to this cpu's TSP context */
|
||||
linear_id = platform_get_core_pos(mpidr);
|
||||
tsp_ctx = &tspd_sp_context[linear_id];
|
||||
assert(&tsp_ctx->cpu_ctx == cm_get_context(mpidr, SECURE));
|
||||
|
||||
/*
|
||||
* Determine if the TSP was previously preempted. Its last known
|
||||
* context has to be preserved in this case.
|
||||
* The TSP should return control to the TSPD after handling this
|
||||
* FIQ. Preserve essential EL3 context to allow entry into the
|
||||
* TSP at the FIQ entry point using the 'cpu_context' structure.
|
||||
* There is no need to save the secure system register context
|
||||
* since the TSP is supposed to preserve it during S-EL1 interrupt
|
||||
* handling.
|
||||
*/
|
||||
if (get_std_smc_active_flag(tsp_ctx->state)) {
|
||||
tsp_ctx->saved_spsr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
|
||||
CTX_SPSR_EL3);
|
||||
tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
|
||||
CTX_ELR_EL3);
|
||||
}
|
||||
|
||||
SMC_SET_EL3(&tsp_ctx->cpu_ctx,
|
||||
CTX_SPSR_EL3,
|
||||
make_spsr(MODE_EL1, MODE_SP_ELX, TSP_AARCH64));
|
||||
SMC_SET_EL3(&tsp_ctx->cpu_ctx,
|
||||
CTX_ELR_EL3,
|
||||
(uint64_t) tsp_entry_info->fiq_entry);
|
||||
cm_el1_sysregs_context_restore(SECURE);
|
||||
cm_set_next_eret_context(SECURE);
|
||||
|
||||
/*
|
||||
* Tell the TSP that it has to handle an FIQ synchronously. Also the
|
||||
* instruction in normal world where the interrupt was generated is
|
||||
* passed for debugging purposes. It is safe to retrieve this address
|
||||
* from ELR_EL3 as the secure context will not take effect until
|
||||
* el3_exit().
|
||||
*/
|
||||
SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_FIQ_AND_RETURN, read_elr_el3());
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type
|
||||
|
@ -105,9 +177,9 @@ int32_t tspd_setup(void)
|
|||
* for the time being.
|
||||
*/
|
||||
rc = tspd_init_secure_context(image_info->entrypoint,
|
||||
TSP_AARCH64,
|
||||
mpidr,
|
||||
&tspd_sp_context[linear_id]);
|
||||
TSP_AARCH64,
|
||||
mpidr,
|
||||
&tspd_sp_context[linear_id]);
|
||||
assert(rc == 0);
|
||||
|
||||
/*
|
||||
|
@ -132,7 +204,7 @@ int32_t tspd_setup(void)
|
|||
int32_t tspd_init(meminfo_t *bl32_meminfo)
|
||||
{
|
||||
uint64_t mpidr = read_mpidr();
|
||||
uint32_t linear_id = platform_get_core_pos(mpidr);
|
||||
uint32_t linear_id = platform_get_core_pos(mpidr), flags;
|
||||
uint64_t rc;
|
||||
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
|
||||
|
||||
|
@ -164,6 +236,18 @@ int32_t tspd_init(meminfo_t *bl32_meminfo)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -196,6 +280,73 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
|
|||
|
||||
switch (smc_fid) {
|
||||
|
||||
/*
|
||||
* This function ID is used only by the TSP to indicate that it has
|
||||
* finished handling a S-EL1 FIQ interrupt. Execution should resume
|
||||
* in the normal world.
|
||||
*/
|
||||
case TSP_HANDLED_S_EL1_FIQ:
|
||||
if (ns)
|
||||
SMC_RET1(handle, SMC_UNK);
|
||||
|
||||
assert(handle == cm_get_context(mpidr, SECURE));
|
||||
|
||||
/*
|
||||
* Restore the relevant EL3 state which saved to service
|
||||
* this SMC.
|
||||
*/
|
||||
if (get_std_smc_active_flag(tsp_ctx->state)) {
|
||||
SMC_SET_EL3(&tsp_ctx->cpu_ctx,
|
||||
CTX_SPSR_EL3,
|
||||
tsp_ctx->saved_spsr_el3);
|
||||
SMC_SET_EL3(&tsp_ctx->cpu_ctx,
|
||||
CTX_ELR_EL3,
|
||||
tsp_ctx->saved_elr_el3);
|
||||
}
|
||||
|
||||
/* Get a reference to the non-secure context */
|
||||
ns_cpu_context = cm_get_context(mpidr, NON_SECURE);
|
||||
assert(ns_cpu_context);
|
||||
|
||||
/*
|
||||
* Restore non-secure state. There is no need to save the
|
||||
* secure system register context since the TSP was supposed
|
||||
* to preserve it during S-EL1 interrupt handling.
|
||||
*/
|
||||
cm_el1_sysregs_context_restore(NON_SECURE);
|
||||
cm_set_next_eret_context(NON_SECURE);
|
||||
|
||||
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(mpidr, 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(mpidr, 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
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <arch.h>
|
||||
#include <context.h>
|
||||
#include <interrupt_mgmt.h>
|
||||
#include <platform.h>
|
||||
#include <psci.h>
|
||||
|
||||
|
@ -137,13 +138,19 @@ CASSERT(TSPD_C_RT_CTX_SIZE == sizeof(c_rt_regs_t), \
|
|||
|
||||
/*******************************************************************************
|
||||
* Structure which helps the SPD to maintain the per-cpu state of the SP.
|
||||
* 'state' - collection of flags to track SP state e.g. on/off
|
||||
* 'mpidr' - mpidr to associate a context with a cpu
|
||||
* 'c_rt_ctx' - stack address to restore C runtime context from after returning
|
||||
* from a synchronous entry into the SP.
|
||||
* 'cpu_ctx' - space to maintain SP architectural state
|
||||
* 'saved_spsr_el3' - temporary copy to allow FIQ handling when the TSP has been
|
||||
* preempted.
|
||||
* 'saved_elr_el3' - temporary copy to allow FIQ handling when the TSP has been
|
||||
* preempted.
|
||||
* 'state' - collection of flags to track SP state e.g. on/off
|
||||
* 'mpidr' - mpidr to associate a context with a cpu
|
||||
* 'c_rt_ctx' - stack address to restore C runtime context from after
|
||||
* returning from a synchronous entry into the SP.
|
||||
* 'cpu_ctx' - space to maintain SP architectural state
|
||||
******************************************************************************/
|
||||
typedef struct tsp_context {
|
||||
uint64_t saved_elr_el3;
|
||||
uint32_t saved_spsr_el3;
|
||||
uint32_t state;
|
||||
uint64_t mpidr;
|
||||
uint64_t c_rt_ctx;
|
||||
|
|
Loading…
Reference in New Issue