xref: /optee_os/core/pta/stats.c (revision 76306f734337ea628c45ed3f0d208d3af33ceadb)
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 
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 			break;
73 
74 		case ALLOC_ID_TA_RAM:
75 			phys_mem_stats(stats, p[0].value.b);
76 			strlcpy(stats->desc, "Physical TA memory",
77 				sizeof(stats->desc));
78 			break;
79 
80 #ifdef CFG_NS_VIRTUALIZATION
81 		case ALLOC_ID_NEXUS_HEAP:
82 			nex_malloc_get_stats(stats);
83 			strlcpy(stats->desc, "KHeap", sizeof(stats->desc));
84 			if (p[0].value.b)
85 				nex_malloc_reset_stats();
86 			break;
87 #endif
88 		case ALLOC_ID_RPMB:
89 			if (rpmb_mem_stats(stats, p[0].value.b))
90 				strlcpy(stats->desc,
91 					"RPMB secure storage (no data)",
92 					sizeof(stats->desc));
93 			else
94 				strlcpy(stats->desc, "RPMB secure storage",
95 					sizeof(stats->desc));
96 			break;
97 		default:
98 			EMSG("Wrong pool id");
99 			break;
100 		}
101 
102 		stats++;
103 	}
104 
105 	return TEE_SUCCESS;
106 }
107 
108 static TEE_Result get_pager_stats(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
109 {
110 	struct tee_pager_stats stats = { };
111 
112 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
113 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
114 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
115 			    TEE_PARAM_TYPE_NONE) != type) {
116 		EMSG("expect 3 output values as argument");
117 		return TEE_ERROR_BAD_PARAMETERS;
118 	}
119 
120 	tee_pager_get_stats(&stats);
121 	p[0].value.a = stats.npages;
122 	p[0].value.b = stats.npages_all;
123 	p[1].value.a = stats.ro_hits;
124 	p[1].value.b = stats.rw_hits;
125 	p[2].value.a = stats.hidden_hits;
126 	p[2].value.b = stats.zi_released;
127 
128 	return TEE_SUCCESS;
129 }
130 
131 static TEE_Result get_memleak_stats(uint32_t type,
132 				    TEE_Param p[TEE_NUM_PARAMS] __maybe_unused)
133 {
134 
135 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE,
136 			    TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE) != type)
137 		return TEE_ERROR_BAD_PARAMETERS;
138 
139 	mdbg_check(1);
140 
141 	return TEE_SUCCESS;
142 }
143 
144 static TEE_Result get_user_ta_stats(uint32_t type,
145 				    TEE_Param p[TEE_NUM_PARAMS] __maybe_unused)
146 {
147 	uint32_t res = TEE_SUCCESS;
148 
149 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
150 			    TEE_PARAM_TYPE_NONE,
151 			    TEE_PARAM_TYPE_NONE,
152 			    TEE_PARAM_TYPE_NONE) != type)
153 		return TEE_ERROR_BAD_PARAMETERS;
154 
155 #if defined(CFG_TA_STATS)
156 	res = tee_ta_instance_stats(p[0].memref.buffer,
157 				    &p[0].memref.size);
158 	if (res != TEE_SUCCESS)
159 		DMSG("tee_ta_dump_stats return: 0x%"PRIx32, res);
160 #else
161 	res = TEE_ERROR_NOT_SUPPORTED;
162 #endif
163 	return res;
164 }
165 
166 static TEE_Result get_system_time(uint32_t type,
167 				  TEE_Param p[TEE_NUM_PARAMS])
168 {
169 	TEE_Result ret = TEE_ERROR_GENERIC;
170 	TEE_Time ree_time = { };
171 	TEE_Time tee_time = { };
172 
173 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
174 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
175 			    TEE_PARAM_TYPE_NONE,
176 			    TEE_PARAM_TYPE_NONE) != type)
177 		return TEE_ERROR_BAD_PARAMETERS;
178 
179 	ret = tee_time_get_sys_time(&tee_time);
180 	if (ret)
181 		return ret;
182 
183 	ret = tee_time_get_ree_time(&ree_time);
184 	if (ret)
185 		return ret;
186 
187 	p[0].value.a = ree_time.seconds;
188 	p[0].value.b = ree_time.millis;
189 	p[1].value.a = tee_time.seconds;
190 	p[1].value.b = tee_time.millis;
191 
192 	return TEE_SUCCESS;
193 }
194 
195 static TEE_Result print_driver_info(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
196 {
197 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
198 			    TEE_PARAM_TYPE_NONE,
199 			    TEE_PARAM_TYPE_NONE,
200 			    TEE_PARAM_TYPE_NONE) != type)
201 		return TEE_ERROR_BAD_PARAMETERS;
202 
203 	switch (p[0].value.a) {
204 	case STATS_DRIVER_TYPE_CLOCK:
205 		clk_print_tree();
206 		break;
207 	case STATS_DRIVER_TYPE_REGULATOR:
208 		regulator_print_tree();
209 		break;
210 	default:
211 		return TEE_ERROR_BAD_PARAMETERS;
212 	}
213 
214 	return TEE_SUCCESS;
215 }
216 
217 /*
218  * Trusted Application Entry Points
219  */
220 
221 static TEE_Result invoke_command(void *psess __unused,
222 				 uint32_t cmd, uint32_t ptypes,
223 				 TEE_Param params[TEE_NUM_PARAMS])
224 {
225 	switch (cmd) {
226 	case STATS_CMD_PAGER_STATS:
227 		return get_pager_stats(ptypes, params);
228 	case STATS_CMD_ALLOC_STATS:
229 		return get_alloc_stats(ptypes, params);
230 	case STATS_CMD_MEMLEAK_STATS:
231 		return get_memleak_stats(ptypes, params);
232 	case STATS_CMD_TA_STATS:
233 		return get_user_ta_stats(ptypes, params);
234 	case STATS_CMD_GET_TIME:
235 		return get_system_time(ptypes, params);
236 	case STATS_CMD_PRINT_DRIVER_INFO:
237 		return print_driver_info(ptypes, params);
238 	default:
239 		break;
240 	}
241 	return TEE_ERROR_BAD_PARAMETERS;
242 }
243 
244 pseudo_ta_register(.uuid = STATS_UUID, .name = "stats.pta",
245 		   .flags = PTA_DEFAULT_FLAGS,
246 		   .invoke_command_entry_point = invoke_command);
247