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