1 /* 2 * Copyright (c) 2013-2017, 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 "opteed_private.h" 14 15 /******************************************************************************* 16 * The target cpu is being turned on. Allow the OPTEED/OPTEE to perform any 17 * actions needed. Nothing at the moment. 18 ******************************************************************************/ 19 static void opteed_cpu_on_handler(u_register_t target_cpu) 20 { 21 } 22 23 /******************************************************************************* 24 * This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions 25 * needed 26 ******************************************************************************/ 27 static int32_t opteed_cpu_off_handler(u_register_t unused) 28 { 29 int32_t rc = 0; 30 uint32_t linear_id = plat_my_core_pos(); 31 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 32 33 assert(optee_vector_table); 34 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 35 36 /* Program the entry point and enter OPTEE */ 37 cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_off_entry); 38 rc = opteed_synchronous_sp_entry(optee_ctx); 39 40 /* 41 * Read the response from OPTEE. A non-zero return means that 42 * something went wrong while communicating with OPTEE. 43 */ 44 if (rc != 0) 45 panic(); 46 47 /* 48 * Reset OPTEE's context for a fresh start when this cpu is turned on 49 * subsequently. 50 */ 51 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF); 52 53 return 0; 54 } 55 56 /******************************************************************************* 57 * This cpu is being suspended. S-EL1 state must have been saved in the 58 * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. 59 ******************************************************************************/ 60 static void opteed_cpu_suspend_handler(u_register_t max_off_pwrlvl) 61 { 62 int32_t rc = 0; 63 uint32_t linear_id = plat_my_core_pos(); 64 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 65 66 assert(optee_vector_table); 67 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 68 69 write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X0, 70 max_off_pwrlvl); 71 72 /* Program the entry point and enter OPTEE */ 73 cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_suspend_entry); 74 rc = opteed_synchronous_sp_entry(optee_ctx); 75 76 /* 77 * Read the response from OPTEE. A non-zero return means that 78 * something went wrong while communicating with OPTEE. 79 */ 80 if (rc != 0) 81 panic(); 82 83 /* Update its context to reflect the state OPTEE is in */ 84 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND); 85 } 86 87 /******************************************************************************* 88 * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits 89 * before passing control back to the Secure Monitor. Entry in S-El1 is done 90 * after initialising minimal architectural state that guarantees safe 91 * execution. 92 ******************************************************************************/ 93 static void opteed_cpu_on_finish_handler(u_register_t unused) 94 { 95 int32_t rc = 0; 96 uint32_t linear_id = plat_my_core_pos(); 97 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 98 entry_point_info_t optee_on_entrypoint; 99 100 assert(optee_vector_table); 101 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF); 102 103 opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw, 104 (uint64_t)&optee_vector_table->cpu_on_entry, 105 0, 0, 0, optee_ctx); 106 107 /* Initialise this cpu's secure context */ 108 cm_init_my_context(&optee_on_entrypoint); 109 110 /* Enter OPTEE */ 111 rc = opteed_synchronous_sp_entry(optee_ctx); 112 113 /* 114 * Read the response from OPTEE. A non-zero return means that 115 * something went wrong while communicating with OPTEE. 116 */ 117 if (rc != 0) 118 panic(); 119 120 /* Update its context to reflect the state OPTEE is in */ 121 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); 122 } 123 124 /******************************************************************************* 125 * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it 126 * completed the preceding suspend call. Use that context to program an entry 127 * into OPTEE to allow it to do any remaining book keeping 128 ******************************************************************************/ 129 static void opteed_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl) 130 { 131 int32_t rc = 0; 132 uint32_t linear_id = plat_my_core_pos(); 133 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 134 135 assert(optee_vector_table); 136 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND); 137 138 /* Program the entry point, max_off_pwrlvl and enter the SP */ 139 write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), 140 CTX_GPREG_X0, 141 max_off_pwrlvl); 142 cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_resume_entry); 143 rc = opteed_synchronous_sp_entry(optee_ctx); 144 145 /* 146 * Read the response from OPTEE. A non-zero return means that 147 * something went wrong while communicating with OPTEE. 148 */ 149 if (rc != 0) 150 panic(); 151 152 /* Update its context to reflect the state OPTEE is in */ 153 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); 154 } 155 156 /******************************************************************************* 157 * Return the type of OPTEE the OPTEED is dealing with. Report the current 158 * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. 159 ******************************************************************************/ 160 static int32_t opteed_cpu_migrate_info(u_register_t *resident_cpu) 161 { 162 return OPTEE_MIGRATE_INFO; 163 } 164 165 /******************************************************************************* 166 * System is about to be switched off. Allow the OPTEED/OPTEE to perform 167 * any actions needed. 168 ******************************************************************************/ 169 static void opteed_system_off(void) 170 { 171 uint32_t linear_id = plat_my_core_pos(); 172 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 173 174 assert(optee_vector_table); 175 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 176 177 /* Program the entry point */ 178 cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_off_entry); 179 180 /* Enter OPTEE. We do not care about the return value because we 181 * must continue the shutdown anyway */ 182 opteed_synchronous_sp_entry(optee_ctx); 183 } 184 185 /******************************************************************************* 186 * System is about to be reset. Allow the OPTEED/OPTEE to perform 187 * any actions needed. 188 ******************************************************************************/ 189 static void opteed_system_reset(void) 190 { 191 uint32_t linear_id = plat_my_core_pos(); 192 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 193 194 assert(optee_vector_table); 195 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 196 197 /* Program the entry point */ 198 cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_reset_entry); 199 200 /* Enter OPTEE. We do not care about the return value because we 201 * must continue the reset anyway */ 202 opteed_synchronous_sp_entry(optee_ctx); 203 } 204 205 206 /******************************************************************************* 207 * Structure populated by the OPTEE Dispatcher to be given a chance to 208 * perform any OPTEE bookkeeping before PSCI executes a power mgmt. 209 * operation. 210 ******************************************************************************/ 211 const spd_pm_ops_t opteed_pm = { 212 .svc_on = opteed_cpu_on_handler, 213 .svc_off = opteed_cpu_off_handler, 214 .svc_suspend = opteed_cpu_suspend_handler, 215 .svc_on_finish = opteed_cpu_on_finish_handler, 216 .svc_suspend_finish = opteed_cpu_suspend_finish_handler, 217 .svc_migrate = NULL, 218 .svc_migrate_info = opteed_cpu_migrate_info, 219 .svc_system_off = opteed_system_off, 220 .svc_system_reset = opteed_system_reset, 221 }; 222