xref: /optee_os/core/pta/gprof.c (revision 9c4aaf67f2fb43aef3446f206dece995217ffdeb)
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 <optee_rpc_cmd.h>
145843bb75SJerome Forissier #include <pta_gprof.h>
155843bb75SJerome Forissier #include <string.h>
165843bb75SJerome Forissier 
gprof_send_rpc(TEE_UUID * uuid,void * buf,size_t len,uint32_t * id)175843bb75SJerome Forissier static TEE_Result gprof_send_rpc(TEE_UUID *uuid, void *buf, size_t len,
185843bb75SJerome Forissier 				 uint32_t *id)
195843bb75SJerome Forissier {
20afb1cc80SJens Wiklander 	struct thread_param params[3] = { };
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 
29*9c4aaf67SJens Wiklander 	va = mobj_get_va(mobj, 0, sizeof(*uuid) + len);
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 
36afb1cc80SJens Wiklander 	params[0] = THREAD_PARAM_VALUE(INOUT, *id, 0, 0);
37afb1cc80SJens Wiklander 	params[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, sizeof(*uuid));
38afb1cc80SJens Wiklander 	params[2] = THREAD_PARAM_MEMREF(IN, mobj, sizeof(*uuid), len);
395843bb75SJerome Forissier 
405843bb75SJerome Forissier 	res = thread_rpc_cmd(OPTEE_RPC_CMD_GPROF, 3, params);
415843bb75SJerome Forissier 	if (res != TEE_SUCCESS)
425843bb75SJerome Forissier 		goto exit;
435843bb75SJerome Forissier 
445843bb75SJerome Forissier 	*id = (uint32_t)params[0].u.value.a;
455843bb75SJerome Forissier exit:
465843bb75SJerome Forissier 	thread_rpc_free_payload(mobj);
475843bb75SJerome Forissier 	return res;
485843bb75SJerome Forissier }
495843bb75SJerome Forissier 
gprof_send(struct ts_session * s,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])5000b3b9a2SJens Wiklander static TEE_Result gprof_send(struct ts_session *s, uint32_t param_types,
515843bb75SJerome Forissier 			     TEE_Param params[TEE_NUM_PARAMS])
525843bb75SJerome Forissier {
535843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
545843bb75SJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_INPUT,
555843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
565843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
575843bb75SJerome Forissier 
585843bb75SJerome Forissier 	if (exp_pt != param_types)
595843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
605843bb75SJerome Forissier 
615843bb75SJerome Forissier 	return gprof_send_rpc(&s->ctx->uuid, params[1].memref.buffer,
625843bb75SJerome Forissier 			      params[1].memref.size, &params[0].value.a);
635843bb75SJerome Forissier }
645843bb75SJerome Forissier 
gprof_start_pc_sampling(struct ts_session * s,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])6500b3b9a2SJens Wiklander static TEE_Result gprof_start_pc_sampling(struct ts_session *s,
665843bb75SJerome Forissier 					  uint32_t param_types,
675843bb75SJerome Forissier 					  TEE_Param params[TEE_NUM_PARAMS])
685843bb75SJerome Forissier {
695843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
705843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT,
715843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
725843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
7300b3b9a2SJens Wiklander 	struct sample_buf *sbuf = NULL;
7400b3b9a2SJens Wiklander 	uint32_t offset = 0;
7500b3b9a2SJens Wiklander 	uint32_t scale = 0;
7600b3b9a2SJens Wiklander 	uint32_t len = 0;
7700b3b9a2SJens Wiklander 	uaddr_t buf = 0;
785843bb75SJerome Forissier 
795843bb75SJerome Forissier 	if (exp_pt != param_types)
805843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
815843bb75SJerome Forissier 
82c24b4f8fSJens Wiklander 	if (s->sbuf) {
83c24b4f8fSJens Wiklander 		DMSG("PC sampling already started");
84c24b4f8fSJens Wiklander 		return TEE_ERROR_BAD_STATE;
85c24b4f8fSJens Wiklander 	}
86c24b4f8fSJens Wiklander 
875843bb75SJerome Forissier 	buf = (uaddr_t)params[0].memref.buffer;
885843bb75SJerome Forissier 	len = params[0].memref.size;
895843bb75SJerome Forissier 	offset = params[1].value.a;
905843bb75SJerome Forissier 	scale = params[1].value.b;
915843bb75SJerome Forissier 
925843bb75SJerome Forissier 	sbuf = calloc(1, sizeof(*sbuf));
935843bb75SJerome Forissier 	if (!sbuf)
945843bb75SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
955843bb75SJerome Forissier 
965843bb75SJerome Forissier 	sbuf->samples = (uint16_t *)buf;
975843bb75SJerome Forissier 	sbuf->nsamples = len / sizeof(*sbuf->samples);
985843bb75SJerome Forissier 	sbuf->offset = offset;
995843bb75SJerome Forissier 	sbuf->scale = scale;
1005843bb75SJerome Forissier 	sbuf->freq = read_cntfrq();
1015843bb75SJerome Forissier 	sbuf->enabled = true;
1025843bb75SJerome Forissier 	s->sbuf = sbuf;
1035843bb75SJerome Forissier 
1045843bb75SJerome Forissier 	return TEE_SUCCESS;
1055843bb75SJerome Forissier }
1065843bb75SJerome Forissier 
gprof_stop_pc_sampling(struct ts_session * s,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])10700b3b9a2SJens Wiklander static TEE_Result gprof_stop_pc_sampling(struct ts_session *s,
1085843bb75SJerome Forissier 					 uint32_t param_types,
1095843bb75SJerome Forissier 					 TEE_Param params[TEE_NUM_PARAMS])
1105843bb75SJerome Forissier {
1115843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
1125843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
1135843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
1145843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
11500b3b9a2SJens Wiklander 	struct sample_buf *sbuf = NULL;
11600b3b9a2SJens Wiklander 	uint32_t rate = 0;
1175843bb75SJerome Forissier 
1185843bb75SJerome Forissier 	if (exp_pt != param_types)
1195843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
1205843bb75SJerome Forissier 
1215843bb75SJerome Forissier 	sbuf = s->sbuf;
1225843bb75SJerome Forissier 	if (!sbuf)
1235843bb75SJerome Forissier 		return TEE_ERROR_BAD_STATE;
1245843bb75SJerome Forissier 	assert(sbuf->samples);
1255843bb75SJerome Forissier 
1265843bb75SJerome Forissier 	/* Stop sampling */
1275843bb75SJerome Forissier 	if (sbuf->enabled)
1285843bb75SJerome Forissier 		sbuf->enabled = false;
1295843bb75SJerome Forissier 
1305843bb75SJerome Forissier 	rate = ((uint64_t)sbuf->count * sbuf->freq) / sbuf->usr;
1315843bb75SJerome Forissier 	params[0].value.a = rate;
1325843bb75SJerome Forissier 
1335843bb75SJerome Forissier 	DMSG("TA sampling stats: sample count=%" PRIu32 " user time=%" PRIu64
1345843bb75SJerome Forissier 	     " cntfrq=%" PRIu32 " rate=%" PRIu32, sbuf->count, sbuf->usr,
1355843bb75SJerome Forissier 	     sbuf->freq, rate);
1365843bb75SJerome Forissier 
1375843bb75SJerome Forissier 	free(sbuf);
1385843bb75SJerome Forissier 	s->sbuf = NULL;
1395843bb75SJerome Forissier 
1405843bb75SJerome Forissier 	return TEE_SUCCESS;
1415843bb75SJerome Forissier }
1425843bb75SJerome Forissier 
1435843bb75SJerome Forissier /*
1445843bb75SJerome Forissier  * Trusted Application Entry Points
1455843bb75SJerome Forissier  */
1465843bb75SJerome Forissier 
open_session(uint32_t param_types __unused,TEE_Param params[TEE_NUM_PARAMS]__unused,void ** sess_ctx __unused)1475843bb75SJerome Forissier static TEE_Result open_session(uint32_t param_types __unused,
1485843bb75SJerome Forissier 			       TEE_Param params[TEE_NUM_PARAMS] __unused,
1495843bb75SJerome Forissier 			       void **sess_ctx __unused)
1505843bb75SJerome Forissier {
15100b3b9a2SJens Wiklander 	struct ts_session *s = ts_get_calling_session();
1525843bb75SJerome Forissier 
1535843bb75SJerome Forissier 	/* Check that we're called from a user TA */
1545843bb75SJerome Forissier 	if (!s)
1555843bb75SJerome Forissier 		return TEE_ERROR_ACCESS_DENIED;
1565843bb75SJerome Forissier 	if (!is_user_ta_ctx(s->ctx))
1575843bb75SJerome Forissier 		return TEE_ERROR_ACCESS_DENIED;
1585843bb75SJerome Forissier 
1595843bb75SJerome Forissier 	return TEE_SUCCESS;
1605843bb75SJerome Forissier }
1615843bb75SJerome Forissier 
invoke_command(void * sess_ctx __unused,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])1625843bb75SJerome Forissier static TEE_Result invoke_command(void *sess_ctx __unused, uint32_t cmd_id,
1635843bb75SJerome Forissier 				 uint32_t param_types,
1645843bb75SJerome Forissier 				 TEE_Param params[TEE_NUM_PARAMS])
1655843bb75SJerome Forissier {
16600b3b9a2SJens Wiklander 	struct ts_session *s = ts_get_calling_session();
1675843bb75SJerome Forissier 
1685843bb75SJerome Forissier 	switch (cmd_id) {
1695843bb75SJerome Forissier 	case PTA_GPROF_SEND:
1705843bb75SJerome Forissier 		return gprof_send(s, param_types, params);
1715843bb75SJerome Forissier 	case PTA_GPROF_START_PC_SAMPLING:
1725843bb75SJerome Forissier 		return gprof_start_pc_sampling(s, param_types, params);
1735843bb75SJerome Forissier 	case PTA_GPROF_STOP_PC_SAMPLING:
1745843bb75SJerome Forissier 		return gprof_stop_pc_sampling(s, param_types, params);
1755843bb75SJerome Forissier 	default:
1765843bb75SJerome Forissier 		break;
1775843bb75SJerome Forissier 	}
1785843bb75SJerome Forissier 	return TEE_ERROR_NOT_IMPLEMENTED;
1795843bb75SJerome Forissier }
1805843bb75SJerome Forissier 
1815843bb75SJerome Forissier pseudo_ta_register(.uuid = PTA_GPROF_UUID, .name = "gprof",
1825843bb75SJerome Forissier 		   .flags = PTA_DEFAULT_FLAGS,
1835843bb75SJerome Forissier 		   .open_session_entry_point = open_session,
1845843bb75SJerome Forissier 		   .invoke_command_entry_point = invoke_command);
185