1*5843bb75SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 2*5843bb75SJerome Forissier /* 3*5843bb75SJerome Forissier * Copyright (c) 2016, Linaro Limited 4*5843bb75SJerome Forissier */ 5*5843bb75SJerome Forissier 6*5843bb75SJerome Forissier #include <kernel/misc.h> 7*5843bb75SJerome Forissier #include <kernel/msg_param.h> 8*5843bb75SJerome Forissier #include <kernel/pseudo_ta.h> 9*5843bb75SJerome Forissier #include <kernel/user_ta.h> 10*5843bb75SJerome Forissier #include <kernel/thread.h> 11*5843bb75SJerome Forissier #include <mm/core_memprot.h> 12*5843bb75SJerome Forissier #include <mm/mobj.h> 13*5843bb75SJerome Forissier #include <mm/tee_mmu.h> 14*5843bb75SJerome Forissier #include <optee_rpc_cmd.h> 15*5843bb75SJerome Forissier #include <pta_gprof.h> 16*5843bb75SJerome Forissier #include <string.h> 17*5843bb75SJerome Forissier 18*5843bb75SJerome Forissier static TEE_Result gprof_send_rpc(TEE_UUID *uuid, void *buf, size_t len, 19*5843bb75SJerome Forissier uint32_t *id) 20*5843bb75SJerome Forissier { 21*5843bb75SJerome Forissier struct mobj *mobj; 22*5843bb75SJerome Forissier TEE_Result res = TEE_ERROR_GENERIC; 23*5843bb75SJerome Forissier char *va; 24*5843bb75SJerome Forissier 25*5843bb75SJerome Forissier mobj = thread_rpc_alloc_payload(sizeof(*uuid) + len); 26*5843bb75SJerome Forissier if (!mobj) 27*5843bb75SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 28*5843bb75SJerome Forissier 29*5843bb75SJerome Forissier va = mobj_get_va(mobj, 0); 30*5843bb75SJerome Forissier if (!va) 31*5843bb75SJerome Forissier goto exit; 32*5843bb75SJerome Forissier 33*5843bb75SJerome Forissier memcpy(va, uuid, sizeof(*uuid)); 34*5843bb75SJerome Forissier memcpy(va + sizeof(*uuid), buf, len); 35*5843bb75SJerome Forissier 36*5843bb75SJerome Forissier struct thread_param params[3] = { 37*5843bb75SJerome Forissier [0] = THREAD_PARAM_VALUE(INOUT, *id, 0, 0), 38*5843bb75SJerome Forissier [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, sizeof(*uuid)), 39*5843bb75SJerome Forissier [2] = THREAD_PARAM_MEMREF(IN, mobj, sizeof(*uuid), len), 40*5843bb75SJerome Forissier }; 41*5843bb75SJerome Forissier 42*5843bb75SJerome Forissier res = thread_rpc_cmd(OPTEE_RPC_CMD_GPROF, 3, params); 43*5843bb75SJerome Forissier if (res != TEE_SUCCESS) 44*5843bb75SJerome Forissier goto exit; 45*5843bb75SJerome Forissier 46*5843bb75SJerome Forissier *id = (uint32_t)params[0].u.value.a; 47*5843bb75SJerome Forissier exit: 48*5843bb75SJerome Forissier thread_rpc_free_payload(mobj); 49*5843bb75SJerome Forissier return res; 50*5843bb75SJerome Forissier } 51*5843bb75SJerome Forissier 52*5843bb75SJerome Forissier static TEE_Result gprof_send(struct tee_ta_session *s, 53*5843bb75SJerome Forissier uint32_t param_types, 54*5843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 55*5843bb75SJerome Forissier { 56*5843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT, 57*5843bb75SJerome Forissier TEE_PARAM_TYPE_MEMREF_INPUT, 58*5843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 59*5843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 60*5843bb75SJerome Forissier 61*5843bb75SJerome Forissier if (exp_pt != param_types) 62*5843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 63*5843bb75SJerome Forissier 64*5843bb75SJerome Forissier return gprof_send_rpc(&s->ctx->uuid, params[1].memref.buffer, 65*5843bb75SJerome Forissier params[1].memref.size, ¶ms[0].value.a); 66*5843bb75SJerome Forissier } 67*5843bb75SJerome Forissier 68*5843bb75SJerome Forissier static TEE_Result gprof_start_pc_sampling(struct tee_ta_session *s, 69*5843bb75SJerome Forissier uint32_t param_types, 70*5843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 71*5843bb75SJerome Forissier { 72*5843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 73*5843bb75SJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT, 74*5843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 75*5843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 76*5843bb75SJerome Forissier struct sample_buf *sbuf; 77*5843bb75SJerome Forissier uint32_t offset; 78*5843bb75SJerome Forissier uint32_t scale; 79*5843bb75SJerome Forissier uint32_t len; 80*5843bb75SJerome Forissier uaddr_t buf; 81*5843bb75SJerome Forissier 82*5843bb75SJerome Forissier if (exp_pt != param_types) 83*5843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 84*5843bb75SJerome Forissier 85*5843bb75SJerome Forissier buf = (uaddr_t)params[0].memref.buffer; 86*5843bb75SJerome Forissier len = params[0].memref.size; 87*5843bb75SJerome Forissier offset = params[1].value.a; 88*5843bb75SJerome Forissier scale = params[1].value.b; 89*5843bb75SJerome Forissier 90*5843bb75SJerome Forissier sbuf = calloc(1, sizeof(*sbuf)); 91*5843bb75SJerome Forissier if (!sbuf) 92*5843bb75SJerome Forissier return TEE_ERROR_OUT_OF_MEMORY; 93*5843bb75SJerome Forissier 94*5843bb75SJerome Forissier sbuf->samples = (uint16_t *)buf; 95*5843bb75SJerome Forissier sbuf->nsamples = len / sizeof(*sbuf->samples); 96*5843bb75SJerome Forissier sbuf->offset = offset; 97*5843bb75SJerome Forissier sbuf->scale = scale; 98*5843bb75SJerome Forissier sbuf->freq = read_cntfrq(); 99*5843bb75SJerome Forissier sbuf->enabled = true; 100*5843bb75SJerome Forissier s->sbuf = sbuf; 101*5843bb75SJerome Forissier 102*5843bb75SJerome Forissier return TEE_SUCCESS; 103*5843bb75SJerome Forissier } 104*5843bb75SJerome Forissier 105*5843bb75SJerome Forissier static TEE_Result gprof_stop_pc_sampling(struct tee_ta_session *s, 106*5843bb75SJerome Forissier uint32_t param_types, 107*5843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 108*5843bb75SJerome Forissier { 109*5843bb75SJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT, 110*5843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 111*5843bb75SJerome Forissier TEE_PARAM_TYPE_NONE, 112*5843bb75SJerome Forissier TEE_PARAM_TYPE_NONE); 113*5843bb75SJerome Forissier struct sample_buf *sbuf; 114*5843bb75SJerome Forissier uint32_t rate; 115*5843bb75SJerome Forissier 116*5843bb75SJerome Forissier if (exp_pt != param_types) 117*5843bb75SJerome Forissier return TEE_ERROR_BAD_PARAMETERS; 118*5843bb75SJerome Forissier 119*5843bb75SJerome Forissier sbuf = s->sbuf; 120*5843bb75SJerome Forissier if (!sbuf) 121*5843bb75SJerome Forissier return TEE_ERROR_BAD_STATE; 122*5843bb75SJerome Forissier assert(sbuf->samples); 123*5843bb75SJerome Forissier 124*5843bb75SJerome Forissier /* Stop sampling */ 125*5843bb75SJerome Forissier if (sbuf->enabled) 126*5843bb75SJerome Forissier sbuf->enabled = false; 127*5843bb75SJerome Forissier 128*5843bb75SJerome Forissier rate = ((uint64_t)sbuf->count * sbuf->freq) / sbuf->usr; 129*5843bb75SJerome Forissier params[0].value.a = rate; 130*5843bb75SJerome Forissier 131*5843bb75SJerome Forissier DMSG("TA sampling stats: sample count=%" PRIu32 " user time=%" PRIu64 132*5843bb75SJerome Forissier " cntfrq=%" PRIu32 " rate=%" PRIu32, sbuf->count, sbuf->usr, 133*5843bb75SJerome Forissier sbuf->freq, rate); 134*5843bb75SJerome Forissier 135*5843bb75SJerome Forissier free(sbuf); 136*5843bb75SJerome Forissier s->sbuf = NULL; 137*5843bb75SJerome Forissier 138*5843bb75SJerome Forissier return TEE_SUCCESS; 139*5843bb75SJerome Forissier } 140*5843bb75SJerome Forissier 141*5843bb75SJerome Forissier /* 142*5843bb75SJerome Forissier * Trusted Application Entry Points 143*5843bb75SJerome Forissier */ 144*5843bb75SJerome Forissier 145*5843bb75SJerome Forissier static TEE_Result open_session(uint32_t param_types __unused, 146*5843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS] __unused, 147*5843bb75SJerome Forissier void **sess_ctx __unused) 148*5843bb75SJerome Forissier { 149*5843bb75SJerome Forissier struct tee_ta_session *s; 150*5843bb75SJerome Forissier 151*5843bb75SJerome Forissier /* Check that we're called from a user TA */ 152*5843bb75SJerome Forissier s = tee_ta_get_calling_session(); 153*5843bb75SJerome Forissier if (!s) 154*5843bb75SJerome Forissier return TEE_ERROR_ACCESS_DENIED; 155*5843bb75SJerome Forissier if (!is_user_ta_ctx(s->ctx)) 156*5843bb75SJerome Forissier return TEE_ERROR_ACCESS_DENIED; 157*5843bb75SJerome Forissier 158*5843bb75SJerome Forissier return TEE_SUCCESS; 159*5843bb75SJerome Forissier } 160*5843bb75SJerome Forissier 161*5843bb75SJerome Forissier static TEE_Result invoke_command(void *sess_ctx __unused, uint32_t cmd_id, 162*5843bb75SJerome Forissier uint32_t param_types, 163*5843bb75SJerome Forissier TEE_Param params[TEE_NUM_PARAMS]) 164*5843bb75SJerome Forissier { 165*5843bb75SJerome Forissier struct tee_ta_session *s = tee_ta_get_calling_session(); 166*5843bb75SJerome Forissier 167*5843bb75SJerome Forissier switch (cmd_id) { 168*5843bb75SJerome Forissier case PTA_GPROF_SEND: 169*5843bb75SJerome Forissier return gprof_send(s, param_types, params); 170*5843bb75SJerome Forissier case PTA_GPROF_START_PC_SAMPLING: 171*5843bb75SJerome Forissier return gprof_start_pc_sampling(s, param_types, params); 172*5843bb75SJerome Forissier case PTA_GPROF_STOP_PC_SAMPLING: 173*5843bb75SJerome Forissier return gprof_stop_pc_sampling(s, param_types, params); 174*5843bb75SJerome Forissier default: 175*5843bb75SJerome Forissier break; 176*5843bb75SJerome Forissier } 177*5843bb75SJerome Forissier return TEE_ERROR_NOT_IMPLEMENTED; 178*5843bb75SJerome Forissier } 179*5843bb75SJerome Forissier 180*5843bb75SJerome Forissier pseudo_ta_register(.uuid = PTA_GPROF_UUID, .name = "gprof", 181*5843bb75SJerome Forissier .flags = PTA_DEFAULT_FLAGS, 182*5843bb75SJerome Forissier .open_session_entry_point = open_session, 183*5843bb75SJerome Forissier .invoke_command_entry_point = invoke_command); 184