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