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
optee_vm_create(uint32_t client_id)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
optee_vm_destroyed(uint32_t client_id)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
optee_exchange_capabilities(uint32_t * sec_caps)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
optee_api_revision_is_compatible(void)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
optee_get_shm_config(phys_addr_t * base,phys_size_t * size)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 */
OpteeClientApiLibInitialize(void)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 */
TEEC_InitializeContext(const char * name,TEEC_Context * context)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 */
TEEC_FinalizeContext(TEEC_Context * context)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 */
TEEC_AllocateSharedMemory(TEEC_Context * context,TEEC_SharedMemory * shared_memory)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 */
TEEC_ReleaseSharedMemory(TEEC_SharedMemory * shared_memory)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 */
TEEC_RegisterSharedMemory(TEEC_Context * context,TEEC_SharedMemory * shared_memory)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 */
TEEC_OpenSession(TEEC_Context * context,TEEC_Session * session,const TEEC_UUID * destination,uint32_t connection_method,const void * connection_data,TEEC_Operation * operation,uint32_t * error_origin)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 */
TEEC_CloseSession(TEEC_Session * session)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 */
TEEC_InvokeCommand(TEEC_Session * session,uint32_t cmd_id,TEEC_Operation * operation,uint32_t * error_origin)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 */
TEEC_RequestCancellation(TEEC_Operation * operation)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