xref: /optee_os/core/pta/stats.c (revision 6cfa381e534b362afbd103f526b132048e54ba47)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  */
5 #include <compiler.h>
6 #include <kernel/pseudo_ta.h>
7 #include <kernel/tee_time.h>
8 #include <malloc.h>
9 #include <mm/tee_mm.h>
10 #include <mm/tee_pager.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <string_ext.h>
14 #include <trace.h>
15 
16 #define TA_NAME		"stats.ta"
17 
18 #define STATS_UUID \
19 		{ 0xd96a5b40, 0xe2c7, 0xb1af, \
20 			{ 0x87, 0x94, 0x10, 0x02, 0xa5, 0xd5, 0xc6, 0x1b } }
21 
22 #define STATS_CMD_PAGER_STATS		0
23 #define STATS_CMD_ALLOC_STATS		1
24 #define STATS_CMD_MEMLEAK_STATS		2
25 /*
26  * UTEE_ENTRY_FUNC_DUMP_MEMSTATS
27  * [out]    memref[0]        Array of context information of loaded TAs
28  *
29  * Each cell of the TA information array contains:
30  * TEE_UUID    TA UUID
31  * uint32_t    Non zero if TA panicked, 0 otherwise
32  * uint32_t    Number of sessions opened by the TA
33  * uint32_t    Byte size currently allocated in TA heap
34  * uint32_t    Max bytes allocated since last stats reset
35  * uint32_t    TA heap pool byte size
36  * uint32_t    Number of failed allocation requests
37  * uint32_t    Biggest byte size which allocation failed
38  * uint32_t    Biggest byte size which allocation succeeded
39  */
40 #define STATS_CMD_TA_STATS		3
41 
42 /*
43  * STATS_CMD_GET_TIME - Get both REE time and TEE time
44  *
45  * [out]    value[0].a        REE time as seen by OP-TEE in seconds
46  * [out]    value[0].b        REE time as seen by OP-TEE, milliseconds part
47  * [out]    value[1].a        TEE system time in seconds
48  * [out]    value[1].b        TEE system time, milliseconds part
49  */
50 #define STATS_CMD_GET_TIME		4
51 
52 #define STATS_NB_POOLS			4
53 
54 static TEE_Result get_alloc_stats(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
55 {
56 	struct malloc_stats *stats;
57 	uint32_t size_to_retrieve;
58 	uint32_t pool_id;
59 	uint32_t i;
60 
61 	/*
62 	 * p[0].value.a = pool id (from 0 to n)
63 	 *   - 0 means all the pools to be retrieved
64 	 *   - 1..n means pool id
65 	 * p[0].value.b = 0 if no reset of the stats
66 	 * p[1].memref.buffer = output buffer to struct malloc_stats
67 	 */
68 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
69 			    TEE_PARAM_TYPE_MEMREF_OUTPUT,
70 			    TEE_PARAM_TYPE_NONE,
71 			    TEE_PARAM_TYPE_NONE) != type) {
72 		return TEE_ERROR_BAD_PARAMETERS;
73 	}
74 
75 	pool_id = p[0].value.a;
76 	if (pool_id > STATS_NB_POOLS)
77 		return TEE_ERROR_BAD_PARAMETERS;
78 
79 	size_to_retrieve = sizeof(struct malloc_stats);
80 	if (!pool_id)
81 		size_to_retrieve *= STATS_NB_POOLS;
82 
83 	if (p[1].memref.size < size_to_retrieve) {
84 		p[1].memref.size = size_to_retrieve;
85 		return TEE_ERROR_SHORT_BUFFER;
86 	}
87 	p[1].memref.size = size_to_retrieve;
88 	stats = p[1].memref.buffer;
89 
90 	for (i = 1; i <= STATS_NB_POOLS; i++) {
91 		if ((pool_id) && (i != pool_id))
92 			continue;
93 
94 		switch (i) {
95 		case 1:
96 			malloc_get_stats(stats);
97 			strlcpy(stats->desc, "Heap", sizeof(stats->desc));
98 			if (p[0].value.b)
99 				malloc_reset_stats();
100 			break;
101 
102 		case 2:
103 			EMSG("public DDR not managed by secure side anymore");
104 			break;
105 
106 		case 3:
107 			tee_mm_get_pool_stats(&tee_mm_sec_ddr, stats,
108 					      !!p[0].value.b);
109 			strlcpy(stats->desc, "Secure DDR", sizeof(stats->desc));
110 			break;
111 
112 #ifdef CFG_NS_VIRTUALIZATION
113 		case 4:
114 			nex_malloc_get_stats(stats);
115 			strlcpy(stats->desc, "KHeap", sizeof(stats->desc));
116 			if (p[0].value.b)
117 				nex_malloc_reset_stats();
118 			break;
119 #endif
120 		default:
121 			EMSG("Wrong pool id");
122 			break;
123 		}
124 
125 		stats++;
126 	}
127 
128 	return TEE_SUCCESS;
129 }
130 
131 static TEE_Result get_pager_stats(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
132 {
133 	struct tee_pager_stats stats;
134 
135 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
136 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
137 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
138 			    TEE_PARAM_TYPE_NONE) != type) {
139 		EMSG("expect 3 output values as argument");
140 		return TEE_ERROR_BAD_PARAMETERS;
141 	}
142 
143 	tee_pager_get_stats(&stats);
144 	p[0].value.a = stats.npages;
145 	p[0].value.b = stats.npages_all;
146 	p[1].value.a = stats.ro_hits;
147 	p[1].value.b = stats.rw_hits;
148 	p[2].value.a = stats.hidden_hits;
149 	p[2].value.b = stats.zi_released;
150 
151 	return TEE_SUCCESS;
152 }
153 
154 static TEE_Result get_memleak_stats(uint32_t type,
155 				    TEE_Param p[TEE_NUM_PARAMS] __maybe_unused)
156 {
157 
158 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE,
159 			    TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE) != type)
160 		return TEE_ERROR_BAD_PARAMETERS;
161 
162 	mdbg_check(1);
163 
164 	return TEE_SUCCESS;
165 }
166 
167 static TEE_Result get_user_ta_stats(uint32_t type,
168 				    TEE_Param p[TEE_NUM_PARAMS] __maybe_unused)
169 {
170 	uint32_t res = TEE_SUCCESS;
171 
172 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
173 			    TEE_PARAM_TYPE_NONE,
174 			    TEE_PARAM_TYPE_NONE,
175 			    TEE_PARAM_TYPE_NONE) != type)
176 		return TEE_ERROR_BAD_PARAMETERS;
177 
178 #if defined(CFG_TA_STATS)
179 	res = tee_ta_instance_stats(p[0].memref.buffer,
180 				    &p[0].memref.size);
181 	if (res != TEE_SUCCESS)
182 		DMSG("tee_ta_dump_stats return: 0x%"PRIx32, res);
183 #else
184 	res = TEE_ERROR_NOT_SUPPORTED;
185 #endif
186 	return res;
187 }
188 
189 static TEE_Result get_system_time(uint32_t type,
190 				  TEE_Param p[TEE_NUM_PARAMS])
191 {
192 	TEE_Time ree_time = { };
193 	TEE_Time tee_time = { };
194 
195 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
196 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
197 			    TEE_PARAM_TYPE_NONE,
198 			    TEE_PARAM_TYPE_NONE) != type)
199 		return TEE_ERROR_BAD_PARAMETERS;
200 
201 	tee_time_get_sys_time(&tee_time);
202 	tee_time_get_ree_time(&ree_time);
203 
204 	p[0].value.a = ree_time.seconds;
205 	p[0].value.b = ree_time.millis;
206 	p[1].value.a = tee_time.seconds;
207 	p[1].value.b = tee_time.millis;
208 
209 	return TEE_SUCCESS;
210 }
211 
212 /*
213  * Trusted Application Entry Points
214  */
215 
216 static TEE_Result invoke_command(void *psess __unused,
217 				 uint32_t cmd, uint32_t ptypes,
218 				 TEE_Param params[TEE_NUM_PARAMS])
219 {
220 	switch (cmd) {
221 	case STATS_CMD_PAGER_STATS:
222 		return get_pager_stats(ptypes, params);
223 	case STATS_CMD_ALLOC_STATS:
224 		return get_alloc_stats(ptypes, params);
225 	case STATS_CMD_MEMLEAK_STATS:
226 		return get_memleak_stats(ptypes, params);
227 	case STATS_CMD_TA_STATS:
228 		return get_user_ta_stats(ptypes, params);
229 	case STATS_CMD_GET_TIME:
230 		return get_system_time(ptypes, params);
231 	default:
232 		break;
233 	}
234 	return TEE_ERROR_BAD_PARAMETERS;
235 }
236 
237 pseudo_ta_register(.uuid = STATS_UUID, .name = TA_NAME,
238 		   .flags = PTA_DEFAULT_FLAGS,
239 		   .invoke_command_entry_point = invoke_command);
240