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