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