1 /* 2 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <arch_helpers.h> 32 #include <assert.h> 33 #include <bl_common.h> 34 #include <context_mgmt.h> 35 #include <debug.h> 36 #include <platform.h> 37 #include "opteed_private.h" 38 39 /******************************************************************************* 40 * The target cpu is being turned on. Allow the OPTEED/OPTEE to perform any 41 * actions needed. Nothing at the moment. 42 ******************************************************************************/ 43 static void opteed_cpu_on_handler(uint64_t target_cpu) 44 { 45 } 46 47 /******************************************************************************* 48 * This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions 49 * needed 50 ******************************************************************************/ 51 static int32_t opteed_cpu_off_handler(uint64_t unused) 52 { 53 int32_t rc = 0; 54 uint32_t linear_id = plat_my_core_pos(); 55 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 56 57 assert(optee_vectors); 58 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 59 60 /* Program the entry point and enter OPTEE */ 61 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_off_entry); 62 rc = opteed_synchronous_sp_entry(optee_ctx); 63 64 /* 65 * Read the response from OPTEE. A non-zero return means that 66 * something went wrong while communicating with OPTEE. 67 */ 68 if (rc != 0) 69 panic(); 70 71 /* 72 * Reset OPTEE's context for a fresh start when this cpu is turned on 73 * subsequently. 74 */ 75 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF); 76 77 return 0; 78 } 79 80 /******************************************************************************* 81 * This cpu is being suspended. S-EL1 state must have been saved in the 82 * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. 83 ******************************************************************************/ 84 static void opteed_cpu_suspend_handler(uint64_t max_off_pwrlvl) 85 { 86 int32_t rc = 0; 87 uint32_t linear_id = plat_my_core_pos(); 88 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 89 90 assert(optee_vectors); 91 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 92 93 /* Program the entry point and enter OPTEE */ 94 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_suspend_entry); 95 rc = opteed_synchronous_sp_entry(optee_ctx); 96 97 /* 98 * Read the response from OPTEE. A non-zero return means that 99 * something went wrong while communicating with OPTEE. 100 */ 101 if (rc != 0) 102 panic(); 103 104 /* Update its context to reflect the state OPTEE is in */ 105 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND); 106 } 107 108 /******************************************************************************* 109 * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits 110 * before passing control back to the Secure Monitor. Entry in S-El1 is done 111 * after initialising minimal architectural state that guarantees safe 112 * execution. 113 ******************************************************************************/ 114 static void opteed_cpu_on_finish_handler(uint64_t unused) 115 { 116 int32_t rc = 0; 117 uint32_t linear_id = plat_my_core_pos(); 118 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 119 entry_point_info_t optee_on_entrypoint; 120 121 assert(optee_vectors); 122 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF); 123 124 opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw, 125 (uint64_t)&optee_vectors->cpu_on_entry, 126 optee_ctx); 127 128 /* Initialise this cpu's secure context */ 129 cm_init_my_context(&optee_on_entrypoint); 130 131 /* Enter OPTEE */ 132 rc = opteed_synchronous_sp_entry(optee_ctx); 133 134 /* 135 * Read the response from OPTEE. A non-zero return means that 136 * something went wrong while communicating with OPTEE. 137 */ 138 if (rc != 0) 139 panic(); 140 141 /* Update its context to reflect the state OPTEE is in */ 142 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); 143 } 144 145 /******************************************************************************* 146 * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it 147 * completed the preceding suspend call. Use that context to program an entry 148 * into OPTEE to allow it to do any remaining book keeping 149 ******************************************************************************/ 150 static void opteed_cpu_suspend_finish_handler(uint64_t max_off_pwrlvl) 151 { 152 int32_t rc = 0; 153 uint32_t linear_id = plat_my_core_pos(); 154 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 155 156 assert(optee_vectors); 157 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND); 158 159 /* Program the entry point, max_off_pwrlvl and enter the SP */ 160 write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), 161 CTX_GPREG_X0, 162 max_off_pwrlvl); 163 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_resume_entry); 164 rc = opteed_synchronous_sp_entry(optee_ctx); 165 166 /* 167 * Read the response from OPTEE. A non-zero return means that 168 * something went wrong while communicating with OPTEE. 169 */ 170 if (rc != 0) 171 panic(); 172 173 /* Update its context to reflect the state OPTEE is in */ 174 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); 175 } 176 177 /******************************************************************************* 178 * Return the type of OPTEE the OPTEED is dealing with. Report the current 179 * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. 180 ******************************************************************************/ 181 static int32_t opteed_cpu_migrate_info(uint64_t *resident_cpu) 182 { 183 return OPTEE_MIGRATE_INFO; 184 } 185 186 /******************************************************************************* 187 * System is about to be switched off. Allow the OPTEED/OPTEE to perform 188 * any actions needed. 189 ******************************************************************************/ 190 static void opteed_system_off(void) 191 { 192 uint32_t linear_id = plat_my_core_pos(); 193 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 194 195 assert(optee_vectors); 196 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 197 198 /* Program the entry point */ 199 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_off_entry); 200 201 /* Enter OPTEE. We do not care about the return value because we 202 * must continue the shutdown anyway */ 203 opteed_synchronous_sp_entry(optee_ctx); 204 } 205 206 /******************************************************************************* 207 * System is about to be reset. Allow the OPTEED/OPTEE to perform 208 * any actions needed. 209 ******************************************************************************/ 210 static void opteed_system_reset(void) 211 { 212 uint32_t linear_id = plat_my_core_pos(); 213 optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 214 215 assert(optee_vectors); 216 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 217 218 /* Program the entry point */ 219 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_reset_entry); 220 221 /* Enter OPTEE. We do not care about the return value because we 222 * must continue the reset anyway */ 223 opteed_synchronous_sp_entry(optee_ctx); 224 } 225 226 227 /******************************************************************************* 228 * Structure populated by the OPTEE Dispatcher to be given a chance to 229 * perform any OPTEE bookkeeping before PSCI executes a power mgmt. 230 * operation. 231 ******************************************************************************/ 232 const spd_pm_ops_t opteed_pm = { 233 .svc_on = opteed_cpu_on_handler, 234 .svc_off = opteed_cpu_off_handler, 235 .svc_suspend = opteed_cpu_suspend_handler, 236 .svc_on_finish = opteed_cpu_on_finish_handler, 237 .svc_suspend_finish = opteed_cpu_suspend_finish_handler, 238 .svc_migrate = NULL, 239 .svc_migrate_info = opteed_cpu_migrate_info, 240 .svc_system_off = opteed_system_off, 241 .svc_system_reset = opteed_system_reset, 242 }; 243 244