xref: /optee_os/core/kernel/tee_ta_manager.c (revision 856a5c769b99b4604345b02dbc33f4d3aebc0115)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
23cf931e5SJens Wiklander /*
33cf931e5SJens Wiklander  * Copyright (c) 2014, STMicroelectronics International N.V.
4e3603bdeSBalint Dobszay  * Copyright (c) 2020, Arm Limited
5*856a5c76SJoseph Lo  * Copyright (c) 2025, NVIDIA Corporation & AFFILIATES.
63cf931e5SJens Wiklander  */
78ddf5a4eSEtienne Carriere 
88ddf5a4eSEtienne Carriere #include <assert.h>
93cf931e5SJens Wiklander #include <kernel/mutex.h>
103cf931e5SJens Wiklander #include <kernel/panic.h>
1142fb5b2eSEtienne Carriere #include <kernel/pseudo_ta.h>
12f9cd31c5SJelle Sels #include <kernel/stmm_sp.h>
133cf931e5SJens Wiklander #include <kernel/tee_common.h>
143cf931e5SJens Wiklander #include <kernel/tee_misc.h>
153cf931e5SJens Wiklander #include <kernel/tee_ta_manager.h>
163cf931e5SJens Wiklander #include <kernel/tee_time.h>
173cf931e5SJens Wiklander #include <kernel/thread.h>
181936dfc7SJens Wiklander #include <kernel/user_mode_ctx.h>
193cf931e5SJens Wiklander #include <kernel/user_ta.h>
20cb94c145SWeizhao Jiang #include <malloc.h>
213cf931e5SJens Wiklander #include <mm/core_memprot.h>
221936dfc7SJens Wiklander #include <mm/core_mmu.h>
2380a4e51dSEtienne Carriere #include <mm/mobj.h>
2489c9728dSJens Wiklander #include <mm/vm.h>
25a05577eaSEtienne Carriere #include <pta_stats.h>
261936dfc7SJens Wiklander #include <stdlib.h>
271936dfc7SJens Wiklander #include <string.h>
283cf931e5SJens Wiklander #include <tee_api_types.h>
291936dfc7SJens Wiklander #include <tee/entry_std.h>
301936dfc7SJens Wiklander #include <tee/tee_obj.h>
313cf931e5SJens Wiklander #include <trace.h>
321936dfc7SJens Wiklander #include <types_ext.h>
33f5df167cSSumit Garg #include <user_ta_header.h>
343cf931e5SJens Wiklander #include <utee_types.h>
353cf931e5SJens Wiklander #include <util.h>
363cf931e5SJens Wiklander 
37cb94c145SWeizhao Jiang #if defined(CFG_TA_STATS)
38cb94c145SWeizhao Jiang #define MAX_DUMP_SESS_NUM	(16)
39cb94c145SWeizhao Jiang 
40cb94c145SWeizhao Jiang struct tee_ta_dump_ctx {
41cb94c145SWeizhao Jiang 	TEE_UUID uuid;
42cb94c145SWeizhao Jiang 	uint32_t panicked;
43cb94c145SWeizhao Jiang 	bool is_user_ta;
44cb94c145SWeizhao Jiang 	uint32_t sess_num;
45cb94c145SWeizhao Jiang 	uint32_t sess_id[MAX_DUMP_SESS_NUM];
46cb94c145SWeizhao Jiang };
47cb94c145SWeizhao Jiang #endif
48cb94c145SWeizhao Jiang 
493cf931e5SJens Wiklander /* This mutex protects the critical section in tee_ta_init_session */
506fde6f02SJerome Forissier struct mutex tee_ta_mutex = MUTEX_INITIALIZER;
51f0ab1c64SJens Wiklander /* This condvar is used when waiting for a TA context to become initialized */
52f0ab1c64SJens Wiklander struct condvar tee_ta_init_cv = CONDVAR_INITIALIZER;
536fde6f02SJerome Forissier struct tee_ta_ctx_head tee_ctxes = TAILQ_HEAD_INITIALIZER(tee_ctxes);
54daeea036SJerome Forissier 
55daeea036SJerome Forissier #ifndef CFG_CONCURRENT_SINGLE_INSTANCE_TA
563cf931e5SJens Wiklander static struct condvar tee_ta_cv = CONDVAR_INITIALIZER;
57f86aa9e1SJerome Forissier static short int tee_ta_single_instance_thread = THREAD_ID_INVALID;
583cf931e5SJens Wiklander static size_t tee_ta_single_instance_count;
59daeea036SJerome Forissier #endif
603cf931e5SJens Wiklander 
61daeea036SJerome Forissier #ifdef CFG_CONCURRENT_SINGLE_INSTANCE_TA
lock_single_instance(void)62daeea036SJerome Forissier static void lock_single_instance(void)
63daeea036SJerome Forissier {
64daeea036SJerome Forissier }
65daeea036SJerome Forissier 
unlock_single_instance(void)66daeea036SJerome Forissier static void unlock_single_instance(void)
67daeea036SJerome Forissier {
68daeea036SJerome Forissier }
69daeea036SJerome Forissier 
has_single_instance_lock(void)70daeea036SJerome Forissier static bool has_single_instance_lock(void)
71daeea036SJerome Forissier {
72daeea036SJerome Forissier 	return false;
73daeea036SJerome Forissier }
74daeea036SJerome Forissier #else
lock_single_instance(void)753cf931e5SJens Wiklander static void lock_single_instance(void)
763cf931e5SJens Wiklander {
773cf931e5SJens Wiklander 	/* Requires tee_ta_mutex to be held */
783cf931e5SJens Wiklander 	if (tee_ta_single_instance_thread != thread_get_id()) {
793cf931e5SJens Wiklander 		/* Wait until the single-instance lock is available. */
803cf931e5SJens Wiklander 		while (tee_ta_single_instance_thread != THREAD_ID_INVALID)
813cf931e5SJens Wiklander 			condvar_wait(&tee_ta_cv, &tee_ta_mutex);
823cf931e5SJens Wiklander 
833cf931e5SJens Wiklander 		tee_ta_single_instance_thread = thread_get_id();
843cf931e5SJens Wiklander 		assert(tee_ta_single_instance_count == 0);
853cf931e5SJens Wiklander 	}
863cf931e5SJens Wiklander 
873cf931e5SJens Wiklander 	tee_ta_single_instance_count++;
883cf931e5SJens Wiklander }
893cf931e5SJens Wiklander 
unlock_single_instance(void)903cf931e5SJens Wiklander static void unlock_single_instance(void)
913cf931e5SJens Wiklander {
923cf931e5SJens Wiklander 	/* Requires tee_ta_mutex to be held */
933cf931e5SJens Wiklander 	assert(tee_ta_single_instance_thread == thread_get_id());
943cf931e5SJens Wiklander 	assert(tee_ta_single_instance_count > 0);
953cf931e5SJens Wiklander 
963cf931e5SJens Wiklander 	tee_ta_single_instance_count--;
973cf931e5SJens Wiklander 	if (tee_ta_single_instance_count == 0) {
983cf931e5SJens Wiklander 		tee_ta_single_instance_thread = THREAD_ID_INVALID;
993cf931e5SJens Wiklander 		condvar_signal(&tee_ta_cv);
1003cf931e5SJens Wiklander 	}
1013cf931e5SJens Wiklander }
1023cf931e5SJens Wiklander 
has_single_instance_lock(void)1033cf931e5SJens Wiklander static bool has_single_instance_lock(void)
1043cf931e5SJens Wiklander {
1053cf931e5SJens Wiklander 	/* Requires tee_ta_mutex to be held */
1063cf931e5SJens Wiklander 	return tee_ta_single_instance_thread == thread_get_id();
1073cf931e5SJens Wiklander }
108daeea036SJerome Forissier #endif
1093cf931e5SJens Wiklander 
to_ta_session(struct ts_session * sess)110521aacf1SEtienne Carriere struct tee_ta_session *__noprof to_ta_session(struct ts_session *sess)
111521aacf1SEtienne Carriere {
112521aacf1SEtienne Carriere 	assert(is_ta_ctx(sess->ctx) || is_stmm_ctx(sess->ctx));
113521aacf1SEtienne Carriere 	return container_of(sess, struct tee_ta_session, ts_sess);
114521aacf1SEtienne Carriere }
115521aacf1SEtienne Carriere 
ts_to_ta_ctx(struct ts_ctx * ctx)116521aacf1SEtienne Carriere static struct tee_ta_ctx *ts_to_ta_ctx(struct ts_ctx *ctx)
117521aacf1SEtienne Carriere {
118521aacf1SEtienne Carriere 	if (is_ta_ctx(ctx))
119521aacf1SEtienne Carriere 		return to_ta_ctx(ctx);
120521aacf1SEtienne Carriere 
121521aacf1SEtienne Carriere 	if (is_stmm_ctx(ctx))
122521aacf1SEtienne Carriere 		return &(to_stmm_ctx(ctx)->ta_ctx);
123521aacf1SEtienne Carriere 
124521aacf1SEtienne Carriere 	panic("bad context");
125521aacf1SEtienne Carriere }
126521aacf1SEtienne Carriere 
tee_ta_try_set_busy(struct tee_ta_ctx * ctx)1273cf931e5SJens Wiklander static bool tee_ta_try_set_busy(struct tee_ta_ctx *ctx)
1283cf931e5SJens Wiklander {
1293cf931e5SJens Wiklander 	bool rc = true;
1303cf931e5SJens Wiklander 
131c7c4b6e3SJens Wiklander 	if (ctx->flags & TA_FLAG_CONCURRENT)
132c7c4b6e3SJens Wiklander 		return true;
133c7c4b6e3SJens Wiklander 
1343cf931e5SJens Wiklander 	mutex_lock(&tee_ta_mutex);
1353cf931e5SJens Wiklander 
1363cf931e5SJens Wiklander 	if (ctx->flags & TA_FLAG_SINGLE_INSTANCE)
1373cf931e5SJens Wiklander 		lock_single_instance();
1383cf931e5SJens Wiklander 
1393cf931e5SJens Wiklander 	if (has_single_instance_lock()) {
1403cf931e5SJens Wiklander 		if (ctx->busy) {
1413cf931e5SJens Wiklander 			/*
1423cf931e5SJens Wiklander 			 * We're holding the single-instance lock and the
1433cf931e5SJens Wiklander 			 * TA is busy, as waiting now would only cause a
1443cf931e5SJens Wiklander 			 * dead-lock, we release the lock and return false.
1453cf931e5SJens Wiklander 			 */
1463cf931e5SJens Wiklander 			rc = false;
1473cf931e5SJens Wiklander 			if (ctx->flags & TA_FLAG_SINGLE_INSTANCE)
1483cf931e5SJens Wiklander 				unlock_single_instance();
1493cf931e5SJens Wiklander 		}
1503cf931e5SJens Wiklander 	} else {
1513cf931e5SJens Wiklander 		/*
1523cf931e5SJens Wiklander 		 * We're not holding the single-instance lock, we're free to
1533cf931e5SJens Wiklander 		 * wait for the TA to become available.
1543cf931e5SJens Wiklander 		 */
1553cf931e5SJens Wiklander 		while (ctx->busy)
1563cf931e5SJens Wiklander 			condvar_wait(&ctx->busy_cv, &tee_ta_mutex);
1573cf931e5SJens Wiklander 	}
1583cf931e5SJens Wiklander 
1593cf931e5SJens Wiklander 	/* Either it's already true or we should set it to true */
1603cf931e5SJens Wiklander 	ctx->busy = true;
1613cf931e5SJens Wiklander 
1623cf931e5SJens Wiklander 	mutex_unlock(&tee_ta_mutex);
1633cf931e5SJens Wiklander 	return rc;
1643cf931e5SJens Wiklander }
1653cf931e5SJens Wiklander 
tee_ta_set_busy(struct tee_ta_ctx * ctx)1663cf931e5SJens Wiklander static void tee_ta_set_busy(struct tee_ta_ctx *ctx)
1673cf931e5SJens Wiklander {
1683cf931e5SJens Wiklander 	if (!tee_ta_try_set_busy(ctx))
1693cf931e5SJens Wiklander 		panic();
1703cf931e5SJens Wiklander }
1713cf931e5SJens Wiklander 
tee_ta_clear_busy(struct tee_ta_ctx * ctx)1723cf931e5SJens Wiklander static void tee_ta_clear_busy(struct tee_ta_ctx *ctx)
1733cf931e5SJens Wiklander {
174c7c4b6e3SJens Wiklander 	if (ctx->flags & TA_FLAG_CONCURRENT)
175c7c4b6e3SJens Wiklander 		return;
176c7c4b6e3SJens Wiklander 
1773cf931e5SJens Wiklander 	mutex_lock(&tee_ta_mutex);
1783cf931e5SJens Wiklander 
1793cf931e5SJens Wiklander 	assert(ctx->busy);
1803cf931e5SJens Wiklander 	ctx->busy = false;
1813cf931e5SJens Wiklander 	condvar_signal(&ctx->busy_cv);
1823cf931e5SJens Wiklander 
183c571b3fdSRueiAnHu 	if (ctx->flags & TA_FLAG_SINGLE_INSTANCE)
1843cf931e5SJens Wiklander 		unlock_single_instance();
1853cf931e5SJens Wiklander 
1863cf931e5SJens Wiklander 	mutex_unlock(&tee_ta_mutex);
1873cf931e5SJens Wiklander }
1883cf931e5SJens Wiklander 
dec_session_ref_count(struct tee_ta_session * s)1893cf931e5SJens Wiklander static void dec_session_ref_count(struct tee_ta_session *s)
1903cf931e5SJens Wiklander {
1913cf931e5SJens Wiklander 	assert(s->ref_count > 0);
1923cf931e5SJens Wiklander 	s->ref_count--;
1933cf931e5SJens Wiklander 	if (s->ref_count == 1)
1943cf931e5SJens Wiklander 		condvar_signal(&s->refc_cv);
1953cf931e5SJens Wiklander }
1963cf931e5SJens Wiklander 
tee_ta_put_session(struct tee_ta_session * s)1973cf931e5SJens Wiklander void tee_ta_put_session(struct tee_ta_session *s)
1983cf931e5SJens Wiklander {
1993cf931e5SJens Wiklander 	mutex_lock(&tee_ta_mutex);
2003cf931e5SJens Wiklander 
2013cf931e5SJens Wiklander 	if (s->lock_thread == thread_get_id()) {
2023cf931e5SJens Wiklander 		s->lock_thread = THREAD_ID_INVALID;
2033cf931e5SJens Wiklander 		condvar_signal(&s->lock_cv);
2043cf931e5SJens Wiklander 	}
2053cf931e5SJens Wiklander 	dec_session_ref_count(s);
2063cf931e5SJens Wiklander 
2073cf931e5SJens Wiklander 	mutex_unlock(&tee_ta_mutex);
2083cf931e5SJens Wiklander }
2093cf931e5SJens Wiklander 
tee_ta_find_session_nolock(uint32_t id,struct tee_ta_session_head * open_sessions)21099164a05SJerome Forissier static struct tee_ta_session *tee_ta_find_session_nolock(uint32_t id,
2113cf931e5SJens Wiklander 			struct tee_ta_session_head *open_sessions)
2123cf931e5SJens Wiklander {
21399164a05SJerome Forissier 	struct tee_ta_session *s = NULL;
21499164a05SJerome Forissier 	struct tee_ta_session *found = NULL;
2153cf931e5SJens Wiklander 
2163cf931e5SJens Wiklander 	TAILQ_FOREACH(s, open_sessions, link) {
21799164a05SJerome Forissier 		if (s->id == id) {
21899164a05SJerome Forissier 			found = s;
21999164a05SJerome Forissier 			break;
2203cf931e5SJens Wiklander 		}
22199164a05SJerome Forissier 	}
22299164a05SJerome Forissier 
22399164a05SJerome Forissier 	return found;
22499164a05SJerome Forissier }
22599164a05SJerome Forissier 
tee_ta_find_session(uint32_t id,struct tee_ta_session_head * open_sessions)22699164a05SJerome Forissier struct tee_ta_session *tee_ta_find_session(uint32_t id,
22799164a05SJerome Forissier 			struct tee_ta_session_head *open_sessions)
22899164a05SJerome Forissier {
22999164a05SJerome Forissier 	struct tee_ta_session *s = NULL;
23099164a05SJerome Forissier 
23199164a05SJerome Forissier 	mutex_lock(&tee_ta_mutex);
23299164a05SJerome Forissier 
23399164a05SJerome Forissier 	s = tee_ta_find_session_nolock(id, open_sessions);
23499164a05SJerome Forissier 
23599164a05SJerome Forissier 	mutex_unlock(&tee_ta_mutex);
23699164a05SJerome Forissier 
23799164a05SJerome Forissier 	return s;
2383cf931e5SJens Wiklander }
2393cf931e5SJens Wiklander 
tee_ta_get_session(uint32_t id,bool exclusive,struct tee_ta_session_head * open_sessions)2403cf931e5SJens Wiklander struct tee_ta_session *tee_ta_get_session(uint32_t id, bool exclusive,
2413cf931e5SJens Wiklander 			struct tee_ta_session_head *open_sessions)
2423cf931e5SJens Wiklander {
2433cf931e5SJens Wiklander 	struct tee_ta_session *s;
2443cf931e5SJens Wiklander 
2453cf931e5SJens Wiklander 	mutex_lock(&tee_ta_mutex);
2463cf931e5SJens Wiklander 
2473cf931e5SJens Wiklander 	while (true) {
24899164a05SJerome Forissier 		s = tee_ta_find_session_nolock(id, open_sessions);
2493cf931e5SJens Wiklander 		if (!s)
2503cf931e5SJens Wiklander 			break;
2513cf931e5SJens Wiklander 		if (s->unlink) {
2523cf931e5SJens Wiklander 			s = NULL;
2533cf931e5SJens Wiklander 			break;
2543cf931e5SJens Wiklander 		}
2553cf931e5SJens Wiklander 		s->ref_count++;
2563cf931e5SJens Wiklander 		if (!exclusive)
2573cf931e5SJens Wiklander 			break;
2583cf931e5SJens Wiklander 
2593cf931e5SJens Wiklander 		assert(s->lock_thread != thread_get_id());
2603cf931e5SJens Wiklander 
2613cf931e5SJens Wiklander 		while (s->lock_thread != THREAD_ID_INVALID && !s->unlink)
2623cf931e5SJens Wiklander 			condvar_wait(&s->lock_cv, &tee_ta_mutex);
2633cf931e5SJens Wiklander 
2643cf931e5SJens Wiklander 		if (s->unlink) {
2653cf931e5SJens Wiklander 			dec_session_ref_count(s);
2663cf931e5SJens Wiklander 			s = NULL;
2673cf931e5SJens Wiklander 			break;
2683cf931e5SJens Wiklander 		}
2693cf931e5SJens Wiklander 
2703cf931e5SJens Wiklander 		s->lock_thread = thread_get_id();
2713cf931e5SJens Wiklander 		break;
2723cf931e5SJens Wiklander 	}
2733cf931e5SJens Wiklander 
2743cf931e5SJens Wiklander 	mutex_unlock(&tee_ta_mutex);
2753cf931e5SJens Wiklander 	return s;
2763cf931e5SJens Wiklander }
2773cf931e5SJens Wiklander 
tee_ta_unlink_session(struct tee_ta_session * s,struct tee_ta_session_head * open_sessions)2783cf931e5SJens Wiklander static void tee_ta_unlink_session(struct tee_ta_session *s,
2793cf931e5SJens Wiklander 			struct tee_ta_session_head *open_sessions)
2803cf931e5SJens Wiklander {
2813cf931e5SJens Wiklander 	mutex_lock(&tee_ta_mutex);
2823cf931e5SJens Wiklander 
2833cf931e5SJens Wiklander 	assert(s->ref_count >= 1);
2843cf931e5SJens Wiklander 	assert(s->lock_thread == thread_get_id());
2853cf931e5SJens Wiklander 	assert(!s->unlink);
2863cf931e5SJens Wiklander 
2873cf931e5SJens Wiklander 	s->unlink = true;
2883cf931e5SJens Wiklander 	condvar_broadcast(&s->lock_cv);
2893cf931e5SJens Wiklander 
2903cf931e5SJens Wiklander 	while (s->ref_count != 1)
2913cf931e5SJens Wiklander 		condvar_wait(&s->refc_cv, &tee_ta_mutex);
2923cf931e5SJens Wiklander 
2933cf931e5SJens Wiklander 	TAILQ_REMOVE(open_sessions, s, link);
2943cf931e5SJens Wiklander 
2953cf931e5SJens Wiklander 	mutex_unlock(&tee_ta_mutex);
2963cf931e5SJens Wiklander }
2973cf931e5SJens Wiklander 
destroy_session(struct tee_ta_session * s,struct tee_ta_session_head * open_sessions)298fd10f62bSOvidiu Mihalachi static void destroy_session(struct tee_ta_session *s,
299fd10f62bSOvidiu Mihalachi 			    struct tee_ta_session_head *open_sessions)
300fd10f62bSOvidiu Mihalachi {
301099918f6SSumit Garg #if defined(CFG_FTRACE_SUPPORT)
30200b3b9a2SJens Wiklander 	if (s->ts_sess.ctx && s->ts_sess.ctx->ops->dump_ftrace) {
30300b3b9a2SJens Wiklander 		ts_push_current_session(&s->ts_sess);
30400b3b9a2SJens Wiklander 		s->ts_sess.fbuf = NULL;
30500b3b9a2SJens Wiklander 		s->ts_sess.ctx->ops->dump_ftrace(s->ts_sess.ctx);
30600b3b9a2SJens Wiklander 		ts_pop_current_session();
307d35a00c7SSumit Garg 	}
308d35a00c7SSumit Garg #endif
309d35a00c7SSumit Garg 
310fd10f62bSOvidiu Mihalachi 	tee_ta_unlink_session(s, open_sessions);
311fd10f62bSOvidiu Mihalachi #if defined(CFG_TA_GPROF_SUPPORT)
31200b3b9a2SJens Wiklander 	free(s->ts_sess.sbuf);
313fd10f62bSOvidiu Mihalachi #endif
314fd10f62bSOvidiu Mihalachi 	free(s);
315fd10f62bSOvidiu Mihalachi }
316fd10f62bSOvidiu Mihalachi 
destroy_context(struct tee_ta_ctx * ctx)317fd10f62bSOvidiu Mihalachi static void destroy_context(struct tee_ta_ctx *ctx)
318fd10f62bSOvidiu Mihalachi {
319fd10f62bSOvidiu Mihalachi 	DMSG("Destroy TA ctx (0x%" PRIxVA ")",  (vaddr_t)ctx);
320fd10f62bSOvidiu Mihalachi 
321fd10f62bSOvidiu Mihalachi 	condvar_destroy(&ctx->busy_cv);
3223560d990SJens Wiklander 	ctx->ts_ctx.ops->destroy(&ctx->ts_ctx);
323fd10f62bSOvidiu Mihalachi }
324fd10f62bSOvidiu Mihalachi 
3253cf931e5SJens Wiklander /*
3263cf931e5SJens Wiklander  * tee_ta_context_find - Find TA in session list based on a UUID (input)
3273cf931e5SJens Wiklander  * Returns a pointer to the session
3283cf931e5SJens Wiklander  */
tee_ta_context_find(const TEE_UUID * uuid)3293cf931e5SJens Wiklander static struct tee_ta_ctx *tee_ta_context_find(const TEE_UUID *uuid)
3303cf931e5SJens Wiklander {
3313cf931e5SJens Wiklander 	struct tee_ta_ctx *ctx;
3323cf931e5SJens Wiklander 
3333cf931e5SJens Wiklander 	TAILQ_FOREACH(ctx, &tee_ctxes, link) {
3343560d990SJens Wiklander 		if (memcmp(&ctx->ts_ctx.uuid, uuid, sizeof(TEE_UUID)) == 0)
3353cf931e5SJens Wiklander 			return ctx;
3363cf931e5SJens Wiklander 	}
3373cf931e5SJens Wiklander 
3383cf931e5SJens Wiklander 	return NULL;
3393cf931e5SJens Wiklander }
3403cf931e5SJens Wiklander 
3413cf931e5SJens Wiklander /* check if requester (client ID) matches session initial client */
check_client(struct tee_ta_session * s,const TEE_Identity * id)3423cf931e5SJens Wiklander static TEE_Result check_client(struct tee_ta_session *s, const TEE_Identity *id)
3433cf931e5SJens Wiklander {
3443cf931e5SJens Wiklander 	if (id == KERN_IDENTITY)
3453cf931e5SJens Wiklander 		return TEE_SUCCESS;
3463cf931e5SJens Wiklander 
3473cf931e5SJens Wiklander 	if (id == NSAPP_IDENTITY) {
3483cf931e5SJens Wiklander 		if (s->clnt_id.login == TEE_LOGIN_TRUSTED_APP) {
3493cf931e5SJens Wiklander 			DMSG("nsec tries to hijack TA session");
3503cf931e5SJens Wiklander 			return TEE_ERROR_ACCESS_DENIED;
3513cf931e5SJens Wiklander 		}
3523cf931e5SJens Wiklander 		return TEE_SUCCESS;
3533cf931e5SJens Wiklander 	}
3543cf931e5SJens Wiklander 
3553cf931e5SJens Wiklander 	if (memcmp(&s->clnt_id, id, sizeof(TEE_Identity)) != 0) {
3563cf931e5SJens Wiklander 		DMSG("client id mismatch");
3573cf931e5SJens Wiklander 		return TEE_ERROR_ACCESS_DENIED;
3583cf931e5SJens Wiklander 	}
3593cf931e5SJens Wiklander 	return TEE_SUCCESS;
3603cf931e5SJens Wiklander }
3613cf931e5SJens Wiklander 
36280a4e51dSEtienne Carriere /*
36380a4e51dSEtienne Carriere  * Check if invocation parameters matches TA properties
36480a4e51dSEtienne Carriere  *
36580a4e51dSEtienne Carriere  * @s - current session handle
36680a4e51dSEtienne Carriere  * @param - already identified memory references hold a valid 'mobj'.
36780a4e51dSEtienne Carriere  *
36880a4e51dSEtienne Carriere  * Policy:
36980a4e51dSEtienne Carriere  * - All TAs can access 'non-secure' shared memory.
37080a4e51dSEtienne Carriere  * - All TAs can access TEE private memory (seccpy)
37180a4e51dSEtienne Carriere  * - Only SDP flagged TAs can accept SDP memory references.
37280a4e51dSEtienne Carriere  */
37380a4e51dSEtienne Carriere #ifndef CFG_SECURE_DATA_PATH
check_params(struct tee_ta_session * sess __unused,struct tee_ta_param * param __unused)37480a4e51dSEtienne Carriere static bool check_params(struct tee_ta_session *sess __unused,
37580a4e51dSEtienne Carriere 			 struct tee_ta_param *param __unused)
37680a4e51dSEtienne Carriere {
37780a4e51dSEtienne Carriere 	/*
37880a4e51dSEtienne Carriere 	 * When CFG_SECURE_DATA_PATH is not enabled, SDP memory references
37980a4e51dSEtienne Carriere 	 * are rejected at OP-TEE core entry. Hence here all TAs have same
38080a4e51dSEtienne Carriere 	 * permissions regarding memory reference parameters.
38180a4e51dSEtienne Carriere 	 */
38280a4e51dSEtienne Carriere 	return true;
38380a4e51dSEtienne Carriere }
38480a4e51dSEtienne Carriere #else
check_params(struct tee_ta_session * sess,struct tee_ta_param * param)38580a4e51dSEtienne Carriere static bool check_params(struct tee_ta_session *sess,
38680a4e51dSEtienne Carriere 			 struct tee_ta_param *param)
38780a4e51dSEtienne Carriere {
38880a4e51dSEtienne Carriere 	int n;
38980a4e51dSEtienne Carriere 
39080a4e51dSEtienne Carriere 	/*
39180a4e51dSEtienne Carriere 	 * When CFG_SECURE_DATA_PATH is enabled, OP-TEE entry allows SHM and
39280a4e51dSEtienne Carriere 	 * SDP memory references. Only TAs flagged SDP can access SDP memory.
39380a4e51dSEtienne Carriere 	 */
39400b3b9a2SJens Wiklander 	if (sess->ts_sess.ctx &&
395521aacf1SEtienne Carriere 	    ts_to_ta_ctx(sess->ts_sess.ctx)->flags & TA_FLAG_SECURE_DATA_PATH)
39680a4e51dSEtienne Carriere 		return true;
39780a4e51dSEtienne Carriere 
39880a4e51dSEtienne Carriere 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
39980a4e51dSEtienne Carriere 		uint32_t param_type = TEE_PARAM_TYPE_GET(param->types, n);
40080a4e51dSEtienne Carriere 		struct param_mem *mem = &param->u[n].mem;
40180a4e51dSEtienne Carriere 
40280a4e51dSEtienne Carriere 		if (param_type != TEE_PARAM_TYPE_MEMREF_INPUT &&
40380a4e51dSEtienne Carriere 		    param_type != TEE_PARAM_TYPE_MEMREF_OUTPUT &&
40480a4e51dSEtienne Carriere 		    param_type != TEE_PARAM_TYPE_MEMREF_INOUT)
40580a4e51dSEtienne Carriere 			continue;
40680a4e51dSEtienne Carriere 		if (!mem->size)
40780a4e51dSEtienne Carriere 			continue;
40880a4e51dSEtienne Carriere 		if (mobj_is_sdp_mem(mem->mobj))
40980a4e51dSEtienne Carriere 			return false;
41080a4e51dSEtienne Carriere 	}
41180a4e51dSEtienne Carriere 	return true;
41280a4e51dSEtienne Carriere }
41380a4e51dSEtienne Carriere #endif
41480a4e51dSEtienne Carriere 
set_invoke_timeout(struct tee_ta_session * sess,uint32_t cancel_req_to)4153cf931e5SJens Wiklander static void set_invoke_timeout(struct tee_ta_session *sess,
4163cf931e5SJens Wiklander 				      uint32_t cancel_req_to)
4173cf931e5SJens Wiklander {
4183cf931e5SJens Wiklander 	TEE_Time current_time;
419159cc1f3SJens Wiklander 	TEE_Time cancel_time;
4203cf931e5SJens Wiklander 
4213cf931e5SJens Wiklander 	if (cancel_req_to == TEE_TIMEOUT_INFINITE)
422159cc1f3SJens Wiklander 		goto infinite;
4233cf931e5SJens Wiklander 
4243cf931e5SJens Wiklander 	if (tee_time_get_sys_time(&current_time) != TEE_SUCCESS)
425159cc1f3SJens Wiklander 		goto infinite;
4263cf931e5SJens Wiklander 
427159cc1f3SJens Wiklander 	if (ADD_OVERFLOW(current_time.seconds, cancel_req_to / 1000,
428159cc1f3SJens Wiklander 			 &cancel_time.seconds))
429159cc1f3SJens Wiklander 		goto infinite;
430159cc1f3SJens Wiklander 
4313cf931e5SJens Wiklander 	cancel_time.millis = current_time.millis + cancel_req_to % 1000;
4323cf931e5SJens Wiklander 	if (cancel_time.millis > 1000) {
433159cc1f3SJens Wiklander 		if (ADD_OVERFLOW(current_time.seconds, 1,
434159cc1f3SJens Wiklander 				 &cancel_time.seconds))
435159cc1f3SJens Wiklander 			goto infinite;
436159cc1f3SJens Wiklander 
4373cf931e5SJens Wiklander 		cancel_time.seconds++;
4383cf931e5SJens Wiklander 		cancel_time.millis -= 1000;
4393cf931e5SJens Wiklander 	}
4403cf931e5SJens Wiklander 
4413cf931e5SJens Wiklander 	sess->cancel_time = cancel_time;
442159cc1f3SJens Wiklander 	return;
443159cc1f3SJens Wiklander 
444159cc1f3SJens Wiklander infinite:
445159cc1f3SJens Wiklander 	sess->cancel_time.seconds = UINT32_MAX;
446159cc1f3SJens Wiklander 	sess->cancel_time.millis = UINT32_MAX;
4473cf931e5SJens Wiklander }
4483cf931e5SJens Wiklander 
4493cf931e5SJens Wiklander /*-----------------------------------------------------------------------------
4503cf931e5SJens Wiklander  * Close a Trusted Application and free available resources
4513cf931e5SJens Wiklander  *---------------------------------------------------------------------------*/
tee_ta_close_session(struct tee_ta_session * csess,struct tee_ta_session_head * open_sessions,const TEE_Identity * clnt_id)4523cf931e5SJens Wiklander TEE_Result tee_ta_close_session(struct tee_ta_session *csess,
4533cf931e5SJens Wiklander 				struct tee_ta_session_head *open_sessions,
4543cf931e5SJens Wiklander 				const TEE_Identity *clnt_id)
4553cf931e5SJens Wiklander {
456521aacf1SEtienne Carriere 	struct tee_ta_session *sess = NULL;
457521aacf1SEtienne Carriere 	struct tee_ta_ctx *ctx = NULL;
458521aacf1SEtienne Carriere 	struct ts_ctx *ts_ctx = NULL;
459941a58d7SJens Wiklander 	bool keep_crashed = false;
460521aacf1SEtienne Carriere 	bool keep_alive = false;
4613cf931e5SJens Wiklander 
462af598004SJens Wiklander 	DMSG("csess 0x%" PRIxVA " id %u",
463af598004SJens Wiklander 	     (vaddr_t)csess, csess ? csess->id : UINT_MAX);
4643cf931e5SJens Wiklander 
4653cf931e5SJens Wiklander 	if (!csess)
4663cf931e5SJens Wiklander 		return TEE_ERROR_ITEM_NOT_FOUND;
4673cf931e5SJens Wiklander 
46899164a05SJerome Forissier 	sess = tee_ta_get_session(csess->id, true, open_sessions);
4693cf931e5SJens Wiklander 
4703cf931e5SJens Wiklander 	if (!sess) {
4713cf931e5SJens Wiklander 		EMSG("session 0x%" PRIxVA " to be removed is not found",
4723cf931e5SJens Wiklander 		     (vaddr_t)csess);
4733cf931e5SJens Wiklander 		return TEE_ERROR_ITEM_NOT_FOUND;
4743cf931e5SJens Wiklander 	}
4753cf931e5SJens Wiklander 
4763cf931e5SJens Wiklander 	if (check_client(sess, clnt_id) != TEE_SUCCESS) {
4773cf931e5SJens Wiklander 		tee_ta_put_session(sess);
4783cf931e5SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS; /* intentional generic error */
4793cf931e5SJens Wiklander 	}
4803cf931e5SJens Wiklander 
4815b2fecf1SJerome Forissier 	DMSG("Destroy session");
4823cf931e5SJens Wiklander 
483521aacf1SEtienne Carriere 	ts_ctx = sess->ts_sess.ctx;
484521aacf1SEtienne Carriere 	if (!ts_ctx) {
485fd10f62bSOvidiu Mihalachi 		destroy_session(sess, open_sessions);
486fd10f62bSOvidiu Mihalachi 		return TEE_SUCCESS;
4873cf931e5SJens Wiklander 	}
4883cf931e5SJens Wiklander 
489521aacf1SEtienne Carriere 	ctx = ts_to_ta_ctx(ts_ctx);
49049d06bffSEtienne Carriere 	if (ctx->panicked) {
49149d06bffSEtienne Carriere 		destroy_session(sess, open_sessions);
49249d06bffSEtienne Carriere 	} else {
493fd10f62bSOvidiu Mihalachi 		tee_ta_set_busy(ctx);
494fd10f62bSOvidiu Mihalachi 		set_invoke_timeout(sess, TEE_TIMEOUT_INFINITE);
495521aacf1SEtienne Carriere 		ts_ctx->ops->enter_close_session(&sess->ts_sess);
496fd10f62bSOvidiu Mihalachi 		destroy_session(sess, open_sessions);
4973cf931e5SJens Wiklander 		tee_ta_clear_busy(ctx);
49849d06bffSEtienne Carriere 	}
4993cf931e5SJens Wiklander 
5003cf931e5SJens Wiklander 	mutex_lock(&tee_ta_mutex);
5013cf931e5SJens Wiklander 
502d13278b8SEtienne Carriere 	if (ctx->ref_count <= 0)
503d13278b8SEtienne Carriere 		panic();
504d13278b8SEtienne Carriere 
5053cf931e5SJens Wiklander 	ctx->ref_count--;
506941a58d7SJens Wiklander 	if (ctx->flags & TA_FLAG_SINGLE_INSTANCE)
507941a58d7SJens Wiklander 		keep_alive = ctx->flags & TA_FLAG_INSTANCE_KEEP_ALIVE;
508941a58d7SJens Wiklander 	if (keep_alive)
509941a58d7SJens Wiklander 		keep_crashed = ctx->flags & TA_FLAG_INSTANCE_KEEP_CRASHED;
510941a58d7SJens Wiklander 	if (!ctx->ref_count &&
511941a58d7SJens Wiklander 	    ((ctx->panicked && !keep_crashed) || !keep_alive)) {
512c10e3fa9SJens Wiklander 		if (!ctx->is_releasing) {
5133cf931e5SJens Wiklander 			TAILQ_REMOVE(&tee_ctxes, ctx, link);
514c10e3fa9SJens Wiklander 			ctx->is_releasing = true;
515c10e3fa9SJens Wiklander 		}
5163cf931e5SJens Wiklander 		mutex_unlock(&tee_ta_mutex);
5173cf931e5SJens Wiklander 
518fd10f62bSOvidiu Mihalachi 		destroy_context(ctx);
5193cf931e5SJens Wiklander 	} else
5203cf931e5SJens Wiklander 		mutex_unlock(&tee_ta_mutex);
5213cf931e5SJens Wiklander 
5223cf931e5SJens Wiklander 	return TEE_SUCCESS;
5233cf931e5SJens Wiklander }
5243cf931e5SJens Wiklander 
tee_ta_init_session_with_context(struct tee_ta_session * s,const TEE_UUID * uuid)525f0ab1c64SJens Wiklander static TEE_Result tee_ta_init_session_with_context(struct tee_ta_session *s,
526f0ab1c64SJens Wiklander 						   const TEE_UUID *uuid)
5273cf931e5SJens Wiklander {
528f0ab1c64SJens Wiklander 	struct tee_ta_ctx *ctx = NULL;
529f0ab1c64SJens Wiklander 
530f0ab1c64SJens Wiklander 	while (true) {
531f0ab1c64SJens Wiklander 		ctx = tee_ta_context_find(uuid);
532f0ab1c64SJens Wiklander 		if (!ctx)
533f0ab1c64SJens Wiklander 			return TEE_ERROR_ITEM_NOT_FOUND;
534f0ab1c64SJens Wiklander 
535fee55718SEtienne Carriere 		if (!ctx->is_initializing)
536f0ab1c64SJens Wiklander 			break;
537f0ab1c64SJens Wiklander 		/*
538f0ab1c64SJens Wiklander 		 * Context is still initializing, wait here until it's
539f0ab1c64SJens Wiklander 		 * fully initialized. Note that we're searching for the
540f0ab1c64SJens Wiklander 		 * context again since it may have been removed while we
541f0ab1c64SJens Wiklander 		 * where sleeping.
542f0ab1c64SJens Wiklander 		 */
543f0ab1c64SJens Wiklander 		condvar_wait(&tee_ta_init_cv, &tee_ta_mutex);
544f0ab1c64SJens Wiklander 	}
545f0ab1c64SJens Wiklander 
5463cf931e5SJens Wiklander 	/*
547fee55718SEtienne Carriere 	 * If the trusted service is not a single instance service (e.g. is
548fee55718SEtienne Carriere 	 * a multi-instance TA) it should be loaded as a new instance instead
549fee55718SEtienne Carriere 	 * of doing anything with this instance. So tell the caller that we
550fee55718SEtienne Carriere 	 * didn't find the TA it the caller will load a new instance.
5513cf931e5SJens Wiklander 	 */
5523cf931e5SJens Wiklander 	if ((ctx->flags & TA_FLAG_SINGLE_INSTANCE) == 0)
5533cf931e5SJens Wiklander 		return TEE_ERROR_ITEM_NOT_FOUND;
5543cf931e5SJens Wiklander 
5553cf931e5SJens Wiklander 	/*
556fee55718SEtienne Carriere 	 * The trusted service is single instance, if it isn't multi session we
557705ee6a3SZeng Tao 	 * can't create another session unless its reference is zero
5583cf931e5SJens Wiklander 	 */
559705ee6a3SZeng Tao 	if (!(ctx->flags & TA_FLAG_MULTI_SESSION) && ctx->ref_count)
5603cf931e5SJens Wiklander 		return TEE_ERROR_BUSY;
5613cf931e5SJens Wiklander 
562fee55718SEtienne Carriere 	DMSG("Re-open trusted service %pUl", (void *)&ctx->ts_ctx.uuid);
5633cf931e5SJens Wiklander 
5643cf931e5SJens Wiklander 	ctx->ref_count++;
5653560d990SJens Wiklander 	s->ts_sess.ctx = &ctx->ts_ctx;
566ab5363c6SJens Wiklander 	s->ts_sess.handle_scall = s->ts_sess.ctx->ops->handle_scall;
5673cf931e5SJens Wiklander 	return TEE_SUCCESS;
5683cf931e5SJens Wiklander }
5693cf931e5SJens Wiklander 
new_session_id(struct tee_ta_session_head * open_sessions)57099164a05SJerome Forissier static uint32_t new_session_id(struct tee_ta_session_head *open_sessions)
57199164a05SJerome Forissier {
57299164a05SJerome Forissier 	struct tee_ta_session *last = NULL;
57399164a05SJerome Forissier 	uint32_t saved = 0;
57499164a05SJerome Forissier 	uint32_t id = 1;
57599164a05SJerome Forissier 
57699164a05SJerome Forissier 	last = TAILQ_LAST(open_sessions, tee_ta_session_head);
57799164a05SJerome Forissier 	if (last) {
57899164a05SJerome Forissier 		/* This value is less likely to be already used */
57999164a05SJerome Forissier 		id = last->id + 1;
58099164a05SJerome Forissier 		if (!id)
58199164a05SJerome Forissier 			id++; /* 0 is not valid */
58299164a05SJerome Forissier 	}
58399164a05SJerome Forissier 
58499164a05SJerome Forissier 	saved = id;
58599164a05SJerome Forissier 	do {
58699164a05SJerome Forissier 		if (!tee_ta_find_session_nolock(id, open_sessions))
58799164a05SJerome Forissier 			return id;
58899164a05SJerome Forissier 		id++;
58999164a05SJerome Forissier 		if (!id)
59099164a05SJerome Forissier 			id++;
59199164a05SJerome Forissier 	} while (id != saved);
59299164a05SJerome Forissier 
59399164a05SJerome Forissier 	return 0;
59499164a05SJerome Forissier }
5953cf931e5SJens Wiklander 
tee_ta_init_session(TEE_ErrorOrigin * err,struct tee_ta_session_head * open_sessions,const TEE_UUID * uuid,struct tee_ta_session ** sess)5963cf931e5SJens Wiklander static TEE_Result tee_ta_init_session(TEE_ErrorOrigin *err,
5973cf931e5SJens Wiklander 				struct tee_ta_session_head *open_sessions,
5983cf931e5SJens Wiklander 				const TEE_UUID *uuid,
5993cf931e5SJens Wiklander 				struct tee_ta_session **sess)
6003cf931e5SJens Wiklander {
6013cf931e5SJens Wiklander 	TEE_Result res;
6023cf931e5SJens Wiklander 	struct tee_ta_session *s = calloc(1, sizeof(struct tee_ta_session));
6033cf931e5SJens Wiklander 
6043cf931e5SJens Wiklander 	*err = TEE_ORIGIN_TEE;
6053cf931e5SJens Wiklander 	if (!s)
6063cf931e5SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
6073cf931e5SJens Wiklander 
6083cf931e5SJens Wiklander 	s->cancel_mask = true;
6093cf931e5SJens Wiklander 	condvar_init(&s->refc_cv);
6103cf931e5SJens Wiklander 	condvar_init(&s->lock_cv);
6113cf931e5SJens Wiklander 	s->lock_thread = THREAD_ID_INVALID;
6123cf931e5SJens Wiklander 	s->ref_count = 1;
6136fde6f02SJerome Forissier 
6143cf931e5SJens Wiklander 	mutex_lock(&tee_ta_mutex);
61599164a05SJerome Forissier 	s->id = new_session_id(open_sessions);
61699164a05SJerome Forissier 	if (!s->id) {
61799164a05SJerome Forissier 		res = TEE_ERROR_OVERFLOW;
618f0ab1c64SJens Wiklander 		goto err_mutex_unlock;
61999164a05SJerome Forissier 	}
620f0ab1c64SJens Wiklander 
6213cf931e5SJens Wiklander 	TAILQ_INSERT_TAIL(open_sessions, s, link);
62299f969ddSJens Wiklander 
6236fde6f02SJerome Forissier 	/* Look for already loaded TA */
624f0ab1c64SJens Wiklander 	res = tee_ta_init_session_with_context(s, uuid);
625956c2d50SEtienne Carriere 	if (res == TEE_SUCCESS || res != TEE_ERROR_ITEM_NOT_FOUND) {
626f0ab1c64SJens Wiklander 		mutex_unlock(&tee_ta_mutex);
6276fde6f02SJerome Forissier 		goto out;
628956c2d50SEtienne Carriere 	}
6296fde6f02SJerome Forissier 
63042471ecfSJens Wiklander 	/* Look for secure partition */
631f9cd31c5SJelle Sels 	res = stmm_init_session(uuid, s);
632956c2d50SEtienne Carriere 	if (res == TEE_SUCCESS || res != TEE_ERROR_ITEM_NOT_FOUND) {
633956c2d50SEtienne Carriere 		mutex_unlock(&tee_ta_mutex);
634956c2d50SEtienne Carriere 		if (res == TEE_SUCCESS)
635956c2d50SEtienne Carriere 			res = stmm_complete_session(s);
636956c2d50SEtienne Carriere 
63742471ecfSJens Wiklander 		goto out;
638956c2d50SEtienne Carriere 	}
63942471ecfSJens Wiklander 
64035964dc9SEtienne Carriere 	/* Look for pseudo TA */
6416fde6f02SJerome Forissier 	res = tee_ta_init_pseudo_ta_session(uuid, s);
642956c2d50SEtienne Carriere 	if (res == TEE_SUCCESS || res != TEE_ERROR_ITEM_NOT_FOUND) {
643956c2d50SEtienne Carriere 		mutex_unlock(&tee_ta_mutex);
6446fde6f02SJerome Forissier 		goto out;
645956c2d50SEtienne Carriere 	}
6466fde6f02SJerome Forissier 
6476fde6f02SJerome Forissier 	/* Look for user TA */
6486fde6f02SJerome Forissier 	res = tee_ta_init_user_ta_session(uuid, s);
649956c2d50SEtienne Carriere 	mutex_unlock(&tee_ta_mutex);
650956c2d50SEtienne Carriere 	if (res == TEE_SUCCESS)
651956c2d50SEtienne Carriere 		res = tee_ta_complete_user_ta_session(s);
6526fde6f02SJerome Forissier 
6536fde6f02SJerome Forissier out:
654f0ab1c64SJens Wiklander 	if (!res) {
6556fde6f02SJerome Forissier 		*sess = s;
656f0ab1c64SJens Wiklander 		return TEE_SUCCESS;
6576fde6f02SJerome Forissier 	}
658f0ab1c64SJens Wiklander 
659f0ab1c64SJens Wiklander 	mutex_lock(&tee_ta_mutex);
660f0ab1c64SJens Wiklander 	TAILQ_REMOVE(open_sessions, s, link);
661f0ab1c64SJens Wiklander err_mutex_unlock:
6626fde6f02SJerome Forissier 	mutex_unlock(&tee_ta_mutex);
663f0ab1c64SJens Wiklander 	free(s);
6646fde6f02SJerome Forissier 	return res;
6653cf931e5SJens Wiklander }
6663cf931e5SJens Wiklander 
maybe_release_ta_ctx(struct tee_ta_ctx * ctx)667*856a5c76SJoseph Lo static void maybe_release_ta_ctx(struct tee_ta_ctx *ctx)
668c10e3fa9SJens Wiklander {
669c10e3fa9SJens Wiklander 	bool was_releasing = false;
670*856a5c76SJoseph Lo 	bool keep_crashed = false;
671*856a5c76SJoseph Lo 	bool keep_alive = false;
672c10e3fa9SJens Wiklander 
673*856a5c76SJoseph Lo 	if (ctx->flags & TA_FLAG_SINGLE_INSTANCE)
674*856a5c76SJoseph Lo 		keep_alive = ctx->flags & TA_FLAG_INSTANCE_KEEP_ALIVE;
675*856a5c76SJoseph Lo 	if (keep_alive)
676*856a5c76SJoseph Lo 		keep_crashed = ctx->flags & TA_FLAG_INSTANCE_KEEP_CRASHED;
677*856a5c76SJoseph Lo 
678*856a5c76SJoseph Lo 	/*
679*856a5c76SJoseph Lo 	 * Keep panicked TAs with SINGLE_INSTANCE, KEEP_ALIVE, and KEEP_CRASHED
680*856a5c76SJoseph Lo 	 * flags in the context list to maintain their panicked status and
681*856a5c76SJoseph Lo 	 * prevent respawning.
682*856a5c76SJoseph Lo 	 */
683*856a5c76SJoseph Lo 	if (!keep_crashed) {
684c10e3fa9SJens Wiklander 		mutex_lock(&tee_ta_mutex);
685c10e3fa9SJens Wiklander 		was_releasing = ctx->is_releasing;
686c10e3fa9SJens Wiklander 		ctx->is_releasing = true;
687c10e3fa9SJens Wiklander 		if (!was_releasing) {
688c10e3fa9SJens Wiklander 			DMSG("Releasing panicked TA ctx");
689c10e3fa9SJens Wiklander 			TAILQ_REMOVE(&tee_ctxes, ctx, link);
690c10e3fa9SJens Wiklander 		}
691c10e3fa9SJens Wiklander 		mutex_unlock(&tee_ta_mutex);
692c10e3fa9SJens Wiklander 
693c10e3fa9SJens Wiklander 		if (!was_releasing)
694c10e3fa9SJens Wiklander 			ctx->ts_ctx.ops->release_state(&ctx->ts_ctx);
695c10e3fa9SJens Wiklander 	}
696*856a5c76SJoseph Lo }
697c10e3fa9SJens Wiklander 
tee_ta_open_session(TEE_ErrorOrigin * err,struct tee_ta_session ** sess,struct tee_ta_session_head * open_sessions,const TEE_UUID * uuid,const TEE_Identity * clnt_id,uint32_t cancel_req_to,struct tee_ta_param * param)6983cf931e5SJens Wiklander TEE_Result tee_ta_open_session(TEE_ErrorOrigin *err,
6993cf931e5SJens Wiklander 			       struct tee_ta_session **sess,
7003cf931e5SJens Wiklander 			       struct tee_ta_session_head *open_sessions,
7013cf931e5SJens Wiklander 			       const TEE_UUID *uuid,
7023cf931e5SJens Wiklander 			       const TEE_Identity *clnt_id,
7033cf931e5SJens Wiklander 			       uint32_t cancel_req_to,
7043cf931e5SJens Wiklander 			       struct tee_ta_param *param)
7053cf931e5SJens Wiklander {
7063560d990SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
7073cf931e5SJens Wiklander 	struct tee_ta_session *s = NULL;
7083560d990SJens Wiklander 	struct tee_ta_ctx *ctx = NULL;
709521aacf1SEtienne Carriere 	struct ts_ctx *ts_ctx = NULL;
7103560d990SJens Wiklander 	bool panicked = false;
7113cf931e5SJens Wiklander 	bool was_busy = false;
7123cf931e5SJens Wiklander 
7133cf931e5SJens Wiklander 	res = tee_ta_init_session(err, open_sessions, uuid, &s);
7143cf931e5SJens Wiklander 	if (res != TEE_SUCCESS) {
7153cf931e5SJens Wiklander 		DMSG("init session failed 0x%x", res);
7163cf931e5SJens Wiklander 		return res;
7173cf931e5SJens Wiklander 	}
7183cf931e5SJens Wiklander 
71980a4e51dSEtienne Carriere 	if (!check_params(s, param))
72080a4e51dSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
72180a4e51dSEtienne Carriere 
722521aacf1SEtienne Carriere 	ts_ctx = s->ts_sess.ctx;
723521aacf1SEtienne Carriere 	ctx = ts_to_ta_ctx(ts_ctx);
7243cf931e5SJens Wiklander 
725c10e3fa9SJens Wiklander 	if (tee_ta_try_set_busy(ctx)) {
726c10e3fa9SJens Wiklander 		if (!ctx->panicked) {
7273cf931e5SJens Wiklander 			/* Save identity of the owner of the session */
7283cf931e5SJens Wiklander 			s->clnt_id = *clnt_id;
72982061b8dSJens Wiklander 			s->param = param;
7303cf931e5SJens Wiklander 			set_invoke_timeout(s, cancel_req_to);
731521aacf1SEtienne Carriere 			res = ts_ctx->ops->enter_open_session(&s->ts_sess);
732c10e3fa9SJens Wiklander 			s->param = NULL;
733c10e3fa9SJens Wiklander 		}
734c10e3fa9SJens Wiklander 
735c10e3fa9SJens Wiklander 		panicked = ctx->panicked;
736c10e3fa9SJens Wiklander 		if (panicked) {
737*856a5c76SJoseph Lo 			maybe_release_ta_ctx(ctx);
738c10e3fa9SJens Wiklander 			res = TEE_ERROR_TARGET_DEAD;
739c10e3fa9SJens Wiklander 		}
740c10e3fa9SJens Wiklander 
7413cf931e5SJens Wiklander 		tee_ta_clear_busy(ctx);
7423cf931e5SJens Wiklander 	} else {
7433cf931e5SJens Wiklander 		/* Deadlock avoided */
7443cf931e5SJens Wiklander 		res = TEE_ERROR_BUSY;
7453cf931e5SJens Wiklander 		was_busy = true;
7463cf931e5SJens Wiklander 	}
7473cf931e5SJens Wiklander 
7483cf931e5SJens Wiklander 	/*
7493cf931e5SJens Wiklander 	 * Origin error equal to TEE_ORIGIN_TRUSTED_APP for "regular" error,
7503cf931e5SJens Wiklander 	 * apart from panicking.
7513cf931e5SJens Wiklander 	 */
7523cf931e5SJens Wiklander 	if (panicked || was_busy)
7533cf931e5SJens Wiklander 		*err = TEE_ORIGIN_TEE;
75482061b8dSJens Wiklander 	else
75582061b8dSJens Wiklander 		*err = s->err_origin;
7563cf931e5SJens Wiklander 
757f6439ceeSJens Wiklander 	tee_ta_put_session(s);
758f6439ceeSJens Wiklander 	if (panicked || res != TEE_SUCCESS)
759f6439ceeSJens Wiklander 		tee_ta_close_session(s, open_sessions, KERN_IDENTITY);
760f6439ceeSJens Wiklander 
761c10e3fa9SJens Wiklander 	if (!res)
762c10e3fa9SJens Wiklander 		*sess = s;
763c10e3fa9SJens Wiklander 	else
7643d8cac14SPatrick Delaunay 		EMSG("Failed for TA %pUl. Return error %#"PRIx32, uuid, res);
7653cf931e5SJens Wiklander 
7663cf931e5SJens Wiklander 	return res;
7673cf931e5SJens Wiklander }
7683cf931e5SJens Wiklander 
tee_ta_invoke_command(TEE_ErrorOrigin * err,struct tee_ta_session * sess,const TEE_Identity * clnt_id,uint32_t cancel_req_to,uint32_t cmd,struct tee_ta_param * param)7693cf931e5SJens Wiklander TEE_Result tee_ta_invoke_command(TEE_ErrorOrigin *err,
7703cf931e5SJens Wiklander 				 struct tee_ta_session *sess,
7713cf931e5SJens Wiklander 				 const TEE_Identity *clnt_id,
7723cf931e5SJens Wiklander 				 uint32_t cancel_req_to, uint32_t cmd,
7733cf931e5SJens Wiklander 				 struct tee_ta_param *param)
7743cf931e5SJens Wiklander {
7753560d990SJens Wiklander 	struct tee_ta_ctx *ta_ctx = NULL;
776521aacf1SEtienne Carriere 	struct ts_ctx *ts_ctx = NULL;
7773560d990SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
778c10e3fa9SJens Wiklander 	bool panicked = false;
7793cf931e5SJens Wiklander 
7803cf931e5SJens Wiklander 	if (check_client(sess, clnt_id) != TEE_SUCCESS)
7813cf931e5SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS; /* intentional generic error */
7823cf931e5SJens Wiklander 
78380a4e51dSEtienne Carriere 	if (!check_params(sess, param))
78480a4e51dSEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
78580a4e51dSEtienne Carriere 
786521aacf1SEtienne Carriere 	ts_ctx = sess->ts_sess.ctx;
787521aacf1SEtienne Carriere 	ta_ctx = ts_to_ta_ctx(ts_ctx);
7883cf931e5SJens Wiklander 
7893560d990SJens Wiklander 	tee_ta_set_busy(ta_ctx);
7903cf931e5SJens Wiklander 
791c10e3fa9SJens Wiklander 	if (!ta_ctx->panicked) {
79282061b8dSJens Wiklander 		sess->param = param;
7933cf931e5SJens Wiklander 		set_invoke_timeout(sess, cancel_req_to);
794521aacf1SEtienne Carriere 		res = ts_ctx->ops->enter_invoke_cmd(&sess->ts_sess, cmd);
79582061b8dSJens Wiklander 		sess->param = NULL;
796fd10f62bSOvidiu Mihalachi 	}
797fd10f62bSOvidiu Mihalachi 
798c10e3fa9SJens Wiklander 	panicked = ta_ctx->panicked;
799c10e3fa9SJens Wiklander 	if (panicked) {
800*856a5c76SJoseph Lo 		maybe_release_ta_ctx(ta_ctx);
801c10e3fa9SJens Wiklander 		res = TEE_ERROR_TARGET_DEAD;
802c10e3fa9SJens Wiklander 	}
803c10e3fa9SJens Wiklander 
804c10e3fa9SJens Wiklander 	tee_ta_clear_busy(ta_ctx);
805c10e3fa9SJens Wiklander 
806c10e3fa9SJens Wiklander 	/*
807c10e3fa9SJens Wiklander 	 * Origin error equal to TEE_ORIGIN_TRUSTED_APP for "regular" error,
808c10e3fa9SJens Wiklander 	 * apart from panicking.
809c10e3fa9SJens Wiklander 	 */
810c10e3fa9SJens Wiklander 	if (panicked)
811c10e3fa9SJens Wiklander 		*err = TEE_ORIGIN_TEE;
812c10e3fa9SJens Wiklander 	else
81382061b8dSJens Wiklander 		*err = sess->err_origin;
81482061b8dSJens Wiklander 
8152e3518aeSEtienne Carriere 	/* Short buffer is not an effective error case */
8162e3518aeSEtienne Carriere 	if (res != TEE_SUCCESS && res != TEE_ERROR_SHORT_BUFFER)
81765fe41dbSEtienne Carriere 		DMSG("Error: %x of %d", res, *err);
8182e3518aeSEtienne Carriere 
8193cf931e5SJens Wiklander 	return res;
8203cf931e5SJens Wiklander }
8213cf931e5SJens Wiklander 
822cb94c145SWeizhao Jiang #if defined(CFG_TA_STATS)
dump_ta_memstats(struct tee_ta_session * s,struct tee_ta_param * param)823cb94c145SWeizhao Jiang static TEE_Result dump_ta_memstats(struct tee_ta_session *s,
824cb94c145SWeizhao Jiang 				   struct tee_ta_param *param)
825cb94c145SWeizhao Jiang {
826cb94c145SWeizhao Jiang 	TEE_Result res = TEE_SUCCESS;
827cb94c145SWeizhao Jiang 	struct tee_ta_ctx *ctx = NULL;
828cb94c145SWeizhao Jiang 	struct ts_ctx *ts_ctx = NULL;
829c10e3fa9SJens Wiklander 	bool panicked = false;
830cb94c145SWeizhao Jiang 
831cb94c145SWeizhao Jiang 	ts_ctx = s->ts_sess.ctx;
832cb94c145SWeizhao Jiang 	if (!ts_ctx)
833cb94c145SWeizhao Jiang 		return TEE_ERROR_ITEM_NOT_FOUND;
834cb94c145SWeizhao Jiang 
835cb94c145SWeizhao Jiang 	ctx = ts_to_ta_ctx(ts_ctx);
836cb94c145SWeizhao Jiang 
837fee55718SEtienne Carriere 	if (ctx->is_initializing)
838fee55718SEtienne Carriere 		return TEE_ERROR_BAD_STATE;
839fee55718SEtienne Carriere 
840cb94c145SWeizhao Jiang 	if (tee_ta_try_set_busy(ctx)) {
841c10e3fa9SJens Wiklander 		if (!ctx->panicked) {
842cb94c145SWeizhao Jiang 			s->param = param;
843cb94c145SWeizhao Jiang 			set_invoke_timeout(s, TEE_TIMEOUT_INFINITE);
844cb94c145SWeizhao Jiang 			res = ts_ctx->ops->dump_mem_stats(&s->ts_sess);
845cb94c145SWeizhao Jiang 			s->param = NULL;
846c10e3fa9SJens Wiklander 		}
847c10e3fa9SJens Wiklander 
848c10e3fa9SJens Wiklander 		panicked = ctx->panicked;
849c10e3fa9SJens Wiklander 		if (panicked) {
850*856a5c76SJoseph Lo 			maybe_release_ta_ctx(ctx);
851c10e3fa9SJens Wiklander 			res = TEE_ERROR_TARGET_DEAD;
852c10e3fa9SJens Wiklander 		}
853c10e3fa9SJens Wiklander 
854cb94c145SWeizhao Jiang 		tee_ta_clear_busy(ctx);
855cb94c145SWeizhao Jiang 	} else {
856cb94c145SWeizhao Jiang 		/* Deadlock avoided */
857cb94c145SWeizhao Jiang 		res = TEE_ERROR_BUSY;
858cb94c145SWeizhao Jiang 	}
859cb94c145SWeizhao Jiang 
860cb94c145SWeizhao Jiang 	return res;
861cb94c145SWeizhao Jiang }
862cb94c145SWeizhao Jiang 
init_dump_ctx(struct tee_ta_dump_ctx * dump_ctx)863cb94c145SWeizhao Jiang static void init_dump_ctx(struct tee_ta_dump_ctx *dump_ctx)
864cb94c145SWeizhao Jiang {
865cb94c145SWeizhao Jiang 	struct tee_ta_session *sess = NULL;
866cb94c145SWeizhao Jiang 	struct tee_ta_session_head *open_sessions = NULL;
867cb94c145SWeizhao Jiang 	struct tee_ta_ctx *ctx = NULL;
868cb94c145SWeizhao Jiang 	unsigned int n = 0;
869cb94c145SWeizhao Jiang 
870cb94c145SWeizhao Jiang 	nsec_sessions_list_head(&open_sessions);
871cb94c145SWeizhao Jiang 	/*
872cb94c145SWeizhao Jiang 	 * Scan all sessions opened from secure side by searching through
873cb94c145SWeizhao Jiang 	 * all available TA instances and for each context, scan all opened
874cb94c145SWeizhao Jiang 	 * sessions.
875cb94c145SWeizhao Jiang 	 */
876cb94c145SWeizhao Jiang 	TAILQ_FOREACH(ctx, &tee_ctxes, link) {
877cb94c145SWeizhao Jiang 		unsigned int cnt = 0;
878cb94c145SWeizhao Jiang 
879cb94c145SWeizhao Jiang 		if (!is_user_ta_ctx(&ctx->ts_ctx))
880cb94c145SWeizhao Jiang 			continue;
881cb94c145SWeizhao Jiang 
882cb94c145SWeizhao Jiang 		memcpy(&dump_ctx[n].uuid, &ctx->ts_ctx.uuid,
883cb94c145SWeizhao Jiang 		       sizeof(ctx->ts_ctx.uuid));
884cb94c145SWeizhao Jiang 		dump_ctx[n].panicked = ctx->panicked;
885cb94c145SWeizhao Jiang 		dump_ctx[n].is_user_ta = is_user_ta_ctx(&ctx->ts_ctx);
886cb94c145SWeizhao Jiang 		TAILQ_FOREACH(sess, open_sessions, link) {
887cb94c145SWeizhao Jiang 			if (sess->ts_sess.ctx == &ctx->ts_ctx) {
888cb94c145SWeizhao Jiang 				if (cnt == MAX_DUMP_SESS_NUM)
889cb94c145SWeizhao Jiang 					break;
890cb94c145SWeizhao Jiang 
891cb94c145SWeizhao Jiang 				dump_ctx[n].sess_id[cnt] = sess->id;
892cb94c145SWeizhao Jiang 				cnt++;
893cb94c145SWeizhao Jiang 			}
894cb94c145SWeizhao Jiang 		}
895cb94c145SWeizhao Jiang 
896cb94c145SWeizhao Jiang 		dump_ctx[n].sess_num = cnt;
897cb94c145SWeizhao Jiang 		n++;
898cb94c145SWeizhao Jiang 	}
899cb94c145SWeizhao Jiang }
900cb94c145SWeizhao Jiang 
dump_ta_stats(struct tee_ta_dump_ctx * dump_ctx,struct pta_stats_ta * dump_stats,size_t ta_count)901cb94c145SWeizhao Jiang static TEE_Result dump_ta_stats(struct tee_ta_dump_ctx *dump_ctx,
90254115809SEtienne Carriere 				struct pta_stats_ta *dump_stats,
903cb94c145SWeizhao Jiang 				size_t ta_count)
904cb94c145SWeizhao Jiang {
905cb94c145SWeizhao Jiang 	TEE_Result res = TEE_SUCCESS;
906cb94c145SWeizhao Jiang 	struct tee_ta_session *sess = NULL;
907cb94c145SWeizhao Jiang 	struct tee_ta_session_head *open_sessions = NULL;
908cb94c145SWeizhao Jiang 	struct tee_ta_param param = { };
909cb94c145SWeizhao Jiang 	unsigned int i = 0;
910cb94c145SWeizhao Jiang 	unsigned int j = 0;
911cb94c145SWeizhao Jiang 
912cb94c145SWeizhao Jiang 	nsec_sessions_list_head(&open_sessions);
913cb94c145SWeizhao Jiang 
914cb94c145SWeizhao Jiang 	for (i = 0; i < ta_count; i++) {
91554115809SEtienne Carriere 		struct pta_stats_ta *stats = &dump_stats[i];
916cb94c145SWeizhao Jiang 
917cb94c145SWeizhao Jiang 		memcpy(&stats->uuid, &dump_ctx[i].uuid,
918cb94c145SWeizhao Jiang 		       sizeof(dump_ctx[i].uuid));
919cb94c145SWeizhao Jiang 		stats->panicked = dump_ctx[i].panicked;
920cb94c145SWeizhao Jiang 		stats->sess_num = dump_ctx[i].sess_num;
921cb94c145SWeizhao Jiang 
922cb94c145SWeizhao Jiang 		/* Find a session from dump context */
923cb94c145SWeizhao Jiang 		for (j = 0, sess = NULL; j < dump_ctx[i].sess_num && !sess; j++)
924cb94c145SWeizhao Jiang 			sess = tee_ta_get_session(dump_ctx[i].sess_id[j], true,
925cb94c145SWeizhao Jiang 						  open_sessions);
926cb94c145SWeizhao Jiang 
927cb94c145SWeizhao Jiang 		if (!sess)
928cb94c145SWeizhao Jiang 			continue;
929cb94c145SWeizhao Jiang 		/* If session is existing, get its heap stats */
930cb94c145SWeizhao Jiang 		memset(&param, 0, sizeof(struct tee_ta_param));
931cb94c145SWeizhao Jiang 		param.types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
932cb94c145SWeizhao Jiang 					      TEE_PARAM_TYPE_VALUE_OUTPUT,
933cb94c145SWeizhao Jiang 					      TEE_PARAM_TYPE_VALUE_OUTPUT,
934cb94c145SWeizhao Jiang 					      TEE_PARAM_TYPE_NONE);
935cb94c145SWeizhao Jiang 		res = dump_ta_memstats(sess, &param);
936cb94c145SWeizhao Jiang 		if (res == TEE_SUCCESS) {
937cb94c145SWeizhao Jiang 			stats->heap.allocated = param.u[0].val.a;
938cb94c145SWeizhao Jiang 			stats->heap.max_allocated = param.u[0].val.b;
939cb94c145SWeizhao Jiang 			stats->heap.size = param.u[1].val.a;
940cb94c145SWeizhao Jiang 			stats->heap.num_alloc_fail = param.u[1].val.b;
941cb94c145SWeizhao Jiang 			stats->heap.biggest_alloc_fail = param.u[2].val.a;
942cb94c145SWeizhao Jiang 			stats->heap.biggest_alloc_fail_used = param.u[2].val.b;
943cb94c145SWeizhao Jiang 		} else {
944cb94c145SWeizhao Jiang 			memset(&stats->heap, 0, sizeof(stats->heap));
945cb94c145SWeizhao Jiang 		}
946cb94c145SWeizhao Jiang 		tee_ta_put_session(sess);
947cb94c145SWeizhao Jiang 	}
948cb94c145SWeizhao Jiang 
949cb94c145SWeizhao Jiang 	return TEE_SUCCESS;
950cb94c145SWeizhao Jiang }
951cb94c145SWeizhao Jiang 
tee_ta_instance_stats(void * buf,size_t * buf_size)952c11218ebSClement Faure TEE_Result tee_ta_instance_stats(void *buf, size_t *buf_size)
953cb94c145SWeizhao Jiang {
954cb94c145SWeizhao Jiang 	TEE_Result res = TEE_SUCCESS;
95554115809SEtienne Carriere 	struct pta_stats_ta *dump_stats = NULL;
956cb94c145SWeizhao Jiang 	struct tee_ta_dump_ctx *dump_ctx = NULL;
957cb94c145SWeizhao Jiang 	struct tee_ta_ctx *ctx = NULL;
958cb94c145SWeizhao Jiang 	size_t sz = 0;
959cb94c145SWeizhao Jiang 	size_t ta_count = 0;
960cb94c145SWeizhao Jiang 
961cb94c145SWeizhao Jiang 	if (!buf_size)
962cb94c145SWeizhao Jiang 		return TEE_ERROR_BAD_PARAMETERS;
963cb94c145SWeizhao Jiang 
964cb94c145SWeizhao Jiang 	mutex_lock(&tee_ta_mutex);
965cb94c145SWeizhao Jiang 
966cb94c145SWeizhao Jiang 	/* Go through all available TA and calc out the actual buffer size. */
967cb94c145SWeizhao Jiang 	TAILQ_FOREACH(ctx, &tee_ctxes, link)
968cb94c145SWeizhao Jiang 		if (is_user_ta_ctx(&ctx->ts_ctx))
969cb94c145SWeizhao Jiang 			ta_count++;
970cb94c145SWeizhao Jiang 
97154115809SEtienne Carriere 	sz = sizeof(struct pta_stats_ta) * ta_count;
972fa40bed5SWeizhao Jiang 	if (!sz) {
973fa40bed5SWeizhao Jiang 		/* sz = 0 means there is no UTA, return no item found. */
974fa40bed5SWeizhao Jiang 		res = TEE_ERROR_ITEM_NOT_FOUND;
975fa40bed5SWeizhao Jiang 	} else if (!buf || *buf_size < sz) {
976cb94c145SWeizhao Jiang 		/*
977cb94c145SWeizhao Jiang 		 * buf is null or pass size less than actual size
978cb94c145SWeizhao Jiang 		 * means caller try to query the buffer size.
979cb94c145SWeizhao Jiang 		 * update *buf_size.
980cb94c145SWeizhao Jiang 		 */
981cb94c145SWeizhao Jiang 		*buf_size = sz;
982cb94c145SWeizhao Jiang 		res = TEE_ERROR_SHORT_BUFFER;
983cb94c145SWeizhao Jiang 	} else if (!IS_ALIGNED_WITH_TYPE(buf, uint32_t)) {
984cb94c145SWeizhao Jiang 		DMSG("Data alignment");
985cb94c145SWeizhao Jiang 		res = TEE_ERROR_BAD_PARAMETERS;
986cb94c145SWeizhao Jiang 	} else {
98754115809SEtienne Carriere 		dump_stats = (struct pta_stats_ta *)buf;
988b031393cSWeizhao Jiang 		dump_ctx = malloc(sizeof(struct tee_ta_dump_ctx) * ta_count);
989cb94c145SWeizhao Jiang 		if (!dump_ctx)
990cb94c145SWeizhao Jiang 			res = TEE_ERROR_OUT_OF_MEMORY;
991cb94c145SWeizhao Jiang 		else
992cb94c145SWeizhao Jiang 			init_dump_ctx(dump_ctx);
993cb94c145SWeizhao Jiang 	}
994cb94c145SWeizhao Jiang 	mutex_unlock(&tee_ta_mutex);
995cb94c145SWeizhao Jiang 
996cb94c145SWeizhao Jiang 	if (res != TEE_SUCCESS)
997cb94c145SWeizhao Jiang 		return res;
998cb94c145SWeizhao Jiang 
999cb94c145SWeizhao Jiang 	/* Dump user ta stats by iterating dump_ctx[] */
1000cb94c145SWeizhao Jiang 	res = dump_ta_stats(dump_ctx, dump_stats, ta_count);
1001cb94c145SWeizhao Jiang 	if (res == TEE_SUCCESS)
1002cb94c145SWeizhao Jiang 		*buf_size = sz;
1003cb94c145SWeizhao Jiang 
1004cb94c145SWeizhao Jiang 	free(dump_ctx);
1005cb94c145SWeizhao Jiang 	return res;
1006cb94c145SWeizhao Jiang }
1007cb94c145SWeizhao Jiang #endif
1008cb94c145SWeizhao Jiang 
tee_ta_cancel_command(TEE_ErrorOrigin * err,struct tee_ta_session * sess,const TEE_Identity * clnt_id)10093cf931e5SJens Wiklander TEE_Result tee_ta_cancel_command(TEE_ErrorOrigin *err,
10103cf931e5SJens Wiklander 				 struct tee_ta_session *sess,
10113cf931e5SJens Wiklander 				 const TEE_Identity *clnt_id)
10123cf931e5SJens Wiklander {
10133cf931e5SJens Wiklander 	*err = TEE_ORIGIN_TEE;
10143cf931e5SJens Wiklander 
10153cf931e5SJens Wiklander 	if (check_client(sess, clnt_id) != TEE_SUCCESS)
10163cf931e5SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS; /* intentional generic error */
10173cf931e5SJens Wiklander 
10183cf931e5SJens Wiklander 	sess->cancel = true;
10193cf931e5SJens Wiklander 	return TEE_SUCCESS;
10203cf931e5SJens Wiklander }
10213cf931e5SJens Wiklander 
tee_ta_session_is_cancelled(struct tee_ta_session * s,TEE_Time * curr_time)102263dc8d4aSJens Wiklander bool tee_ta_session_is_cancelled(struct tee_ta_session *s, TEE_Time *curr_time)
102363dc8d4aSJens Wiklander {
102463dc8d4aSJens Wiklander 	TEE_Time current_time;
102563dc8d4aSJens Wiklander 
102663dc8d4aSJens Wiklander 	if (s->cancel_mask)
102763dc8d4aSJens Wiklander 		return false;
102863dc8d4aSJens Wiklander 
102963dc8d4aSJens Wiklander 	if (s->cancel)
103063dc8d4aSJens Wiklander 		return true;
103163dc8d4aSJens Wiklander 
103263dc8d4aSJens Wiklander 	if (s->cancel_time.seconds == UINT32_MAX)
103363dc8d4aSJens Wiklander 		return false;
103463dc8d4aSJens Wiklander 
103563dc8d4aSJens Wiklander 	if (curr_time != NULL)
103663dc8d4aSJens Wiklander 		current_time = *curr_time;
103763dc8d4aSJens Wiklander 	else if (tee_time_get_sys_time(&current_time) != TEE_SUCCESS)
103863dc8d4aSJens Wiklander 		return false;
103963dc8d4aSJens Wiklander 
104063dc8d4aSJens Wiklander 	if (current_time.seconds > s->cancel_time.seconds ||
104163dc8d4aSJens Wiklander 	    (current_time.seconds == s->cancel_time.seconds &&
104263dc8d4aSJens Wiklander 	     current_time.millis >= s->cancel_time.millis)) {
104363dc8d4aSJens Wiklander 		return true;
104463dc8d4aSJens Wiklander 	}
104563dc8d4aSJens Wiklander 
104663dc8d4aSJens Wiklander 	return false;
104763dc8d4aSJens Wiklander }
104863dc8d4aSJens Wiklander 
1049883c4be3SJerome Forissier #if defined(CFG_TA_GPROF_SUPPORT)
tee_ta_gprof_sample_pc(vaddr_t pc)1050883c4be3SJerome Forissier void tee_ta_gprof_sample_pc(vaddr_t pc)
1051883c4be3SJerome Forissier {
105200b3b9a2SJens Wiklander 	struct ts_session *s = ts_get_current_session();
10538800b01dSJerome Forissier 	struct user_ta_ctx *utc = NULL;
1054f5df167cSSumit Garg 	struct sample_buf *sbuf = NULL;
10558800b01dSJerome Forissier 	TEE_Result res = 0;
1056f5df167cSSumit Garg 	size_t idx = 0;
1057883c4be3SJerome Forissier 
1058883c4be3SJerome Forissier 	sbuf = s->sbuf;
1059883c4be3SJerome Forissier 	if (!sbuf || !sbuf->enabled)
1060883c4be3SJerome Forissier 		return; /* PC sampling is not enabled */
1061883c4be3SJerome Forissier 
1062883c4be3SJerome Forissier 	idx = (((uint64_t)pc - sbuf->offset)/2 * sbuf->scale)/65536;
10638800b01dSJerome Forissier 	if (idx < sbuf->nsamples) {
10648800b01dSJerome Forissier 		utc = to_user_ta_ctx(s->ctx);
106589c9728dSJens Wiklander 		res = vm_check_access_rights(&utc->uctx,
10668800b01dSJerome Forissier 					     TEE_MEMORY_ACCESS_READ |
10678800b01dSJerome Forissier 					     TEE_MEMORY_ACCESS_WRITE |
10688800b01dSJerome Forissier 					     TEE_MEMORY_ACCESS_ANY_OWNER,
10698800b01dSJerome Forissier 					     (uaddr_t)&sbuf->samples[idx],
10708800b01dSJerome Forissier 					     sizeof(*sbuf->samples));
10718800b01dSJerome Forissier 		if (res != TEE_SUCCESS)
10728800b01dSJerome Forissier 			return;
1073883c4be3SJerome Forissier 		sbuf->samples[idx]++;
10748800b01dSJerome Forissier 	}
1075883c4be3SJerome Forissier 	sbuf->count++;
1076883c4be3SJerome Forissier }
1077883c4be3SJerome Forissier 
gprof_update_session_utime(bool suspend,struct ts_session * s,uint64_t now)107800b3b9a2SJens Wiklander static void gprof_update_session_utime(bool suspend, struct ts_session *s,
1079f5df167cSSumit Garg 				       uint64_t now)
1080883c4be3SJerome Forissier {
108100b3b9a2SJens Wiklander 	struct sample_buf *sbuf = s->sbuf;
1082883c4be3SJerome Forissier 
1083883c4be3SJerome Forissier 	if (!sbuf)
1084883c4be3SJerome Forissier 		return;
1085f5df167cSSumit Garg 
1086883c4be3SJerome Forissier 	if (suspend) {
1087883c4be3SJerome Forissier 		assert(sbuf->usr_entered);
1088883c4be3SJerome Forissier 		sbuf->usr += now - sbuf->usr_entered;
1089883c4be3SJerome Forissier 		sbuf->usr_entered = 0;
1090883c4be3SJerome Forissier 	} else {
1091883c4be3SJerome Forissier 		assert(!sbuf->usr_entered);
1092883c4be3SJerome Forissier 		if (!now)
1093883c4be3SJerome Forissier 			now++; /* 0 is reserved */
1094883c4be3SJerome Forissier 		sbuf->usr_entered = now;
1095883c4be3SJerome Forissier 	}
1096883c4be3SJerome Forissier }
1097f5df167cSSumit Garg 
1098f5df167cSSumit Garg /*
1099f5df167cSSumit Garg  * Update user-mode CPU time for the current session
1100f5df167cSSumit Garg  * @suspend: true if session is being suspended (leaving user mode), false if
1101f5df167cSSumit Garg  * it is resumed (entering user mode)
1102f5df167cSSumit Garg  */
tee_ta_update_session_utime(bool suspend)1103f5df167cSSumit Garg static void tee_ta_update_session_utime(bool suspend)
1104f5df167cSSumit Garg {
110500b3b9a2SJens Wiklander 	struct ts_session *s = ts_get_current_session();
1106c6e827c0SJens Wiklander 	uint64_t now = barrier_read_counter_timer();
1107f5df167cSSumit Garg 
1108f5df167cSSumit Garg 	gprof_update_session_utime(suspend, s, now);
1109f5df167cSSumit Garg }
1110883c4be3SJerome Forissier 
tee_ta_update_session_utime_suspend(void)1111883c4be3SJerome Forissier void tee_ta_update_session_utime_suspend(void)
1112883c4be3SJerome Forissier {
1113883c4be3SJerome Forissier 	tee_ta_update_session_utime(true);
1114883c4be3SJerome Forissier }
1115883c4be3SJerome Forissier 
tee_ta_update_session_utime_resume(void)1116883c4be3SJerome Forissier void tee_ta_update_session_utime_resume(void)
1117883c4be3SJerome Forissier {
1118883c4be3SJerome Forissier 	tee_ta_update_session_utime(false);
1119883c4be3SJerome Forissier }
1120883c4be3SJerome Forissier #endif
11211df107b6SSumit Garg 
1122099918f6SSumit Garg #if defined(CFG_FTRACE_SUPPORT)
ftrace_update_times(bool suspend)11231df107b6SSumit Garg static void ftrace_update_times(bool suspend)
11241df107b6SSumit Garg {
11252a7b4219SJerome Forissier 	struct ts_session *s = ts_get_current_session_may_fail();
11261df107b6SSumit Garg 	struct ftrace_buf *fbuf = NULL;
11271df107b6SSumit Garg 	uint64_t now = 0;
11281df107b6SSumit Garg 	uint32_t i = 0;
11291df107b6SSumit Garg 
11302a7b4219SJerome Forissier 	if (!s)
11312a7b4219SJerome Forissier 		return;
11322a7b4219SJerome Forissier 
1133c6e827c0SJens Wiklander 	now = barrier_read_counter_timer();
11341df107b6SSumit Garg 
11351df107b6SSumit Garg 	fbuf = s->fbuf;
11361df107b6SSumit Garg 	if (!fbuf)
11371df107b6SSumit Garg 		return;
11381df107b6SSumit Garg 
11391df107b6SSumit Garg 	if (suspend) {
11401df107b6SSumit Garg 		fbuf->suspend_time = now;
11411df107b6SSumit Garg 	} else {
11421df107b6SSumit Garg 		for (i = 0; i <= fbuf->ret_idx; i++)
11431df107b6SSumit Garg 			fbuf->begin_time[i] += now - fbuf->suspend_time;
11441df107b6SSumit Garg 	}
11451df107b6SSumit Garg }
11461df107b6SSumit Garg 
tee_ta_ftrace_update_times_suspend(void)11471df107b6SSumit Garg void tee_ta_ftrace_update_times_suspend(void)
11481df107b6SSumit Garg {
11491df107b6SSumit Garg 	ftrace_update_times(true);
11501df107b6SSumit Garg }
11511df107b6SSumit Garg 
tee_ta_ftrace_update_times_resume(void)11521df107b6SSumit Garg void tee_ta_ftrace_update_times_resume(void)
11531df107b6SSumit Garg {
11541df107b6SSumit Garg 	ftrace_update_times(false);
11551df107b6SSumit Garg }
11561df107b6SSumit Garg #endif
1157ce332a51SJens Wiklander 
is_ta_ctx(struct ts_ctx * ctx)11580a75d408SJens Wiklander bool __noprof is_ta_ctx(struct ts_ctx *ctx)
1159ce332a51SJens Wiklander {
1160ce332a51SJens Wiklander 	return is_user_ta_ctx(ctx) || is_pseudo_ta_ctx(ctx);
1161ce332a51SJens Wiklander }
1162