xref: /optee_os/ldelf/main.c (revision b8a0c52c847baf133e08f19f69759eb8a5de1a2c)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2019, Linaro Limited
4  * Copyright (c) 2022-2023, Arm Limited
5  */
6 
7 #include <assert.h>
8 #include <config.h>
9 #include <ldelf.h>
10 #include <malloc.h>
11 #include <printk.h>
12 #include <string.h>
13 #include <sys/queue.h>
14 #include <tee_api_types.h>
15 #include <trace.h>
16 #include <types_ext.h>
17 #include <util.h>
18 
19 #include "asan.h"
20 #include "dl.h"
21 #include "ftrace.h"
22 #include "sys.h"
23 #include "ta_elf.h"
24 
25 static size_t mpool_size = 4 * SMALL_PAGE_SIZE;
26 static vaddr_t mpool_base;
27 
print_to_console(void * pctx __unused,const char * fmt,va_list ap)28 static void __printf(2, 0) print_to_console(void *pctx __unused,
29 					    const char *fmt, va_list ap)
30 {
31 	trace_vprintf(NULL, 0, TRACE_ERROR, true, fmt, ap);
32 }
33 
dump_ta_state(struct dump_entry_arg * arg)34 static void __noreturn __maybe_unused dump_ta_state(struct dump_entry_arg *arg)
35 {
36 	struct ta_elf *elf = TAILQ_FIRST(&main_elf_queue);
37 
38 	assert(elf && elf->is_main);
39 	EMSG_RAW("Status of TA %pUl", (void *)&elf->uuid);
40 #if defined(ARM32) || defined(ARM64)
41 	EMSG_RAW(" arch: %s", elf->is_32bit ? "arm" : "aarch64");
42 #elif defined(RV32) || defined(RV64)
43 	EMSG_RAW(" arch: %s", elf->is_32bit ? "riscv32" : "riscv64");
44 #endif
45 
46 	ta_elf_print_mappings(NULL, print_to_console, &main_elf_queue,
47 			      arg->num_maps, arg->maps, mpool_base);
48 
49 #if defined(ARM32) || defined(ARM64)
50 	if (arg->is_32bit)
51 		ta_elf_stack_trace_a32(arg->arm32.regs);
52 	else
53 		ta_elf_stack_trace_a64(arg->arm64.fp, arg->arm64.sp,
54 				       arg->arm64.pc);
55 #elif defined(RV32) || defined(RV64)
56 	ta_elf_stack_trace_riscv(arg->rv.fp, arg->rv.pc);
57 #endif
58 
59 	sys_return_cleanup();
60 }
61 
62 #ifdef CFG_FTRACE_SUPPORT
63 struct print_buf_ctx {
64 	char *buf;
65 	size_t blen;
66 	size_t ret;
67 };
68 
print_to_pbuf(void * pctx,const char * fmt,va_list ap)69 static void __printf(2, 0) print_to_pbuf(void *pctx, const char *fmt,
70 					 va_list ap)
71 {
72 	struct print_buf_ctx *pbuf = pctx;
73 	char *buf = NULL;
74 	size_t blen = 0;
75 	int ret = 0;
76 
77 	if (pbuf->buf && pbuf->blen > pbuf->ret) {
78 		buf = pbuf->buf + pbuf->ret;
79 		blen = pbuf->blen - pbuf->ret;
80 	}
81 
82 	ret = vsnprintk(buf, blen, fmt, ap);
83 	assert(ret >= 0);
84 
85 	pbuf->ret += ret;
86 }
87 
copy_to_pbuf(void * pctx,void * b,size_t bl)88 static void copy_to_pbuf(void *pctx, void *b, size_t bl)
89 {
90 	struct print_buf_ctx *pbuf = pctx;
91 	char *buf = NULL;
92 	size_t blen = 0;
93 
94 	if (pbuf->buf && pbuf->blen > pbuf->ret) {
95 		buf = pbuf->buf + pbuf->ret;
96 		blen = pbuf->blen - pbuf->ret;
97 		memcpy(buf, b, MIN(blen, bl));
98 	}
99 
100 	pbuf->ret += bl;
101 
102 }
103 
ftrace_dump(void * buf,size_t * blen)104 static void __noreturn ftrace_dump(void *buf, size_t *blen)
105 {
106 	struct print_buf_ctx pbuf = { .buf = buf, .blen = *blen };
107 
108 	/* only print the header when this is a new dump */
109 	if (!ftrace_get_dump_id())
110 		ta_elf_print_mappings(&pbuf, print_to_pbuf, &main_elf_queue,
111 				      0, NULL, mpool_base);
112 	ftrace_copy_buf(&pbuf, copy_to_pbuf);
113 	/*
114 	 * Reset the buffer after dump if this is the actual write
115 	 * The OS may call this function with buf == NULL,
116 	 * in order to get the length required to write ftrace data.
117 	 */
118 	if (buf)
119 		ftrace_reset_buf();
120 	*blen = pbuf.ret;
121 	sys_return_cleanup();
122 }
123 #endif
124 
dl_entry(struct dl_entry_arg * arg)125 static void __noreturn dl_entry(struct dl_entry_arg *arg)
126 {
127 	switch (arg->cmd) {
128 	case LDELF_DL_ENTRY_DLOPEN:
129 		arg->ret = dlopen_entry(arg);
130 		break;
131 	case LDELF_DL_ENTRY_DLSYM:
132 		arg->ret = dlsym_entry(arg);
133 		break;
134 	default:
135 		arg->ret = TEE_ERROR_NOT_SUPPORTED;
136 	}
137 
138 	sys_return_cleanup();
139 }
140 
141 /*
142  * ldelf()- Loads ELF into memory
143  * @arg:	Argument passing to/from TEE Core
144  *
145  * Only called from assembly
146  */
147 void __noreturn __no_asan ldelf(struct ldelf_arg *arg);
ldelf(struct ldelf_arg * arg)148 void ldelf(struct ldelf_arg *arg)
149 {
150 	TEE_Result res = TEE_SUCCESS;
151 	struct ta_elf *elf = NULL;
152 
153 	res = asan_init_ldelf();
154 	if (res) {
155 		EMSG("asan init result %"PRIx32, res);
156 		panic();
157 	}
158 
159 	DMSG("Loading TS %pUl", (void *)&arg->uuid);
160 	res = sys_map_zi(mpool_size, 0, &mpool_base, 0, 0);
161 	if (res) {
162 		EMSG("sys_map_zi(%zu): result %"PRIx32, mpool_size, res);
163 		panic();
164 	}
165 	malloc_add_pool((void *)mpool_base, mpool_size);
166 
167 	asan_start();
168 
169 	/* Load the main binary and get a list of dependencies, if any. */
170 	ta_elf_load_main(&arg->uuid, &arg->is_32bit, &arg->stack_ptr,
171 			 &arg->flags);
172 
173 	/*
174 	 * Load binaries, ta_elf_load() may add external libraries to the
175 	 * list, so the loop will end when all the dependencies are
176 	 * satisfied.
177 	 */
178 	TAILQ_FOREACH(elf, &main_elf_queue, link)
179 		ta_elf_load_dependency(elf, arg->is_32bit);
180 
181 	TAILQ_FOREACH(elf, &main_elf_queue, link) {
182 		ta_elf_relocate(elf);
183 		ta_elf_finalize_mappings(elf);
184 	}
185 
186 	ta_elf_finalize_load_main(&arg->entry_func, &arg->load_addr);
187 
188 	arg->ftrace_entry = 0;
189 #ifdef CFG_FTRACE_SUPPORT
190 	if (ftrace_init(&arg->fbuf))
191 		arg->ftrace_entry = (vaddr_t)(void *)ftrace_dump;
192 #endif
193 
194 	TAILQ_FOREACH(elf, &main_elf_queue, link) {
195 		if (IS_ENABLED(CFG_TA_SANITIZE_KADDRESS)) {
196 			TEE_Result rc = TEE_ERROR_GENERIC;
197 
198 			rc = asan_user_map_shadow((void *)elf->load_addr,
199 						  (void *)elf->max_addr,
200 						  ASAN_REG_ELF);
201 			if (rc) {
202 				EMSG("Failed to map shadow for ELF (%pUl)",
203 				     (void *)&elf->uuid);
204 				panic();
205 			}
206 		}
207 		DMSG("ELF (%pUl) at %#"PRIxVA,
208 		     (void *)&elf->uuid, elf->load_addr);
209 	}
210 
211 #if TRACE_LEVEL >= TRACE_ERROR
212 	arg->dump_entry = (vaddr_t)(void *)dump_ta_state;
213 #else
214 	arg->dump_entry = 0;
215 #endif
216 	arg->dl_entry = (vaddr_t)(void *)dl_entry;
217 
218 	sys_return_cleanup();
219 }
220