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(¤t_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(¤t_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