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 = ¶m->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(¤t_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(¶m, 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, ¶m);
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(¤t_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