1d8e4ae07SMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause 2d8e4ae07SMarouene Boubakri /* 3d8e4ae07SMarouene Boubakri * Copyright (c) 2014, STMicroelectronics International N.V. 4d8e4ae07SMarouene Boubakri * Copyright (c) 2015-2020, 2022 Linaro Limited 5af78e1b1SImre Kis * Copyright (c) 2020-2023, Arm Limited 6d8e4ae07SMarouene Boubakri */ 7d8e4ae07SMarouene Boubakri 8d8e4ae07SMarouene Boubakri #include <assert.h> 9d8e4ae07SMarouene Boubakri #include <kernel/ldelf_loader.h> 10d8e4ae07SMarouene Boubakri #include <kernel/ldelf_syscalls.h> 11d8e4ae07SMarouene Boubakri #include <kernel/scall.h> 12*52e7b1a6SJens Wiklander #include <kernel/user_access.h> 13d8e4ae07SMarouene Boubakri #include <ldelf.h> 14d8e4ae07SMarouene Boubakri #include <mm/mobj.h> 15d8e4ae07SMarouene Boubakri #include <mm/vm.h> 16d8e4ae07SMarouene Boubakri 17c5a0db99SJens Wiklander #define BOUNCE_BUFFER_SIZE 4096 18c5a0db99SJens Wiklander 19d8e4ae07SMarouene Boubakri extern uint8_t ldelf_data[]; 20d8e4ae07SMarouene Boubakri extern const unsigned int ldelf_code_size; 21d8e4ae07SMarouene Boubakri extern const unsigned int ldelf_data_size; 22d8e4ae07SMarouene Boubakri extern const unsigned int ldelf_entry; 23d8e4ae07SMarouene Boubakri 24d8e4ae07SMarouene Boubakri /* ldelf has the same architecture/register width as the kernel */ 25cb5f271cSMarouene Boubakri #if defined(ARM32) || defined(RV32) 26cb5f271cSMarouene Boubakri static const bool is_32bit = true; 27d8e4ae07SMarouene Boubakri #else 28cb5f271cSMarouene Boubakri static const bool is_32bit; 29d8e4ae07SMarouene Boubakri #endif 30d8e4ae07SMarouene Boubakri 31c5a0db99SJens Wiklander static TEE_Result alloc_and_map_fobj(struct user_mode_ctx *uctx, size_t sz, 32c5a0db99SJens Wiklander uint32_t prot, uint32_t flags, vaddr_t *va) 33d8e4ae07SMarouene Boubakri { 34d8e4ae07SMarouene Boubakri size_t num_pgs = ROUNDUP(sz, SMALL_PAGE_SIZE) / SMALL_PAGE_SIZE; 35d8e4ae07SMarouene Boubakri struct fobj *fobj = fobj_ta_mem_alloc(num_pgs); 36d8e4ae07SMarouene Boubakri struct mobj *mobj = mobj_with_fobj_alloc(fobj, NULL, 37d8e4ae07SMarouene Boubakri TEE_MATTR_MEM_TYPE_TAGGED); 38d8e4ae07SMarouene Boubakri TEE_Result res = TEE_SUCCESS; 39d8e4ae07SMarouene Boubakri 40d8e4ae07SMarouene Boubakri fobj_put(fobj); 41d8e4ae07SMarouene Boubakri if (!mobj) 42d8e4ae07SMarouene Boubakri return TEE_ERROR_OUT_OF_MEMORY; 43c5a0db99SJens Wiklander res = vm_map(uctx, va, num_pgs * SMALL_PAGE_SIZE, prot, flags, mobj, 0); 44d8e4ae07SMarouene Boubakri mobj_put(mobj); 45d8e4ae07SMarouene Boubakri 46d8e4ae07SMarouene Boubakri return res; 47d8e4ae07SMarouene Boubakri } 48d8e4ae07SMarouene Boubakri 49d8e4ae07SMarouene Boubakri /* 50d8e4ae07SMarouene Boubakri * This function may leave a few mappings behind on error, but that's taken 51d8e4ae07SMarouene Boubakri * care of by tee_ta_init_user_ta_session() since the entire context is 52d8e4ae07SMarouene Boubakri * removed then. 53d8e4ae07SMarouene Boubakri */ 54d8e4ae07SMarouene Boubakri TEE_Result ldelf_load_ldelf(struct user_mode_ctx *uctx) 55d8e4ae07SMarouene Boubakri { 56d8e4ae07SMarouene Boubakri TEE_Result res = TEE_SUCCESS; 57d8e4ae07SMarouene Boubakri vaddr_t stack_addr = 0; 58d8e4ae07SMarouene Boubakri vaddr_t code_addr = 0; 59d8e4ae07SMarouene Boubakri vaddr_t rw_addr = 0; 60c5a0db99SJens Wiklander vaddr_t bb_addr = 0; 61d8e4ae07SMarouene Boubakri uint32_t prot = 0; 62d8e4ae07SMarouene Boubakri 63cb5f271cSMarouene Boubakri uctx->is_32bit = is_32bit; 64d8e4ae07SMarouene Boubakri 65c5a0db99SJens Wiklander res = alloc_and_map_fobj(uctx, BOUNCE_BUFFER_SIZE, TEE_MATTR_PRW, 0, 66c5a0db99SJens Wiklander &bb_addr); 67c5a0db99SJens Wiklander if (res) 68c5a0db99SJens Wiklander return res; 69c5a0db99SJens Wiklander uctx->bbuf = (void *)bb_addr; 70c5a0db99SJens Wiklander uctx->bbuf_size = BOUNCE_BUFFER_SIZE; 71c5a0db99SJens Wiklander 72c5a0db99SJens Wiklander res = alloc_and_map_fobj(uctx, LDELF_STACK_SIZE, 73c5a0db99SJens Wiklander TEE_MATTR_URW | TEE_MATTR_PRW, VM_FLAG_LDELF, 74d8e4ae07SMarouene Boubakri &stack_addr); 75d8e4ae07SMarouene Boubakri if (res) 76d8e4ae07SMarouene Boubakri return res; 77d8e4ae07SMarouene Boubakri uctx->ldelf_stack_ptr = stack_addr + LDELF_STACK_SIZE; 78d8e4ae07SMarouene Boubakri 79c5a0db99SJens Wiklander res = alloc_and_map_fobj(uctx, ldelf_code_size, TEE_MATTR_PRW, 80c5a0db99SJens Wiklander VM_FLAG_LDELF, &code_addr); 81d8e4ae07SMarouene Boubakri if (res) 82d8e4ae07SMarouene Boubakri return res; 83d8e4ae07SMarouene Boubakri uctx->entry_func = code_addr + ldelf_entry; 84d8e4ae07SMarouene Boubakri 85d8e4ae07SMarouene Boubakri rw_addr = ROUNDUP(code_addr + ldelf_code_size, SMALL_PAGE_SIZE); 86c5a0db99SJens Wiklander res = alloc_and_map_fobj(uctx, ldelf_data_size, 87c5a0db99SJens Wiklander TEE_MATTR_URW | TEE_MATTR_PRW, VM_FLAG_LDELF, 88c5a0db99SJens Wiklander &rw_addr); 89d8e4ae07SMarouene Boubakri if (res) 90d8e4ae07SMarouene Boubakri return res; 91d8e4ae07SMarouene Boubakri 92d8e4ae07SMarouene Boubakri vm_set_ctx(uctx->ts_ctx); 93d8e4ae07SMarouene Boubakri 94d8e4ae07SMarouene Boubakri memcpy((void *)code_addr, ldelf_data, ldelf_code_size); 95*52e7b1a6SJens Wiklander 96*52e7b1a6SJens Wiklander res = copy_to_user((void *)rw_addr, ldelf_data + ldelf_code_size, 97*52e7b1a6SJens Wiklander ldelf_data_size); 98*52e7b1a6SJens Wiklander if (res) 99*52e7b1a6SJens Wiklander return res; 100d8e4ae07SMarouene Boubakri 101d8e4ae07SMarouene Boubakri prot = TEE_MATTR_URX; 102d8e4ae07SMarouene Boubakri if (IS_ENABLED(CFG_CORE_BTI)) 103d8e4ae07SMarouene Boubakri prot |= TEE_MATTR_GUARDED; 104d8e4ae07SMarouene Boubakri 105d8e4ae07SMarouene Boubakri res = vm_set_prot(uctx, code_addr, 106d8e4ae07SMarouene Boubakri ROUNDUP(ldelf_code_size, SMALL_PAGE_SIZE), prot); 107d8e4ae07SMarouene Boubakri if (res) 108d8e4ae07SMarouene Boubakri return res; 109d8e4ae07SMarouene Boubakri 110d8e4ae07SMarouene Boubakri DMSG("ldelf load address %#"PRIxVA, code_addr); 111d8e4ae07SMarouene Boubakri 112d8e4ae07SMarouene Boubakri return TEE_SUCCESS; 113d8e4ae07SMarouene Boubakri } 114d8e4ae07SMarouene Boubakri 115d8e4ae07SMarouene Boubakri TEE_Result ldelf_init_with_ldelf(struct ts_session *sess, 116d8e4ae07SMarouene Boubakri struct user_mode_ctx *uctx) 117d8e4ae07SMarouene Boubakri { 118d8e4ae07SMarouene Boubakri TEE_Result res = TEE_SUCCESS; 119d8e4ae07SMarouene Boubakri struct ldelf_arg *arg = NULL; 120d8e4ae07SMarouene Boubakri uint32_t panic_code = 0; 121d8e4ae07SMarouene Boubakri uint32_t panicked = 0; 122d8e4ae07SMarouene Boubakri uaddr_t usr_stack = 0; 123d8e4ae07SMarouene Boubakri 124d8e4ae07SMarouene Boubakri usr_stack = uctx->ldelf_stack_ptr; 125d8e4ae07SMarouene Boubakri usr_stack -= ROUNDUP(sizeof(*arg), STACK_ALIGNMENT); 126d8e4ae07SMarouene Boubakri arg = (struct ldelf_arg *)usr_stack; 127d8e4ae07SMarouene Boubakri sess->handle_scall = scall_handle_ldelf; 128d8e4ae07SMarouene Boubakri 129*52e7b1a6SJens Wiklander res = clear_user(arg, sizeof(*arg)); 130*52e7b1a6SJens Wiklander if (res) 131*52e7b1a6SJens Wiklander return res; 132*52e7b1a6SJens Wiklander 133*52e7b1a6SJens Wiklander res = PUT_USER_SCALAR(uctx->ts_ctx->uuid, &arg->uuid); 134*52e7b1a6SJens Wiklander if (res) 135*52e7b1a6SJens Wiklander return res; 136*52e7b1a6SJens Wiklander 137d8e4ae07SMarouene Boubakri res = thread_enter_user_mode((vaddr_t)arg, 0, 0, 0, 138d8e4ae07SMarouene Boubakri usr_stack, uctx->entry_func, 139cb5f271cSMarouene Boubakri is_32bit, &panicked, &panic_code); 140d8e4ae07SMarouene Boubakri 141d8e4ae07SMarouene Boubakri sess->handle_scall = sess->ctx->ops->handle_scall; 142d8e4ae07SMarouene Boubakri thread_user_clear_vfp(uctx); 143d8e4ae07SMarouene Boubakri ldelf_sess_cleanup(sess); 144d8e4ae07SMarouene Boubakri 145d8e4ae07SMarouene Boubakri if (panicked) { 146d8e4ae07SMarouene Boubakri abort_print_current_ts(); 147d8e4ae07SMarouene Boubakri EMSG("ldelf panicked"); 148d8e4ae07SMarouene Boubakri return TEE_ERROR_GENERIC; 149d8e4ae07SMarouene Boubakri } 150d8e4ae07SMarouene Boubakri if (res) { 151d8e4ae07SMarouene Boubakri EMSG("ldelf failed with res: %#"PRIx32, res); 152d8e4ae07SMarouene Boubakri return res; 153d8e4ae07SMarouene Boubakri } 154d8e4ae07SMarouene Boubakri 155d8e4ae07SMarouene Boubakri res = vm_check_access_rights(uctx, 156d8e4ae07SMarouene Boubakri TEE_MEMORY_ACCESS_READ | 157d8e4ae07SMarouene Boubakri TEE_MEMORY_ACCESS_ANY_OWNER, 158d8e4ae07SMarouene Boubakri (uaddr_t)arg, sizeof(*arg)); 159d8e4ae07SMarouene Boubakri if (res) 160d8e4ae07SMarouene Boubakri return res; 161d8e4ae07SMarouene Boubakri 162d8e4ae07SMarouene Boubakri if (is_user_ta_ctx(uctx->ts_ctx)) { 163d8e4ae07SMarouene Boubakri /* 164d8e4ae07SMarouene Boubakri * This is already checked by the elf loader, but since it runs 165d8e4ae07SMarouene Boubakri * in user mode we're not trusting it entirely. 166d8e4ae07SMarouene Boubakri */ 167d8e4ae07SMarouene Boubakri if (arg->flags & ~TA_FLAGS_MASK) 168d8e4ae07SMarouene Boubakri return TEE_ERROR_BAD_FORMAT; 169d8e4ae07SMarouene Boubakri 170d8e4ae07SMarouene Boubakri to_user_ta_ctx(uctx->ts_ctx)->ta_ctx.flags = arg->flags; 171d8e4ae07SMarouene Boubakri } 172d8e4ae07SMarouene Boubakri 173d8e4ae07SMarouene Boubakri uctx->is_32bit = arg->is_32bit; 174d8e4ae07SMarouene Boubakri uctx->entry_func = arg->entry_func; 175af78e1b1SImre Kis uctx->load_addr = arg->load_addr; 176d8e4ae07SMarouene Boubakri uctx->stack_ptr = arg->stack_ptr; 177d8e4ae07SMarouene Boubakri uctx->dump_entry_func = arg->dump_entry; 178d8e4ae07SMarouene Boubakri #ifdef CFG_FTRACE_SUPPORT 179d8e4ae07SMarouene Boubakri uctx->ftrace_entry_func = arg->ftrace_entry; 180d8e4ae07SMarouene Boubakri sess->fbuf = arg->fbuf; 181d8e4ae07SMarouene Boubakri #endif 182d8e4ae07SMarouene Boubakri uctx->dl_entry_func = arg->dl_entry; 183d8e4ae07SMarouene Boubakri 184d8e4ae07SMarouene Boubakri return TEE_SUCCESS; 185d8e4ae07SMarouene Boubakri } 186d8e4ae07SMarouene Boubakri 187d8e4ae07SMarouene Boubakri TEE_Result ldelf_dump_state(struct user_mode_ctx *uctx) 188d8e4ae07SMarouene Boubakri { 189d8e4ae07SMarouene Boubakri TEE_Result res = TEE_SUCCESS; 190d8e4ae07SMarouene Boubakri uaddr_t usr_stack = uctx->ldelf_stack_ptr; 191d8e4ae07SMarouene Boubakri struct dump_entry_arg *arg = NULL; 192d8e4ae07SMarouene Boubakri uint32_t panic_code = 0; 193d8e4ae07SMarouene Boubakri uint32_t panicked = 0; 194d8e4ae07SMarouene Boubakri struct thread_specific_data *tsd = thread_get_tsd(); 195d8e4ae07SMarouene Boubakri struct ts_session *sess = NULL; 196d8e4ae07SMarouene Boubakri struct vm_region *r = NULL; 197*52e7b1a6SJens Wiklander size_t arg_size = 0; 198d8e4ae07SMarouene Boubakri size_t n = 0; 199d8e4ae07SMarouene Boubakri 200d8e4ae07SMarouene Boubakri TAILQ_FOREACH(r, &uctx->vm_info.regions, link) 201d8e4ae07SMarouene Boubakri if (r->attr & TEE_MATTR_URWX) 202d8e4ae07SMarouene Boubakri n++; 203d8e4ae07SMarouene Boubakri 204*52e7b1a6SJens Wiklander arg_size = ROUNDUP(sizeof(*arg) + n * sizeof(struct dump_map), 205d8e4ae07SMarouene Boubakri STACK_ALIGNMENT); 206d8e4ae07SMarouene Boubakri 207*52e7b1a6SJens Wiklander usr_stack = uctx->ldelf_stack_ptr; 208*52e7b1a6SJens Wiklander usr_stack -= arg_size; 209d8e4ae07SMarouene Boubakri 210*52e7b1a6SJens Wiklander arg = bb_alloc(arg_size); 211*52e7b1a6SJens Wiklander if (!arg) 212*52e7b1a6SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 213*52e7b1a6SJens Wiklander memset(arg, 0, arg_size); 214d8e4ae07SMarouene Boubakri 215d8e4ae07SMarouene Boubakri arg->num_maps = n; 216d8e4ae07SMarouene Boubakri n = 0; 217d8e4ae07SMarouene Boubakri TAILQ_FOREACH(r, &uctx->vm_info.regions, link) { 218d8e4ae07SMarouene Boubakri if (r->attr & TEE_MATTR_URWX) { 219d8e4ae07SMarouene Boubakri if (r->mobj) 220d8e4ae07SMarouene Boubakri mobj_get_pa(r->mobj, r->offset, 0, 221d8e4ae07SMarouene Boubakri &arg->maps[n].pa); 222d8e4ae07SMarouene Boubakri arg->maps[n].va = r->va; 223d8e4ae07SMarouene Boubakri arg->maps[n].sz = r->size; 224d8e4ae07SMarouene Boubakri if (r->attr & TEE_MATTR_UR) 225d8e4ae07SMarouene Boubakri arg->maps[n].flags |= DUMP_MAP_READ; 226d8e4ae07SMarouene Boubakri if (r->attr & TEE_MATTR_UW) 227d8e4ae07SMarouene Boubakri arg->maps[n].flags |= DUMP_MAP_WRITE; 228d8e4ae07SMarouene Boubakri if (r->attr & TEE_MATTR_UX) 229d8e4ae07SMarouene Boubakri arg->maps[n].flags |= DUMP_MAP_EXEC; 230d8e4ae07SMarouene Boubakri if (r->attr & TEE_MATTR_SECURE) 231d8e4ae07SMarouene Boubakri arg->maps[n].flags |= DUMP_MAP_SECURE; 232d8e4ae07SMarouene Boubakri if (r->flags & VM_FLAG_EPHEMERAL) 233d8e4ae07SMarouene Boubakri arg->maps[n].flags |= DUMP_MAP_EPHEM; 234d8e4ae07SMarouene Boubakri if (r->flags & VM_FLAG_LDELF) 235d8e4ae07SMarouene Boubakri arg->maps[n].flags |= DUMP_MAP_LDELF; 236d8e4ae07SMarouene Boubakri n++; 237d8e4ae07SMarouene Boubakri } 238d8e4ae07SMarouene Boubakri } 239d8e4ae07SMarouene Boubakri 240cb5f271cSMarouene Boubakri arg->is_32bit = uctx->is_32bit; 241d8e4ae07SMarouene Boubakri #ifdef ARM32 242d8e4ae07SMarouene Boubakri arg->arm32.regs[0] = tsd->abort_regs.r0; 243d8e4ae07SMarouene Boubakri arg->arm32.regs[1] = tsd->abort_regs.r1; 244d8e4ae07SMarouene Boubakri arg->arm32.regs[2] = tsd->abort_regs.r2; 245d8e4ae07SMarouene Boubakri arg->arm32.regs[3] = tsd->abort_regs.r3; 246d8e4ae07SMarouene Boubakri arg->arm32.regs[4] = tsd->abort_regs.r4; 247d8e4ae07SMarouene Boubakri arg->arm32.regs[5] = tsd->abort_regs.r5; 248d8e4ae07SMarouene Boubakri arg->arm32.regs[6] = tsd->abort_regs.r6; 249d8e4ae07SMarouene Boubakri arg->arm32.regs[7] = tsd->abort_regs.r7; 250d8e4ae07SMarouene Boubakri arg->arm32.regs[8] = tsd->abort_regs.r8; 251d8e4ae07SMarouene Boubakri arg->arm32.regs[9] = tsd->abort_regs.r9; 252d8e4ae07SMarouene Boubakri arg->arm32.regs[10] = tsd->abort_regs.r10; 253d8e4ae07SMarouene Boubakri arg->arm32.regs[11] = tsd->abort_regs.r11; 254d8e4ae07SMarouene Boubakri arg->arm32.regs[12] = tsd->abort_regs.ip; 255d8e4ae07SMarouene Boubakri arg->arm32.regs[13] = tsd->abort_regs.usr_sp; /*SP*/ 256d8e4ae07SMarouene Boubakri arg->arm32.regs[14] = tsd->abort_regs.usr_lr; /*LR*/ 257d8e4ae07SMarouene Boubakri arg->arm32.regs[15] = tsd->abort_regs.elr; /*PC*/ 258d8e4ae07SMarouene Boubakri #endif /*ARM32*/ 259d8e4ae07SMarouene Boubakri #ifdef ARM64 260d8e4ae07SMarouene Boubakri if (uctx->is_32bit) { 261d8e4ae07SMarouene Boubakri arg->arm32.regs[0] = tsd->abort_regs.x0; 262d8e4ae07SMarouene Boubakri arg->arm32.regs[1] = tsd->abort_regs.x1; 263d8e4ae07SMarouene Boubakri arg->arm32.regs[2] = tsd->abort_regs.x2; 264d8e4ae07SMarouene Boubakri arg->arm32.regs[3] = tsd->abort_regs.x3; 265d8e4ae07SMarouene Boubakri arg->arm32.regs[4] = tsd->abort_regs.x4; 266d8e4ae07SMarouene Boubakri arg->arm32.regs[5] = tsd->abort_regs.x5; 267d8e4ae07SMarouene Boubakri arg->arm32.regs[6] = tsd->abort_regs.x6; 268d8e4ae07SMarouene Boubakri arg->arm32.regs[7] = tsd->abort_regs.x7; 269d8e4ae07SMarouene Boubakri arg->arm32.regs[8] = tsd->abort_regs.x8; 270d8e4ae07SMarouene Boubakri arg->arm32.regs[9] = tsd->abort_regs.x9; 271d8e4ae07SMarouene Boubakri arg->arm32.regs[10] = tsd->abort_regs.x10; 272d8e4ae07SMarouene Boubakri arg->arm32.regs[11] = tsd->abort_regs.x11; 273d8e4ae07SMarouene Boubakri arg->arm32.regs[12] = tsd->abort_regs.x12; 274d8e4ae07SMarouene Boubakri arg->arm32.regs[13] = tsd->abort_regs.x13; /*SP*/ 275d8e4ae07SMarouene Boubakri arg->arm32.regs[14] = tsd->abort_regs.x14; /*LR*/ 276d8e4ae07SMarouene Boubakri arg->arm32.regs[15] = tsd->abort_regs.elr; /*PC*/ 277d8e4ae07SMarouene Boubakri } else { 278d8e4ae07SMarouene Boubakri arg->arm64.fp = tsd->abort_regs.x29; 279d8e4ae07SMarouene Boubakri arg->arm64.pc = tsd->abort_regs.elr; 280d8e4ae07SMarouene Boubakri arg->arm64.sp = tsd->abort_regs.sp_el0; 281d8e4ae07SMarouene Boubakri } 282d8e4ae07SMarouene Boubakri #endif /*ARM64*/ 28374f6dd9bSMarouene Boubakri #if defined(RV64) || defined(RV32) 28474f6dd9bSMarouene Boubakri arg->rv.fp = tsd->abort_regs.s0; 28574f6dd9bSMarouene Boubakri arg->rv.pc = tsd->abort_regs.epc; 28674f6dd9bSMarouene Boubakri arg->rv.sp = tsd->abort_regs.sp; 28774f6dd9bSMarouene Boubakri #endif /*RV64||RV32*/ 288d8e4ae07SMarouene Boubakri 289*52e7b1a6SJens Wiklander res = copy_to_user((void *)usr_stack, arg, arg_size); 290*52e7b1a6SJens Wiklander if (res) 291*52e7b1a6SJens Wiklander return res; 292*52e7b1a6SJens Wiklander 293d8e4ae07SMarouene Boubakri sess = ts_get_current_session(); 294d8e4ae07SMarouene Boubakri sess->handle_scall = scall_handle_ldelf; 295d8e4ae07SMarouene Boubakri 296*52e7b1a6SJens Wiklander res = thread_enter_user_mode(usr_stack, 0, 0, 0, 297d8e4ae07SMarouene Boubakri usr_stack, uctx->dump_entry_func, 298cb5f271cSMarouene Boubakri is_32bit, &panicked, &panic_code); 299d8e4ae07SMarouene Boubakri 300d8e4ae07SMarouene Boubakri sess->handle_scall = sess->ctx->ops->handle_scall; 301d8e4ae07SMarouene Boubakri thread_user_clear_vfp(uctx); 302d8e4ae07SMarouene Boubakri ldelf_sess_cleanup(sess); 303d8e4ae07SMarouene Boubakri 304d8e4ae07SMarouene Boubakri if (panicked) { 305d8e4ae07SMarouene Boubakri uctx->dump_entry_func = 0; 306d8e4ae07SMarouene Boubakri EMSG("ldelf dump function panicked"); 307d8e4ae07SMarouene Boubakri abort_print_current_ts(); 308d8e4ae07SMarouene Boubakri res = TEE_ERROR_TARGET_DEAD; 309d8e4ae07SMarouene Boubakri } 310d8e4ae07SMarouene Boubakri 311d8e4ae07SMarouene Boubakri return res; 312d8e4ae07SMarouene Boubakri } 313d8e4ae07SMarouene Boubakri 314d8e4ae07SMarouene Boubakri #ifdef CFG_FTRACE_SUPPORT 315d8e4ae07SMarouene Boubakri TEE_Result ldelf_dump_ftrace(struct user_mode_ctx *uctx, 316d8e4ae07SMarouene Boubakri void *buf, size_t *blen) 317d8e4ae07SMarouene Boubakri { 318d8e4ae07SMarouene Boubakri uaddr_t usr_stack = uctx->ldelf_stack_ptr; 319d8e4ae07SMarouene Boubakri TEE_Result res = TEE_SUCCESS; 320d8e4ae07SMarouene Boubakri uint32_t panic_code = 0; 321d8e4ae07SMarouene Boubakri uint32_t panicked = 0; 322d8e4ae07SMarouene Boubakri size_t *arg = NULL; 323d8e4ae07SMarouene Boubakri struct ts_session *sess = NULL; 324d8e4ae07SMarouene Boubakri 325d8e4ae07SMarouene Boubakri if (!uctx->ftrace_entry_func) 326d8e4ae07SMarouene Boubakri return TEE_ERROR_NOT_SUPPORTED; 327d8e4ae07SMarouene Boubakri 328d8e4ae07SMarouene Boubakri usr_stack -= ROUNDUP(sizeof(*arg), STACK_ALIGNMENT); 329d8e4ae07SMarouene Boubakri arg = (size_t *)usr_stack; 330d8e4ae07SMarouene Boubakri 331d8e4ae07SMarouene Boubakri res = vm_check_access_rights(uctx, 332d8e4ae07SMarouene Boubakri TEE_MEMORY_ACCESS_READ | 333d8e4ae07SMarouene Boubakri TEE_MEMORY_ACCESS_ANY_OWNER, 334d8e4ae07SMarouene Boubakri (uaddr_t)arg, sizeof(*arg)); 335d8e4ae07SMarouene Boubakri if (res) { 336d8e4ae07SMarouene Boubakri EMSG("ldelf stack is inaccessible!"); 337d8e4ae07SMarouene Boubakri return res; 338d8e4ae07SMarouene Boubakri } 339d8e4ae07SMarouene Boubakri 340d8e4ae07SMarouene Boubakri *arg = *blen; 341d8e4ae07SMarouene Boubakri 342d8e4ae07SMarouene Boubakri sess = ts_get_current_session(); 343d8e4ae07SMarouene Boubakri sess->handle_scall = scall_handle_ldelf; 344d8e4ae07SMarouene Boubakri 345d8e4ae07SMarouene Boubakri res = thread_enter_user_mode((vaddr_t)buf, (vaddr_t)arg, 0, 0, 346d8e4ae07SMarouene Boubakri usr_stack, uctx->ftrace_entry_func, 347cb5f271cSMarouene Boubakri is_32bit, &panicked, &panic_code); 348d8e4ae07SMarouene Boubakri 349d8e4ae07SMarouene Boubakri sess->handle_scall = sess->ctx->ops->handle_scall; 350d8e4ae07SMarouene Boubakri thread_user_clear_vfp(uctx); 351d8e4ae07SMarouene Boubakri ldelf_sess_cleanup(sess); 352d8e4ae07SMarouene Boubakri 353d8e4ae07SMarouene Boubakri if (panicked) { 354d8e4ae07SMarouene Boubakri uctx->ftrace_entry_func = 0; 355d8e4ae07SMarouene Boubakri EMSG("ldelf ftrace function panicked"); 356d8e4ae07SMarouene Boubakri abort_print_current_ts(); 357d8e4ae07SMarouene Boubakri res = TEE_ERROR_TARGET_DEAD; 358d8e4ae07SMarouene Boubakri } 359d8e4ae07SMarouene Boubakri 360d8e4ae07SMarouene Boubakri if (!res) { 361d8e4ae07SMarouene Boubakri if (*arg > *blen) 362d8e4ae07SMarouene Boubakri res = TEE_ERROR_SHORT_BUFFER; 363d8e4ae07SMarouene Boubakri *blen = *arg; 364d8e4ae07SMarouene Boubakri } 365d8e4ae07SMarouene Boubakri 366d8e4ae07SMarouene Boubakri return res; 367d8e4ae07SMarouene Boubakri } 368d8e4ae07SMarouene Boubakri #endif /*CFG_FTRACE_SUPPORT*/ 369d8e4ae07SMarouene Boubakri 370d8e4ae07SMarouene Boubakri TEE_Result ldelf_dlopen(struct user_mode_ctx *uctx, TEE_UUID *uuid, 371d8e4ae07SMarouene Boubakri uint32_t flags) 372d8e4ae07SMarouene Boubakri { 373d8e4ae07SMarouene Boubakri uaddr_t usr_stack = uctx->ldelf_stack_ptr; 374d8e4ae07SMarouene Boubakri TEE_Result res = TEE_ERROR_GENERIC; 375d8e4ae07SMarouene Boubakri struct dl_entry_arg *arg = NULL; 376d8e4ae07SMarouene Boubakri uint32_t panic_code = 0; 377d8e4ae07SMarouene Boubakri uint32_t panicked = 0; 378d8e4ae07SMarouene Boubakri struct ts_session *sess = NULL; 379d8e4ae07SMarouene Boubakri 380d8e4ae07SMarouene Boubakri assert(uuid); 381d8e4ae07SMarouene Boubakri 382*52e7b1a6SJens Wiklander arg = bb_alloc(sizeof(*arg)); 383*52e7b1a6SJens Wiklander if (!arg) 384*52e7b1a6SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 385d8e4ae07SMarouene Boubakri 386d8e4ae07SMarouene Boubakri memset(arg, 0, sizeof(*arg)); 387d8e4ae07SMarouene Boubakri arg->cmd = LDELF_DL_ENTRY_DLOPEN; 388d8e4ae07SMarouene Boubakri arg->dlopen.uuid = *uuid; 389d8e4ae07SMarouene Boubakri arg->dlopen.flags = flags; 390d8e4ae07SMarouene Boubakri 391*52e7b1a6SJens Wiklander usr_stack -= ROUNDUP(sizeof(*arg), STACK_ALIGNMENT); 392*52e7b1a6SJens Wiklander 393*52e7b1a6SJens Wiklander res = copy_to_user((void *)usr_stack, arg, sizeof(*arg)); 394*52e7b1a6SJens Wiklander if (res) 395*52e7b1a6SJens Wiklander return res; 396*52e7b1a6SJens Wiklander 397d8e4ae07SMarouene Boubakri sess = ts_get_current_session(); 398d8e4ae07SMarouene Boubakri sess->handle_scall = scall_handle_ldelf; 399d8e4ae07SMarouene Boubakri 400*52e7b1a6SJens Wiklander res = thread_enter_user_mode(usr_stack, 0, 0, 0, 401d8e4ae07SMarouene Boubakri usr_stack, uctx->dl_entry_func, 402cb5f271cSMarouene Boubakri is_32bit, &panicked, &panic_code); 403d8e4ae07SMarouene Boubakri 404d8e4ae07SMarouene Boubakri sess->handle_scall = sess->ctx->ops->handle_scall; 405d8e4ae07SMarouene Boubakri ldelf_sess_cleanup(sess); 406d8e4ae07SMarouene Boubakri 407d8e4ae07SMarouene Boubakri if (panicked) { 408d8e4ae07SMarouene Boubakri EMSG("ldelf dl_entry function panicked"); 409d8e4ae07SMarouene Boubakri abort_print_current_ts(); 410d8e4ae07SMarouene Boubakri res = TEE_ERROR_TARGET_DEAD; 411d8e4ae07SMarouene Boubakri } 412d8e4ae07SMarouene Boubakri if (!res) 413d8e4ae07SMarouene Boubakri res = arg->ret; 414d8e4ae07SMarouene Boubakri 415d8e4ae07SMarouene Boubakri return res; 416d8e4ae07SMarouene Boubakri } 417d8e4ae07SMarouene Boubakri 418d8e4ae07SMarouene Boubakri TEE_Result ldelf_dlsym(struct user_mode_ctx *uctx, TEE_UUID *uuid, 419*52e7b1a6SJens Wiklander const char *sym, size_t symlen, vaddr_t *val) 420d8e4ae07SMarouene Boubakri { 421d8e4ae07SMarouene Boubakri uaddr_t usr_stack = uctx->ldelf_stack_ptr; 422d8e4ae07SMarouene Boubakri TEE_Result res = TEE_ERROR_GENERIC; 423*52e7b1a6SJens Wiklander struct dl_entry_arg *usr_arg = NULL; 424d8e4ae07SMarouene Boubakri struct dl_entry_arg *arg = NULL; 425d8e4ae07SMarouene Boubakri uint32_t panic_code = 0; 426d8e4ae07SMarouene Boubakri uint32_t panicked = 0; 427d8e4ae07SMarouene Boubakri struct ts_session *sess = NULL; 428d8e4ae07SMarouene Boubakri 429*52e7b1a6SJens Wiklander usr_stack -= ROUNDUP(sizeof(*arg) + symlen + 1, STACK_ALIGNMENT); 430*52e7b1a6SJens Wiklander usr_arg = (void *)usr_stack; 431*52e7b1a6SJens Wiklander arg = bb_alloc(sizeof(*arg)); 432*52e7b1a6SJens Wiklander if (!arg) 433*52e7b1a6SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 434d8e4ae07SMarouene Boubakri memset(arg, 0, sizeof(*arg)); 435d8e4ae07SMarouene Boubakri arg->cmd = LDELF_DL_ENTRY_DLSYM; 436d8e4ae07SMarouene Boubakri arg->dlsym.uuid = *uuid; 437*52e7b1a6SJens Wiklander res = copy_to_user(usr_arg, arg, sizeof(*arg)); 438*52e7b1a6SJens Wiklander if (res) 439*52e7b1a6SJens Wiklander return res; 440*52e7b1a6SJens Wiklander res = copy_to_user(usr_arg->dlsym.symbol, sym, symlen + 1); 441*52e7b1a6SJens Wiklander if (res) 442*52e7b1a6SJens Wiklander return res; 443d8e4ae07SMarouene Boubakri 444d8e4ae07SMarouene Boubakri sess = ts_get_current_session(); 445d8e4ae07SMarouene Boubakri sess->handle_scall = scall_handle_ldelf; 446d8e4ae07SMarouene Boubakri 447*52e7b1a6SJens Wiklander res = thread_enter_user_mode((vaddr_t)usr_arg, 0, 0, 0, 448d8e4ae07SMarouene Boubakri usr_stack, uctx->dl_entry_func, 449cb5f271cSMarouene Boubakri is_32bit, &panicked, &panic_code); 450d8e4ae07SMarouene Boubakri 451d8e4ae07SMarouene Boubakri sess->handle_scall = sess->ctx->ops->handle_scall; 452d8e4ae07SMarouene Boubakri ldelf_sess_cleanup(sess); 453d8e4ae07SMarouene Boubakri 454d8e4ae07SMarouene Boubakri if (panicked) { 455d8e4ae07SMarouene Boubakri EMSG("ldelf dl_entry function panicked"); 456d8e4ae07SMarouene Boubakri abort_print_current_ts(); 457d8e4ae07SMarouene Boubakri res = TEE_ERROR_TARGET_DEAD; 458d8e4ae07SMarouene Boubakri } 459d8e4ae07SMarouene Boubakri if (!res) { 460*52e7b1a6SJens Wiklander TEE_Result res2 = TEE_SUCCESS; 461*52e7b1a6SJens Wiklander 462*52e7b1a6SJens Wiklander res2 = GET_USER_SCALAR(res, &usr_arg->ret); 463*52e7b1a6SJens Wiklander if (res2) 464*52e7b1a6SJens Wiklander res = res2; 465d8e4ae07SMarouene Boubakri if (!res) 466*52e7b1a6SJens Wiklander res = GET_USER_SCALAR(*val, &usr_arg->dlsym.val); 467d8e4ae07SMarouene Boubakri } 468d8e4ae07SMarouene Boubakri 469d8e4ae07SMarouene Boubakri return res; 470d8e4ae07SMarouene Boubakri } 471