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