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