xref: /optee_os/core/pta/gprof.c (revision 5843bb755f152c7961130e90bba969b8a1ce8f64)
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, &params[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