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