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>
1252e7b1a6SJens 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
alloc_and_map_fobj(struct user_mode_ctx * uctx,size_t sz,uint32_t prot,uint32_t flags,vaddr_t * va)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 {
34*04e46975SEtienne Carriere size_t num_pgs = ROUNDUP_DIV(sz, 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 */
ldelf_load_ldelf(struct user_mode_ctx * uctx)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);
9552e7b1a6SJens Wiklander
9652e7b1a6SJens Wiklander res = copy_to_user((void *)rw_addr, ldelf_data + ldelf_code_size,
9752e7b1a6SJens Wiklander ldelf_data_size);
9852e7b1a6SJens Wiklander if (res)
9952e7b1a6SJens 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
ldelf_init_with_ldelf(struct ts_session * sess,struct user_mode_ctx * uctx)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;
123415e25bbSAlvin Chang struct ldelf_arg *arg_bbuf = NULL;
124d8e4ae07SMarouene Boubakri
125d8e4ae07SMarouene Boubakri usr_stack = uctx->ldelf_stack_ptr;
126d8e4ae07SMarouene Boubakri usr_stack -= ROUNDUP(sizeof(*arg), STACK_ALIGNMENT);
127d8e4ae07SMarouene Boubakri arg = (struct ldelf_arg *)usr_stack;
128d8e4ae07SMarouene Boubakri sess->handle_scall = scall_handle_ldelf;
129d8e4ae07SMarouene Boubakri
13052e7b1a6SJens Wiklander res = clear_user(arg, sizeof(*arg));
13152e7b1a6SJens Wiklander if (res)
13252e7b1a6SJens Wiklander return res;
13352e7b1a6SJens Wiklander
13452e7b1a6SJens Wiklander res = PUT_USER_SCALAR(uctx->ts_ctx->uuid, &arg->uuid);
13552e7b1a6SJens Wiklander if (res)
13652e7b1a6SJens Wiklander return res;
13752e7b1a6SJens Wiklander
138d8e4ae07SMarouene Boubakri res = thread_enter_user_mode((vaddr_t)arg, 0, 0, 0,
139d8e4ae07SMarouene Boubakri usr_stack, uctx->entry_func,
140cb5f271cSMarouene Boubakri is_32bit, &panicked, &panic_code);
141d8e4ae07SMarouene Boubakri
142d8e4ae07SMarouene Boubakri sess->handle_scall = sess->ctx->ops->handle_scall;
143d8e4ae07SMarouene Boubakri thread_user_clear_vfp(uctx);
144d8e4ae07SMarouene Boubakri ldelf_sess_cleanup(sess);
145d8e4ae07SMarouene Boubakri
146d8e4ae07SMarouene Boubakri if (panicked) {
147d8e4ae07SMarouene Boubakri abort_print_current_ts();
148d8e4ae07SMarouene Boubakri EMSG("ldelf panicked");
149d8e4ae07SMarouene Boubakri return TEE_ERROR_GENERIC;
150d8e4ae07SMarouene Boubakri }
151d8e4ae07SMarouene Boubakri if (res) {
152d8e4ae07SMarouene Boubakri EMSG("ldelf failed with res: %#"PRIx32, res);
153d8e4ae07SMarouene Boubakri return res;
154d8e4ae07SMarouene Boubakri }
155d8e4ae07SMarouene Boubakri
1568670803bSJens Wiklander res = BB_MEMDUP_USER(arg, sizeof(*arg), &arg_bbuf);
157d8e4ae07SMarouene Boubakri if (res)
158d8e4ae07SMarouene Boubakri return res;
159d8e4ae07SMarouene Boubakri
160d8e4ae07SMarouene Boubakri if (is_user_ta_ctx(uctx->ts_ctx)) {
161d8e4ae07SMarouene Boubakri /*
162d8e4ae07SMarouene Boubakri * This is already checked by the elf loader, but since it runs
163d8e4ae07SMarouene Boubakri * in user mode we're not trusting it entirely.
164d8e4ae07SMarouene Boubakri */
165415e25bbSAlvin Chang if (arg_bbuf->flags & ~TA_FLAGS_MASK)
166d8e4ae07SMarouene Boubakri return TEE_ERROR_BAD_FORMAT;
167d8e4ae07SMarouene Boubakri
168415e25bbSAlvin Chang to_user_ta_ctx(uctx->ts_ctx)->ta_ctx.flags = arg_bbuf->flags;
169d8e4ae07SMarouene Boubakri }
170d8e4ae07SMarouene Boubakri
171415e25bbSAlvin Chang uctx->is_32bit = arg_bbuf->is_32bit;
172415e25bbSAlvin Chang uctx->entry_func = arg_bbuf->entry_func;
173415e25bbSAlvin Chang uctx->load_addr = arg_bbuf->load_addr;
174415e25bbSAlvin Chang uctx->stack_ptr = arg_bbuf->stack_ptr;
175415e25bbSAlvin Chang uctx->dump_entry_func = arg_bbuf->dump_entry;
176d8e4ae07SMarouene Boubakri #ifdef CFG_FTRACE_SUPPORT
177415e25bbSAlvin Chang uctx->ftrace_entry_func = arg_bbuf->ftrace_entry;
178415e25bbSAlvin Chang sess->fbuf = arg_bbuf->fbuf;
179d8e4ae07SMarouene Boubakri #endif
180415e25bbSAlvin Chang uctx->dl_entry_func = arg_bbuf->dl_entry;
181415e25bbSAlvin Chang
1828670803bSJens Wiklander bb_free(arg_bbuf, sizeof(*arg));
183d8e4ae07SMarouene Boubakri
184d8e4ae07SMarouene Boubakri return TEE_SUCCESS;
185d8e4ae07SMarouene Boubakri }
186d8e4ae07SMarouene Boubakri
ldelf_dump_state(struct user_mode_ctx * uctx)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;
19752e7b1a6SJens 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
20452e7b1a6SJens Wiklander arg_size = ROUNDUP(sizeof(*arg) + n * sizeof(struct dump_map),
205d8e4ae07SMarouene Boubakri STACK_ALIGNMENT);
206d8e4ae07SMarouene Boubakri
20752e7b1a6SJens Wiklander usr_stack = uctx->ldelf_stack_ptr;
20852e7b1a6SJens Wiklander usr_stack -= arg_size;
209d8e4ae07SMarouene Boubakri
21052e7b1a6SJens Wiklander arg = bb_alloc(arg_size);
21152e7b1a6SJens Wiklander if (!arg)
21252e7b1a6SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
21352e7b1a6SJens 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
28952e7b1a6SJens Wiklander res = copy_to_user((void *)usr_stack, arg, arg_size);
29052e7b1a6SJens Wiklander if (res)
29152e7b1a6SJens Wiklander return res;
29252e7b1a6SJens Wiklander
293d8e4ae07SMarouene Boubakri sess = ts_get_current_session();
294d8e4ae07SMarouene Boubakri sess->handle_scall = scall_handle_ldelf;
295d8e4ae07SMarouene Boubakri
29652e7b1a6SJens 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
ldelf_dump_ftrace(struct user_mode_ctx * uctx,void * buf,size_t * blen)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
ldelf_dlopen(struct user_mode_ctx * uctx,TEE_UUID * uuid,uint32_t flags)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;
375031dca8eSJens Wiklander struct dl_entry_arg *usr_arg = NULL;
376d8e4ae07SMarouene Boubakri struct dl_entry_arg *arg = NULL;
377d8e4ae07SMarouene Boubakri uint32_t panic_code = 0;
378d8e4ae07SMarouene Boubakri uint32_t panicked = 0;
379d8e4ae07SMarouene Boubakri struct ts_session *sess = NULL;
380d8e4ae07SMarouene Boubakri
381d8e4ae07SMarouene Boubakri assert(uuid);
382d8e4ae07SMarouene Boubakri
38352e7b1a6SJens Wiklander arg = bb_alloc(sizeof(*arg));
38452e7b1a6SJens Wiklander if (!arg)
38552e7b1a6SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
386d8e4ae07SMarouene Boubakri
387d8e4ae07SMarouene Boubakri memset(arg, 0, sizeof(*arg));
388d8e4ae07SMarouene Boubakri arg->cmd = LDELF_DL_ENTRY_DLOPEN;
389d8e4ae07SMarouene Boubakri arg->dlopen.uuid = *uuid;
390d8e4ae07SMarouene Boubakri arg->dlopen.flags = flags;
391d8e4ae07SMarouene Boubakri
39252e7b1a6SJens Wiklander usr_stack -= ROUNDUP(sizeof(*arg), STACK_ALIGNMENT);
393031dca8eSJens Wiklander usr_arg = (void *)usr_stack;
39452e7b1a6SJens Wiklander
395031dca8eSJens Wiklander res = copy_to_user(usr_arg, arg, sizeof(*arg));
39652e7b1a6SJens Wiklander if (res)
39752e7b1a6SJens Wiklander return res;
39852e7b1a6SJens Wiklander
399d8e4ae07SMarouene Boubakri sess = ts_get_current_session();
400d8e4ae07SMarouene Boubakri sess->handle_scall = scall_handle_ldelf;
401d8e4ae07SMarouene Boubakri
40252e7b1a6SJens Wiklander res = thread_enter_user_mode(usr_stack, 0, 0, 0,
403d8e4ae07SMarouene Boubakri usr_stack, uctx->dl_entry_func,
404cb5f271cSMarouene Boubakri is_32bit, &panicked, &panic_code);
405d8e4ae07SMarouene Boubakri
406d8e4ae07SMarouene Boubakri sess->handle_scall = sess->ctx->ops->handle_scall;
407d8e4ae07SMarouene Boubakri ldelf_sess_cleanup(sess);
408d8e4ae07SMarouene Boubakri
409d8e4ae07SMarouene Boubakri if (panicked) {
410d8e4ae07SMarouene Boubakri EMSG("ldelf dl_entry function panicked");
411d8e4ae07SMarouene Boubakri abort_print_current_ts();
412d8e4ae07SMarouene Boubakri res = TEE_ERROR_TARGET_DEAD;
413d8e4ae07SMarouene Boubakri }
414031dca8eSJens Wiklander if (!res) {
415031dca8eSJens Wiklander TEE_Result res2 = TEE_SUCCESS;
416031dca8eSJens Wiklander
417031dca8eSJens Wiklander res2 = GET_USER_SCALAR(res, &usr_arg->ret);
418031dca8eSJens Wiklander if (res2)
419031dca8eSJens Wiklander res = res2;
420031dca8eSJens Wiklander }
421d8e4ae07SMarouene Boubakri
422d8e4ae07SMarouene Boubakri return res;
423d8e4ae07SMarouene Boubakri }
424d8e4ae07SMarouene Boubakri
ldelf_dlsym(struct user_mode_ctx * uctx,TEE_UUID * uuid,const char * sym,size_t symlen,vaddr_t * val)425d8e4ae07SMarouene Boubakri TEE_Result ldelf_dlsym(struct user_mode_ctx *uctx, TEE_UUID *uuid,
42652e7b1a6SJens Wiklander const char *sym, size_t symlen, vaddr_t *val)
427d8e4ae07SMarouene Boubakri {
428d8e4ae07SMarouene Boubakri uaddr_t usr_stack = uctx->ldelf_stack_ptr;
429d8e4ae07SMarouene Boubakri TEE_Result res = TEE_ERROR_GENERIC;
43052e7b1a6SJens Wiklander struct dl_entry_arg *usr_arg = NULL;
431d8e4ae07SMarouene Boubakri struct dl_entry_arg *arg = NULL;
432d8e4ae07SMarouene Boubakri uint32_t panic_code = 0;
433d8e4ae07SMarouene Boubakri uint32_t panicked = 0;
434d8e4ae07SMarouene Boubakri struct ts_session *sess = NULL;
435d8e4ae07SMarouene Boubakri
43652e7b1a6SJens Wiklander usr_stack -= ROUNDUP(sizeof(*arg) + symlen + 1, STACK_ALIGNMENT);
43752e7b1a6SJens Wiklander usr_arg = (void *)usr_stack;
43852e7b1a6SJens Wiklander arg = bb_alloc(sizeof(*arg));
43952e7b1a6SJens Wiklander if (!arg)
44052e7b1a6SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
441d8e4ae07SMarouene Boubakri memset(arg, 0, sizeof(*arg));
442d8e4ae07SMarouene Boubakri arg->cmd = LDELF_DL_ENTRY_DLSYM;
443d8e4ae07SMarouene Boubakri arg->dlsym.uuid = *uuid;
44452e7b1a6SJens Wiklander res = copy_to_user(usr_arg, arg, sizeof(*arg));
44552e7b1a6SJens Wiklander if (res)
44652e7b1a6SJens Wiklander return res;
44752e7b1a6SJens Wiklander res = copy_to_user(usr_arg->dlsym.symbol, sym, symlen + 1);
44852e7b1a6SJens Wiklander if (res)
44952e7b1a6SJens Wiklander return res;
450d8e4ae07SMarouene Boubakri
451d8e4ae07SMarouene Boubakri sess = ts_get_current_session();
452d8e4ae07SMarouene Boubakri sess->handle_scall = scall_handle_ldelf;
453d8e4ae07SMarouene Boubakri
45452e7b1a6SJens Wiklander res = thread_enter_user_mode((vaddr_t)usr_arg, 0, 0, 0,
455d8e4ae07SMarouene Boubakri usr_stack, uctx->dl_entry_func,
456cb5f271cSMarouene Boubakri is_32bit, &panicked, &panic_code);
457d8e4ae07SMarouene Boubakri
458d8e4ae07SMarouene Boubakri sess->handle_scall = sess->ctx->ops->handle_scall;
459d8e4ae07SMarouene Boubakri ldelf_sess_cleanup(sess);
460d8e4ae07SMarouene Boubakri
461d8e4ae07SMarouene Boubakri if (panicked) {
462d8e4ae07SMarouene Boubakri EMSG("ldelf dl_entry function panicked");
463d8e4ae07SMarouene Boubakri abort_print_current_ts();
464d8e4ae07SMarouene Boubakri res = TEE_ERROR_TARGET_DEAD;
465d8e4ae07SMarouene Boubakri }
466d8e4ae07SMarouene Boubakri if (!res) {
46752e7b1a6SJens Wiklander TEE_Result res2 = TEE_SUCCESS;
46852e7b1a6SJens Wiklander
46952e7b1a6SJens Wiklander res2 = GET_USER_SCALAR(res, &usr_arg->ret);
47052e7b1a6SJens Wiklander if (res2)
47152e7b1a6SJens Wiklander res = res2;
472d8e4ae07SMarouene Boubakri if (!res)
47352e7b1a6SJens Wiklander res = GET_USER_SCALAR(*val, &usr_arg->dlsym.val);
474d8e4ae07SMarouene Boubakri }
475d8e4ae07SMarouene Boubakri
476d8e4ae07SMarouene Boubakri return res;
477d8e4ae07SMarouene Boubakri }
478