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