xref: /rk3399_rockchip-uboot/lib/optee_clientApi/OpteeClientSMC.c (revision 2ba7147f8008e675b31a0a5c13b8366431ea09ae)
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/OpteeClientMem.h>
9 #include <optee_include/OpteeClientSMC.h>
10 #include <optee_include/OpteeClientRPC.h>
11 #include <optee_include/teesmc.h>
12 #include <optee_include/teesmc_v2.h>
13 
14 
15 #define TEEC_SMC_DEFAULT_CACHE_ATTRIBUTES \
16 	(TEESMC_ATTR_CACHE_DEFAULT << TEESMC_ATTR_CACHE_SHIFT);
17 
18 static void SetTeeSmc32Params(TEEC_Operation *operation,
19 	t_teesmc32_param *TeeSmc32Param);
20 static void GetTeeSmc32Params(t_teesmc32_param *TeeSmc32Param,
21 	TEEC_Operation *operation);
22 static TEEC_Result OpteeSmcCall(t_teesmc32_arg *TeeSmc32Arg);
23 
24 void tee_uuid_to_octets(uint8_t *d, const TEEC_UUID *s)
25 {
26 	d[0] = s->timeLow >> 24;
27 	d[1] = s->timeLow >> 16;
28 	d[2] = s->timeLow >> 8;
29 	d[3] = s->timeLow;
30 	d[4] = s->timeMid >> 8;
31 	d[5] = s->timeMid;
32 	d[6] = s->timeHiAndVersion >> 8;
33 	d[7] = s->timeHiAndVersion;
34 	memcpy(d + 8, s->clockSeqAndNode, sizeof(s->clockSeqAndNode));
35 }
36 
37 /*
38  * This function opens a new Session between the Client application and the
39  * specified TEE application.
40  *
41  * Only connection_method == TEEC_LOGIN_PUBLIC is supported connection_data and
42  * operation shall be set to NULL.
43  */
44 TEEC_Result TEEC_SMC_OpenSession(TEEC_Context *context,
45 				TEEC_Session *session,
46 				const TEEC_UUID *destination,
47 				TEEC_Operation  *operation,
48 				uint32_t *error_origin)
49 {
50 	TEEC_Result TeecResult = TEEC_SUCCESS;
51 	uint32_t TeeSmc32ArgLength;
52 	uint32_t TeeSmcMetaSessionLength;
53 
54 	t_teesmc32_arg *TeeSmc32Arg = NULL;
55 	t_teesmc32_param *TeeSmc32Param = NULL;
56 
57 	t_teesmc_meta_open_session *TeeSmcMetaSession = NULL;
58 
59 #ifdef CONFIG_OPTEE_V1
60 	uint32_t MetaNum = 1;
61 #endif
62 
63 #ifdef CONFIG_OPTEE_V2
64 	uint32_t MetaNum = 2;
65 #endif
66 
67 	*error_origin = TEEC_ORIGIN_API;
68 
69 	TeeSmc32ArgLength =
70 		TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum);
71 
72 	TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength);
73 
74 	if (TeeSmc32Arg == NULL) {
75 		TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
76 		goto Exit;
77 	}
78 
79 	memset(TeeSmc32Arg, 0, TeeSmc32ArgLength);
80 
81 	TeeSmcMetaSessionLength = sizeof(*TeeSmcMetaSession);
82 
83 	TeeSmcMetaSession = (t_teesmc_meta_open_session *)
84 		OpteeClientMemAlloc(TeeSmcMetaSessionLength);
85 
86 	if (TeeSmcMetaSession == NULL) {
87 		TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
88 		goto Exit;
89 	}
90 
91 	memset(TeeSmcMetaSession, 0, TeeSmcMetaSessionLength);
92 
93 	TeeSmc32Arg->cmd = TEESMC_CMD_OPEN_SESSION;
94 	TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum;
95 
96 	TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg);
97 
98 	memcpy(&TeeSmcMetaSession->uuid,
99 		destination,
100 		sizeof(TeeSmcMetaSession->uuid));
101 	TeeSmcMetaSession->clnt_login = TEEC_LOGIN_PUBLIC;
102 
103 	TeeSmc32Param[0].u.memref.buf_ptr = (uint32_t) (size_t)TeeSmcMetaSession;
104 	TeeSmc32Param[0].u.memref.size = sizeof(*TeeSmcMetaSession);
105 
106 #ifdef CONFIG_OPTEE_V1
107 #ifdef CONFIG_ARM64
108 	TeeSmc32Param[0].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
109 				TEESMC_ATTR_META              |
110 				TEEC_SMC_DEFAULT_CACHE_ATTRIBUTES;
111 #else
112 	TeeSmc32Param[0].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
113 				TEESMC_ATTR_META;
114 #endif
115 #endif
116 
117 #ifdef CONFIG_OPTEE_V2
118 #if defined CONFIG_ARM64 || defined CONFIG_ARM64_BOOT_AARCH32
119 	uint8_t * session_uuid = (uint8_t *)&TeeSmcMetaSession->uuid;
120 	tee_uuid_to_octets(session_uuid, destination);
121 	memcpy((void *)&TeeSmc32Param[0].u.value, &TeeSmcMetaSession->uuid, sizeof(TeeSmcMetaSession->uuid));
122 	TeeSmc32Param[1].u.value.c = TeeSmcMetaSession->clnt_login;
123 
124 	TeeSmc32Param[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 |
125 				OPTEE_MSG_ATTR_META_V2;
126 	TeeSmc32Param[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 |
127 				OPTEE_MSG_ATTR_META_V2;
128 #else
129 	printf("TEEC: Not support! All rockchips use optee v2.5 are 64 bits! \n");
130 #endif
131 #endif
132 
133 	SetTeeSmc32Params(operation, TeeSmc32Param + MetaNum);
134 
135 	*error_origin = TEEC_ORIGIN_COMMS;
136 
137 	TeecResult = OpteeSmcCall(TeeSmc32Arg);
138 	if (TeecResult != TEEC_SUCCESS)
139 		goto Exit;
140 
141 	session->id = TeeSmc32Arg->session;
142 	TeecResult = TeeSmc32Arg->ret;
143 	*error_origin = TeeSmc32Arg->ret_origin;
144 
145 	GetTeeSmc32Params(TeeSmc32Param + MetaNum, operation);
146 
147 Exit:
148 	if (TeeSmc32Arg != NULL)
149 		OpteeClientMemFree(TeeSmc32Arg);
150 
151 	if (TeeSmcMetaSession != NULL)
152 		OpteeClientMemFree(TeeSmcMetaSession);
153 
154 	return TeecResult;
155 }
156 
157 /*
158  * This function closes a session which has been opened with a TEE
159  * application.
160  *
161  * Note that the GP specification does not allow for this API to fail and return
162  * a failure code however we'll support this at the SMC level so we can get
163  * see debug information about such failures.
164  */
165 TEEC_Result TEEC_SMC_CloseSession(TEEC_Session *session,
166 				uint32_t *error_origin)
167 {
168 	TEEC_Result TeecResult = TEEC_SUCCESS;
169 	uint32_t TeeSmc32ArgLength;
170 
171 	t_teesmc32_arg *TeeSmc32Arg = NULL;
172 
173 	*error_origin = TEEC_ORIGIN_API;
174 
175 	TeeSmc32ArgLength =
176 		TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT);
177 
178 	TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength);
179 
180 	if (TeeSmc32Arg == NULL) {
181 		TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
182 		goto Exit;
183 	}
184 
185 	memset(TeeSmc32Arg, 0, TeeSmc32ArgLength);
186 
187 	TeeSmc32Arg->cmd = TEESMC_CMD_CLOSE_SESSION;
188 	TeeSmc32Arg->session = session->id;
189 
190 	*error_origin = TEEC_ORIGIN_COMMS;
191 
192 	TeecResult = OpteeSmcCall(TeeSmc32Arg);
193 
194 	if (TeecResult != TEEC_SUCCESS)
195 		goto Exit;
196 
197 	TeecResult = TeeSmc32Arg->ret;
198 	*error_origin = TeeSmc32Arg->ret_origin;
199 
200 Exit:
201 	if (TeeSmc32Arg != NULL)
202 		OpteeClientMemFree(TeeSmc32Arg);
203 
204 	return TeecResult;
205 }
206 
207 /*
208  * Invokes a TEE command (secure service, sub-PA or whatever).
209  */
210 TEEC_Result TEEC_SMC_InvokeCommand(TEEC_Session *session,
211 				uint32_t cmd_id,
212 				TEEC_Operation *operation,
213 				uint32_t *error_origin)
214 {
215 	TEEC_Result TeecResult = TEEC_SUCCESS;
216 	uint32_t TeeSmc32ArgLength;
217 
218 	t_teesmc32_arg *TeeSmc32Arg = NULL;
219 	t_teesmc32_param *TeeSmc32Param = NULL;
220 
221 	*error_origin = TEEC_ORIGIN_API;
222 
223 	TeeSmc32ArgLength =
224 		TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT);
225 
226 	TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength);
227 
228 	if (TeeSmc32Arg == NULL) {
229 		TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
230 		goto Exit;
231 	}
232 
233 	memset(TeeSmc32Arg, 0, TeeSmc32ArgLength);
234 
235 	TeeSmc32Arg->cmd = TEESMC_CMD_INVOKE_COMMAND;
236 	TeeSmc32Arg->ta_func = cmd_id;
237 	TeeSmc32Arg->session = session->id;
238 	TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
239 
240 	TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg);
241 
242 	SetTeeSmc32Params(operation, TeeSmc32Param);
243 
244 	*error_origin = TEEC_ORIGIN_COMMS;
245 
246 	TeecResult = OpteeSmcCall(TeeSmc32Arg);
247 	if (TeecResult != TEEC_SUCCESS)
248 		goto Exit;
249 
250 	TeecResult = TeeSmc32Arg->ret;
251 	*error_origin = TeeSmc32Arg->ret_origin;
252 
253 	GetTeeSmc32Params(TeeSmc32Param, operation);
254 
255 Exit:
256 	if (TeeSmc32Arg != NULL)
257 		OpteeClientMemFree(TeeSmc32Arg);
258 
259 
260 	return TeecResult;
261 }
262 
263 /*
264  * Request a cancellation of a in-progress operation (best effort)
265  *
266  * Note that the GP specification does not allow for this API to fail and return
267  * a failure code however we'll support this at the SMC level so we can get
268  * see debug information about such failures.
269  */
270 TEEC_Result TEEC_SMC_RequestCancellation(TEEC_Operation *operation,
271 					uint32_t *error_origin)
272 {
273 	return TEEC_ERROR_NOT_IMPLEMENTED;
274 }
275 
276 /*
277  * Set the call parameter blocks in the
278  * SMC call based on the TEEC parameter supplied.
279  * This only handles the parameters supplied in
280  * the originating call and not those
281  * considered internal meta parameters and is
282  * thus constrained by the build
283  * constants exposed to callers.
284  */
285 void SetTeeSmc32Params(TEEC_Operation *operation,
286 						t_teesmc32_param *TeeSmc32Param)
287 {
288 	uint32_t ParamCount;
289 
290 	for (ParamCount = 0;
291 		ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT;
292 		ParamCount++) {
293 		uint32_t attr =
294 			TEEC_PARAM_TYPE_GET(operation->paramTypes, ParamCount);
295 
296 		if (attr == TEEC_MEMREF_TEMP_INPUT ||
297 			attr == TEEC_MEMREF_TEMP_OUTPUT ||
298 			attr == TEEC_MEMREF_TEMP_INOUT) {
299 
300 #ifdef CONFIG_OPTEE_V1
301 #ifdef CONFIG_ARM64
302 			attr |= TEEC_SMC_DEFAULT_CACHE_ATTRIBUTES;
303 			debug("TEEC: OPTEE_OS_V1 ARCH64 attr %x\n", attr);
304 #else
305 			debug("TEEC: OPTEE_OS_V1 ARCH32 attr %x\n", attr);
306 #endif
307 #endif
308 
309 #ifdef CONFIG_OPTEE_V2
310 #if defined CONFIG_ARM64 || defined CONFIG_ARM64_BOOT_AARCH32
311 			attr += (OPTEE_MSG_ATTR_TYPE_TMEM_INPUT_V2 - TEEC_MEMREF_TEMP_INPUT);
312 			debug("TEEC: OPTEE_OS_V2 ARCH64 attr %x\n", attr);
313 #else
314 			printf("TEEC: Not support! All rockchips use optee v2 are 64 bits! \n");
315 #endif
316 #endif
317 
318 			TeeSmc32Param[ParamCount].attr = attr;
319 			TeeSmc32Param[ParamCount].u.memref.buf_ptr =
320 			(uint32_t)(size_t)operation->params[ParamCount].tmpref.buffer;
321 			TeeSmc32Param[ParamCount].u.memref.size =
322 				operation->params[ParamCount].tmpref.size;
323 		} else {
324 			TeeSmc32Param[ParamCount].attr = attr;
325 			TeeSmc32Param[ParamCount].u.value.a =
326 				operation->params[ParamCount].value.a;
327 			TeeSmc32Param[ParamCount].u.value.b =
328 				operation->params[ParamCount].value.b;
329 		}
330 	}
331 }
332 
333 /*
334  * Get the return parameter blocks from
335  * the SMC call into the TEEC parameter supplied.
336  * This only handles the parameters supplied
337  * in the originating call and not those
338  * considered internal meta parameters and
339  * is thus constrained by the build
340  * constants exposed to callers.
341  */
342 void GetTeeSmc32Params(t_teesmc32_param *TeeSmc32Param,
343 				TEEC_Operation *operation)
344 {
345 	uint32_t ParamCount;
346 
347 	for (ParamCount = 0;
348 	ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT;
349 	ParamCount++) {
350 		operation->params[ParamCount].value.a =
351 			TeeSmc32Param[ParamCount].u.value.a;
352 		operation->params[ParamCount].value.b =
353 			TeeSmc32Param[ParamCount].u.value.b;
354 	}
355 }
356 
357 /*
358  * Populate the SMC registers and make
359  * the call with OpTEE specific handling.
360  */
361 TEEC_Result OpteeSmcCall(t_teesmc32_arg *TeeSmc32Arg)
362 {
363 	TEEC_Result TeecResult = TEEC_SUCCESS;
364 	ARM_SMC_ARGS ArmSmcArgs = {0};
365 
366 #ifdef CONFIG_OPTEE_V1
367 	ArmSmcArgs.Arg0 = TEESMC32_CALL_WITH_ARG;
368 	ArmSmcArgs.Arg1 = (uint32_t) (size_t)TeeSmc32Arg;
369 #endif
370 
371 #ifdef CONFIG_OPTEE_V2
372 	ArmSmcArgs.Arg0 = OPTEE_SMC_CALL_WITH_ARG_V2;
373 	ArmSmcArgs.Arg1 = 0;
374 	ArmSmcArgs.Arg2 = (uint32_t) (size_t)TeeSmc32Arg;
375 #endif
376 
377 	while (1) {
378 		tee_smc_call(&ArmSmcArgs);
379 		debug("TEEC: arg0=0x%x arg1=0x%x arg2=0x%x arg3=0x%x \n",
380 			ArmSmcArgs.Arg0, ArmSmcArgs.Arg1, ArmSmcArgs.Arg2, ArmSmcArgs.Arg3);
381 		if (TEESMC_RETURN_IS_RPC(ArmSmcArgs.Arg0)) {
382 			(void) OpteeRpcCallback(&ArmSmcArgs);
383 		} else if (ArmSmcArgs.Arg0 == TEESMC_RETURN_UNKNOWN_FUNCTION) {
384 			TeecResult = TEEC_ERROR_NOT_IMPLEMENTED;
385 			break;
386 		} else if (ArmSmcArgs.Arg0 != TEESMC_RETURN_OK) {
387 			TeecResult = TEEC_ERROR_COMMUNICATION;
388 			break;
389 		} else {
390 			TeecResult = TEEC_SUCCESS;
391 			break;
392 		}
393 	}
394 
395 	return TeecResult;
396 }
397 
398