1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4
5 #include <assert.h>
6 #include <hyptypes.h>
7 #include <string.h>
8
9 #if ARCH_IS_64BIT
10 #define USE_ELF64
11 #endif
12
13 #include <compiler.h>
14 #include <elf.h>
15 #include <elf_loader.h>
16 #include <log.h>
17 #include <partition.h>
18 #include <pgtable.h>
19 #include <trace.h>
20 #include <util.h>
21
22 static const unsigned char *elf_ident = (const unsigned char *)EI_MAG_STR;
23
24 // Simple unoptimized non-terminated string comparison
25 static bool
str_equal(const unsigned char * s1,const unsigned char * s2,size_t n)26 str_equal(const unsigned char *s1, const unsigned char *s2, size_t n)
27 {
28 bool ret = true;
29 index_t i;
30
31 assert(n > 0);
32
33 for (i = 0; i < n; i++) {
34 if (s1[i] != s2[i]) {
35 ret = false;
36 break;
37 }
38 }
39
40 return ret;
41 }
42
43 bool
elf_valid(void * elf_file,size_t max_size)44 elf_valid(void *elf_file, size_t max_size)
45 {
46 index_t i;
47 bool ret = false;
48 uintptr_t area_end = (uintptr_t)elf_file + max_size;
49
50 Elf_Ehdr *ehdr = (Elf_Ehdr *)(uintptr_t)elf_file;
51
52 if ((area_end < (uintptr_t)elf_file) ||
53 util_add_overflows((uintptr_t)ehdr, sizeof(ehdr)) ||
54 (((uintptr_t)ehdr + sizeof(ehdr)) > area_end)) {
55 goto out;
56 }
57
58 if (!str_equal(ehdr->e_ident, elf_ident, EI_MAG_SIZE)) {
59 goto out;
60 }
61 if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) {
62 goto out;
63 }
64 if (ehdr->e_ident[EI_DATA] != ELF_DATA_2LSB) {
65 goto out;
66 }
67 if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
68 goto out;
69 }
70 if (ehdr->e_ident[EI_OSABI] != 0U) {
71 goto out;
72 }
73 if (ehdr->e_ident[EI_ABIVERSION] != 0U) {
74 goto out;
75 }
76 if (ehdr->e_type != ET_DYN) {
77 goto out;
78 }
79 #if defined(ARCH_ARM)
80 if (ehdr->e_machine != EM_AARCH64) {
81 goto out;
82 }
83 #else
84 #error unimplemented
85 #endif
86
87 if (util_add_overflows((uintptr_t)elf_file, ehdr->e_phoff)) {
88 goto out;
89 }
90
91 Elf_Phdr *phdr = (Elf_Phdr *)((uintptr_t)elf_file + ehdr->e_phoff);
92 Elf_Half phnum = ehdr->e_phnum;
93
94 if (ehdr->e_phentsize != sizeof(Elf_Phdr)) {
95 goto out;
96 }
97 if (util_add_overflows((uintptr_t)phdr, sizeof(phdr) * phnum) ||
98 ((((uintptr_t)phdr + (sizeof(phdr) * phnum)) > area_end))) {
99 goto out;
100 }
101
102 // Ensure there is at least one load segment
103 for (i = 0; i < phnum; i++) {
104 if (phdr[i].p_type == PT_LOAD) {
105 ret = true;
106 break;
107 }
108 }
109
110 out:
111 return ret;
112 }
113
114 Elf_Addr
elf_get_entry(void * elf_file)115 elf_get_entry(void *elf_file)
116 {
117 Elf_Ehdr *ehdr = (Elf_Ehdr *)(uintptr_t)elf_file;
118
119 return ehdr->e_entry;
120 }
121
122 count_t
elf_get_num_phdrs(void * elf_file)123 elf_get_num_phdrs(void *elf_file)
124 {
125 Elf_Ehdr *ehdr = (Elf_Ehdr *)(uintptr_t)elf_file;
126
127 return ehdr->e_phnum;
128 }
129
130 Elf_Phdr *
elf_get_phdr(void * elf_file,count_t index)131 elf_get_phdr(void *elf_file, count_t index)
132 {
133 Elf_Ehdr *ehdr = (Elf_Ehdr *)(uintptr_t)elf_file;
134 Elf_Phdr *phdr = (Elf_Phdr *)((uintptr_t)elf_file + ehdr->e_phoff);
135 Elf_Half phnum = ehdr->e_phnum;
136
137 assert(index < phnum);
138
139 return &phdr[index];
140 }
141
142 error_t
elf_load_phys(void * elf_file,size_t elf_max_size,paddr_t phys_base)143 elf_load_phys(void *elf_file, size_t elf_max_size, paddr_t phys_base)
144 {
145 error_t ret;
146 index_t i;
147 uintptr_t elf_base = (uintptr_t)elf_file;
148 Elf_Ehdr *ehdr = (Elf_Ehdr *)(uintptr_t)elf_file;
149 Elf_Phdr *phdr = (Elf_Phdr *)((uintptr_t)elf_file + ehdr->e_phoff);
150 Elf_Half phnum = ehdr->e_phnum;
151
152 // Copy all segments to the requested memory addresses
153 for (i = 0; i < phnum; i++) {
154 Elf_Phdr *cur_phdr = &phdr[i];
155 Elf_Word type = cur_phdr->p_type;
156
157 // FIXME:
158 assert(type != PT_TLS);
159
160 if (type != PT_LOAD) {
161 continue;
162 }
163
164 if (cur_phdr->p_filesz > cur_phdr->p_memsz) {
165 ret = ERROR_ARGUMENT_SIZE;
166 goto out;
167 }
168
169 if (util_add_overflows(cur_phdr->p_paddr, cur_phdr->p_memsz) ||
170 util_add_overflows(phys_base,
171 cur_phdr->p_paddr + cur_phdr->p_memsz) ||
172 ((cur_phdr->p_offset + cur_phdr->p_filesz) >
173 elf_max_size)) {
174 ret = ERROR_ARGUMENT_SIZE;
175 goto out;
176 }
177
178 if (util_add_overflows(cur_phdr->p_offset, cur_phdr->p_memsz) ||
179 util_add_overflows(elf_base, cur_phdr->p_offset +
180 cur_phdr->p_memsz)) {
181 ret = ERROR_ARGUMENT_SIZE;
182 goto out;
183 }
184
185 uintptr_t seg_base = elf_base + cur_phdr->p_offset;
186 paddr_t seg_dest = phys_base + cur_phdr->p_paddr;
187
188 char *dest =
189 (char *)partition_phys_map(seg_dest, cur_phdr->p_memsz);
190 partition_phys_access_enable(dest);
191
192 // copy elf segment data
193 (void)memcpy(dest, (char *)seg_base, cur_phdr->p_filesz);
194 // zero bss
195 size_t bss_size = cur_phdr->p_memsz - cur_phdr->p_filesz;
196 (void)memset_s(dest + cur_phdr->p_filesz, bss_size, 0,
197 bss_size);
198
199 partition_phys_access_disable(dest);
200 partition_phys_unmap(dest, seg_dest, cur_phdr->p_memsz);
201
202 LOG(DEBUG, INFO, "Elf copied from {:#x} to {:#x} - size {:#x}",
203 seg_base, seg_dest, cur_phdr->p_filesz);
204 }
205
206 ret = OK;
207 out:
208 return ret;
209 }
210