15843bb75SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 25843bb75SJerome Forissier /* 35843bb75SJerome Forissier * Copyright (c) 2016, Linaro Limited 45843bb75SJerome Forissier */ 55843bb75SJerome Forissier 65843bb75SJerome Forissier #include <kernel/misc.h> 75843bb75SJerome Forissier #include <kernel/msg_param.h> 85843bb75SJerome Forissier #include <kernel/pseudo_ta.h> 95843bb75SJerome Forissier #include <kernel/user_ta.h> 105843bb75SJerome Forissier #include <kernel/thread.h> 115843bb75SJerome Forissier #include <mm/core_memprot.h> 125843bb75SJerome Forissier #include <mm/mobj.h> 135843bb75SJerome Forissier #include <mm/tee_mmu.h> 145843bb75SJerome Forissier #include <optee_rpc_cmd.h> 155843bb75SJerome Forissier #include <pta_gprof.h> 165843bb75SJerome Forissier #include <string.h> 175843bb75SJerome Forissier 185843bb75SJerome Forissier static TEE_Result gprof_send_rpc(TEE_UUID *uuid, void *buf, size_t len, 195843bb75SJerome Forissier uint32_t *id) 205843bb75SJerome Forissier { 215843bb75SJerome Forissier struct mobj *mobj; 225843bb75SJerome Forissier TEE_Result res = TEE_ERROR_GENERIC; 235843bb75SJerome Forissier char *va; 245843bb75SJerome Forissier 255843bb75SJerome Forissier mobj = thread_rpc_alloc_payload(sizeof(*uuid) + len); 265843bb75SJerome Forissier if (!mobj) 275843bb75SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 285843bb75SJerome Forissier 295843bb75SJerome Forissier va = mobj_get_va(mobj, 0); 305843bb75SJerome Forissier if (!va) 315843bb75SJerome Forissier goto exit; 325843bb75SJerome Forissier 335843bb75SJerome Forissier memcpy(va, uuid, sizeof(*uuid)); 345843bb75SJerome Forissier memcpy(va + sizeof(*uuid), buf, len); 355843bb75SJerome Forissier 365843bb75SJerome Forissier struct thread_param params[3] = { 375843bb75SJerome Forissier [0] = THREAD_PARAM_VALUE(INOUT, *id, 0, 0), 385843bb75SJerome Forissier [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, sizeof(*uuid)), 395843bb75SJerome Forissier [2] = THREAD_PARAM_MEMREF(IN, mobj, sizeof(*uuid), len), 405843bb75SJerome Forissier }; 415843bb75SJerome Forissier 425843bb75SJerome Forissier res = thread_rpc_cmd(OPTEE_RPC_CMD_GPROF, 3, params); 435843bb75SJerome Forissier if (res != TEE_SUCCESS) 445843bb75SJerome Forissier goto exit; 455843bb75SJerome Forissier 465843bb75SJerome Forissier *id = (uint32_t)params[0].u.value.a; 475843bb75SJerome Forissier exit: 485843bb75SJerome Forissier thread_rpc_free_payload(mobj); 495843bb75SJerome Forissier return res; 505843bb75SJerome Forissier } 515843bb75SJerome Forissier 52*00b3b9a2SJens Wiklander static TEE_Result gprof_send(struct ts_session *s, uint32_t param_types, 535843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 545843bb75SJerome Forissier { 555843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT, 565843bb75SJerome Forissier TEE_PARAM_TYPE_MEMREF_INPUT, 575843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 585843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 595843bb75SJerome Forissier 605843bb75SJerome Forissier if (exp_pt != param_types) 615843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 625843bb75SJerome Forissier 635843bb75SJerome Forissier return gprof_send_rpc(&s->ctx->uuid, params[1].memref.buffer, 645843bb75SJerome Forissier params[1].memref.size, ¶ms[0].value.a); 655843bb75SJerome Forissier } 665843bb75SJerome Forissier 67*00b3b9a2SJens Wiklander static TEE_Result gprof_start_pc_sampling(struct ts_session *s, 685843bb75SJerome Forissier uint32_t param_types, 695843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 705843bb75SJerome Forissier { 715843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 725843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT, 735843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 745843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 75*00b3b9a2SJens Wiklander struct sample_buf *sbuf = NULL; 76*00b3b9a2SJens Wiklander uint32_t offset = 0; 77*00b3b9a2SJens Wiklander uint32_t scale = 0; 78*00b3b9a2SJens Wiklander uint32_t len = 0; 79*00b3b9a2SJens Wiklander uaddr_t buf = 0; 805843bb75SJerome Forissier 815843bb75SJerome Forissier if (exp_pt != param_types) 825843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 835843bb75SJerome Forissier 84c24b4f8fSJens Wiklander if (s->sbuf) { 85c24b4f8fSJens Wiklander DMSG("PC sampling already started"); 86c24b4f8fSJens Wiklander return TEE_ERROR_BAD_STATE; 87c24b4f8fSJens Wiklander } 88c24b4f8fSJens Wiklander 895843bb75SJerome Forissier buf = (uaddr_t)params[0].memref.buffer; 905843bb75SJerome Forissier len = params[0].memref.size; 915843bb75SJerome Forissier offset = params[1].value.a; 925843bb75SJerome Forissier scale = params[1].value.b; 935843bb75SJerome Forissier 945843bb75SJerome Forissier sbuf = calloc(1, sizeof(*sbuf)); 955843bb75SJerome Forissier if (!sbuf) 965843bb75SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 975843bb75SJerome Forissier 985843bb75SJerome Forissier sbuf->samples = (uint16_t *)buf; 995843bb75SJerome Forissier sbuf->nsamples = len / sizeof(*sbuf->samples); 1005843bb75SJerome Forissier sbuf->offset = offset; 1015843bb75SJerome Forissier sbuf->scale = scale; 1025843bb75SJerome Forissier sbuf->freq = read_cntfrq(); 1035843bb75SJerome Forissier sbuf->enabled = true; 1045843bb75SJerome Forissier s->sbuf = sbuf; 1055843bb75SJerome Forissier 1065843bb75SJerome Forissier return TEE_SUCCESS; 1075843bb75SJerome Forissier } 1085843bb75SJerome Forissier 109*00b3b9a2SJens Wiklander static TEE_Result gprof_stop_pc_sampling(struct ts_session *s, 1105843bb75SJerome Forissier uint32_t param_types, 1115843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 1125843bb75SJerome Forissier { 1135843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT, 1145843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 1155843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 1165843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 117*00b3b9a2SJens Wiklander struct sample_buf *sbuf = NULL; 118*00b3b9a2SJens Wiklander uint32_t rate = 0; 1195843bb75SJerome Forissier 1205843bb75SJerome Forissier if (exp_pt != param_types) 1215843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 1225843bb75SJerome Forissier 1235843bb75SJerome Forissier sbuf = s->sbuf; 1245843bb75SJerome Forissier if (!sbuf) 1255843bb75SJerome Forissier return TEE_ERROR_BAD_STATE; 1265843bb75SJerome Forissier assert(sbuf->samples); 1275843bb75SJerome Forissier 1285843bb75SJerome Forissier /* Stop sampling */ 1295843bb75SJerome Forissier if (sbuf->enabled) 1305843bb75SJerome Forissier sbuf->enabled = false; 1315843bb75SJerome Forissier 1325843bb75SJerome Forissier rate = ((uint64_t)sbuf->count * sbuf->freq) / sbuf->usr; 1335843bb75SJerome Forissier params[0].value.a = rate; 1345843bb75SJerome Forissier 1355843bb75SJerome Forissier DMSG("TA sampling stats: sample count=%" PRIu32 " user time=%" PRIu64 1365843bb75SJerome Forissier " cntfrq=%" PRIu32 " rate=%" PRIu32, sbuf->count, sbuf->usr, 1375843bb75SJerome Forissier sbuf->freq, rate); 1385843bb75SJerome Forissier 1395843bb75SJerome Forissier free(sbuf); 1405843bb75SJerome Forissier s->sbuf = NULL; 1415843bb75SJerome Forissier 1425843bb75SJerome Forissier return TEE_SUCCESS; 1435843bb75SJerome Forissier } 1445843bb75SJerome Forissier 1455843bb75SJerome Forissier /* 1465843bb75SJerome Forissier * Trusted Application Entry Points 1475843bb75SJerome Forissier */ 1485843bb75SJerome Forissier 1495843bb75SJerome Forissier static TEE_Result open_session(uint32_t param_types __unused, 1505843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS] __unused, 1515843bb75SJerome Forissier void **sess_ctx __unused) 1525843bb75SJerome Forissier { 153*00b3b9a2SJens Wiklander struct ts_session *s = ts_get_calling_session(); 1545843bb75SJerome Forissier 1555843bb75SJerome Forissier /* Check that we're called from a user TA */ 1565843bb75SJerome Forissier if (!s) 1575843bb75SJerome Forissier return TEE_ERROR_ACCESS_DENIED; 1585843bb75SJerome Forissier if (!is_user_ta_ctx(s->ctx)) 1595843bb75SJerome Forissier return TEE_ERROR_ACCESS_DENIED; 1605843bb75SJerome Forissier 1615843bb75SJerome Forissier return TEE_SUCCESS; 1625843bb75SJerome Forissier } 1635843bb75SJerome Forissier 1645843bb75SJerome Forissier static TEE_Result invoke_command(void *sess_ctx __unused, uint32_t cmd_id, 1655843bb75SJerome Forissier uint32_t param_types, 1665843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 1675843bb75SJerome Forissier { 168*00b3b9a2SJens Wiklander struct ts_session *s = ts_get_calling_session(); 1695843bb75SJerome Forissier 1705843bb75SJerome Forissier switch (cmd_id) { 1715843bb75SJerome Forissier case PTA_GPROF_SEND: 1725843bb75SJerome Forissier return gprof_send(s, param_types, params); 1735843bb75SJerome Forissier case PTA_GPROF_START_PC_SAMPLING: 1745843bb75SJerome Forissier return gprof_start_pc_sampling(s, param_types, params); 1755843bb75SJerome Forissier case PTA_GPROF_STOP_PC_SAMPLING: 1765843bb75SJerome Forissier return gprof_stop_pc_sampling(s, param_types, params); 1775843bb75SJerome Forissier default: 1785843bb75SJerome Forissier break; 1795843bb75SJerome Forissier } 1805843bb75SJerome Forissier return TEE_ERROR_NOT_IMPLEMENTED; 1815843bb75SJerome Forissier } 1825843bb75SJerome Forissier 1835843bb75SJerome Forissier pseudo_ta_register(.uuid = PTA_GPROF_UUID, .name = "gprof", 1845843bb75SJerome Forissier .flags = PTA_DEFAULT_FLAGS, 1855843bb75SJerome Forissier .open_session_entry_point = open_session, 1865843bb75SJerome Forissier .invoke_command_entry_point = invoke_command); 187