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