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