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