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 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_NS_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 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 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 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 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