1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2014, STMicroelectronics International N.V.
4 */
5 #include <compiler.h>
6 #include <link.h>
7 #include <stdbool.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/queue.h>
11 #include <tee_api.h>
12 #include <tee_ta_api.h>
13 #include <tee_internal_api_extensions.h>
14 #include <user_ta_header.h>
15 #include <utee_syscalls.h>
16 #include <tee_arith_internal.h>
17 #include <malloc.h>
18 #include "tee_api_private.h"
19
20 struct ta_session {
21 uint32_t session_id;
22 void *session_ctx;
23 TAILQ_ENTRY(ta_session) link;
24 };
25
26 static TAILQ_HEAD(ta_sessions, ta_session) ta_sessions =
27 TAILQ_HEAD_INITIALIZER(ta_sessions);
28
29 static bool init_done;
30
31 /* From user_ta_header.c, built within TA */
32 extern uint8_t ta_heap[];
33 extern const size_t ta_heap_size;
34 extern struct ta_head ta_head;
35
36 uint32_t ta_param_types;
37 TEE_Param ta_params[TEE_NUM_PARAMS];
38 struct __elf_phdr_info __elf_phdr_info;
39
40 struct phdr_info {
41 struct dl_phdr_info info;
42 TAILQ_ENTRY(phdr_info) link;
43 };
44
45 static TAILQ_HEAD(phdr_info_head, phdr_info) __phdr_info_head =
46 TAILQ_HEAD_INITIALIZER(__phdr_info_head);
47 /*
48 * Keep track of how many modules have been initialized so that subsequent
49 * dlopen() calls will not run the same initializers again
50 */
51 static size_t _num_mod_init;
52
_init_iterate_phdr_cb(struct dl_phdr_info * info,size_t size __unused,void * data)53 static int _init_iterate_phdr_cb(struct dl_phdr_info *info,
54 size_t size __unused, void *data)
55 {
56 struct phdr_info *qe = NULL;
57 size_t *count = data;
58
59 qe = malloc(sizeof(*qe));
60 if (!qe) {
61 EMSG("init/fini: out of memory");
62 abort();
63 }
64 qe->info = *info;
65 TAILQ_INSERT_TAIL(&__phdr_info_head, qe, link);
66 (*count)++;
67 return 0;
68 }
69
_get_fn_array(struct dl_phdr_info * info,Elf_Sword tag_a,Elf_Sword tag_s,void (*** fn)(void),size_t * num_fn)70 static void _get_fn_array(struct dl_phdr_info *info, Elf_Sword tag_a,
71 Elf_Sword tag_s, void (***fn)(void), size_t *num_fn)
72 {
73 const Elf_Phdr *phdr = NULL;
74 Elf_Dyn *dyn = NULL;
75 size_t num_dyn = 0;
76 size_t i = 0;
77 size_t j = 0;
78
79 for (i = 0; i < info->dlpi_phnum; i++) {
80 phdr = info->dlpi_phdr + i;
81 if (phdr->p_type != PT_DYNAMIC)
82 continue;
83 num_dyn = phdr->p_memsz / sizeof(Elf_Dyn);
84 dyn = (Elf_Dyn *)(phdr->p_vaddr + info->dlpi_addr);
85 for (j = 0; j < num_dyn; j++) {
86 if (*fn && *num_fn)
87 break;
88 if (dyn->d_tag == DT_NULL) {
89 break;
90 } else if (dyn->d_tag == tag_a) {
91 *fn = (void (**)(void))(dyn->d_un.d_ptr +
92 info->dlpi_addr);
93 } else if (dyn->d_tag == tag_s) {
94 *num_fn = dyn->d_un.d_val / sizeof(Elf_Addr);
95 }
96 dyn++;
97 }
98 }
99 }
100
__utee_call_elf_init_fn(void)101 void __utee_call_elf_init_fn(void)
102 {
103 void (**fn)(void) = NULL;
104 size_t num_mod = 0;
105 size_t num_fn = 0;
106 size_t mod = 0;
107 size_t i = 0;
108 struct phdr_info *qe = NULL;
109 struct phdr_info *qe2 = NULL;
110
111 dl_iterate_phdr(_init_iterate_phdr_cb, &num_mod);
112
113 /* Reverse order: dependencies first */
114 TAILQ_FOREACH_REVERSE(qe, &__phdr_info_head, phdr_info_head, link) {
115 if (mod == num_mod - _num_mod_init)
116 break;
117 _get_fn_array(&qe->info, DT_INIT_ARRAY, DT_INIT_ARRAYSZ, &fn,
118 &num_fn);
119 for (i = 0; i < num_fn; i++)
120 fn[i]();
121 fn = NULL;
122 num_fn = 0;
123 mod++;
124 }
125 _num_mod_init += mod;
126
127 TAILQ_FOREACH_SAFE(qe, &__phdr_info_head, link, qe2) {
128 TAILQ_REMOVE(&__phdr_info_head, qe, link);
129 free(qe);
130 }
131 }
132
_fini_iterate_phdr_cb(struct dl_phdr_info * info,size_t size __unused,void * data __unused)133 static int _fini_iterate_phdr_cb(struct dl_phdr_info *info,
134 size_t size __unused, void *data __unused)
135 {
136 void (**fn)(void) = NULL;
137 size_t num_fn = 0;
138 size_t i = 0;
139
140 _get_fn_array(info, DT_FINI_ARRAY, DT_FINI_ARRAYSZ, &fn, &num_fn);
141
142 for (i = 1; i <= num_fn; i++)
143 fn[num_fn - i]();
144
145 return 0;
146 }
147
__utee_call_elf_fini_fn(void)148 void __utee_call_elf_fini_fn(void)
149 {
150 dl_iterate_phdr(_fini_iterate_phdr_cb, NULL);
151 }
152
init_instance(void)153 static TEE_Result init_instance(void)
154 {
155 trace_set_level(tahead_get_trace_level());
156 __utee_gprof_init();
157 malloc_add_pool(ta_heap, ta_heap_size);
158 _TEE_MathAPI_Init();
159 __utee_tcb_init();
160 __utee_call_elf_init_fn();
161 return TA_CreateEntryPoint();
162 }
163
uninit_instance(void)164 static void uninit_instance(void)
165 {
166 __utee_gprof_fini();
167 TA_DestroyEntryPoint();
168 __utee_call_elf_fini_fn();
169 }
170
ta_header_save_params(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])171 static void ta_header_save_params(uint32_t param_types,
172 TEE_Param params[TEE_NUM_PARAMS])
173 {
174 ta_param_types = param_types;
175
176 if (params)
177 memcpy(ta_params, params, sizeof(ta_params));
178 else
179 memset(ta_params, 0, sizeof(ta_params));
180 }
181
ta_header_get_session(uint32_t session_id)182 static struct ta_session *ta_header_get_session(uint32_t session_id)
183 {
184 struct ta_session *itr;
185
186 TAILQ_FOREACH(itr, &ta_sessions, link) {
187 if (itr->session_id == session_id)
188 return itr;
189 }
190 return NULL;
191 }
192
ta_header_add_session(uint32_t session_id)193 static TEE_Result ta_header_add_session(uint32_t session_id)
194 {
195 struct ta_session *itr = ta_header_get_session(session_id);
196 TEE_Result res;
197
198 if (itr)
199 return TEE_SUCCESS;
200
201 if (!init_done) {
202 init_done = true;
203 res = init_instance();
204 if (res)
205 return res;
206 }
207
208 itr = TEE_Malloc(sizeof(struct ta_session),
209 TEE_USER_MEM_HINT_NO_FILL_ZERO);
210 if (!itr)
211 return TEE_ERROR_OUT_OF_MEMORY;
212 itr->session_id = session_id;
213 itr->session_ctx = 0;
214 TAILQ_INSERT_TAIL(&ta_sessions, itr, link);
215
216 return TEE_SUCCESS;
217 }
218
ta_header_remove_session(uint32_t session_id)219 static void ta_header_remove_session(uint32_t session_id)
220 {
221 struct ta_session *itr;
222 bool keep_alive;
223
224 TAILQ_FOREACH(itr, &ta_sessions, link) {
225 if (itr->session_id == session_id) {
226 TAILQ_REMOVE(&ta_sessions, itr, link);
227 TEE_Free(itr);
228
229 keep_alive =
230 (ta_head.flags & TA_FLAG_SINGLE_INSTANCE) &&
231 (ta_head.flags & TA_FLAG_INSTANCE_KEEP_ALIVE);
232 if (TAILQ_EMPTY(&ta_sessions) && !keep_alive)
233 uninit_instance();
234
235 return;
236 }
237 }
238 }
239
to_utee_params(struct utee_params * up,uint32_t param_types,const TEE_Param params[TEE_NUM_PARAMS])240 static void to_utee_params(struct utee_params *up, uint32_t param_types,
241 const TEE_Param params[TEE_NUM_PARAMS])
242 {
243 size_t n = 0;
244
245 up->types = param_types;
246 for (n = 0; n < TEE_NUM_PARAMS; n++) {
247 switch (TEE_PARAM_TYPE_GET(param_types, n)) {
248 case TEE_PARAM_TYPE_VALUE_INPUT:
249 case TEE_PARAM_TYPE_VALUE_OUTPUT:
250 case TEE_PARAM_TYPE_VALUE_INOUT:
251 up->vals[n * 2] = params[n].value.a;
252 up->vals[n * 2 + 1] = params[n].value.b;
253 break;
254 case TEE_PARAM_TYPE_MEMREF_INPUT:
255 case TEE_PARAM_TYPE_MEMREF_OUTPUT:
256 case TEE_PARAM_TYPE_MEMREF_INOUT:
257 up->vals[n * 2] = (uintptr_t)params[n].memref.buffer;
258 up->vals[n * 2 + 1] = params[n].memref.size;
259 break;
260 default:
261 up->vals[n * 2] = 0;
262 up->vals[n * 2 + 1] = 0;
263 break;
264 }
265 }
266 }
267
from_utee_params(TEE_Param params[TEE_NUM_PARAMS],uint32_t * param_types,const struct utee_params * up)268 static void from_utee_params(TEE_Param params[TEE_NUM_PARAMS],
269 uint32_t *param_types,
270 const struct utee_params *up)
271 {
272 size_t n;
273 uint32_t types = up->types;
274
275 for (n = 0; n < TEE_NUM_PARAMS; n++) {
276 uintptr_t a = up->vals[n * 2];
277 uintptr_t b = up->vals[n * 2 + 1];
278
279 switch (TEE_PARAM_TYPE_GET(types, n)) {
280 case TEE_PARAM_TYPE_VALUE_INPUT:
281 case TEE_PARAM_TYPE_VALUE_OUTPUT:
282 case TEE_PARAM_TYPE_VALUE_INOUT:
283 params[n].value.a = a;
284 params[n].value.b = b;
285 break;
286 case TEE_PARAM_TYPE_MEMREF_INPUT:
287 case TEE_PARAM_TYPE_MEMREF_OUTPUT:
288 case TEE_PARAM_TYPE_MEMREF_INOUT:
289 params[n].memref.buffer = (void *)a;
290 params[n].memref.size = b;
291 break;
292 default:
293 break;
294 }
295 }
296
297 if (param_types)
298 *param_types = types;
299 }
300
entry_open_session(unsigned long session_id,struct utee_params * up)301 static TEE_Result entry_open_session(unsigned long session_id,
302 struct utee_params *up)
303 {
304 TEE_Result res;
305 struct ta_session *session;
306 uint32_t param_types;
307 TEE_Param params[TEE_NUM_PARAMS];
308
309 res = ta_header_add_session(session_id);
310 if (res != TEE_SUCCESS)
311 return res;
312
313 session = ta_header_get_session(session_id);
314 if (!session)
315 return TEE_ERROR_BAD_STATE;
316
317 from_utee_params(params, ¶m_types, up);
318 ta_header_save_params(param_types, params);
319
320 res = TA_OpenSessionEntryPoint(param_types, params,
321 &session->session_ctx);
322
323 to_utee_params(up, param_types, params);
324
325 if (res != TEE_SUCCESS)
326 ta_header_remove_session(session_id);
327 return res;
328 }
329
entry_close_session(unsigned long session_id)330 static TEE_Result entry_close_session(unsigned long session_id)
331 {
332 struct ta_session *session = ta_header_get_session(session_id);
333
334 if (!session)
335 return TEE_ERROR_BAD_STATE;
336
337 TA_CloseSessionEntryPoint(session->session_ctx);
338
339 ta_header_remove_session(session_id);
340 return TEE_SUCCESS;
341 }
342
entry_invoke_command(unsigned long session_id,struct utee_params * up,unsigned long cmd_id)343 static TEE_Result entry_invoke_command(unsigned long session_id,
344 struct utee_params *up, unsigned long cmd_id)
345 {
346 TEE_Result res;
347 uint32_t param_types;
348 TEE_Param params[TEE_NUM_PARAMS];
349 struct ta_session *session = ta_header_get_session(session_id);
350
351 if (!session)
352 return TEE_ERROR_BAD_STATE;
353
354 from_utee_params(params, ¶m_types, up);
355 ta_header_save_params(param_types, params);
356
357 res = TA_InvokeCommandEntryPoint(session->session_ctx, cmd_id,
358 param_types, params);
359
360 to_utee_params(up, param_types, params);
361 return res;
362 }
363
__utee_entry(unsigned long func,unsigned long session_id,struct utee_params * up,unsigned long cmd_id)364 TEE_Result __utee_entry(unsigned long func, unsigned long session_id,
365 struct utee_params *up, unsigned long cmd_id)
366 {
367 TEE_Result res;
368
369 switch (func) {
370 case UTEE_ENTRY_FUNC_OPEN_SESSION:
371 res = entry_open_session(session_id, up);
372 break;
373 case UTEE_ENTRY_FUNC_CLOSE_SESSION:
374 res = entry_close_session(session_id);
375 break;
376 case UTEE_ENTRY_FUNC_INVOKE_COMMAND:
377 res = entry_invoke_command(session_id, up, cmd_id);
378 break;
379 default:
380 res = 0xffffffff;
381 TEE_Panic(0);
382 break;
383 }
384 ta_header_save_params(0, NULL);
385
386 return res;
387 }
388