c0c4545a761bbbb2b18b45985147c5b92c39457c
[platform/core/security/tef-optee_os.git] / core / kernel / tee_ta_manager.c
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <types_ext.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <arm.h>
34 #include <assert.h>
35 #include <kernel/mutex.h>
36 #include <kernel/panic.h>
37 #include <kernel/pseudo_ta.h>
38 #include <kernel/tee_common.h>
39 #include <kernel/tee_misc.h>
40 #include <kernel/tee_ta_manager.h>
41 #include <kernel/tee_time.h>
42 #include <kernel/thread.h>
43 #include <kernel/user_ta.h>
44 #include <mm/core_mmu.h>
45 #include <mm/core_memprot.h>
46 #include <mm/tee_mmu.h>
47 #include <tee/tee_svc_cryp.h>
48 #include <tee/tee_obj.h>
49 #include <tee/tee_svc_storage.h>
50 #include <tee_api_types.h>
51 #include <trace.h>
52 #include <utee_types.h>
53 #include <util.h>
54
55 /* This mutex protects the critical section in tee_ta_init_session */
56 struct mutex tee_ta_mutex = MUTEX_INITIALIZER;
57 static struct condvar tee_ta_cv = CONDVAR_INITIALIZER;
58 static int tee_ta_single_instance_thread = THREAD_ID_INVALID;
59 static size_t tee_ta_single_instance_count;
60 struct tee_ta_ctx_head tee_ctxes = TAILQ_HEAD_INITIALIZER(tee_ctxes);
61
62 static void lock_single_instance(void)
63 {
64         /* Requires tee_ta_mutex to be held */
65         if (tee_ta_single_instance_thread != thread_get_id()) {
66                 /* Wait until the single-instance lock is available. */
67                 while (tee_ta_single_instance_thread != THREAD_ID_INVALID)
68                         condvar_wait(&tee_ta_cv, &tee_ta_mutex);
69
70                 tee_ta_single_instance_thread = thread_get_id();
71                 assert(tee_ta_single_instance_count == 0);
72         }
73
74         tee_ta_single_instance_count++;
75 }
76
77 static void unlock_single_instance(void)
78 {
79         /* Requires tee_ta_mutex to be held */
80         assert(tee_ta_single_instance_thread == thread_get_id());
81         assert(tee_ta_single_instance_count > 0);
82
83         tee_ta_single_instance_count--;
84         if (tee_ta_single_instance_count == 0) {
85                 tee_ta_single_instance_thread = THREAD_ID_INVALID;
86                 condvar_signal(&tee_ta_cv);
87         }
88 }
89
90 static bool has_single_instance_lock(void)
91 {
92         /* Requires tee_ta_mutex to be held */
93         return tee_ta_single_instance_thread == thread_get_id();
94 }
95
96 static bool tee_ta_try_set_busy(struct tee_ta_ctx *ctx)
97 {
98         bool rc = true;
99
100         mutex_lock(&tee_ta_mutex);
101
102         if (ctx->flags & TA_FLAG_SINGLE_INSTANCE)
103                 lock_single_instance();
104
105         if (has_single_instance_lock()) {
106                 if (ctx->busy) {
107                         /*
108                          * We're holding the single-instance lock and the
109                          * TA is busy, as waiting now would only cause a
110                          * dead-lock, we release the lock and return false.
111                          */
112                         rc = false;
113                         if (ctx->flags & TA_FLAG_SINGLE_INSTANCE)
114                                 unlock_single_instance();
115                 }
116         } else {
117                 /*
118                  * We're not holding the single-instance lock, we're free to
119                  * wait for the TA to become available.
120                  */
121                 while (ctx->busy)
122                         condvar_wait(&ctx->busy_cv, &tee_ta_mutex);
123         }
124
125         /* Either it's already true or we should set it to true */
126         ctx->busy = true;
127
128         mutex_unlock(&tee_ta_mutex);
129         return rc;
130 }
131
132 static void tee_ta_set_busy(struct tee_ta_ctx *ctx)
133 {
134         if (!tee_ta_try_set_busy(ctx))
135                 panic();
136 }
137
138 static void tee_ta_clear_busy(struct tee_ta_ctx *ctx)
139 {
140         mutex_lock(&tee_ta_mutex);
141
142         assert(ctx->busy);
143         ctx->busy = false;
144         condvar_signal(&ctx->busy_cv);
145
146         if (ctx->flags & TA_FLAG_SINGLE_INSTANCE)
147                 unlock_single_instance();
148
149         mutex_unlock(&tee_ta_mutex);
150 }
151
152 static void dec_session_ref_count(struct tee_ta_session *s)
153 {
154         assert(s->ref_count > 0);
155         s->ref_count--;
156         if (s->ref_count == 1)
157                 condvar_signal(&s->refc_cv);
158 }
159
160 void tee_ta_put_session(struct tee_ta_session *s)
161 {
162         mutex_lock(&tee_ta_mutex);
163
164         if (s->lock_thread == thread_get_id()) {
165                 s->lock_thread = THREAD_ID_INVALID;
166                 condvar_signal(&s->lock_cv);
167         }
168         dec_session_ref_count(s);
169
170         mutex_unlock(&tee_ta_mutex);
171 }
172
173 static struct tee_ta_session *find_session(uint32_t id,
174                         struct tee_ta_session_head *open_sessions)
175 {
176         struct tee_ta_session *s;
177
178         TAILQ_FOREACH(s, open_sessions, link) {
179                 if ((vaddr_t)s == id)
180                         return s;
181         }
182         return NULL;
183 }
184
185 struct tee_ta_session *tee_ta_get_session(uint32_t id, bool exclusive,
186                         struct tee_ta_session_head *open_sessions)
187 {
188         struct tee_ta_session *s;
189
190         mutex_lock(&tee_ta_mutex);
191
192         while (true) {
193                 s = find_session(id, open_sessions);
194                 if (!s)
195                         break;
196                 if (s->unlink) {
197                         s = NULL;
198                         break;
199                 }
200                 s->ref_count++;
201                 if (!exclusive)
202                         break;
203
204                 assert(s->lock_thread != thread_get_id());
205
206                 while (s->lock_thread != THREAD_ID_INVALID && !s->unlink)
207                         condvar_wait(&s->lock_cv, &tee_ta_mutex);
208
209                 if (s->unlink) {
210                         dec_session_ref_count(s);
211                         s = NULL;
212                         break;
213                 }
214
215                 s->lock_thread = thread_get_id();
216                 break;
217         }
218
219         mutex_unlock(&tee_ta_mutex);
220         return s;
221 }
222
223 static void tee_ta_unlink_session(struct tee_ta_session *s,
224                         struct tee_ta_session_head *open_sessions)
225 {
226         mutex_lock(&tee_ta_mutex);
227
228         assert(s->ref_count >= 1);
229         assert(s->lock_thread == thread_get_id());
230         assert(!s->unlink);
231
232         s->unlink = true;
233         condvar_broadcast(&s->lock_cv);
234
235         while (s->ref_count != 1)
236                 condvar_wait(&s->refc_cv, &tee_ta_mutex);
237
238         TAILQ_REMOVE(open_sessions, s, link);
239
240         mutex_unlock(&tee_ta_mutex);
241 }
242
243 /*
244  * tee_ta_context_find - Find TA in session list based on a UUID (input)
245  * Returns a pointer to the session
246  */
247 static struct tee_ta_ctx *tee_ta_context_find(const TEE_UUID *uuid)
248 {
249         struct tee_ta_ctx *ctx;
250
251         TAILQ_FOREACH(ctx, &tee_ctxes, link) {
252                 if (memcmp(&ctx->uuid, uuid, sizeof(TEE_UUID)) == 0)
253                         return ctx;
254         }
255
256         return NULL;
257 }
258
259 /* check if requester (client ID) matches session initial client */
260 static TEE_Result check_client(struct tee_ta_session *s, const TEE_Identity *id)
261 {
262         if (id == KERN_IDENTITY)
263                 return TEE_SUCCESS;
264
265         if (id == NSAPP_IDENTITY) {
266                 if (s->clnt_id.login == TEE_LOGIN_TRUSTED_APP) {
267                         DMSG("nsec tries to hijack TA session");
268                         return TEE_ERROR_ACCESS_DENIED;
269                 }
270                 return TEE_SUCCESS;
271         }
272
273         if (memcmp(&s->clnt_id, id, sizeof(TEE_Identity)) != 0) {
274                 DMSG("client id mismatch");
275                 return TEE_ERROR_ACCESS_DENIED;
276         }
277         return TEE_SUCCESS;
278 }
279
280 static void set_invoke_timeout(struct tee_ta_session *sess,
281                                       uint32_t cancel_req_to)
282 {
283         TEE_Time current_time;
284         TEE_Time cancel_time = { UINT32_MAX, UINT32_MAX };
285
286         if (cancel_req_to == TEE_TIMEOUT_INFINITE)
287                 goto out;
288
289         if (tee_time_get_sys_time(&current_time) != TEE_SUCCESS)
290                 goto out;
291
292         /* Check that it doesn't wrap */
293         if (current_time.seconds + (cancel_req_to / 1000) >=
294             current_time.seconds) {
295                 cancel_time.seconds =
296                     current_time.seconds + cancel_req_to / 1000;
297                 cancel_time.millis = current_time.millis + cancel_req_to % 1000;
298                 if (cancel_time.millis > 1000) {
299                         cancel_time.seconds++;
300                         cancel_time.millis -= 1000;
301                 }
302         }
303
304 out:
305         sess->cancel_time = cancel_time;
306 }
307
308 /*-----------------------------------------------------------------------------
309  * Close a Trusted Application and free available resources
310  *---------------------------------------------------------------------------*/
311 TEE_Result tee_ta_close_session(struct tee_ta_session *csess,
312                                 struct tee_ta_session_head *open_sessions,
313                                 const TEE_Identity *clnt_id)
314 {
315         struct tee_ta_session *sess;
316         struct tee_ta_ctx *ctx;
317
318         DMSG("tee_ta_close_session(0x%" PRIxVA ")",  (vaddr_t)csess);
319
320         if (!csess)
321                 return TEE_ERROR_ITEM_NOT_FOUND;
322
323         sess = tee_ta_get_session((vaddr_t)csess, true, open_sessions);
324
325         if (!sess) {
326                 EMSG("session 0x%" PRIxVA " to be removed is not found",
327                      (vaddr_t)csess);
328                 return TEE_ERROR_ITEM_NOT_FOUND;
329         }
330
331         if (check_client(sess, clnt_id) != TEE_SUCCESS) {
332                 tee_ta_put_session(sess);
333                 return TEE_ERROR_BAD_PARAMETERS; /* intentional generic error */
334         }
335
336         ctx = sess->ctx;
337         DMSG("   ... Destroy session");
338
339         tee_ta_set_busy(ctx);
340
341         if (!ctx->panicked) {
342                 set_invoke_timeout(sess, TEE_TIMEOUT_INFINITE);
343                 ctx->ops->enter_close_session(sess);
344         }
345
346         tee_ta_unlink_session(sess, open_sessions);
347 #if defined(CFG_TA_GPROF_SUPPORT)
348         free(sess->sbuf);
349 #endif
350         free(sess);
351
352         tee_ta_clear_busy(ctx);
353
354         mutex_lock(&tee_ta_mutex);
355
356         if (ctx->ref_count <= 0)
357                 panic();
358
359         ctx->ref_count--;
360         if (!ctx->ref_count && !(ctx->flags & TA_FLAG_INSTANCE_KEEP_ALIVE)) {
361                 DMSG("   ... Destroy TA ctx");
362
363                 TAILQ_REMOVE(&tee_ctxes, ctx, link);
364                 mutex_unlock(&tee_ta_mutex);
365
366                 condvar_destroy(&ctx->busy_cv);
367
368                 pgt_flush_ctx(ctx);
369                 ctx->ops->destroy(ctx);
370         } else
371                 mutex_unlock(&tee_ta_mutex);
372
373         return TEE_SUCCESS;
374 }
375
376 static TEE_Result tee_ta_init_session_with_context(struct tee_ta_ctx *ctx,
377                         struct tee_ta_session *s)
378 {
379         /*
380          * If TA isn't single instance it should be loaded as new
381          * instance instead of doing anything with this instance.
382          * So tell the caller that we didn't find the TA it the
383          * caller will load a new instance.
384          */
385         if ((ctx->flags & TA_FLAG_SINGLE_INSTANCE) == 0)
386                 return TEE_ERROR_ITEM_NOT_FOUND;
387
388         /*
389          * The TA is single instance, if it isn't multi session we
390          * can't create another session unless it's the first
391          * new session towards a keepAlive TA.
392          */
393
394         if (((ctx->flags & TA_FLAG_MULTI_SESSION) == 0) &&
395             !(((ctx->flags & TA_FLAG_INSTANCE_KEEP_ALIVE) != 0) &&
396               (ctx->ref_count == 0)))
397                 return TEE_ERROR_BUSY;
398
399         DMSG("   ... Re-open TA %pUl", (void *)&ctx->uuid);
400
401         ctx->ref_count++;
402         s->ctx = ctx;
403         return TEE_SUCCESS;
404 }
405
406
407 static TEE_Result tee_ta_init_session(TEE_ErrorOrigin *err,
408                                 struct tee_ta_session_head *open_sessions,
409                                 const TEE_UUID *uuid,
410                                 struct tee_ta_session **sess)
411 {
412         TEE_Result res;
413         struct tee_ta_ctx *ctx;
414         struct tee_ta_session *s = calloc(1, sizeof(struct tee_ta_session));
415
416         *err = TEE_ORIGIN_TEE;
417         if (!s)
418                 return TEE_ERROR_OUT_OF_MEMORY;
419
420         s->cancel_mask = true;
421         condvar_init(&s->refc_cv);
422         condvar_init(&s->lock_cv);
423         s->lock_thread = THREAD_ID_INVALID;
424         s->ref_count = 1;
425
426
427         /*
428          * We take the global TA mutex here and hold it while doing
429          * RPC to load the TA. This big critical section should be broken
430          * down into smaller pieces.
431          */
432
433
434         mutex_lock(&tee_ta_mutex);
435         TAILQ_INSERT_TAIL(open_sessions, s, link);
436
437         /* Look for already loaded TA */
438         ctx = tee_ta_context_find(uuid);
439         if (ctx) {
440                 res = tee_ta_init_session_with_context(ctx, s);
441                 if (res == TEE_SUCCESS || res != TEE_ERROR_ITEM_NOT_FOUND)
442                         goto out;
443         }
444
445         /* Look for static TA */
446         res = tee_ta_init_pseudo_ta_session(uuid, s);
447         if (res == TEE_SUCCESS || res != TEE_ERROR_ITEM_NOT_FOUND)
448                 goto out;
449
450         /* Look for user TA */
451         res = tee_ta_init_user_ta_session(uuid, s);
452
453 out:
454         if (res == TEE_SUCCESS) {
455                 *sess = s;
456         } else {
457                 TAILQ_REMOVE(open_sessions, s, link);
458                 free(s);
459         }
460         mutex_unlock(&tee_ta_mutex);
461         return res;
462 }
463
464 TEE_Result tee_ta_open_session(TEE_ErrorOrigin *err,
465                                struct tee_ta_session **sess,
466                                struct tee_ta_session_head *open_sessions,
467                                const TEE_UUID *uuid,
468                                const TEE_Identity *clnt_id,
469                                uint32_t cancel_req_to,
470                                struct tee_ta_param *param)
471 {
472         TEE_Result res;
473         struct tee_ta_session *s = NULL;
474         struct tee_ta_ctx *ctx;
475         bool panicked;
476         bool was_busy = false;
477
478         res = tee_ta_init_session(err, open_sessions, uuid, &s);
479         if (res != TEE_SUCCESS) {
480                 DMSG("init session failed 0x%x", res);
481                 return res;
482         }
483
484         ctx = s->ctx;
485
486         if (ctx->panicked) {
487                 DMSG("panicked, call tee_ta_close_session()");
488                 tee_ta_close_session(s, open_sessions, KERN_IDENTITY);
489                 *err = TEE_ORIGIN_TEE;
490                 return TEE_ERROR_TARGET_DEAD;
491         }
492
493         *sess = s;
494         /* Save identity of the owner of the session */
495         s->clnt_id = *clnt_id;
496
497         if (tee_ta_try_set_busy(ctx)) {
498                 set_invoke_timeout(s, cancel_req_to);
499                 res = ctx->ops->enter_open_session(s, param, err);
500                 tee_ta_clear_busy(ctx);
501         } else {
502                 /* Deadlock avoided */
503                 res = TEE_ERROR_BUSY;
504                 was_busy = true;
505         }
506
507         panicked = ctx->panicked;
508
509         tee_ta_put_session(s);
510         if (panicked || (res != TEE_SUCCESS))
511                 tee_ta_close_session(s, open_sessions, KERN_IDENTITY);
512
513         /*
514          * Origin error equal to TEE_ORIGIN_TRUSTED_APP for "regular" error,
515          * apart from panicking.
516          */
517         if (panicked || was_busy)
518                 *err = TEE_ORIGIN_TEE;
519         else
520                 *err = TEE_ORIGIN_TRUSTED_APP;
521
522         if (res != TEE_SUCCESS)
523                 EMSG("Failed. Return error 0x%x", res);
524
525         return res;
526 }
527
528 TEE_Result tee_ta_invoke_command(TEE_ErrorOrigin *err,
529                                  struct tee_ta_session *sess,
530                                  const TEE_Identity *clnt_id,
531                                  uint32_t cancel_req_to, uint32_t cmd,
532                                  struct tee_ta_param *param)
533 {
534         TEE_Result res;
535
536         if (check_client(sess, clnt_id) != TEE_SUCCESS)
537                 return TEE_ERROR_BAD_PARAMETERS; /* intentional generic error */
538
539         if (sess->ctx->panicked) {
540                 DMSG("   Panicked !");
541                 *err = TEE_ORIGIN_TEE;
542                 return TEE_ERROR_TARGET_DEAD;
543         }
544
545         tee_ta_set_busy(sess->ctx);
546
547         set_invoke_timeout(sess, cancel_req_to);
548         res = sess->ctx->ops->enter_invoke_cmd(sess, cmd, param, err);
549
550         if (sess->ctx->panicked) {
551                 *err = TEE_ORIGIN_TEE;
552                 res = TEE_ERROR_TARGET_DEAD;
553         }
554
555         tee_ta_clear_busy(sess->ctx);
556         if (res != TEE_SUCCESS)
557                 DMSG("  => Error: %x of %d\n", res, *err);
558         return res;
559 }
560
561 TEE_Result tee_ta_cancel_command(TEE_ErrorOrigin *err,
562                                  struct tee_ta_session *sess,
563                                  const TEE_Identity *clnt_id)
564 {
565         *err = TEE_ORIGIN_TEE;
566
567         if (check_client(sess, clnt_id) != TEE_SUCCESS)
568                 return TEE_ERROR_BAD_PARAMETERS; /* intentional generic error */
569
570         sess->cancel = true;
571         return TEE_SUCCESS;
572 }
573
574 bool tee_ta_session_is_cancelled(struct tee_ta_session *s, TEE_Time *curr_time)
575 {
576         TEE_Time current_time;
577
578         if (s->cancel_mask)
579                 return false;
580
581         if (s->cancel)
582                 return true;
583
584         if (s->cancel_time.seconds == UINT32_MAX)
585                 return false;
586
587         if (curr_time != NULL)
588                 current_time = *curr_time;
589         else if (tee_time_get_sys_time(&current_time) != TEE_SUCCESS)
590                 return false;
591
592         if (current_time.seconds > s->cancel_time.seconds ||
593             (current_time.seconds == s->cancel_time.seconds &&
594              current_time.millis >= s->cancel_time.millis)) {
595                 return true;
596         }
597
598         return false;
599 }
600
601 static void update_current_ctx(struct thread_specific_data *tsd)
602 {
603         struct tee_ta_ctx *ctx = NULL;
604         struct tee_ta_session *s = TAILQ_FIRST(&tsd->sess_stack);
605
606         if (s) {
607                 if (is_pseudo_ta_ctx(s->ctx))
608                         s = TAILQ_NEXT(s, link_tsd);
609
610                 if (s)
611                         ctx = s->ctx;
612         }
613
614         if (tsd->ctx != ctx)
615                 tee_mmu_set_ctx(ctx);
616         /*
617          * If ctx->mmu == NULL we must not have user mapping active,
618          * if ctx->mmu != NULL we must have user mapping active.
619          */
620         if (((ctx && is_user_ta_ctx(ctx) ?
621                         to_user_ta_ctx(ctx)->mmu : NULL) == NULL) ==
622                                         core_mmu_user_mapping_is_active())
623                 panic("unexpected active mapping");
624 }
625
626 void tee_ta_push_current_session(struct tee_ta_session *sess)
627 {
628         struct thread_specific_data *tsd = thread_get_tsd();
629
630         TAILQ_INSERT_HEAD(&tsd->sess_stack, sess, link_tsd);
631         update_current_ctx(tsd);
632 }
633
634 struct tee_ta_session *tee_ta_pop_current_session(void)
635 {
636         struct thread_specific_data *tsd = thread_get_tsd();
637         struct tee_ta_session *s = TAILQ_FIRST(&tsd->sess_stack);
638
639         if (s) {
640                 TAILQ_REMOVE(&tsd->sess_stack, s, link_tsd);
641                 update_current_ctx(tsd);
642         }
643         return s;
644 }
645
646 TEE_Result tee_ta_get_current_session(struct tee_ta_session **sess)
647 {
648         struct tee_ta_session *s = TAILQ_FIRST(&thread_get_tsd()->sess_stack);
649
650         if (!s)
651                 return TEE_ERROR_BAD_STATE;
652         *sess = s;
653         return TEE_SUCCESS;
654 }
655
656 struct tee_ta_session *tee_ta_get_calling_session(void)
657 {
658         struct tee_ta_session *s = TAILQ_FIRST(&thread_get_tsd()->sess_stack);
659
660         if (s)
661                 s = TAILQ_NEXT(s, link_tsd);
662         return s;
663 }
664
665 TEE_Result tee_ta_get_client_id(TEE_Identity *id)
666 {
667         TEE_Result res;
668         struct tee_ta_session *sess;
669
670         res = tee_ta_get_current_session(&sess);
671         if (res != TEE_SUCCESS)
672                 return res;
673
674         if (id == NULL)
675                 return TEE_ERROR_BAD_PARAMETERS;
676
677         *id = sess->clnt_id;
678         return TEE_SUCCESS;
679 }
680
681 /*
682  * dump_state - Display TA state as an error log.
683  */
684 static void dump_state(struct tee_ta_ctx *ctx)
685 {
686         struct tee_ta_session *s = NULL;
687         bool active __maybe_unused;
688
689         active = ((tee_ta_get_current_session(&s) == TEE_SUCCESS) &&
690                   s && s->ctx == ctx);
691
692         EMSG_RAW("Status of TA %pUl (%p) %s", (void *)&ctx->uuid, (void *)ctx,
693                 active ? "(active)" : "");
694         ctx->ops->dump_state(ctx);
695 }
696
697 void tee_ta_dump_current(void)
698 {
699         struct tee_ta_session *s = NULL;
700
701         if (tee_ta_get_current_session(&s) != TEE_SUCCESS) {
702                 EMSG("no valid session found, cannot log TA status");
703                 return;
704         }
705
706         dump_state(s->ctx);
707 }
708
709 #if defined(CFG_TA_GPROF_SUPPORT)
710 void tee_ta_gprof_sample_pc(vaddr_t pc)
711 {
712         struct tee_ta_session *s;
713         struct sample_buf *sbuf;
714         size_t idx;
715
716         if (tee_ta_get_current_session(&s) != TEE_SUCCESS)
717                 return;
718         sbuf = s->sbuf;
719         if (!sbuf || !sbuf->enabled)
720                 return; /* PC sampling is not enabled */
721
722         idx = (((uint64_t)pc - sbuf->offset)/2 * sbuf->scale)/65536;
723         if (idx < sbuf->nsamples)
724                 sbuf->samples[idx]++;
725         sbuf->count++;
726 }
727
728 /*
729  * Update user-mode CPU time for the current session
730  * @suspend: true if session is being suspended (leaving user mode), false if
731  * it is resumed (entering user mode)
732  */
733 static void tee_ta_update_session_utime(bool suspend)
734 {
735         struct tee_ta_session *s;
736         struct sample_buf *sbuf;
737         uint64_t now;
738
739         if (tee_ta_get_current_session(&s) != TEE_SUCCESS)
740                 return;
741         sbuf = s->sbuf;
742         if (!sbuf)
743                 return;
744         now = read_cntpct();
745         if (suspend) {
746                 assert(sbuf->usr_entered);
747                 sbuf->usr += now - sbuf->usr_entered;
748                 sbuf->usr_entered = 0;
749         } else {
750                 assert(!sbuf->usr_entered);
751                 if (!now)
752                         now++; /* 0 is reserved */
753                 sbuf->usr_entered = now;
754         }
755 }
756
757 void tee_ta_update_session_utime_suspend(void)
758 {
759         tee_ta_update_session_utime(true);
760 }
761
762 void tee_ta_update_session_utime_resume(void)
763 {
764         tee_ta_update_session_utime(false);
765 }
766 #endif