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