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 #ifdef CONFIG_OPTEE_V1 60 uint32_t MetaNum = 1; 61 #endif 62 63 #ifdef CONFIG_OPTEE_V2 64 uint32_t MetaNum = 2; 65 #endif 66 67 *error_origin = TEEC_ORIGIN_API; 68 69 TeeSmc32ArgLength = 70 TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum); 71 72 TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength); 73 74 if (TeeSmc32Arg == NULL) { 75 TeecResult = TEEC_ERROR_OUT_OF_MEMORY; 76 goto Exit; 77 } 78 79 memset(TeeSmc32Arg, 0, TeeSmc32ArgLength); 80 81 TeeSmcMetaSessionLength = sizeof(*TeeSmcMetaSession); 82 83 TeeSmcMetaSession = (t_teesmc_meta_open_session *) 84 OpteeClientMemAlloc(TeeSmcMetaSessionLength); 85 86 if (TeeSmcMetaSession == NULL) { 87 TeecResult = TEEC_ERROR_OUT_OF_MEMORY; 88 goto Exit; 89 } 90 91 memset(TeeSmcMetaSession, 0, TeeSmcMetaSessionLength); 92 93 TeeSmc32Arg->cmd = TEESMC_CMD_OPEN_SESSION; 94 TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum; 95 96 TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg); 97 98 memcpy(&TeeSmcMetaSession->uuid, 99 destination, 100 sizeof(TeeSmcMetaSession->uuid)); 101 TeeSmcMetaSession->clnt_login = TEEC_LOGIN_PUBLIC; 102 103 TeeSmc32Param[0].u.memref.buf_ptr = (uint32_t) (size_t)TeeSmcMetaSession; 104 TeeSmc32Param[0].u.memref.size = sizeof(*TeeSmcMetaSession); 105 106 #ifdef CONFIG_OPTEE_V1 107 #ifdef CONFIG_ARM64 108 TeeSmc32Param[0].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT | 109 TEESMC_ATTR_META | 110 TEEC_SMC_DEFAULT_CACHE_ATTRIBUTES; 111 #else 112 TeeSmc32Param[0].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT | 113 TEESMC_ATTR_META; 114 #endif 115 #endif 116 117 #ifdef CONFIG_OPTEE_V2 118 uint8_t * session_uuid = (uint8_t *)&TeeSmcMetaSession->uuid; 119 tee_uuid_to_octets(session_uuid, destination); 120 memcpy((void *)&TeeSmc32Param[0].u.value, &TeeSmcMetaSession->uuid, sizeof(TeeSmcMetaSession->uuid)); 121 TeeSmc32Param[1].u.value.c = TeeSmcMetaSession->clnt_login; 122 123 TeeSmc32Param[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 | 124 OPTEE_MSG_ATTR_META_V2; 125 TeeSmc32Param[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 | 126 OPTEE_MSG_ATTR_META_V2; 127 #endif 128 129 SetTeeSmc32Params(operation, TeeSmc32Param + MetaNum); 130 131 *error_origin = TEEC_ORIGIN_COMMS; 132 133 TeecResult = OpteeSmcCall(TeeSmc32Arg); 134 if (TeecResult != TEEC_SUCCESS) 135 goto Exit; 136 137 session->id = TeeSmc32Arg->session; 138 TeecResult = TeeSmc32Arg->ret; 139 *error_origin = TeeSmc32Arg->ret_origin; 140 141 GetTeeSmc32Params(TeeSmc32Param + MetaNum, operation); 142 143 Exit: 144 if (TeeSmc32Arg != NULL) 145 OpteeClientMemFree(TeeSmc32Arg); 146 147 if (TeeSmcMetaSession != NULL) 148 OpteeClientMemFree(TeeSmcMetaSession); 149 150 return TeecResult; 151 } 152 153 /* 154 * This function closes a session which has been opened with a TEE 155 * application. 156 * 157 * Note that the GP specification does not allow for this API to fail and return 158 * a failure code however we'll support this at the SMC level so we can get 159 * see debug information about such failures. 160 */ 161 TEEC_Result TEEC_SMC_CloseSession(TEEC_Session *session, 162 uint32_t *error_origin) 163 { 164 TEEC_Result TeecResult = TEEC_SUCCESS; 165 uint32_t TeeSmc32ArgLength; 166 167 t_teesmc32_arg *TeeSmc32Arg = NULL; 168 169 *error_origin = TEEC_ORIGIN_API; 170 171 TeeSmc32ArgLength = 172 TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT); 173 174 TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength); 175 176 if (TeeSmc32Arg == NULL) { 177 TeecResult = TEEC_ERROR_OUT_OF_MEMORY; 178 goto Exit; 179 } 180 181 memset(TeeSmc32Arg, 0, TeeSmc32ArgLength); 182 183 TeeSmc32Arg->cmd = TEESMC_CMD_CLOSE_SESSION; 184 TeeSmc32Arg->session = session->id; 185 186 *error_origin = TEEC_ORIGIN_COMMS; 187 188 TeecResult = OpteeSmcCall(TeeSmc32Arg); 189 190 if (TeecResult != TEEC_SUCCESS) 191 goto Exit; 192 193 TeecResult = TeeSmc32Arg->ret; 194 *error_origin = TeeSmc32Arg->ret_origin; 195 196 Exit: 197 if (TeeSmc32Arg != NULL) 198 OpteeClientMemFree(TeeSmc32Arg); 199 200 return TeecResult; 201 } 202 203 /* 204 * Invokes a TEE command (secure service, sub-PA or whatever). 205 */ 206 TEEC_Result TEEC_SMC_InvokeCommand(TEEC_Session *session, 207 uint32_t cmd_id, 208 TEEC_Operation *operation, 209 uint32_t *error_origin) 210 { 211 TEEC_Result TeecResult = TEEC_SUCCESS; 212 uint32_t TeeSmc32ArgLength; 213 214 t_teesmc32_arg *TeeSmc32Arg = NULL; 215 t_teesmc32_param *TeeSmc32Param = NULL; 216 217 *error_origin = TEEC_ORIGIN_API; 218 219 TeeSmc32ArgLength = 220 TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT); 221 222 TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength); 223 224 if (TeeSmc32Arg == NULL) { 225 TeecResult = TEEC_ERROR_OUT_OF_MEMORY; 226 goto Exit; 227 } 228 229 memset(TeeSmc32Arg, 0, TeeSmc32ArgLength); 230 231 TeeSmc32Arg->cmd = TEESMC_CMD_INVOKE_COMMAND; 232 TeeSmc32Arg->ta_func = cmd_id; 233 TeeSmc32Arg->session = session->id; 234 TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT; 235 236 TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg); 237 238 SetTeeSmc32Params(operation, TeeSmc32Param); 239 240 *error_origin = TEEC_ORIGIN_COMMS; 241 242 TeecResult = OpteeSmcCall(TeeSmc32Arg); 243 if (TeecResult != TEEC_SUCCESS) 244 goto Exit; 245 246 TeecResult = TeeSmc32Arg->ret; 247 *error_origin = TeeSmc32Arg->ret_origin; 248 249 GetTeeSmc32Params(TeeSmc32Param, operation); 250 251 Exit: 252 if (TeeSmc32Arg != NULL) 253 OpteeClientMemFree(TeeSmc32Arg); 254 255 256 return TeecResult; 257 } 258 259 /* 260 * Request a cancellation of a in-progress operation (best effort) 261 * 262 * Note that the GP specification does not allow for this API to fail and return 263 * a failure code however we'll support this at the SMC level so we can get 264 * see debug information about such failures. 265 */ 266 TEEC_Result TEEC_SMC_RequestCancellation(TEEC_Operation *operation, 267 uint32_t *error_origin) 268 { 269 return TEEC_ERROR_NOT_IMPLEMENTED; 270 } 271 272 /* 273 * Set the call parameter blocks in the 274 * SMC call based on the TEEC parameter supplied. 275 * This only handles the parameters supplied in 276 * the originating call and not those 277 * considered internal meta parameters and is 278 * thus constrained by the build 279 * constants exposed to callers. 280 */ 281 void SetTeeSmc32Params(TEEC_Operation *operation, 282 t_teesmc32_param *TeeSmc32Param) 283 { 284 uint32_t ParamCount; 285 286 for (ParamCount = 0; 287 ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT; 288 ParamCount++) { 289 uint32_t attr = 290 TEEC_PARAM_TYPE_GET(operation->paramTypes, ParamCount); 291 292 if (attr == TEEC_MEMREF_TEMP_INPUT || 293 attr == TEEC_MEMREF_TEMP_OUTPUT || 294 attr == TEEC_MEMREF_TEMP_INOUT) { 295 296 #ifdef CONFIG_OPTEE_V1 297 #ifdef CONFIG_ARM64 298 attr |= TEEC_SMC_DEFAULT_CACHE_ATTRIBUTES; 299 debug("TEEC: OPTEE_OS_V1 ARCH64 attr %x\n", attr); 300 #else 301 debug("TEEC: OPTEE_OS_V1 ARCH32 attr %x\n", attr); 302 #endif 303 #endif 304 305 #ifdef CONFIG_OPTEE_V2 306 attr += (OPTEE_MSG_ATTR_TYPE_TMEM_INPUT_V2 - TEEC_MEMREF_TEMP_INPUT); 307 debug("TEEC: OPTEE_OS_V2 ARCH64 attr %x\n", attr); 308 #endif 309 310 TeeSmc32Param[ParamCount].attr = attr; 311 TeeSmc32Param[ParamCount].u.memref.buf_ptr = 312 (uint32_t)(size_t)operation->params[ParamCount].tmpref.buffer; 313 TeeSmc32Param[ParamCount].u.memref.size = 314 operation->params[ParamCount].tmpref.size; 315 } else { 316 TeeSmc32Param[ParamCount].attr = attr; 317 TeeSmc32Param[ParamCount].u.value.a = 318 operation->params[ParamCount].value.a; 319 TeeSmc32Param[ParamCount].u.value.b = 320 operation->params[ParamCount].value.b; 321 } 322 } 323 } 324 325 /* 326 * Get the return parameter blocks from 327 * the SMC call into the TEEC parameter supplied. 328 * This only handles the parameters supplied 329 * in the originating call and not those 330 * considered internal meta parameters and 331 * is thus constrained by the build 332 * constants exposed to callers. 333 */ 334 void GetTeeSmc32Params(t_teesmc32_param *TeeSmc32Param, 335 TEEC_Operation *operation) 336 { 337 uint32_t ParamCount; 338 339 for (ParamCount = 0; 340 ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT; 341 ParamCount++) { 342 operation->params[ParamCount].value.a = 343 TeeSmc32Param[ParamCount].u.value.a; 344 operation->params[ParamCount].value.b = 345 TeeSmc32Param[ParamCount].u.value.b; 346 } 347 } 348 349 /* 350 * Populate the SMC registers and make 351 * the call with OpTEE specific handling. 352 */ 353 TEEC_Result OpteeSmcCall(t_teesmc32_arg *TeeSmc32Arg) 354 { 355 TEEC_Result TeecResult = TEEC_SUCCESS; 356 ARM_SMC_ARGS ArmSmcArgs = {0}; 357 358 #ifdef CONFIG_OPTEE_V1 359 ArmSmcArgs.Arg0 = TEESMC32_CALL_WITH_ARG; 360 ArmSmcArgs.Arg1 = (uint32_t) (size_t)TeeSmc32Arg; 361 #endif 362 363 #ifdef CONFIG_OPTEE_V2 364 ArmSmcArgs.Arg0 = OPTEE_SMC_CALL_WITH_ARG_V2; 365 ArmSmcArgs.Arg1 = 0; 366 ArmSmcArgs.Arg2 = (uint32_t) (size_t)TeeSmc32Arg; 367 #endif 368 369 while (1) { 370 tee_smc_call(&ArmSmcArgs); 371 debug("TEEC: arg0=0x%x arg1=0x%x arg2=0x%x arg3=0x%x \n", 372 ArmSmcArgs.Arg0, ArmSmcArgs.Arg1, ArmSmcArgs.Arg2, ArmSmcArgs.Arg3); 373 if (TEESMC_RETURN_IS_RPC(ArmSmcArgs.Arg0)) { 374 (void) OpteeRpcCallback(&ArmSmcArgs); 375 } else if (ArmSmcArgs.Arg0 == TEESMC_RETURN_UNKNOWN_FUNCTION) { 376 TeecResult = TEEC_ERROR_NOT_IMPLEMENTED; 377 break; 378 } else if (ArmSmcArgs.Arg0 != TEESMC_RETURN_OK) { 379 TeecResult = TEEC_ERROR_COMMUNICATION; 380 break; 381 } else { 382 TeecResult = TEEC_SUCCESS; 383 break; 384 } 385 } 386 387 return TeecResult; 388 } 389 390