xref: /rk3399_rockchip-uboot/lib/optee_clientApi/OpteeClientApiLib.c (revision 548715c7d5ed761875cc95bcb03b9b4519687db6)
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