1 /* 2 * Copyright 2017, Rockchip Electronics Co., Ltd 3 * hisping lin, <hisping.lin@rock-chips.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 #include <common.h> 8 #include <optee_include/OpteeClientMem.h> 9 #include <optee_include/OpteeClientSMC.h> 10 #include <optee_include/OpteeClientRPC.h> 11 #include <optee_include/teesmc.h> 12 #include <optee_include/teesmc_v2.h> 13 14 15 #define TEEC_SMC_DEFAULT_CACHE_ATTRIBUTES \ 16 (TEESMC_ATTR_CACHE_DEFAULT << TEESMC_ATTR_CACHE_SHIFT); 17 18 static void SetTeeSmc32Params(TEEC_Operation *operation, 19 t_teesmc32_param *TeeSmc32Param); 20 static void GetTeeSmc32Params(t_teesmc32_param *TeeSmc32Param, 21 TEEC_Operation *operation); 22 static TEEC_Result OpteeSmcCall(t_teesmc32_arg *TeeSmc32Arg); 23 24 void tee_uuid_to_octets(uint8_t *d, const TEEC_UUID *s) 25 { 26 d[0] = s->timeLow >> 24; 27 d[1] = s->timeLow >> 16; 28 d[2] = s->timeLow >> 8; 29 d[3] = s->timeLow; 30 d[4] = s->timeMid >> 8; 31 d[5] = s->timeMid; 32 d[6] = s->timeHiAndVersion >> 8; 33 d[7] = s->timeHiAndVersion; 34 memcpy(d + 8, s->clockSeqAndNode, sizeof(s->clockSeqAndNode)); 35 } 36 37 /* 38 * This function opens a new Session between the Client application and the 39 * specified TEE application. 40 * 41 * Only connection_method == TEEC_LOGIN_PUBLIC is supported connection_data and 42 * operation shall be set to NULL. 43 */ 44 TEEC_Result TEEC_SMC_OpenSession(TEEC_Context *context, 45 TEEC_Session *session, 46 const TEEC_UUID *destination, 47 TEEC_Operation *operation, 48 uint32_t *error_origin) 49 { 50 TEEC_Result TeecResult = TEEC_SUCCESS; 51 uint32_t TeeSmc32ArgLength; 52 uint32_t TeeSmcMetaSessionLength; 53 54 t_teesmc32_arg *TeeSmc32Arg = NULL; 55 t_teesmc32_param *TeeSmc32Param = NULL; 56 57 t_teesmc_meta_open_session *TeeSmcMetaSession = NULL; 58 59 uint32_t MetaNum = 2; 60 61 *error_origin = TEEC_ORIGIN_API; 62 63 TeeSmc32ArgLength = 64 TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum); 65 66 TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength); 67 68 if (TeeSmc32Arg == NULL) { 69 TeecResult = TEEC_ERROR_OUT_OF_MEMORY; 70 goto Exit; 71 } 72 73 memset(TeeSmc32Arg, 0, TeeSmc32ArgLength); 74 75 TeeSmcMetaSessionLength = sizeof(*TeeSmcMetaSession); 76 77 TeeSmcMetaSession = (t_teesmc_meta_open_session *) 78 OpteeClientMemAlloc(TeeSmcMetaSessionLength); 79 80 if (TeeSmcMetaSession == NULL) { 81 TeecResult = TEEC_ERROR_OUT_OF_MEMORY; 82 goto Exit; 83 } 84 85 memset(TeeSmcMetaSession, 0, TeeSmcMetaSessionLength); 86 87 TeeSmc32Arg->cmd = TEESMC_CMD_OPEN_SESSION; 88 TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum; 89 90 TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg); 91 92 memcpy(&TeeSmcMetaSession->uuid, 93 destination, 94 sizeof(TeeSmcMetaSession->uuid)); 95 TeeSmcMetaSession->clnt_login = TEEC_LOGIN_PUBLIC; 96 97 TeeSmc32Param[0].u.memref.buf_ptr = (uint32_t) (size_t)TeeSmcMetaSession; 98 TeeSmc32Param[0].u.memref.size = sizeof(*TeeSmcMetaSession); 99 100 #ifdef CONFIG_OPTEE_V1 101 memcpy((void *)&TeeSmc32Param[0].u.value, &TeeSmcMetaSession->uuid, sizeof(TeeSmcMetaSession->uuid)); 102 #endif 103 104 #ifdef CONFIG_OPTEE_V2 105 uint8_t * session_uuid = (uint8_t *)&TeeSmcMetaSession->uuid; 106 tee_uuid_to_octets(session_uuid, destination); 107 memcpy((void *)&TeeSmc32Param[0].u.value, &TeeSmcMetaSession->uuid, sizeof(TeeSmcMetaSession->uuid)); 108 #endif 109 TeeSmc32Param[1].u.value.c = TeeSmcMetaSession->clnt_login; 110 111 TeeSmc32Param[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 | 112 OPTEE_MSG_ATTR_META_V2; 113 TeeSmc32Param[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 | 114 OPTEE_MSG_ATTR_META_V2; 115 116 SetTeeSmc32Params(operation, TeeSmc32Param + MetaNum); 117 118 *error_origin = TEEC_ORIGIN_COMMS; 119 120 TeecResult = OpteeSmcCall(TeeSmc32Arg); 121 if (TeecResult != TEEC_SUCCESS) 122 goto Exit; 123 124 session->id = TeeSmc32Arg->session; 125 TeecResult = TeeSmc32Arg->ret; 126 *error_origin = TeeSmc32Arg->ret_origin; 127 128 GetTeeSmc32Params(TeeSmc32Param + MetaNum, operation); 129 130 Exit: 131 if (TeeSmc32Arg != NULL) 132 OpteeClientMemFree(TeeSmc32Arg); 133 134 if (TeeSmcMetaSession != NULL) 135 OpteeClientMemFree(TeeSmcMetaSession); 136 137 return TeecResult; 138 } 139 140 /* 141 * This function closes a session which has been opened with a TEE 142 * application. 143 * 144 * Note that the GP specification does not allow for this API to fail and return 145 * a failure code however we'll support this at the SMC level so we can get 146 * see debug information about such failures. 147 */ 148 TEEC_Result TEEC_SMC_CloseSession(TEEC_Session *session, 149 uint32_t *error_origin) 150 { 151 TEEC_Result TeecResult = TEEC_SUCCESS; 152 uint32_t TeeSmc32ArgLength; 153 154 t_teesmc32_arg *TeeSmc32Arg = NULL; 155 156 *error_origin = TEEC_ORIGIN_API; 157 158 TeeSmc32ArgLength = 159 TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT); 160 161 TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength); 162 163 if (TeeSmc32Arg == NULL) { 164 TeecResult = TEEC_ERROR_OUT_OF_MEMORY; 165 goto Exit; 166 } 167 168 memset(TeeSmc32Arg, 0, TeeSmc32ArgLength); 169 170 TeeSmc32Arg->cmd = TEESMC_CMD_CLOSE_SESSION; 171 TeeSmc32Arg->session = session->id; 172 173 *error_origin = TEEC_ORIGIN_COMMS; 174 175 TeecResult = OpteeSmcCall(TeeSmc32Arg); 176 177 if (TeecResult != TEEC_SUCCESS) 178 goto Exit; 179 180 TeecResult = TeeSmc32Arg->ret; 181 *error_origin = TeeSmc32Arg->ret_origin; 182 183 Exit: 184 if (TeeSmc32Arg != NULL) 185 OpteeClientMemFree(TeeSmc32Arg); 186 187 return TeecResult; 188 } 189 190 /* 191 * Invokes a TEE command (secure service, sub-PA or whatever). 192 */ 193 TEEC_Result TEEC_SMC_InvokeCommand(TEEC_Session *session, 194 uint32_t cmd_id, 195 TEEC_Operation *operation, 196 uint32_t *error_origin) 197 { 198 TEEC_Result TeecResult = TEEC_SUCCESS; 199 uint32_t TeeSmc32ArgLength; 200 201 t_teesmc32_arg *TeeSmc32Arg = NULL; 202 t_teesmc32_param *TeeSmc32Param = NULL; 203 204 *error_origin = TEEC_ORIGIN_API; 205 206 TeeSmc32ArgLength = 207 TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT); 208 209 TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength); 210 211 if (TeeSmc32Arg == NULL) { 212 TeecResult = TEEC_ERROR_OUT_OF_MEMORY; 213 goto Exit; 214 } 215 216 memset(TeeSmc32Arg, 0, TeeSmc32ArgLength); 217 218 TeeSmc32Arg->cmd = TEESMC_CMD_INVOKE_COMMAND; 219 TeeSmc32Arg->ta_func = cmd_id; 220 TeeSmc32Arg->session = session->id; 221 TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; 222 223 TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg); 224 225 SetTeeSmc32Params(operation, TeeSmc32Param); 226 227 *error_origin = TEEC_ORIGIN_COMMS; 228 229 TeecResult = OpteeSmcCall(TeeSmc32Arg); 230 if (TeecResult != TEEC_SUCCESS) 231 goto Exit; 232 233 TeecResult = TeeSmc32Arg->ret; 234 *error_origin = TeeSmc32Arg->ret_origin; 235 236 GetTeeSmc32Params(TeeSmc32Param, operation); 237 238 Exit: 239 if (TeeSmc32Arg != NULL) 240 OpteeClientMemFree(TeeSmc32Arg); 241 242 243 return TeecResult; 244 } 245 246 /* 247 * Request a cancellation of a in-progress operation (best effort) 248 * 249 * Note that the GP specification does not allow for this API to fail and return 250 * a failure code however we'll support this at the SMC level so we can get 251 * see debug information about such failures. 252 */ 253 TEEC_Result TEEC_SMC_RequestCancellation(TEEC_Operation *operation, 254 uint32_t *error_origin) 255 { 256 return TEEC_ERROR_NOT_IMPLEMENTED; 257 } 258 259 /* 260 * Set the call parameter blocks in the 261 * SMC call based on the TEEC parameter supplied. 262 * This only handles the parameters supplied in 263 * the originating call and not those 264 * considered internal meta parameters and is 265 * thus constrained by the build 266 * constants exposed to callers. 267 */ 268 void SetTeeSmc32Params(TEEC_Operation *operation, 269 t_teesmc32_param *TeeSmc32Param) 270 { 271 uint32_t ParamCount; 272 273 for (ParamCount = 0; 274 ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT; 275 ParamCount++) { 276 uint32_t attr = 277 TEEC_PARAM_TYPE_GET(operation->paramTypes, ParamCount); 278 279 if (attr == TEEC_MEMREF_TEMP_INPUT || 280 attr == TEEC_MEMREF_TEMP_OUTPUT || 281 attr == TEEC_MEMREF_TEMP_INOUT) { 282 283 attr += (OPTEE_MSG_ATTR_TYPE_TMEM_INPUT_V2 - TEEC_MEMREF_TEMP_INPUT); 284 debug("TEEC: OPTEE_OS_V2 ARCH64 attr %x\n", attr); 285 286 TeeSmc32Param[ParamCount].attr = attr; 287 TeeSmc32Param[ParamCount].u.memref.buf_ptr = 288 (uint32_t)(size_t)operation->params[ParamCount].tmpref.buffer; 289 TeeSmc32Param[ParamCount].u.memref.size = 290 operation->params[ParamCount].tmpref.size; 291 } else { 292 TeeSmc32Param[ParamCount].attr = attr; 293 TeeSmc32Param[ParamCount].u.value.a = 294 operation->params[ParamCount].value.a; 295 TeeSmc32Param[ParamCount].u.value.b = 296 operation->params[ParamCount].value.b; 297 } 298 } 299 } 300 301 /* 302 * Get the return parameter blocks from 303 * the SMC call into the TEEC parameter supplied. 304 * This only handles the parameters supplied 305 * in the originating call and not those 306 * considered internal meta parameters and 307 * is thus constrained by the build 308 * constants exposed to callers. 309 */ 310 void GetTeeSmc32Params(t_teesmc32_param *TeeSmc32Param, 311 TEEC_Operation *operation) 312 { 313 uint32_t ParamCount; 314 315 for (ParamCount = 0; 316 ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT; 317 ParamCount++) { 318 operation->params[ParamCount].value.a = 319 TeeSmc32Param[ParamCount].u.value.a; 320 operation->params[ParamCount].value.b = 321 TeeSmc32Param[ParamCount].u.value.b; 322 } 323 } 324 325 /* 326 * Populate the SMC registers and make 327 * the call with OpTEE specific handling. 328 */ 329 TEEC_Result OpteeSmcCall(t_teesmc32_arg *TeeSmc32Arg) 330 { 331 TEEC_Result TeecResult = TEEC_SUCCESS; 332 ARM_SMC_ARGS ArmSmcArgs = {0}; 333 334 ArmSmcArgs.Arg0 = OPTEE_SMC_CALL_WITH_ARG_V2; 335 ArmSmcArgs.Arg1 = 0; 336 ArmSmcArgs.Arg2 = (uint32_t) (size_t)TeeSmc32Arg; 337 338 while (1) { 339 tee_smc_call(&ArmSmcArgs); 340 debug("TEEC: arg0=0x%x arg1=0x%x arg2=0x%x arg3=0x%x \n", 341 ArmSmcArgs.Arg0, ArmSmcArgs.Arg1, ArmSmcArgs.Arg2, ArmSmcArgs.Arg3); 342 if (TEESMC_RETURN_IS_RPC(ArmSmcArgs.Arg0)) { 343 (void) OpteeRpcCallback(&ArmSmcArgs); 344 } else if (ArmSmcArgs.Arg0 == TEESMC_RETURN_UNKNOWN_FUNCTION) { 345 TeecResult = TEEC_ERROR_NOT_IMPLEMENTED; 346 break; 347 } else if (ArmSmcArgs.Arg0 != TEESMC_RETURN_OK) { 348 TeecResult = TEEC_ERROR_COMMUNICATION; 349 break; 350 } else { 351 TeecResult = TEEC_SUCCESS; 352 break; 353 } 354 } 355 356 return TeecResult; 357 } 358 359