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