xref: /optee_os/core/pta/stats.c (revision 8261ca4b6970e536f8a4c833d6659fed148b9cec)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  */
5 #include <compiler.h>
6 #include <drivers/clk.h>
7 #include <drivers/regulator.h>
8 #include <kernel/pseudo_ta.h>
9 #include <kernel/tee_time.h>
10 #include <malloc.h>
11 #include <mm/phys_mem.h>
12 #include <mm/tee_mm.h>
13 #include <mm/tee_pager.h>
14 #include <pta_stats.h>
15 #include <string.h>
16 #include <string_ext.h>
17 #include <tee_api_types.h>
18 #include <tee/tee_fs.h>
19 #include <trace.h>
20 
get_alloc_stats(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])21 static TEE_Result get_alloc_stats(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
22 {
23 	struct pta_stats_alloc *stats = NULL;
24 	uint32_t size_to_retrieve = 0;
25 	uint32_t pool_id = 0;
26 	uint32_t i = 0;
27 
28 	/*
29 	 * p[0].value.a = pool id (from 0 to n)
30 	 *   - 0 means all the pools to be retrieved
31 	 *   - 1..n means pool id
32 	 * p[0].value.b = 0 if no reset of the stats
33 	 * p[1].memref.buffer = output buffer to struct pta_stats_alloc
34 	 */
35 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
36 			    TEE_PARAM_TYPE_MEMREF_OUTPUT,
37 			    TEE_PARAM_TYPE_NONE,
38 			    TEE_PARAM_TYPE_NONE) != type) {
39 		return TEE_ERROR_BAD_PARAMETERS;
40 	}
41 
42 	pool_id = p[0].value.a;
43 	if (pool_id > STATS_NB_POOLS)
44 		return TEE_ERROR_BAD_PARAMETERS;
45 
46 	size_to_retrieve = sizeof(struct pta_stats_alloc);
47 	if (pool_id == ALLOC_ID_ALL)
48 		size_to_retrieve *= STATS_NB_POOLS;
49 
50 	if (p[1].memref.size < size_to_retrieve) {
51 		p[1].memref.size = size_to_retrieve;
52 		return TEE_ERROR_SHORT_BUFFER;
53 	}
54 	p[1].memref.size = size_to_retrieve;
55 	stats = p[1].memref.buffer;
56 	memset(stats, 0, size_to_retrieve);
57 
58 	for (i = ALLOC_ID_HEAP; i <= STATS_NB_POOLS; i++) {
59 		if (pool_id != ALLOC_ID_ALL && i != pool_id)
60 			continue;
61 
62 		switch (i) {
63 		case ALLOC_ID_HEAP:
64 			malloc_get_stats(stats);
65 			strlcpy(stats->desc, "Heap", sizeof(stats->desc));
66 			if (p[0].value.b)
67 				malloc_reset_stats();
68 			break;
69 
70 		case ALLOC_ID_PUBLIC_DDR:
71 			EMSG("public DDR not managed by secure side anymore");
72 			strlcpy(stats->desc, "Public DDR (deprecated)",
73 				sizeof(stats->desc));
74 			break;
75 
76 		case ALLOC_ID_TA_RAM:
77 			phys_mem_stats(stats, p[0].value.b);
78 			strlcpy(stats->desc, "Physical TA memory",
79 				sizeof(stats->desc));
80 			break;
81 
82 		case ALLOC_ID_NEXUS_HEAP:
83 #ifdef CFG_NS_VIRTUALIZATION
84 			nex_malloc_get_stats(stats);
85 			strlcpy(stats->desc, "KHeap", sizeof(stats->desc));
86 			if (p[0].value.b)
87 				nex_malloc_reset_stats();
88 #else
89 			strlcpy(stats->desc, "KHeap (disabled)",
90 				sizeof(stats->desc));
91 #endif
92 			break;
93 		case ALLOC_ID_RPMB:
94 			if (rpmb_mem_stats(stats, p[0].value.b))
95 				strlcpy(stats->desc,
96 					"RPMB secure storage (no data)",
97 					sizeof(stats->desc));
98 			else
99 				strlcpy(stats->desc, "RPMB secure storage",
100 					sizeof(stats->desc));
101 			break;
102 		default:
103 			EMSG("Wrong pool id");
104 			break;
105 		}
106 
107 		stats++;
108 	}
109 
110 	return TEE_SUCCESS;
111 }
112 
get_pager_stats(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])113 static TEE_Result get_pager_stats(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
114 {
115 	struct tee_pager_stats stats = { };
116 
117 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
118 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
119 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
120 			    TEE_PARAM_TYPE_NONE) != type) {
121 		EMSG("expect 3 output values as argument");
122 		return TEE_ERROR_BAD_PARAMETERS;
123 	}
124 
125 	tee_pager_get_stats(&stats);
126 	p[0].value.a = stats.npages;
127 	p[0].value.b = stats.npages_all;
128 	p[1].value.a = stats.ro_hits;
129 	p[1].value.b = stats.rw_hits;
130 	p[2].value.a = stats.hidden_hits;
131 	p[2].value.b = stats.zi_released;
132 
133 	return TEE_SUCCESS;
134 }
135 
get_memleak_stats(uint32_t type,TEE_Param p[TEE_NUM_PARAMS]__maybe_unused)136 static TEE_Result get_memleak_stats(uint32_t type,
137 				    TEE_Param p[TEE_NUM_PARAMS] __maybe_unused)
138 {
139 
140 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE,
141 			    TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE) != type)
142 		return TEE_ERROR_BAD_PARAMETERS;
143 
144 	mdbg_check(1);
145 
146 	return TEE_SUCCESS;
147 }
148 
get_user_ta_stats(uint32_t type,TEE_Param p[TEE_NUM_PARAMS]__maybe_unused)149 static TEE_Result get_user_ta_stats(uint32_t type,
150 				    TEE_Param p[TEE_NUM_PARAMS] __maybe_unused)
151 {
152 	uint32_t res = TEE_SUCCESS;
153 
154 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
155 			    TEE_PARAM_TYPE_NONE,
156 			    TEE_PARAM_TYPE_NONE,
157 			    TEE_PARAM_TYPE_NONE) != type)
158 		return TEE_ERROR_BAD_PARAMETERS;
159 
160 #if defined(CFG_TA_STATS)
161 	res = tee_ta_instance_stats(p[0].memref.buffer,
162 				    &p[0].memref.size);
163 	if (res != TEE_SUCCESS)
164 		DMSG("tee_ta_dump_stats return: 0x%"PRIx32, res);
165 #else
166 	res = TEE_ERROR_NOT_SUPPORTED;
167 #endif
168 	return res;
169 }
170 
get_system_time(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])171 static TEE_Result get_system_time(uint32_t type,
172 				  TEE_Param p[TEE_NUM_PARAMS])
173 {
174 	TEE_Result ret = TEE_ERROR_GENERIC;
175 	TEE_Time ree_time = { };
176 	TEE_Time tee_time = { };
177 
178 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
179 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
180 			    TEE_PARAM_TYPE_NONE,
181 			    TEE_PARAM_TYPE_NONE) != type)
182 		return TEE_ERROR_BAD_PARAMETERS;
183 
184 	ret = tee_time_get_sys_time(&tee_time);
185 	if (ret)
186 		return ret;
187 
188 	ret = tee_time_get_ree_time(&ree_time);
189 	if (ret)
190 		return ret;
191 
192 	p[0].value.a = ree_time.seconds;
193 	p[0].value.b = ree_time.millis;
194 	p[1].value.a = tee_time.seconds;
195 	p[1].value.b = tee_time.millis;
196 
197 	return TEE_SUCCESS;
198 }
199 
print_driver_info(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])200 static TEE_Result print_driver_info(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
201 {
202 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
203 			    TEE_PARAM_TYPE_NONE,
204 			    TEE_PARAM_TYPE_NONE,
205 			    TEE_PARAM_TYPE_NONE) != type)
206 		return TEE_ERROR_BAD_PARAMETERS;
207 
208 	switch (p[0].value.a) {
209 	case STATS_DRIVER_TYPE_CLOCK:
210 		clk_print_tree();
211 		break;
212 	case STATS_DRIVER_TYPE_REGULATOR:
213 		regulator_print_tree();
214 		break;
215 	default:
216 		return TEE_ERROR_BAD_PARAMETERS;
217 	}
218 
219 	return TEE_SUCCESS;
220 }
221 
222 /*
223  * Trusted Application Entry Points
224  */
225 
invoke_command(void * psess __unused,uint32_t cmd,uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])226 static TEE_Result invoke_command(void *psess __unused,
227 				 uint32_t cmd, uint32_t ptypes,
228 				 TEE_Param params[TEE_NUM_PARAMS])
229 {
230 	switch (cmd) {
231 	case STATS_CMD_PAGER_STATS:
232 		return get_pager_stats(ptypes, params);
233 	case STATS_CMD_ALLOC_STATS:
234 		return get_alloc_stats(ptypes, params);
235 	case STATS_CMD_MEMLEAK_STATS:
236 		return get_memleak_stats(ptypes, params);
237 	case STATS_CMD_TA_STATS:
238 		return get_user_ta_stats(ptypes, params);
239 	case STATS_CMD_GET_TIME:
240 		return get_system_time(ptypes, params);
241 	case STATS_CMD_PRINT_DRIVER_INFO:
242 		return print_driver_info(ptypes, params);
243 	default:
244 		break;
245 	}
246 	return TEE_ERROR_BAD_PARAMETERS;
247 }
248 
249 pseudo_ta_register(.uuid = STATS_UUID, .name = "stats.pta",
250 		   .flags = PTA_DEFAULT_FLAGS,
251 		   .invoke_command_entry_point = invoke_command);
252