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