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/OpteeClientApiLib.h> 9 #include <optee_include/OpteeClientMem.h> 10 #include <optee_include/OpteeClientRPC.h> 11 #include <optee_include/OpteeClientSMC.h> 12 #include <optee_include/OpteeClientRkFs.h> 13 #include <optee_include/teesmc.h> 14 #include <optee_include/teesmc_optee.h> 15 #include <optee_include/teesmc_v2.h> 16 17 #define OPTEE_MSG_REVISION_MAJOR 2 18 #define OPTEE_MSG_REVISION_MINOR 0 19 20 static bool optee_is_init; 21 22 static bool optee_vm_create(uint32_t client_id) 23 { 24 ARM_SMC_ARGS ArmSmcArgs = {0}; 25 26 ArmSmcArgs.Arg0 = OPTEE_SMC_VM_CREATED; 27 ArmSmcArgs.Arg1 = client_id; 28 29 tee_smc_call(&ArmSmcArgs); 30 31 if (ArmSmcArgs.Arg0 != 0) 32 return false; 33 34 return true; 35 } 36 37 static bool optee_vm_destroyed(uint32_t client_id) 38 { 39 ARM_SMC_ARGS ArmSmcArgs = {0}; 40 41 ArmSmcArgs.Arg0 = OPTEE_SMC_VM_DESTROYED; 42 ArmSmcArgs.Arg1 = client_id; 43 44 tee_smc_call(&ArmSmcArgs); 45 46 if (ArmSmcArgs.Arg0 != 0) 47 return false; 48 49 return true; 50 } 51 52 static bool optee_exchange_capabilities(uint32_t *sec_caps) 53 { 54 ARM_SMC_ARGS ArmSmcArgs = {0}; 55 56 ArmSmcArgs.Arg0 = OPTEE_SMC_EXCHANGE_CAPABILITIES; 57 58 tee_smc_call(&ArmSmcArgs); 59 60 if (ArmSmcArgs.Arg0 != 0) 61 return false; 62 *sec_caps = ArmSmcArgs.Arg1; 63 return true; 64 } 65 66 static bool optee_api_revision_is_compatible(void) 67 { 68 ARM_SMC_ARGS ArmSmcArgs = {0}; 69 70 ArmSmcArgs.Arg0 = OPTEE_SMC_CALLS_REVISION; 71 72 tee_smc_call(&ArmSmcArgs); 73 74 if (ArmSmcArgs.Arg0 == OPTEE_MSG_REVISION_MAJOR && 75 ArmSmcArgs.Arg1 >= OPTEE_MSG_REVISION_MINOR) { 76 printf("optee api revision: %d.%d\n", 77 ArmSmcArgs.Arg0, ArmSmcArgs.Arg1); 78 return true; 79 } else { 80 printf("optee check api revision fail: %d.%d\n", 81 ArmSmcArgs.Arg0, ArmSmcArgs.Arg1); 82 return false; 83 } 84 } 85 86 void optee_get_shm_config(phys_addr_t *base, phys_size_t *size) 87 { 88 ARM_SMC_ARGS ArmSmcArgs = {0}; 89 90 ArmSmcArgs.Arg0 = OPTEE_SMC_GET_SHM_CONFIG_V2; 91 92 tee_smc_call(&ArmSmcArgs); 93 94 *base = ArmSmcArgs.Arg1; 95 *size = ArmSmcArgs.Arg2; 96 } 97 98 /* 99 * Initlialize the library 100 */ 101 TEEC_Result OpteeClientApiLibInitialize(void) 102 { 103 TEEC_Result status = TEEC_SUCCESS; 104 105 if (optee_is_init) 106 return TEEC_SUCCESS; 107 108 /* check api revision compatibility */ 109 if (!optee_api_revision_is_compatible()) 110 panic("optee api revision is too low"); 111 112 status = OpteeClientMemInit(); 113 if (status != TEEC_SUCCESS) { 114 printf("TEEC: OpteeClientMemInit fail!\n"); 115 return status; 116 } 117 status = OpteeClientRkFsInit(); 118 if (status != TEEC_SUCCESS) { 119 printf("TEEC: OpteeClientRkFsInit fail!\n"); 120 return status; 121 } 122 123 optee_is_init = true; 124 125 return TEEC_SUCCESS; 126 } 127 128 /* 129 * This function initializes a new TEE Context, connecting this Client 130 * application to the TEE indentified by the name name. 131 * 132 * name == NULL will give the default TEE. 133 * 134 * In this implementation only the default name is supported. 135 * If name != NULL then TEEC_ERROR_ITEM_NOT_FOUND is returned. 136 */ 137 TEEC_Result TEEC_InitializeContext(const char *name, 138 TEEC_Context *context) 139 { 140 TEEC_Result teecresult = TEEC_SUCCESS; 141 uint32_t sec_caps = 0; 142 143 debug("TEEC_InitializeContext Enter: name=%s context=%s 0x%X\n", 144 name, context->devname, context->fd); 145 146 147 if (context == NULL) { 148 teecresult = TEEC_ERROR_BAD_PARAMETERS; 149 goto exit; 150 } 151 152 if (name != NULL) { 153 teecresult = TEEC_ERROR_ITEM_NOT_FOUND; 154 goto exit; 155 } 156 157 memset(context, 0, sizeof(*context)); 158 159 /* get optee capabilities */ 160 if (!optee_exchange_capabilities(&sec_caps)) 161 panic("optee exchange capabilities fail!"); 162 163 /* optee vm create */ 164 if (sec_caps & OPTEE_SMC_SEC_CAP_VIRTUALIZATION) { 165 if (!optee_vm_create(0)) 166 panic("optee vm create fail!"); 167 } 168 169 exit: 170 debug("TEEC_InitializeContext Exit : teecresult=0x%X\n", teecresult); 171 return teecresult; 172 } 173 174 /* 175 * This function destroys an initialized TEE Context, closing the connection 176 * between the Client and the TEE. 177 * The function implementation MUST do nothing if context is NULL 178 * 179 * There is nothing to do here since there is no context state. 180 */ 181 TEEC_Result TEEC_FinalizeContext(TEEC_Context *context) 182 { 183 uint32_t sec_caps = 0; 184 185 /* get optee capabilities */ 186 if (!optee_exchange_capabilities(&sec_caps)) 187 panic("optee exchange capabilities fail!"); 188 189 /* optee vm destroyed */ 190 if (sec_caps & OPTEE_SMC_SEC_CAP_VIRTUALIZATION) { 191 if (!optee_vm_destroyed(0)) 192 panic("optee vm destroyed fail!"); 193 } 194 195 debug("TEEC_FinalizeContext Enter-Exit: context=0x%zu\n", 196 (size_t)context); 197 return TEEC_SUCCESS; 198 } 199 200 /* 201 * Allocates or registers shared memory. 202 * 203 * Since EDK2 is configured flat with virtual memory == physical memory 204 * then we don't need to perform any special operations to get physical 205 * contiguous memory. 206 */ 207 TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context, 208 TEEC_SharedMemory *shared_memory) 209 { 210 TEEC_Result TeecResult = TEEC_SUCCESS; 211 212 debug("TEEC_AllocateSharedMemory Enter: context=%s 0x%X, shared_memory=0x%zu\n", 213 context->devname, context->fd, shared_memory->size); 214 215 if ((context == NULL) || (shared_memory == NULL)) { 216 TeecResult = TEEC_ERROR_BAD_PARAMETERS; 217 goto Exit; 218 } 219 220 if (shared_memory->flags != 0) { 221 TeecResult = TEEC_ERROR_BAD_PARAMETERS; 222 goto Exit; 223 } 224 225 shared_memory->buffer = NULL; 226 shared_memory->alloc_buffer = 0; 227 228 debug("TEEC_AllocateSharedMemory: size=0x%zu, flags=0x%X\n", 229 shared_memory->size, shared_memory->flags); 230 231 shared_memory->buffer = OpteeClientMemAlloc(shared_memory->size); 232 if (shared_memory->buffer == NULL) { 233 TeecResult = TEEC_ERROR_OUT_OF_MEMORY; 234 goto Exit; 235 } 236 237 shared_memory->alloc_buffer = shared_memory->buffer; 238 239 Exit: 240 debug("TEEC_AllocateSharedMemory Exit : TeecResult=0x%X\n", TeecResult); 241 return TeecResult; 242 } 243 244 /* 245 * Releases shared memory. 246 * 247 * The optee_client implementation allows this to be called with a null pointer 248 * and null buffer but we'll assert this is not the case for better debugging. 249 */ 250 void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *shared_memory) 251 { 252 debug("TEEC_ReleaseSharedMemory Enter: shared_memory=0x%zu\n", 253 shared_memory->size); 254 255 if (shared_memory == NULL) 256 goto Exit; 257 258 if (shared_memory->buffer == NULL) 259 goto Exit; 260 261 if (shared_memory->alloc_buffer != 0) { 262 OpteeClientMemFree(shared_memory->alloc_buffer); 263 shared_memory->alloc_buffer = 0; 264 } 265 266 shared_memory->buffer = NULL; 267 shared_memory->size = 0; 268 269 Exit: 270 return; 271 } 272 273 /* 274 * Register shared memory 275 * 276 * If the supplied buffer is compatible we can use it as supplied otherwise 277 * we'll need to allocate a copy buffer for the transfer instead. 278 */ 279 TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context, 280 TEEC_SharedMemory *shared_memory) 281 { 282 TEEC_Result TeecResult = TEEC_SUCCESS; 283 284 if ((context == NULL) || (shared_memory == NULL)) { 285 TeecResult = TEEC_ERROR_BAD_PARAMETERS; 286 goto Exit; 287 } 288 289 if (shared_memory->buffer == NULL) { 290 TeecResult = TEEC_ERROR_BAD_PARAMETERS; 291 goto Exit; 292 } 293 294 shared_memory->alloc_buffer = 0; 295 296 phys_addr_t start = (phys_addr_t) shared_memory->buffer; 297 298 if ((start % 4096) != 0) { 299 TEEC_SharedMemory TempSharedMemory; 300 TempSharedMemory.size = shared_memory->size; 301 TempSharedMemory.flags = shared_memory->flags; 302 303 TeecResult = TEEC_AllocateSharedMemory 304 (context, &TempSharedMemory); 305 306 if (TeecResult != TEEC_SUCCESS) 307 goto Exit; 308 309 shared_memory->alloc_buffer = TempSharedMemory.alloc_buffer; 310 } 311 312 Exit: 313 debug("TEEC_RegisterSharedMemory Exit : TeecResult=0x%X\n", TeecResult); 314 return TeecResult; 315 } 316 317 /* 318 * This function opens a new Session between the Client application and the 319 * specified TEE application. 320 * 321 * Only connection_method == TEEC_LOGIN_PUBLIC is supported connection_data and 322 * operation shall be set to NULL. 323 */ 324 TEEC_Result TEEC_OpenSession(TEEC_Context *context, 325 TEEC_Session *session, 326 const TEEC_UUID *destination, 327 uint32_t connection_method, 328 const void *connection_data, 329 TEEC_Operation *operation, 330 uint32_t *error_origin) 331 { 332 TEEC_Result TeecResult = TEEC_SUCCESS; 333 uint32_t TeecErrorOrigin = TEEC_ORIGIN_API; 334 335 debug("TEEC_OpenSession: session=0x%X, ...\n", session->id); 336 337 if ((context == NULL) || (session == NULL) || (destination == NULL)) { 338 TeecResult = TEEC_ERROR_BAD_PARAMETERS; 339 goto Exit; 340 } 341 342 if (connection_method != TEEC_LOGIN_PUBLIC) { 343 TeecResult = TEEC_ERROR_NOT_SUPPORTED; 344 goto Exit; 345 } 346 347 TEEC_Operation TeecNullOperation = {0}; 348 TEEC_Operation *TeecOperation; 349 350 if (operation == NULL) { 351 memset(&TeecNullOperation, 0, sizeof(TEEC_Operation)); 352 TeecOperation = &TeecNullOperation; 353 } else { 354 TeecOperation = operation; 355 } 356 357 TeecResult = TEEC_SMC_OpenSession(context, session, destination, 358 TeecOperation, &TeecErrorOrigin); 359 360 Exit: 361 if (error_origin != NULL) 362 *error_origin = TeecErrorOrigin; 363 364 debug("TEEC_OpenSession Exit : TeecResult=0x%X, TeecErrorOrigin=0x%X\n", 365 TeecResult, TeecErrorOrigin); 366 return TeecResult; 367 } 368 369 /* 370 * This function closes a session which has been opened with a TEE 371 * application. 372 */ 373 void TEEC_CloseSession(TEEC_Session *session) 374 { 375 TEEC_Result TeecResult = TEEC_SUCCESS; 376 uint32_t TeecErrorOrigin = TEEC_ORIGIN_API; 377 378 debug("TEEC_CloseSession Enter: session=0x%X\n", session->id); 379 380 if (session == NULL) 381 goto Exit; 382 383 TeecResult = TEEC_SMC_CloseSession(session, &TeecErrorOrigin); 384 385 Exit: 386 debug("TEEC_CloseSession Exit : TeecResult=0x%X, TeecErrorOrigin=0x%X\n", 387 TeecResult, TeecErrorOrigin); 388 return; 389 } 390 391 /* 392 * Invokes a TEE command (secure service, sub-PA or whatever). 393 */ 394 TEEC_Result TEEC_InvokeCommand(TEEC_Session *session, 395 uint32_t cmd_id, 396 TEEC_Operation *operation, 397 uint32_t *error_origin) 398 { 399 TEEC_Result TeecResult = TEEC_SUCCESS; 400 uint32_t TeecErrorOrigin = TEEC_ORIGIN_API; 401 402 debug("TEEC_InvokeCommand Enter: session=0x%X, cmd_id=0x%X\n", 403 session->id, cmd_id); 404 405 if (session == NULL) { 406 TeecResult = TEEC_ERROR_BAD_PARAMETERS; 407 goto Exit; 408 } 409 410 TEEC_Operation TeecNullOperation = {0}; 411 TEEC_Operation *TeecOperation; 412 413 if (operation == NULL) 414 TeecOperation = &TeecNullOperation; 415 else 416 TeecOperation = operation; 417 418 TeecResult = TEEC_SMC_InvokeCommand(session, cmd_id, 419 TeecOperation, &TeecErrorOrigin); 420 421 Exit: 422 if (error_origin != NULL) 423 *error_origin = TeecErrorOrigin; 424 425 debug("TEEC_InvokeCommand Exit : TeecResult=0x%X, TeecErrorOrigin=0x%X\n", 426 TeecResult, TeecErrorOrigin); 427 428 return TeecResult; 429 } 430 431 /* 432 * Request a cancellation of a in-progress operation (best effort) 433 */ 434 void TEEC_RequestCancellation(TEEC_Operation *operation) 435 { 436 TEEC_Result TeecResult = TEEC_SUCCESS; 437 uint32_t TeecErrorOrigin = TEEC_ORIGIN_API; 438 439 if (operation == NULL) 440 goto Exit; 441 442 TeecResult = TEEC_SMC_RequestCancellation(operation, &TeecErrorOrigin); 443 444 Exit: 445 debug("TEEC_RequestCancellation Exit : TeecResult=0x%X, TeecErrorOrigin=0x%X\n", 446 TeecResult, TeecErrorOrigin); 447 448 return; 449 } 450