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 #define STATS_NB_POOLS			4
26 
get_alloc_stats(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])27 static TEE_Result get_alloc_stats(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
28 {
29 	struct malloc_stats *stats;
30 	uint32_t size_to_retrieve;
31 	uint32_t pool_id;
32 	uint32_t i;
33 
34 	/*
35 	 * p[0].value.a = pool id (from 0 to n)
36 	 *   - 0 means all the pools to be retrieved
37 	 *   - 1..n means pool id
38 	 * p[0].value.b = 0 if no reset of the stats
39 	 * p[1].memref.buffer = output buffer to struct malloc_stats
40 	 */
41 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
42 			    TEE_PARAM_TYPE_MEMREF_OUTPUT,
43 			    TEE_PARAM_TYPE_NONE,
44 			    TEE_PARAM_TYPE_NONE) != type) {
45 		return TEE_ERROR_BAD_PARAMETERS;
46 	}
47 
48 	pool_id = p[0].value.a;
49 	if (pool_id > STATS_NB_POOLS)
50 		return TEE_ERROR_BAD_PARAMETERS;
51 
52 	size_to_retrieve = sizeof(struct malloc_stats);
53 	if (!pool_id)
54 		size_to_retrieve *= STATS_NB_POOLS;
55 
56 	if (p[1].memref.size < size_to_retrieve) {
57 		p[1].memref.size = size_to_retrieve;
58 		return TEE_ERROR_SHORT_BUFFER;
59 	}
60 	p[1].memref.size = size_to_retrieve;
61 	stats = p[1].memref.buffer;
62 
63 	for (i = 1; i <= STATS_NB_POOLS; i++) {
64 		if ((pool_id) && (i != pool_id))
65 			continue;
66 
67 		switch (i) {
68 		case 1:
69 			malloc_get_stats(stats);
70 			strlcpy(stats->desc, "Heap", sizeof(stats->desc));
71 			if (p[0].value.b)
72 				malloc_reset_stats();
73 			break;
74 
75 		case 2:
76 			EMSG("public DDR not managed by secure side anymore");
77 			break;
78 
79 		case 3:
80 			tee_mm_get_pool_stats(&tee_mm_sec_ddr, stats,
81 					      !!p[0].value.b);
82 			strlcpy(stats->desc, "Secure DDR", sizeof(stats->desc));
83 			break;
84 
85 #ifdef CFG_VIRTUALIZATION
86 		case 4:
87 			nex_malloc_get_stats(stats);
88 			strlcpy(stats->desc, "KHeap", sizeof(stats->desc));
89 			if (p[0].value.b)
90 				nex_malloc_reset_stats();
91 			break;
92 #endif
93 		default:
94 			EMSG("Wrong pool id");
95 			break;
96 		}
97 
98 		stats++;
99 	}
100 
101 	return TEE_SUCCESS;
102 }
103 
get_pager_stats(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])104 static TEE_Result get_pager_stats(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
105 {
106 	struct tee_pager_stats stats;
107 
108 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
109 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
110 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
111 			    TEE_PARAM_TYPE_NONE) != type) {
112 		EMSG("expect 3 output values as argument");
113 		return TEE_ERROR_BAD_PARAMETERS;
114 	}
115 
116 	tee_pager_get_stats(&stats);
117 	p[0].value.a = stats.npages;
118 	p[0].value.b = stats.npages_all;
119 	p[1].value.a = stats.ro_hits;
120 	p[1].value.b = stats.rw_hits;
121 	p[2].value.a = stats.hidden_hits;
122 	p[2].value.b = stats.zi_released;
123 
124 	return TEE_SUCCESS;
125 }
126 
get_memleak_stats(uint32_t type,TEE_Param p[TEE_NUM_PARAMS]__unused)127 static TEE_Result get_memleak_stats(uint32_t type,
128 				    TEE_Param p[TEE_NUM_PARAMS] __unused)
129 {
130 
131 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE,
132 			    TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE) != type)
133 		return TEE_ERROR_BAD_PARAMETERS;
134 
135 	mdbg_check(1);
136 
137 	return TEE_SUCCESS;
138 }
139 
140 /*
141  * Trusted Application Entry Points
142  */
143 
invoke_command(void * psess __unused,uint32_t cmd,uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])144 static TEE_Result invoke_command(void *psess __unused,
145 				 uint32_t cmd, uint32_t ptypes,
146 				 TEE_Param params[TEE_NUM_PARAMS])
147 {
148 	switch (cmd) {
149 	case STATS_CMD_PAGER_STATS:
150 		return get_pager_stats(ptypes, params);
151 	case STATS_CMD_ALLOC_STATS:
152 		return get_alloc_stats(ptypes, params);
153 	case STATS_CMD_MEMLEAK_STATS:
154 		return get_memleak_stats(ptypes, params);
155 	default:
156 		break;
157 	}
158 	return TEE_ERROR_BAD_PARAMETERS;
159 }
160 
161 pseudo_ta_register(.uuid = STATS_UUID, .name = TA_NAME,
162 		   .flags = PTA_DEFAULT_FLAGS,
163 		   .invoke_command_entry_point = invoke_command);
164