xref: /optee_os/core/kernel/tee_ta_manager.c (revision 5acb1bc6e8ece254ffe7dbdc41605ad5613b6ab7)
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
767