blob: 5c8014f072a43bd81e663745eae5c313e14aae6e [file] [log] [blame]
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +00001/*
Peter Stuge45ae92ff2009-04-14 19:48:32 +00002 * cbfs-mkstage
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +00003 *
4 * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net>
Patrick Georgib7b56dd82009-09-14 13:29:27 +00005 * 2009 coresystems GmbH
6 * written by Patrick Georgi <patrick.georgi@coresystems.de>
David Hendricks90ca3b62012-11-16 14:48:22 -08007 * Copyright (C) 2012 Google, Inc.
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +00008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +000026
27#include "common.h"
Patrick Georgib7b56dd82009-09-14 13:29:27 +000028#include "cbfs.h"
Hung-Te Lin4505ceb2013-01-28 22:40:10 +080029#include "elf.h"
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +000030
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -080031/*
32 * Short form: this is complicated, but we've tried making it simple
33 * and we keep hitting problems with our ELF parsing.
34 *
35 * The ELF parsing situation has always been a bit tricky. In fact,
36 * we (and most others) have been getting it wrong in small ways for
37 * years. Recently this has caused real trouble for the ARM V8 build.
38 * In this file we attempt to finally get it right for all variations
39 * of endian-ness and word size and target architectures and
40 * architectures we might get run on. Phew!. To do this we borrow a
41 * page from the FreeBSD NFS xdr model (see elf_ehdr and elf_phdr),
42 * the Plan 9 endianness functions (see xdr.c), and Go interfaces (see
43 * how we use buffer structs in this file). This ends up being a bit
44 * wordy at the lowest level, but greatly simplifies the elf parsing
45 * code and removes a common source of bugs, namely, forgetting to
46 * flip type endianness when referencing a struct member.
47 *
48 * ELF files can have four combinations of data layout: 32/64, and
49 * big/little endian. Further, to add to the fun, depending on the
50 * word size, the size of the ELF structs varies. The coreboot SELF
51 * format is simpler in theory: it's supposed to be always BE, and the
52 * various struct members allow room for growth: the entry point is
53 * always 64 bits, for example, so the size of a SELF struct is
54 * constant, regardless of target architecture word size. Hence, we
55 * need to do some transformation of the ELF files.
56 *
57 * A given architecture, realistically, only supports one of the four
58 * combinations at a time as the 'native' format. Hence, our code has
59 * been sprinkled with every variation of [nh]to[hn][sll] over the
60 * years. We've never quite gotten it all right, however, and a quick
61 * pass over this code revealed another bug. It's all worked because,
62 * until now, all the working platforms that had CBFS were 32 LE. Even then,
63 * however, bugs crept in: we recently realized that we're not
64 * transforming the entry point to big format when we store into the
65 * SELF image.
66 *
67 * The problem is essentially an XDR operation:
68 * we have something in a foreign format and need to transform it.
69 * It's most like XDR because:
70 * 1) the byte order can be wrong
71 * 2) the word size can be wrong
72 * 3) the size of elements in the stream depends on the value
73 * of other elements in the stream
74 * it's not like XDR because:
75 * 1) the byte order can be right
76 * 2) the word size can be right
77 * 3) the struct members are all on a natural alignment
78 *
79 * Hence, this new approach. To cover word size issues, we *always*
80 * transform the two structs we care about, the file header and
81 * program header, into a native struct in the 64 bit format:
82 *
83 * [32,little] -> [Elf64_Ehdr, Elf64_Phdr]
84 * [64,little] -> [Elf64_Ehdr, Elf64_Phdr]
85 * [32,big] -> [Elf64_Ehdr, Elf64_Phdr]
86 * [64,big] -> [Elf64_Ehdr, Elf64_Phdr]
87 * Then we just use those structs, and all the need for inline ntoh* goes away,
88 * as well as all the chances for error.
89 * This works because all the SELF structs have fields large enough for
90 * the largest ELF 64 struct members, and all the Elf64 struct members
91 * are at least large enough for all ELF 32 struct members.
92 * We end up with one function to do all our ELF parsing, and two functions
93 * to transform the headers. For the put case, we also have
94 * XDR functions, and hopefully we'll never again spend 5 years with the
95 * wrong endian-ness on an output value :-)
96 * This should work for all word sizes and endianness we hope to target.
97 * I *really* don't want to be here for 128 bit addresses.
98 *
99 * The parse functions are called with a pointer to an input buffer
100 * struct. One might ask: are there enough bytes in the input buffer?
101 * We know there need to be at *least* sizeof(Elf32_Ehdr) +
102 * sizeof(Elf32_Phdr) bytes. Realistically, there has to be some data
103 * too. If we start to worry, though we have not in the past, we
104 * might apply the simple test: the input buffer needs to be at least
105 * sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) bytes because, even if it's
106 * ELF 32, there's got to be *some* data! This is not theoretically
107 * accurate but it is actually good enough in practice. It allows the
108 * header transformation code to ignore the possibility of underrun.
109 *
110 * We also must accomodate different ELF files, and hence formats,
111 * in the same cbfs invocation. We might load a 64-bit payload
112 * on a 32-bit machine; we might even have a mixed armv7/armv8
113 * SOC or even a system with an x86/ARM!
114 *
115 * A possibly problematic (though unlikely to be so) assumption
116 * is that we expect the BIOS to remain in the lowest 32 bits
117 * of the physical address space. Since ARMV8 has standardized
118 * on that, and x86_64 also has, this seems a safe assumption.
119 *
120 * To repeat, ELF structs are different sizes because ELF struct
121 * members are different sizes, depending on values in the ELF file
122 * header. For this we use the functions defined in xdr.c, which
123 * consume bytes, convert the endianness, and advance the data pointer
124 * in the buffer struct.
Stefan Reinauera1e48242011-10-21 14:24:57 -0700125 */
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800126
127/* Get the ident array, so we can figure out
128 * endian-ness, word size, and in future other useful
129 * parameters
130 */
131static void
132elf_eident(struct buffer *input, Elf64_Ehdr *ehdr)
Patrick Georgib203c2f2009-08-20 14:48:03 +0000133{
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800134 memmove(ehdr->e_ident, input->data, sizeof(ehdr->e_ident));
135 input->data += sizeof(ehdr->e_ident);
136 input->size -= sizeof(ehdr->e_ident);
Patrick Georgib203c2f2009-08-20 14:48:03 +0000137}
138
Patrick Georgib203c2f2009-08-20 14:48:03 +0000139
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800140static void
141elf_ehdr(struct buffer *input, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64)
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000142{
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800143 ehdr->e_type = xdr->get16(input);
144 ehdr->e_machine = xdr->get16(input);
145 ehdr->e_version = xdr->get32(input);
146 if (bit64){
147 ehdr->e_entry = xdr->get64(input);
148 ehdr->e_phoff = xdr->get64(input);
149 ehdr->e_shoff = xdr->get64(input);
150 } else {
151 ehdr->e_entry = xdr->get32(input);
152 ehdr->e_phoff = xdr->get32(input);
153 ehdr->e_shoff = xdr->get32(input);
154 }
155 ehdr->e_flags = xdr->get32(input);
156 ehdr->e_ehsize = xdr->get16(input);
157 ehdr->e_phentsize = xdr->get16(input);
158 ehdr->e_phnum = xdr->get16(input);
159 ehdr->e_shentsize = xdr->get16(input);
160 ehdr->e_shnum = xdr->get16(input);
161 ehdr->e_shstrndx = xdr->get16(input);
162}
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000163
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800164static void
165elf_phdr(struct buffer *pinput, Elf64_Phdr *phdr,
166 int entsize, struct xdr *xdr, int bit64)
167{
168 /*
169 * The entsize need not be sizeof(*phdr).
170 * Hence, it is easier to keep a copy of the input,
171 * as the xdr functions may not advance the input
172 * pointer the full entsize; rather than get tricky
173 * we just advance it below.
174 */
175 struct buffer input = *pinput;
176 if (bit64){
177 phdr->p_type = xdr->get32(&input);
178 phdr->p_flags = xdr->get32(&input);
179 phdr->p_offset = xdr->get64(&input);
180 phdr->p_vaddr = xdr->get64(&input);
181 phdr->p_paddr = xdr->get64(&input);
182 phdr->p_filesz = xdr->get64(&input);
183 phdr->p_memsz = xdr->get64(&input);
184 phdr->p_align = xdr->get64(&input);
185 } else {
186 phdr->p_type = xdr->get32(&input);
187 phdr->p_offset = xdr->get32(&input);
188 phdr->p_vaddr = xdr->get32(&input);
189 phdr->p_paddr = xdr->get32(&input);
190 phdr->p_filesz = xdr->get32(&input);
191 phdr->p_memsz = xdr->get32(&input);
192 phdr->p_flags = xdr->get32(&input);
193 phdr->p_align = xdr->get32(&input);
194 }
195 pinput->size -= entsize;
196 pinput->data += entsize;
197}
198
199/* Get the headers from the buffer.
200 * Return -1 in the event of an error.
201 */
202static int
203elf_headers(const struct buffer *pinput, Elf64_Ehdr *ehdr, Elf64_Phdr **pphdr)
204{
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000205 int i;
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800206 struct xdr *xdr = &xdr_le;
207 int bit64 = 0;
208 struct buffer input = *(struct buffer *)pinput;
209 struct buffer phdr_buf;
210 Elf64_Phdr *phdr;
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000211
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800212 if (!iself((unsigned char *)pinput->data)) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800213 ERROR("The stage file is not in ELF format!\n");
David Hendricks90ca3b62012-11-16 14:48:22 -0800214 return -1;
215 }
216
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800217 elf_eident(&input, ehdr);
218 bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
219 /* Assume LE unless we are sure otherwise.
220 * We're not going to take on the task of
221 * fully validating the ELF file. That way
222 * lies madness.
223 */
224 if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
225 xdr = &xdr_be;
226
227 elf_ehdr(&input, ehdr, xdr, bit64);
228
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800229 // The tool may work in architecture-independent way.
230 if (arch != CBFS_ARCHITECTURE_UNKNOWN &&
231 !((ehdr->e_machine == EM_ARM) && (arch == CBFS_ARCHITECTURE_ARMV7)) &&
David Hendricks90ca3b62012-11-16 14:48:22 -0800232 !((ehdr->e_machine == EM_386) && (arch == CBFS_ARCHITECTURE_X86))) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800233 ERROR("The stage file has the wrong architecture\n");
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000234 return -1;
235 }
236
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800237 if (pinput->size < ehdr->e_phoff){
238 ERROR("The program header offset is greater than "
239 "the remaining file size."
240 "%ld bytes left, program header offset is %ld \n",
241 pinput->size, ehdr->e_phoff);
242 return -1;
Patrick Georgib203c2f2009-08-20 14:48:03 +0000243 }
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800244 /* cons up an input buffer for the headers.
245 * Note that the program headers can be anywhere,
246 * per the ELF spec, You'd be surprised how many ELF
247 * readers miss this little detail.
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000248 */
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800249 phdr_buf.data = &pinput->data[ehdr->e_phoff];
250 phdr_buf.size = ehdr->e_phentsize * ehdr->e_phnum;
251 if (phdr_buf.size > (pinput->size - ehdr->e_phoff)){
252 ERROR("The file is not large enough for the program headers."
253 "%ld bytes left, %ld bytes of headers\n",
254 pinput->size - ehdr->e_phoff, phdr_buf.size);
255 return -1;
256 }
257 /* gather up all the phdrs.
258 * We do them all at once because there is more
259 * than one loop over all the phdrs.
260 */
261 phdr = calloc(sizeof(*phdr), ehdr->e_phnum);
262 for (i = 0; i < ehdr->e_phnum; i++)
263 elf_phdr(&phdr_buf, &phdr[i], ehdr->e_phentsize, xdr, bit64);
264 *pphdr = phdr;
265 return 0;
266}
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000267
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800268/* returns size of result, or -1 if error.
269 * Note that, with the new code, this function
270 * works for all elf files, not just the restricted set.
271 */
272int parse_elf_to_stage(const struct buffer *input, struct buffer *output,
273 comp_algo algo, uint32_t *location)
274{
275 Elf64_Phdr *phdr;
276 Elf64_Ehdr ehdr;
277 char *buffer;
278 struct buffer outheader;
279
280 int headers;
281 int i, outlen;
282 uint32_t data_start, data_end, mem_end;
283
284 comp_func_ptr compress = compression_function(algo);
285 if (!compress)
286 return -1;
287
288 DEBUG("start: parse_elf_to_stage(location=0x%x)\n", *location);
289
290 if (elf_headers(input, &ehdr, &phdr) < 0)
291 return -1;
292
293 headers = ehdr.e_phnum;
294
295 data_start = ~0;
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000296 data_end = 0;
297 mem_end = 0;
298
299 for (i = 0; i < headers; i++) {
300 unsigned int start, mend, rend;
301
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800302 if (phdr[i].p_type != PT_LOAD)
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000303 continue;
304
305 /* Empty segments are never interesting */
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800306 if (phdr[i].p_memsz == 0)
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000307 continue;
308
309 /* BSS */
310
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800311 start = phdr[i].p_paddr;
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000312
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800313 mend = start + phdr[i].p_memsz;
314 rend = start + phdr[i].p_filesz;
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000315
316 if (start < data_start)
317 data_start = start;
318
319 if (rend > data_end)
320 data_end = rend;
321
322 if (mend > mem_end)
323 mem_end = mend;
324 }
325
Patrick Georgi9341acd2009-12-23 12:52:56 +0000326 if (data_start < *location) {
327 data_start = *location;
328 }
329
Patrick Georgia6c337d2010-02-03 17:56:37 +0000330 if (data_end <= data_start) {
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800331 ERROR("data ends (%08lx) before it starts (%08lx). Make sure "
332 "the ELF file is correct and resides in ROM space.\n",
333 (unsigned long)data_end, (unsigned long)data_start);
Patrick Georgia6c337d2010-02-03 17:56:37 +0000334 exit(1);
335 }
336
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000337 /* allocate an intermediate buffer for the data */
338 buffer = calloc(data_end - data_start, 1);
339
340 if (buffer == NULL) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800341 ERROR("Unable to allocate memory: %m\n");
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000342 return -1;
343 }
344
345 /* Copy the file data into the buffer */
346
347 for (i = 0; i < headers; i++) {
Patrick Georgi9341acd2009-12-23 12:52:56 +0000348 unsigned int l_start, l_offset = 0;
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000349
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800350 if (phdr[i].p_type != PT_LOAD)
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000351 continue;
352
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800353 if (phdr[i].p_memsz == 0)
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000354 continue;
355
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800356 l_start = phdr[i].p_paddr;
Patrick Georgi9341acd2009-12-23 12:52:56 +0000357 if (l_start < *location) {
358 l_offset = *location - l_start;
359 l_start = *location;
360 }
361
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800362 /* A legal ELF file can have a program header with
363 * non-zero length but zero-length file size and a
364 * non-zero offset which, added together, are > than
365 * input->size (i.e. the total file size). So we need
366 * to not even test in the case that p_filesz is zero.
367 */
368 if (! phdr[i].p_filesz)
369 continue;
370 if (input->size < (phdr[i].p_offset + phdr[i].p_filesz)){
371 ERROR("Underflow copying out the segment."
372 "File has %ld bytes left, segment end is %ld\n",
373 input->size, phdr[i].p_offset + phdr[i].p_filesz);
374 return -1;
375 }
Patrick Georgi9341acd2009-12-23 12:52:56 +0000376 memcpy(buffer + (l_start - data_start),
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800377 &input->data[phdr[i].p_offset + l_offset],
378 phdr[i].p_filesz - l_offset);
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000379 }
380
381 /* Now make the output buffer */
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800382 if (buffer_create(output, sizeof(struct cbfs_stage) + data_end - data_start,
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800383 input->name) != 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800384 ERROR("Unable to allocate memory: %m\n");
Paul Menzel2c8f81b2013-04-11 10:45:11 +0200385 free(buffer);
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000386 return -1;
387 }
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800388 memset(output->data, 0, output->size);
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000389
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800390 /* Compress the data, at which point we'll know information
391 * to fill out the header. This seems backward but it works because
392 * - the output header is a known size (not always true in many xdr's)
393 * - we do need to know the compressed output size first
394 */
395 compress(buffer, data_end - data_start,
396 (output->data + sizeof(struct cbfs_stage)),
397 &outlen);
Stefan Reinauer63217582012-10-29 16:52:36 -0700398 free(buffer);
399
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800400 /* Set up for output marshaling. */
401 outheader.data = output->data;
402 outheader.size = 0;
403 /* N.B. The original plan was that SELF data was B.E.
404 * but: this is all L.E.
405 * Maybe we should just change the spec.
406 */
407 xdr_le.put32(&outheader, algo);
408 xdr_le.put64(&outheader, ehdr.e_entry);
409 xdr_le.put64(&outheader, data_start);
410 xdr_le.put32(&outheader, outlen);
411 xdr_le.put32(&outheader, mem_end - data_start);
412
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000413 if (*location)
414 *location -= sizeof(struct cbfs_stage);
Ronald G. Minnichaa2f7392013-12-03 11:13:35 -0800415 output->size = sizeof(struct cbfs_stage) + outlen;
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800416 return 0;
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +0000417}