1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014, STMicroelectronics International N.V. 4 * Copyright (c) 2022, Linaro Limited. 5 */ 6 #include <compiler.h> 7 #include <link.h> 8 #include <malloc.h> 9 #include <memtag.h> 10 #include <stdbool.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <sys/queue.h> 14 #include <tee_api.h> 15 #include <tee_arith_internal.h> 16 #include <tee_internal_api_extensions.h> 17 #include <tee_ta_api.h> 18 #include <user_ta_header.h> 19 #include <utee_syscalls.h> 20 #include "tee_api_private.h" 21 22 struct ta_session { 23 uint32_t session_id; 24 void *session_ctx; 25 TAILQ_ENTRY(ta_session) link; 26 }; 27 28 static TAILQ_HEAD(ta_sessions, ta_session) ta_sessions = 29 TAILQ_HEAD_INITIALIZER(ta_sessions); 30 31 static bool init_done; 32 33 /* From user_ta_header.c, built within TA */ 34 extern uint8_t ta_heap[]; 35 extern const size_t ta_heap_size; 36 extern struct ta_head ta_head; 37 38 uint32_t ta_param_types; 39 TEE_Param ta_params[TEE_NUM_PARAMS]; 40 41 struct malloc_ctx *__ta_no_share_malloc_ctx; 42 43 struct __elf_phdr_info __elf_phdr_info; 44 45 struct phdr_info { 46 struct dl_phdr_info info; 47 TAILQ_ENTRY(phdr_info) link; 48 }; 49 50 static TAILQ_HEAD(phdr_info_head, phdr_info) __phdr_info_head = 51 TAILQ_HEAD_INITIALIZER(__phdr_info_head); 52 /* 53 * Keep track of how many modules have been initialized so that subsequent 54 * dlopen() calls will not run the same initializers again 55 */ 56 static size_t _num_mod_init; 57 58 static int _init_iterate_phdr_cb(struct dl_phdr_info *info, 59 size_t size __unused, void *data) 60 { 61 struct phdr_info *qe = NULL; 62 size_t *count = data; 63 64 qe = malloc(sizeof(*qe)); 65 if (!qe) { 66 EMSG("init/fini: out of memory"); 67 abort(); 68 } 69 qe->info = *info; 70 TAILQ_INSERT_TAIL(&__phdr_info_head, qe, link); 71 (*count)++; 72 return 0; 73 } 74 75 static void _get_fn_array(struct dl_phdr_info *info, Elf_Sword tag_a, 76 Elf_Sword tag_s, void (***fn)(void), size_t *num_fn) 77 { 78 const Elf_Phdr *phdr = NULL; 79 Elf_Dyn *dyn = NULL; 80 size_t num_dyn = 0; 81 size_t i = 0; 82 size_t j = 0; 83 84 for (i = 0; i < info->dlpi_phnum; i++) { 85 phdr = info->dlpi_phdr + i; 86 if (phdr->p_type != PT_DYNAMIC) 87 continue; 88 num_dyn = phdr->p_memsz / sizeof(Elf_Dyn); 89 dyn = (Elf_Dyn *)(phdr->p_vaddr + info->dlpi_addr); 90 for (j = 0; j < num_dyn; j++) { 91 if (*fn && *num_fn) 92 break; 93 if (dyn->d_tag == DT_NULL) { 94 break; 95 } else if (dyn->d_tag == tag_a) { 96 *fn = (void (**)(void))(dyn->d_un.d_ptr + 97 info->dlpi_addr); 98 } else if (dyn->d_tag == tag_s) { 99 *num_fn = dyn->d_un.d_val / sizeof(Elf_Addr); 100 } 101 dyn++; 102 } 103 } 104 } 105 106 void __utee_call_elf_init_fn(void) 107 { 108 void (**fn)(void) = NULL; 109 size_t num_mod = 0; 110 size_t num_fn = 0; 111 size_t mod = 0; 112 size_t i = 0; 113 struct phdr_info *qe = NULL; 114 struct phdr_info *qe2 = NULL; 115 116 dl_iterate_phdr(_init_iterate_phdr_cb, &num_mod); 117 118 /* Reverse order: dependencies first */ 119 TAILQ_FOREACH_REVERSE(qe, &__phdr_info_head, phdr_info_head, link) { 120 if (mod == num_mod - _num_mod_init) 121 break; 122 _get_fn_array(&qe->info, DT_INIT_ARRAY, DT_INIT_ARRAYSZ, &fn, 123 &num_fn); 124 for (i = 0; i < num_fn; i++) 125 fn[i](); 126 fn = NULL; 127 num_fn = 0; 128 mod++; 129 } 130 _num_mod_init += mod; 131 132 TAILQ_FOREACH_SAFE(qe, &__phdr_info_head, link, qe2) { 133 TAILQ_REMOVE(&__phdr_info_head, qe, link); 134 free(qe); 135 } 136 } 137 138 static int _fini_iterate_phdr_cb(struct dl_phdr_info *info, 139 size_t size __unused, void *data __unused) 140 { 141 void (**fn)(void) = NULL; 142 size_t num_fn = 0; 143 size_t i = 0; 144 145 _get_fn_array(info, DT_FINI_ARRAY, DT_FINI_ARRAYSZ, &fn, &num_fn); 146 147 for (i = 1; i <= num_fn; i++) 148 fn[num_fn - i](); 149 150 return 0; 151 } 152 153 void __utee_call_elf_fini_fn(void) 154 { 155 dl_iterate_phdr(_fini_iterate_phdr_cb, NULL); 156 } 157 158 static unsigned int get_memtag_implementation(void) 159 { 160 const char *s = "org.trustedfirmware.optee.cpu.feat_memtag_implemented"; 161 uint32_t v = 0; 162 163 if (TEE_GetPropertyAsU32(TEE_PROPSET_TEE_IMPLEMENTATION, s, &v)) 164 return 0; 165 return v; 166 } 167 168 static TEE_Result init_instance(void) 169 { 170 trace_set_level(tahead_get_trace_level()); 171 __utee_gprof_init(); 172 malloc_add_pool(ta_heap, ta_heap_size); 173 if (__ta_no_share_heap_size) { 174 __ta_no_share_malloc_ctx = malloc(raw_malloc_get_ctx_size()); 175 if (__ta_no_share_malloc_ctx) { 176 raw_malloc_init_ctx(__ta_no_share_malloc_ctx); 177 raw_malloc_add_pool(__ta_no_share_malloc_ctx, 178 __ta_no_share_heap, 179 __ta_no_share_heap_size); 180 } 181 } 182 memtag_init_ops(get_memtag_implementation()); 183 _TEE_MathAPI_Init(); 184 __utee_tcb_init(); 185 __utee_call_elf_init_fn(); 186 return TA_CreateEntryPoint(); 187 } 188 189 static void uninit_instance(void) 190 { 191 __utee_gprof_fini(); 192 TA_DestroyEntryPoint(); 193 __utee_call_elf_fini_fn(); 194 } 195 196 static void ta_header_save_params(uint32_t param_types, 197 TEE_Param params[TEE_NUM_PARAMS]) 198 { 199 ta_param_types = param_types; 200 201 if (params) 202 memcpy(ta_params, params, sizeof(ta_params)); 203 else 204 memset(ta_params, 0, sizeof(ta_params)); 205 } 206 207 static struct ta_session *ta_header_get_session(uint32_t session_id) 208 { 209 struct ta_session *itr; 210 211 TAILQ_FOREACH(itr, &ta_sessions, link) { 212 if (itr->session_id == session_id) 213 return itr; 214 } 215 return NULL; 216 } 217 218 static TEE_Result ta_header_add_session(uint32_t session_id) 219 { 220 struct ta_session *itr = ta_header_get_session(session_id); 221 TEE_Result res; 222 223 if (itr) 224 return TEE_SUCCESS; 225 226 if (!init_done) { 227 init_done = true; 228 res = init_instance(); 229 if (res) 230 return res; 231 } 232 233 itr = TEE_Malloc(sizeof(struct ta_session), 234 TEE_USER_MEM_HINT_NO_FILL_ZERO); 235 if (!itr) 236 return TEE_ERROR_OUT_OF_MEMORY; 237 itr->session_id = session_id; 238 itr->session_ctx = 0; 239 TAILQ_INSERT_TAIL(&ta_sessions, itr, link); 240 241 return TEE_SUCCESS; 242 } 243 244 static void ta_header_remove_session(uint32_t session_id) 245 { 246 struct ta_session *itr; 247 bool keep_alive; 248 249 TAILQ_FOREACH(itr, &ta_sessions, link) { 250 if (itr->session_id == session_id) { 251 TAILQ_REMOVE(&ta_sessions, itr, link); 252 TEE_Free(itr); 253 254 keep_alive = 255 (ta_head.flags & TA_FLAG_SINGLE_INSTANCE) && 256 (ta_head.flags & TA_FLAG_INSTANCE_KEEP_ALIVE); 257 if (TAILQ_EMPTY(&ta_sessions) && !keep_alive) 258 uninit_instance(); 259 260 return; 261 } 262 } 263 } 264 265 static void to_utee_params(struct utee_params *up, uint32_t param_types, 266 const TEE_Param params[TEE_NUM_PARAMS]) 267 { 268 size_t n = 0; 269 270 up->types = param_types; 271 for (n = 0; n < TEE_NUM_PARAMS; n++) { 272 switch (TEE_PARAM_TYPE_GET(param_types, n)) { 273 case TEE_PARAM_TYPE_VALUE_INPUT: 274 case TEE_PARAM_TYPE_VALUE_OUTPUT: 275 case TEE_PARAM_TYPE_VALUE_INOUT: 276 up->vals[n * 2] = params[n].value.a; 277 up->vals[n * 2 + 1] = params[n].value.b; 278 break; 279 case TEE_PARAM_TYPE_MEMREF_INPUT: 280 case TEE_PARAM_TYPE_MEMREF_OUTPUT: 281 case TEE_PARAM_TYPE_MEMREF_INOUT: 282 up->vals[n * 2] = (uintptr_t)params[n].memref.buffer; 283 up->vals[n * 2 + 1] = params[n].memref.size; 284 break; 285 default: 286 up->vals[n * 2] = 0; 287 up->vals[n * 2 + 1] = 0; 288 break; 289 } 290 } 291 } 292 293 static void from_utee_params(TEE_Param params[TEE_NUM_PARAMS], 294 uint32_t *param_types, 295 const struct utee_params *up) 296 { 297 size_t n; 298 uint32_t types = up->types; 299 300 for (n = 0; n < TEE_NUM_PARAMS; n++) { 301 uintptr_t a = up->vals[n * 2]; 302 uintptr_t b = up->vals[n * 2 + 1]; 303 304 switch (TEE_PARAM_TYPE_GET(types, n)) { 305 case TEE_PARAM_TYPE_VALUE_INPUT: 306 case TEE_PARAM_TYPE_VALUE_OUTPUT: 307 case TEE_PARAM_TYPE_VALUE_INOUT: 308 params[n].value.a = a; 309 params[n].value.b = b; 310 break; 311 case TEE_PARAM_TYPE_MEMREF_INPUT: 312 case TEE_PARAM_TYPE_MEMREF_OUTPUT: 313 case TEE_PARAM_TYPE_MEMREF_INOUT: 314 params[n].memref.buffer = (void *)a; 315 params[n].memref.size = b; 316 break; 317 default: 318 break; 319 } 320 } 321 322 if (param_types) 323 *param_types = types; 324 } 325 326 static TEE_Result entry_open_session(unsigned long session_id, 327 struct utee_params *up) 328 { 329 TEE_Result res; 330 struct ta_session *session; 331 uint32_t param_types; 332 TEE_Param params[TEE_NUM_PARAMS]; 333 334 res = ta_header_add_session(session_id); 335 if (res != TEE_SUCCESS) 336 return res; 337 338 session = ta_header_get_session(session_id); 339 if (!session) 340 return TEE_ERROR_BAD_STATE; 341 342 from_utee_params(params, ¶m_types, up); 343 ta_header_save_params(param_types, params); 344 345 res = TA_OpenSessionEntryPoint(param_types, params, 346 &session->session_ctx); 347 348 to_utee_params(up, param_types, params); 349 350 if (res != TEE_SUCCESS) 351 ta_header_remove_session(session_id); 352 return res; 353 } 354 355 static TEE_Result entry_close_session(unsigned long session_id) 356 { 357 struct ta_session *session = ta_header_get_session(session_id); 358 359 if (!session) 360 return TEE_ERROR_BAD_STATE; 361 362 TA_CloseSessionEntryPoint(session->session_ctx); 363 364 ta_header_remove_session(session_id); 365 return TEE_SUCCESS; 366 } 367 368 static TEE_Result entry_invoke_command(unsigned long session_id, 369 struct utee_params *up, unsigned long cmd_id) 370 { 371 TEE_Result res; 372 uint32_t param_types; 373 TEE_Param params[TEE_NUM_PARAMS]; 374 struct ta_session *session = ta_header_get_session(session_id); 375 376 if (!session) 377 return TEE_ERROR_BAD_STATE; 378 379 from_utee_params(params, ¶m_types, up); 380 ta_header_save_params(param_types, params); 381 382 res = TA_InvokeCommandEntryPoint(session->session_ctx, cmd_id, 383 param_types, params); 384 385 to_utee_params(up, param_types, params); 386 return res; 387 } 388 389 #if defined(CFG_TA_STATS) 390 static TEE_Result entry_dump_memstats(unsigned long session_id __unused, 391 struct utee_params *up) 392 { 393 uint32_t param_types = 0; 394 TEE_Param params[TEE_NUM_PARAMS] = { }; 395 struct pta_stats_alloc stats = { }; 396 397 from_utee_params(params, ¶m_types, up); 398 ta_header_save_params(param_types, params); 399 400 if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT, 401 TEE_PARAM_TYPE_VALUE_OUTPUT, 402 TEE_PARAM_TYPE_VALUE_OUTPUT, 403 TEE_PARAM_TYPE_NONE) != param_types) 404 return TEE_ERROR_BAD_PARAMETERS; 405 406 malloc_get_stats(&stats); 407 params[0].value.a = stats.allocated; 408 params[0].value.b = stats.max_allocated; 409 params[1].value.a = stats.size; 410 params[1].value.b = stats.num_alloc_fail; 411 params[2].value.a = stats.biggest_alloc_fail; 412 params[2].value.b = stats.biggest_alloc_fail_used; 413 to_utee_params(up, param_types, params); 414 415 return TEE_SUCCESS; 416 } 417 #endif 418 419 TEE_Result __utee_entry(unsigned long func, unsigned long session_id, 420 struct utee_params *up, unsigned long cmd_id) 421 { 422 TEE_Result res; 423 424 switch (func) { 425 case UTEE_ENTRY_FUNC_OPEN_SESSION: 426 res = entry_open_session(session_id, up); 427 break; 428 case UTEE_ENTRY_FUNC_CLOSE_SESSION: 429 res = entry_close_session(session_id); 430 break; 431 case UTEE_ENTRY_FUNC_INVOKE_COMMAND: 432 res = entry_invoke_command(session_id, up, cmd_id); 433 break; 434 #if defined(CFG_TA_STATS) 435 case UTEE_ENTRY_FUNC_DUMP_MEMSTATS: 436 res = entry_dump_memstats(session_id, up); 437 break; 438 #endif 439 default: 440 res = TEE_ERROR_NOT_SUPPORTED; 441 break; 442 } 443 ta_header_save_params(0, NULL); 444 445 return res; 446 } 447