/******************************************************************************* * This function is the handler registered for S-EL1 interrupts by the * OPTEED. It validates the interrupt and upon success arranges entry into * the OPTEE at 'optee_fiq_entry()' for handling the interrupt. ******************************************************************************/ static uint64_t opteed_sel1_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { uint32_t linear_id; optee_context_t *optee_ctx; /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == NON_SECURE); /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(NON_SECURE)); /* Save the non-secure context before entering the OPTEE */ cm_el1_sysregs_context_save(NON_SECURE); /* Get a reference to this cpu's OPTEE context */ linear_id = plat_my_core_pos(); optee_ctx = &opteed_sp_context[linear_id]; assert(&optee_ctx->cpu_ctx == cm_get_context(SECURE)); cm_set_elr_el3(SECURE, (uint64_t)&optee_vectors->fiq_entry); cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); /* * Tell the OPTEE 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_RET1(&optee_ctx->cpu_ctx, read_elr_el3()); }
/******************************************************************************* * This function is the handler registered for Non secure interrupts by the SPM. * It validates the interrupt and upon success arranges entry into the normal * world for handling the interrupt. ******************************************************************************/ static uint64_t spm_ns_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == SECURE); spm_sp_synchronous_exit(SPM_SECURE_PARTITION_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 * 'tsp_sel1_intr_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; tsp_context_t *tsp_ctx; /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == NON_SECURE); /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(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 = plat_my_core_pos(); tsp_ctx = &tspd_sp_context[linear_id]; assert(&tsp_ctx->cpu_ctx == cm_get_context(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 * S-EL1 interrupt. Preserve essential EL3 context to allow entry into * the TSP at the S-EL1 interrupt 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); #if TSP_NS_INTR_ASYNC_PREEMPT /*Need to save the previously interrupted secure context */ memcpy(&tsp_ctx->sp_ctx, &tsp_ctx->cpu_ctx, TSPD_SP_CTX_SIZE); #endif } cm_el1_sysregs_context_restore(SECURE); cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->sel1_intr_entry, SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)); cm_set_next_eret_context(SECURE); /* * Tell the TSP that it has to handle a S-EL1 interrupt 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_SEL1_INTR_AND_RETURN, read_elr_el3()); }
/******************************************************************************* * This function is the handler registered for Non secure interrupts by the * TSPD. It validates the interrupt and upon success arranges entry into the * normal world for handling the interrupt. ******************************************************************************/ static uint64_t tspd_ns_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == SECURE); /* * Disable the routing of NS interrupts from secure world to EL3 while * interrupted on this core. */ disable_intr_rm_local(INTR_TYPE_NS, SECURE); return tspd_handle_sp_preemption(handle); }
/******************************************************************************* * This function is the handler registered for S-EL1 interrupts by the FIQD. It * validates the interrupt and upon success arranges entry into the TSP at * 'tsp_fiq_entry()' for handling the interrupt. ******************************************************************************/ static uint64_t fiqd_sel1_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { unsigned int iar; /* 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(plat_ic_get_interrupt_type(id) == INTR_TYPE_S_EL1); #endif /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(NON_SECURE)); /* Save the non-secure context before entering the TSP */ cm_el1_sysregs_context_save(NON_SECURE); iar = get_ack_info(); ack_sgi(iar); if(id == WDT_IRQ_BIT_ID) { /* FIX-ME : change 0xFE to the kernel online CPU mask */ fiq_smp_call_function(0xFE, aee_wdt_dump, 0, 0); aee_wdt_dump(); } if(id == FIQ_SMP_CALL_SGI) { fiq_icc_isr(); } SMC_RET0(handle); #if 0 /* Get a reference to this cpu's TSP context */ linear_id = platform_get_core_pos(mpidr); tsp_ctx = &fiqd_sp_context[linear_id]; assert(&tsp_ctx->cpu_ctx == cm_get_context(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 FIQD 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); } cm_el1_sysregs_context_restore(SECURE); cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->fiq_entry, SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)); 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()); #endif }
//************************************************************************************************ // FIQ handler for FIQ when in NWd uint64_t tbase_fiq_handler( uint32_t id, uint32_t flags, void *handle, void *cookie) { uint64_t mpidr; uint32_t linear_id; tbase_context *tbase_ctx; mpidr = read_mpidr(); linear_id = platform_get_core_pos(mpidr); tbase_ctx = &secure_context[linear_id]; assert(&tbase_ctx->cpu_ctx == cm_get_context(SECURE)); /* Check if the vector has been entered for SGI/FIQ dump reason */ if (id == FIQ_SMP_CALL_SGI) { /* ACK gic */ { unsigned int iar; iar = gicc_read_IAR(get_plat_config()->gicc_base); gicc_write_EOIR(get_plat_config()->gicc_base, iar); } /* Save the non-secure context before entering the TSP */ cm_el1_sysregs_context_save(NON_SECURE); /* Call customer's dump implementation */ plat_tbase_dump(); // Load NWd //cm_el1_sysregs_context_restore(NON_SECURE); //cm_set_next_eret_context(NON_SECURE); } else { /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == NON_SECURE); /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(NON_SECURE)); if ((tbaseExecutionStatus&TBASE_STATUS_SMC_OK_BIT)==0) { // TBASE must be initialized to be usable // TODO: What should we really do here? // We should disable FIQs to prevent futher interrupts DBG_PRINTF( "tbase_interrupt_handler tbase not ready for interrupt\n\r" ); return 1; } if(tbase_ctx->state == TBASE_STATE_OFF) { DBG_PRINTF( "tbase_interrupt_handler tbase not ready for fastcall\n\r" ); return 1; } /* Save the non-secure context before entering the TSP */ cm_el1_sysregs_context_save(NON_SECURE); /* Switch to secure context now */ cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); // Load SWd context tbase_setup_entry_nwd((cpu_context_t *)handle,ENTRY_OFFSET_FIQ); // Enter tbase. tbase must return using normal SMC, which will continue here. tbase_synchronous_sp_entry(tbase_ctx); // Load NWd cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); } return 0; }