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, &param_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, &param_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