xref: /OK3568_Linux_fs/u-boot/lib/optee_clientApi/OpteeClientSMC.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/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 
tee_uuid_to_octets(uint8_t * d,const TEEC_UUID * s)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  */
TEEC_SMC_OpenSession(TEEC_Context * context,TEEC_Session * session,const TEEC_UUID * destination,TEEC_Operation * operation,uint32_t * error_origin)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 	uint32_t MetaNum = 2;
60 
61 	*error_origin = TEEC_ORIGIN_API;
62 
63 	TeeSmc32ArgLength =
64 		TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum);
65 
66 	TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength);
67 
68 	if (TeeSmc32Arg == NULL) {
69 		TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
70 		goto Exit;
71 	}
72 
73 	memset(TeeSmc32Arg, 0, TeeSmc32ArgLength);
74 
75 	TeeSmcMetaSessionLength = sizeof(*TeeSmcMetaSession);
76 
77 	TeeSmcMetaSession = (t_teesmc_meta_open_session *)
78 		OpteeClientMemAlloc(TeeSmcMetaSessionLength);
79 
80 	if (TeeSmcMetaSession == NULL) {
81 		TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
82 		goto Exit;
83 	}
84 
85 	memset(TeeSmcMetaSession, 0, TeeSmcMetaSessionLength);
86 
87 	TeeSmc32Arg->cmd = TEESMC_CMD_OPEN_SESSION;
88 	TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + MetaNum;
89 
90 	TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg);
91 
92 	memcpy(&TeeSmcMetaSession->uuid,
93 		destination,
94 		sizeof(TeeSmcMetaSession->uuid));
95 	TeeSmcMetaSession->clnt_login = TEEC_LOGIN_PUBLIC;
96 
97 	TeeSmc32Param[0].u.memref.buf_ptr = (uint32_t) (size_t)TeeSmcMetaSession;
98 	TeeSmc32Param[0].u.memref.size = sizeof(*TeeSmcMetaSession);
99 
100 #ifdef CONFIG_OPTEE_V1
101 	memcpy((void *)&TeeSmc32Param[0].u.value, &TeeSmcMetaSession->uuid, sizeof(TeeSmcMetaSession->uuid));
102 #endif
103 
104 #ifdef CONFIG_OPTEE_V2
105 	uint8_t * session_uuid = (uint8_t *)&TeeSmcMetaSession->uuid;
106 	tee_uuid_to_octets(session_uuid, destination);
107 	memcpy((void *)&TeeSmc32Param[0].u.value, &TeeSmcMetaSession->uuid, sizeof(TeeSmcMetaSession->uuid));
108 #endif
109 	TeeSmc32Param[1].u.value.c = TeeSmcMetaSession->clnt_login;
110 
111 	TeeSmc32Param[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 |
112 				OPTEE_MSG_ATTR_META_V2;
113 	TeeSmc32Param[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT_V2 |
114 				OPTEE_MSG_ATTR_META_V2;
115 
116 	SetTeeSmc32Params(operation, TeeSmc32Param + MetaNum);
117 
118 	*error_origin = TEEC_ORIGIN_COMMS;
119 
120 	TeecResult = OpteeSmcCall(TeeSmc32Arg);
121 	if (TeecResult != TEEC_SUCCESS)
122 		goto Exit;
123 
124 	session->id = TeeSmc32Arg->session;
125 	TeecResult = TeeSmc32Arg->ret;
126 	*error_origin = TeeSmc32Arg->ret_origin;
127 
128 	GetTeeSmc32Params(TeeSmc32Param + MetaNum, operation);
129 
130 Exit:
131 	if (TeeSmc32Arg != NULL)
132 		OpteeClientMemFree(TeeSmc32Arg);
133 
134 	if (TeeSmcMetaSession != NULL)
135 		OpteeClientMemFree(TeeSmcMetaSession);
136 
137 	return TeecResult;
138 }
139 
140 /*
141  * This function closes a session which has been opened with a TEE
142  * application.
143  *
144  * Note that the GP specification does not allow for this API to fail and return
145  * a failure code however we'll support this at the SMC level so we can get
146  * see debug information about such failures.
147  */
TEEC_SMC_CloseSession(TEEC_Session * session,uint32_t * error_origin)148 TEEC_Result TEEC_SMC_CloseSession(TEEC_Session *session,
149 				uint32_t *error_origin)
150 {
151 	TEEC_Result TeecResult = TEEC_SUCCESS;
152 	uint32_t TeeSmc32ArgLength;
153 
154 	t_teesmc32_arg *TeeSmc32Arg = NULL;
155 
156 	*error_origin = TEEC_ORIGIN_API;
157 
158 	TeeSmc32ArgLength =
159 		TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT);
160 
161 	TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength);
162 
163 	if (TeeSmc32Arg == NULL) {
164 		TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
165 		goto Exit;
166 	}
167 
168 	memset(TeeSmc32Arg, 0, TeeSmc32ArgLength);
169 
170 	TeeSmc32Arg->cmd = TEESMC_CMD_CLOSE_SESSION;
171 	TeeSmc32Arg->session = session->id;
172 
173 	*error_origin = TEEC_ORIGIN_COMMS;
174 
175 	TeecResult = OpteeSmcCall(TeeSmc32Arg);
176 
177 	if (TeecResult != TEEC_SUCCESS)
178 		goto Exit;
179 
180 	TeecResult = TeeSmc32Arg->ret;
181 	*error_origin = TeeSmc32Arg->ret_origin;
182 
183 Exit:
184 	if (TeeSmc32Arg != NULL)
185 		OpteeClientMemFree(TeeSmc32Arg);
186 
187 	return TeecResult;
188 }
189 
190 /*
191  * Invokes a TEE command (secure service, sub-PA or whatever).
192  */
TEEC_SMC_InvokeCommand(TEEC_Session * session,uint32_t cmd_id,TEEC_Operation * operation,uint32_t * error_origin)193 TEEC_Result TEEC_SMC_InvokeCommand(TEEC_Session *session,
194 				uint32_t cmd_id,
195 				TEEC_Operation *operation,
196 				uint32_t *error_origin)
197 {
198 	TEEC_Result TeecResult = TEEC_SUCCESS;
199 	uint32_t TeeSmc32ArgLength;
200 
201 	t_teesmc32_arg *TeeSmc32Arg = NULL;
202 	t_teesmc32_param *TeeSmc32Param = NULL;
203 
204 	*error_origin = TEEC_ORIGIN_API;
205 
206 	TeeSmc32ArgLength =
207 		TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT);
208 
209 	TeeSmc32Arg = (t_teesmc32_arg *)OpteeClientMemAlloc(TeeSmc32ArgLength);
210 
211 	if (TeeSmc32Arg == NULL) {
212 		TeecResult = TEEC_ERROR_OUT_OF_MEMORY;
213 		goto Exit;
214 	}
215 
216 	memset(TeeSmc32Arg, 0, TeeSmc32ArgLength);
217 
218 	TeeSmc32Arg->cmd = TEESMC_CMD_INVOKE_COMMAND;
219 	TeeSmc32Arg->ta_func = cmd_id;
220 	TeeSmc32Arg->session = session->id;
221 	TeeSmc32Arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
222 
223 	TeeSmc32Param = TEESMC32_GET_PARAMS(TeeSmc32Arg);
224 
225 	SetTeeSmc32Params(operation, TeeSmc32Param);
226 
227 	*error_origin = TEEC_ORIGIN_COMMS;
228 
229 	TeecResult = OpteeSmcCall(TeeSmc32Arg);
230 	if (TeecResult != TEEC_SUCCESS)
231 		goto Exit;
232 
233 	TeecResult = TeeSmc32Arg->ret;
234 	*error_origin = TeeSmc32Arg->ret_origin;
235 
236 	GetTeeSmc32Params(TeeSmc32Param, operation);
237 
238 Exit:
239 	if (TeeSmc32Arg != NULL)
240 		OpteeClientMemFree(TeeSmc32Arg);
241 
242 
243 	return TeecResult;
244 }
245 
246 /*
247  * Request a cancellation of a in-progress operation (best effort)
248  *
249  * Note that the GP specification does not allow for this API to fail and return
250  * a failure code however we'll support this at the SMC level so we can get
251  * see debug information about such failures.
252  */
TEEC_SMC_RequestCancellation(TEEC_Operation * operation,uint32_t * error_origin)253 TEEC_Result TEEC_SMC_RequestCancellation(TEEC_Operation *operation,
254 					uint32_t *error_origin)
255 {
256 	return TEEC_ERROR_NOT_IMPLEMENTED;
257 }
258 
259 /*
260  * Set the call parameter blocks in the
261  * SMC call based on the TEEC parameter supplied.
262  * This only handles the parameters supplied in
263  * the originating call and not those
264  * considered internal meta parameters and is
265  * thus constrained by the build
266  * constants exposed to callers.
267  */
SetTeeSmc32Params(TEEC_Operation * operation,t_teesmc32_param * TeeSmc32Param)268 void SetTeeSmc32Params(TEEC_Operation *operation,
269 						t_teesmc32_param *TeeSmc32Param)
270 {
271 	uint32_t ParamCount;
272 
273 	for (ParamCount = 0;
274 		ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT;
275 		ParamCount++) {
276 		uint32_t attr =
277 			TEEC_PARAM_TYPE_GET(operation->paramTypes, ParamCount);
278 
279 		if (attr == TEEC_MEMREF_TEMP_INPUT ||
280 			attr == TEEC_MEMREF_TEMP_OUTPUT ||
281 			attr == TEEC_MEMREF_TEMP_INOUT) {
282 
283 			attr += (OPTEE_MSG_ATTR_TYPE_TMEM_INPUT_V2 - TEEC_MEMREF_TEMP_INPUT);
284 			debug("TEEC: OPTEE_OS_V2 ARCH64 attr %x\n", attr);
285 
286 			TeeSmc32Param[ParamCount].attr = attr;
287 			TeeSmc32Param[ParamCount].u.memref.buf_ptr =
288 			(uint32_t)(size_t)operation->params[ParamCount].tmpref.buffer;
289 			TeeSmc32Param[ParamCount].u.memref.size =
290 				operation->params[ParamCount].tmpref.size;
291 		} else {
292 			TeeSmc32Param[ParamCount].attr = attr;
293 			TeeSmc32Param[ParamCount].u.value.a =
294 				operation->params[ParamCount].value.a;
295 			TeeSmc32Param[ParamCount].u.value.b =
296 				operation->params[ParamCount].value.b;
297 		}
298 	}
299 }
300 
301 /*
302  * Get the return parameter blocks from
303  * the SMC call into the TEEC parameter supplied.
304  * This only handles the parameters supplied
305  * in the originating call and not those
306  * considered internal meta parameters and
307  * is thus constrained by the build
308  * constants exposed to callers.
309  */
GetTeeSmc32Params(t_teesmc32_param * TeeSmc32Param,TEEC_Operation * operation)310 void GetTeeSmc32Params(t_teesmc32_param *TeeSmc32Param,
311 				TEEC_Operation *operation)
312 {
313 	uint32_t ParamCount;
314 
315 	for (ParamCount = 0;
316 	ParamCount < TEEC_CONFIG_PAYLOAD_REF_COUNT;
317 	ParamCount++) {
318 		operation->params[ParamCount].value.a =
319 			TeeSmc32Param[ParamCount].u.value.a;
320 		operation->params[ParamCount].value.b =
321 			TeeSmc32Param[ParamCount].u.value.b;
322 	}
323 }
324 
325 /*
326  * Populate the SMC registers and make
327  * the call with OpTEE specific handling.
328  */
OpteeSmcCall(t_teesmc32_arg * TeeSmc32Arg)329 TEEC_Result OpteeSmcCall(t_teesmc32_arg *TeeSmc32Arg)
330 {
331 	TEEC_Result TeecResult = TEEC_SUCCESS;
332 	ARM_SMC_ARGS ArmSmcArgs = {0};
333 
334 	ArmSmcArgs.Arg0 = OPTEE_SMC_CALL_WITH_ARG_V2;
335 	ArmSmcArgs.Arg1 = 0;
336 	ArmSmcArgs.Arg2 = (uint32_t) (size_t)TeeSmc32Arg;
337 
338 	while (1) {
339 		tee_smc_call(&ArmSmcArgs);
340 		debug("TEEC: arg0=0x%x arg1=0x%x arg2=0x%x arg3=0x%x \n",
341 			ArmSmcArgs.Arg0, ArmSmcArgs.Arg1, ArmSmcArgs.Arg2, ArmSmcArgs.Arg3);
342 		if (TEESMC_RETURN_IS_RPC(ArmSmcArgs.Arg0)) {
343 			(void) OpteeRpcCallback(&ArmSmcArgs);
344 		} else if (ArmSmcArgs.Arg0 == TEESMC_RETURN_UNKNOWN_FUNCTION) {
345 			TeecResult = TEEC_ERROR_NOT_IMPLEMENTED;
346 			break;
347 		} else if (ArmSmcArgs.Arg0 != TEESMC_RETURN_OK) {
348 			TeecResult = TEEC_ERROR_COMMUNICATION;
349 			break;
350 		} else {
351 			TeecResult = TEEC_SUCCESS;
352 			break;
353 		}
354 	}
355 
356 	return TeecResult;
357 }
358 
359