/******************************************************************************* * This cpu is being turned off. Allow the TSPD/TSP to perform any actions * needed ******************************************************************************/ static int32_t tspd_cpu_off_handler(uint64_t unused) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); /* Program the entry point and enter the TSP */ cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_off_entry); rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the TSP. */ if (rc != 0) panic(); /* * Reset TSP's context for a fresh start when this cpu is turned on * subsequently. */ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF); return 0; }
/******************************************************************************* * This function passes control to the Secure Payload image (BL32) for the first * time on the primary cpu after a cold boot. It assumes that a valid secure * context has already been created by tspd_setup() which can be directly used. * It also assumes that a valid non-secure context has been initialised by PSCI * so it does not need to save and restore any non-secure state. This function * performs a synchronous entry into the Secure payload. The SP passes control * back to this routine through a SMC. ******************************************************************************/ int32_t tspd_init(void) { uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; entry_point_info_t *tsp_entry_point; uint64_t rc; /* * Get information about the Secure Payload (BL32) image. Its * absence is a critical failure. */ tsp_entry_point = bl31_plat_get_next_image_ep_info(SECURE); assert(tsp_entry_point); cm_init_my_context(tsp_entry_point); /* * Arrange for an entry into the test secure payload. It will be * returned via TSP_ENTRY_DONE case */ rc = tspd_synchronous_sp_entry(tsp_ctx); assert(rc != 0); return rc; }
/******************************************************************************* * This cpu has resumed from suspend. The SPD saved the TSP context when it * completed the preceding suspend call. Use that context to program an entry * into the TSP to allow it to do any remaining book keeping ******************************************************************************/ static void tspd_cpu_suspend_finish_handler(uint64_t max_off_pwrlvl) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_SUSPEND); /* Program the entry point, max_off_pwrlvl and enter the SP */ write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx), CTX_GPREG_X0, max_off_pwrlvl); cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_resume_entry); rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the TSP. */ if (rc != 0) panic(); /* Update its context to reflect the state the SP is in */ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); }
/******************************************************************************* * This cpu is being suspended. S-EL1 state must have been saved in the * resident cpu (mpidr format) if it is a UP/UP migratable TSP. ******************************************************************************/ static void tspd_cpu_suspend_handler(uint64_t power_state) { int32_t rc = 0; uint64_t mpidr = read_mpidr(); uint32_t linear_id = platform_get_core_pos(mpidr); tsp_context *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_entry_info); assert(tsp_ctx->state == TSP_STATE_ON); /* Program the entry point, power_state parameter and enter the TSP */ write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx), CTX_GPREG_X0, power_state); cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_suspend_entry); rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the TSP. */ if (rc != 0) panic(); /* Update its context to reflect the state the TSP is in */ tsp_ctx->state = TSP_STATE_SUSPEND; }
/******************************************************************************* * This cpu is being turned off. Allow the TSPD/TSP to perform any actions * needed ******************************************************************************/ static int32_t tspd_cpu_off_handler(uint64_t cookie) { int32_t rc = 0; uint64_t mpidr = read_mpidr(); uint32_t linear_id = platform_get_core_pos(mpidr); tsp_context *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_entry_info); assert(tsp_ctx->state == TSP_STATE_ON); /* Program the entry point and enter the TSP */ cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_off_entry); rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the TSP. */ if (rc != 0) panic(); /* * Reset TSP's context for a fresh start when this cpu is turned on * subsequently. */ tsp_ctx->state = TSP_STATE_OFF; return 0; }
/******************************************************************************* * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits * before passing control back to the Secure Monitor. Entry in S-El1 is done * after initialising minimal architectural state that guarantees safe * execution. ******************************************************************************/ static void tspd_cpu_on_finish_handler(uint64_t cookie) { int32_t rc = 0; uint64_t mpidr = read_mpidr(); uint32_t linear_id = platform_get_core_pos(mpidr); tsp_context *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_entry_info); assert(tsp_ctx->state == TSP_STATE_OFF); /* Initialise this cpu's secure context */ tspd_init_secure_context((uint64_t) tsp_entry_info->cpu_on_entry, TSP_AARCH64, mpidr, tsp_ctx); /* Enter the TSP */ rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the SP. */ if (rc != 0) panic(); /* Update its context to reflect the state the SP is in */ tsp_ctx->state = TSP_STATE_ON; }
/******************************************************************************* * System is about to be reset. Allow the TSPD/TSP to perform * any actions needed. ******************************************************************************/ static void tspd_system_reset(void) { uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); /* Program the entry point */ cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_reset_entry); /* Enter the TSP. We do not care about the return value because we * must continue the reset anyway */ tspd_synchronous_sp_entry(tsp_ctx); }
/******************************************************************************* * This function takes an SP context pointer and abort any preempted SMC * request. * Return 1 if there was a preempted SMC request, 0 otherwise. ******************************************************************************/ int tspd_abort_preempted_smc(tsp_context_t *tsp_ctx) { if (!get_yield_smc_active_flag(tsp_ctx->state)) return 0; /* Abort any preempted SMC request */ clr_yield_smc_active_flag(tsp_ctx->state); /* * Arrange for an entry into the test secure payload. It will * be returned via TSP_ABORT_DONE case in tspd_smc_handler. */ cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->abort_yield_smc_entry); uint64_t rc = tspd_synchronous_sp_entry(tsp_ctx); if (rc != 0) panic(); return 1; }
/******************************************************************************* * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits * before passing control back to the Secure Monitor. Entry in S-El1 is done * after initialising minimal architectural state that guarantees safe * execution. ******************************************************************************/ static void tspd_cpu_on_finish_handler(uint64_t unused) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; entry_point_info_t tsp_on_entrypoint; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF); tspd_init_tsp_ep_state(&tsp_on_entrypoint, TSP_AARCH64, (uint64_t) &tsp_vectors->cpu_on_entry, tsp_ctx); /* Initialise this cpu's secure context */ cm_init_my_context(&tsp_on_entrypoint); #if TSP_NS_INTR_ASYNC_PREEMPT /* * Disable the NS interrupt locally since it will be enabled globally * within cm_init_my_context. */ disable_intr_rm_local(INTR_TYPE_NS, SECURE); #endif /* Enter the TSP */ rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the SP. */ if (rc != 0) panic(); /* Update its context to reflect the state the SP is in */ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); }