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