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