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