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