xref: /OK3568_Linux_fs/u-boot/lib/optee_clientApi/OpteeClientApiLib.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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