Home | History | Annotate | Download | only in tspd
      1 /*
      2  * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch_helpers.h>
      8 #include <assert.h>
      9 #include <bl_common.h>
     10 #include <context_mgmt.h>
     11 #include <debug.h>
     12 #include <platform.h>
     13 #include <tsp.h>
     14 #include "tspd_private.h"
     15 
     16 /*******************************************************************************
     17  * The target cpu is being turned on. Allow the TSPD/TSP to perform any actions
     18  * needed. Nothing at the moment.
     19  ******************************************************************************/
     20 static void tspd_cpu_on_handler(uint64_t target_cpu)
     21 {
     22 }
     23 
     24 /*******************************************************************************
     25  * This cpu is being turned off. Allow the TSPD/TSP to perform any actions
     26  * needed
     27  ******************************************************************************/
     28 static int32_t tspd_cpu_off_handler(uint64_t unused)
     29 {
     30 	int32_t rc = 0;
     31 	uint32_t linear_id = plat_my_core_pos();
     32 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
     33 
     34 	assert(tsp_vectors);
     35 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
     36 
     37 	/*
     38 	 * Abort any preempted SMC request before overwriting the SECURE
     39 	 * context.
     40 	 */
     41 	tspd_abort_preempted_smc(tsp_ctx);
     42 
     43 	/* Program the entry point and enter the TSP */
     44 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_off_entry);
     45 	rc = tspd_synchronous_sp_entry(tsp_ctx);
     46 
     47 	/*
     48 	 * Read the response from the TSP. A non-zero return means that
     49 	 * something went wrong while communicating with the TSP.
     50 	 */
     51 	if (rc != 0)
     52 		panic();
     53 
     54 	/*
     55 	 * Reset TSP's context for a fresh start when this cpu is turned on
     56 	 * subsequently.
     57 	 */
     58 	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF);
     59 
     60 	return 0;
     61 }
     62 
     63 /*******************************************************************************
     64  * This cpu is being suspended. S-EL1 state must have been saved in the
     65  * resident cpu (mpidr format) if it is a UP/UP migratable TSP.
     66  ******************************************************************************/
     67 static void tspd_cpu_suspend_handler(uint64_t max_off_pwrlvl)
     68 {
     69 	int32_t rc = 0;
     70 	uint32_t linear_id = plat_my_core_pos();
     71 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
     72 
     73 	assert(tsp_vectors);
     74 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
     75 
     76 	/*
     77 	 * Abort any preempted SMC request before overwriting the SECURE
     78 	 * context.
     79 	 */
     80 	tspd_abort_preempted_smc(tsp_ctx);
     81 
     82 	/* Program the entry point and enter the TSP */
     83 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_suspend_entry);
     84 	rc = tspd_synchronous_sp_entry(tsp_ctx);
     85 
     86 	/*
     87 	 * Read the response from the TSP. A non-zero return means that
     88 	 * something went wrong while communicating with the TSP.
     89 	 */
     90 	if (rc)
     91 		panic();
     92 
     93 	/* Update its context to reflect the state the TSP is in */
     94 	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_SUSPEND);
     95 }
     96 
     97 /*******************************************************************************
     98  * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits
     99  * before passing control back to the Secure Monitor. Entry in S-EL1 is done
    100  * after initialising minimal architectural state that guarantees safe
    101  * execution.
    102  ******************************************************************************/
    103 static void tspd_cpu_on_finish_handler(uint64_t unused)
    104 {
    105 	int32_t rc = 0;
    106 	uint32_t linear_id = plat_my_core_pos();
    107 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
    108 	entry_point_info_t tsp_on_entrypoint;
    109 
    110 	assert(tsp_vectors);
    111 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF);
    112 
    113 	tspd_init_tsp_ep_state(&tsp_on_entrypoint,
    114 				TSP_AARCH64,
    115 				(uint64_t) &tsp_vectors->cpu_on_entry,
    116 				tsp_ctx);
    117 
    118 	/* Initialise this cpu's secure context */
    119 	cm_init_my_context(&tsp_on_entrypoint);
    120 
    121 #if TSP_NS_INTR_ASYNC_PREEMPT
    122 	/*
    123 	 * Disable the NS interrupt locally since it will be enabled globally
    124 	 * within cm_init_my_context.
    125 	 */
    126 	disable_intr_rm_local(INTR_TYPE_NS, SECURE);
    127 #endif
    128 
    129 	/* Enter the TSP */
    130 	rc = tspd_synchronous_sp_entry(tsp_ctx);
    131 
    132 	/*
    133 	 * Read the response from the TSP. A non-zero return means that
    134 	 * something went wrong while communicating with the SP.
    135 	 */
    136 	if (rc != 0)
    137 		panic();
    138 
    139 	/* Update its context to reflect the state the SP is in */
    140 	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
    141 }
    142 
    143 /*******************************************************************************
    144  * This cpu has resumed from suspend. The SPD saved the TSP context when it
    145  * completed the preceding suspend call. Use that context to program an entry
    146  * into the TSP to allow it to do any remaining book keeping
    147  ******************************************************************************/
    148 static void tspd_cpu_suspend_finish_handler(uint64_t max_off_pwrlvl)
    149 {
    150 	int32_t rc = 0;
    151 	uint32_t linear_id = plat_my_core_pos();
    152 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
    153 
    154 	assert(tsp_vectors);
    155 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_SUSPEND);
    156 
    157 	/* Program the entry point, max_off_pwrlvl and enter the SP */
    158 	write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx),
    159 		      CTX_GPREG_X0,
    160 		      max_off_pwrlvl);
    161 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_resume_entry);
    162 	rc = tspd_synchronous_sp_entry(tsp_ctx);
    163 
    164 	/*
    165 	 * Read the response from the TSP. A non-zero return means that
    166 	 * something went wrong while communicating with the TSP.
    167 	 */
    168 	if (rc != 0)
    169 		panic();
    170 
    171 	/* Update its context to reflect the state the SP is in */
    172 	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
    173 }
    174 
    175 /*******************************************************************************
    176  * Return the type of TSP the TSPD is dealing with. Report the current resident
    177  * cpu (mpidr format) if it is a UP/UP migratable TSP.
    178  ******************************************************************************/
    179 static int32_t tspd_cpu_migrate_info(uint64_t *resident_cpu)
    180 {
    181 	return TSP_MIGRATE_INFO;
    182 }
    183 
    184 /*******************************************************************************
    185  * System is about to be switched off. Allow the TSPD/TSP to perform
    186  * any actions needed.
    187  ******************************************************************************/
    188 static void tspd_system_off(void)
    189 {
    190 	uint32_t linear_id = plat_my_core_pos();
    191 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
    192 
    193 	assert(tsp_vectors);
    194 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
    195 
    196 	/*
    197 	 * Abort any preempted SMC request before overwriting the SECURE
    198 	 * context.
    199 	 */
    200 	tspd_abort_preempted_smc(tsp_ctx);
    201 
    202 	/* Program the entry point */
    203 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_off_entry);
    204 
    205 	/* Enter the TSP. We do not care about the return value because we
    206 	 * must continue the shutdown anyway */
    207 	tspd_synchronous_sp_entry(tsp_ctx);
    208 }
    209 
    210 /*******************************************************************************
    211  * System is about to be reset. Allow the TSPD/TSP to perform
    212  * any actions needed.
    213  ******************************************************************************/
    214 static void tspd_system_reset(void)
    215 {
    216 	uint32_t linear_id = plat_my_core_pos();
    217 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
    218 
    219 	assert(tsp_vectors);
    220 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
    221 
    222 	/*
    223 	 * Abort any preempted SMC request before overwriting the SECURE
    224 	 * context.
    225 	 */
    226 	tspd_abort_preempted_smc(tsp_ctx);
    227 
    228 	/* Program the entry point */
    229 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_reset_entry);
    230 
    231 	/*
    232 	 * Enter the TSP. We do not care about the return value because we
    233 	 * must continue the reset anyway
    234 	 */
    235 	tspd_synchronous_sp_entry(tsp_ctx);
    236 }
    237 
    238 /*******************************************************************************
    239  * Structure populated by the TSP Dispatcher to be given a chance to perform any
    240  * TSP bookkeeping before PSCI executes a power mgmt.  operation.
    241  ******************************************************************************/
    242 const spd_pm_ops_t tspd_pm = {
    243 	.svc_on = tspd_cpu_on_handler,
    244 	.svc_off = tspd_cpu_off_handler,
    245 	.svc_suspend = tspd_cpu_suspend_handler,
    246 	.svc_on_finish = tspd_cpu_on_finish_handler,
    247 	.svc_suspend_finish = tspd_cpu_suspend_finish_handler,
    248 	.svc_migrate = NULL,
    249 	.svc_migrate_info = tspd_cpu_migrate_info,
    250 	.svc_system_off = tspd_system_off,
    251 	.svc_system_reset = tspd_system_reset
    252 };
    253