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