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