1/*
2 * A static 'bootloader' for ARMv7 platforms.
3 *
4 * This tool loads and relocates the boot driver (into physical addresses) and
5 * the CPU driver into kernel virtual.  It also constructs a multiboot image,
6 * and places the lot into an ELF file with a single loadable segment.  Thus,
7 * if this ELF file is passed to a simulator, or loaded onto a pandaboard, on
8 * jumping to its start address, we're ready to go, just as if we'd been
9 * started by a dynamic bootloader.
10 *
11 * Copyright (c) 2016, ETH Zurich.
12 * All rights reserved.
13 *
14 * This file is distributed under the terms in the attached LICENSE file.
15 * If you do not find this file, copies can be found by writing to:
16 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
17 */
18
19#include <sys/stat.h>
20#include <sys/types.h>
21
22#include <assert.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <libelf.h>
26#include <limits.h>
27#include <stdarg.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33
34/* We need to be able to parse menu.lst files, create multiboot images. */
35#include "../../include/grubmenu.h"
36#include "../../include/multiboot.h"
37
38/* XXX - this should be taken from the kernel offsets.h. */
39#define KERNEL_WINDOW 0x80000000
40#define BASE_PAGE_SIZE (1<<12)
41
42#undef DEBUG
43
44#ifdef DEBUG
45#define DBG(format, ...) printf(format, ## __VA_ARGS__)
46#else
47#define DBG(format, ...)
48#endif
49
50/* Keep physical addresses and kernel virtual addresses separated, as far as
51 * possible. */
52typedef uint32_t kvaddr_t;
53typedef uint32_t paddr_t;
54
55/*** A Linear Memory Allocator ***/
56
57static paddr_t phys_alloc_start;
58
59static uint32_t
60round_up(uint32_t x, uint32_t y) {
61    assert(y > 0);
62    uint32_t z= x + (y - 1);
63    return z - (z % y);
64}
65
66/* Advance the allocator to an address with the given alignment. */
67static paddr_t
68align_alloc(paddr_t align) {
69    phys_alloc_start= round_up(phys_alloc_start, align);
70    return phys_alloc_start;
71}
72
73/* Allocate an aligned block. */
74static paddr_t
75phys_alloc(size_t size, size_t align) {
76    align_alloc(align);
77    paddr_t addr= phys_alloc_start;
78    phys_alloc_start+= size;
79    return addr;
80}
81
82/*** Failure Handling ***/
83
84void
85fail(const char *fmt, ...) {
86    va_list ap;
87    va_start(ap, fmt);
88    vfprintf(stderr, fmt, ap);
89    va_end(ap);
90    exit(EXIT_FAILURE);
91}
92
93static void
94fail_errno(const char *fmt, ...) {
95    char s[1024];
96
97    va_list ap;
98    va_start(ap, fmt);
99    vsnprintf(s, 1024, fmt, ap);
100    va_end(ap);
101
102    perror(s);
103    exit(EXIT_FAILURE);
104}
105
106static void
107fail_elf(const char *s) {
108    fprintf(stderr, "%s: %s\n", s, elf_errmsg(elf_errno()));
109    exit(EXIT_FAILURE);
110}
111
112struct loaded_image {
113    void *segment;
114    paddr_t segment_base; /* Unrelocated. */
115    size_t segment_size;
116
117    size_t loaded_size;
118    paddr_t loaded_paddr;
119    kvaddr_t loaded_vaddr;
120
121    kvaddr_t relocated_entry;
122    const char *extrasym_name;
123    void *extrasym_ptr;
124
125    void *shdrs, *symtab, *strtab, *shstrtab;
126    size_t shdrs_size, symtab_size, strtab_size, shstrtab_size;
127    size_t shdrs_entsize, symtab_entsize;
128};
129
130/* Load and relocate an ELF, with the given offset between the physical
131 * address at which it is loaded, and the virtual address at which it
132 * executes.  For the boot driver, the offset is zero.  Return a variety of
133 * information about the loaded image. */
134static void *
135load(int in_fd, uint32_t vp_offset, struct loaded_image *image,
136     int save_sections) {
137    /* Open the ELF. */
138    Elf *elf= elf_begin(in_fd, ELF_C_READ, NULL);
139    if(!elf) fail_elf("elf_begin");
140
141    /* Grab the unrelocated entry address from the header. */
142    Elf32_Ehdr *ehdr= elf32_getehdr(elf);
143    if(!ehdr) fail_elf("elf32_getehdr");
144    uint32_t entry= ehdr->e_entry;
145
146    /* Grab the program headers i.e. the list of loadable segments. */
147    size_t phnum;
148    if(elf_getphdrnum(elf, &phnum)) fail_elf("elf_getphnum");
149
150    Elf32_Phdr *ph= elf32_getphdr(elf);
151    if(!ph) fail_elf("elf_getphdr");
152
153    DBG("%d program segments.\n", phnum);
154
155    /* Grab the raw ELF data. */
156    size_t elfsize;
157    void *elfdata= elf_rawfile(elf, &elfsize);
158    if(!elfdata) fail_elf("elf_rawfile");
159
160    /* Find the section header names. */
161    Elf_Scn *shstrscn= elf_getscn(elf, ehdr->e_shstrndx);
162    if(!shstrscn) fail_elf("elf_getscn");
163    Elf32_Shdr *shstrshdr= elf32_getshdr(shstrscn);
164    if(!shstrshdr) fail_elf("elf_getshdr");
165    assert(shstrshdr->sh_offset + shstrshdr->sh_size <= elfsize);
166    char *shstr= (char *)(elfdata + shstrshdr->sh_offset);
167    if(save_sections) {
168        /* Save a copy, if we've been asked to. */
169        image->shstrtab_size= shstrshdr->sh_size;
170        image->shstrtab= malloc(image->shstrtab_size);
171        if(!image->shstrtab) fail_errno("malloc");
172        memcpy(image->shstrtab, shstr, image->shstrtab_size);
173    }
174
175    /* Save the section headers, if required. */
176    if(save_sections) {
177        size_t sh_totalsize= ehdr->e_shnum * ehdr->e_shentsize;
178        assert(ehdr->e_shoff + sh_totalsize <= elfsize);
179
180        image->shdrs_size= sh_totalsize;
181        image->shdrs_entsize= ehdr->e_shentsize;
182        image->shdrs= malloc(sh_totalsize);
183        if(!image->shdrs) fail_errno("malloc");
184        memcpy(image->shdrs, elfdata + ehdr->e_shoff, sh_totalsize);
185    }
186
187    /* We need the dynamic relocation section, the string table, and the
188     * dynamic symbol table. */
189    Elf32_Shdr *shdr_rel= NULL, *shdr_sym= NULL;
190
191    /* Find the dynamic relocation section. */
192    Elf_Scn *scn;
193    for(scn= elf_nextscn(elf, NULL); scn; scn= elf_nextscn(elf, scn)) {
194
195        Elf32_Shdr *shdr= elf32_getshdr(scn);
196        if(!shdr) fail_elf("elf_getshdr");
197
198        switch(shdr->sh_type) {
199            case SHT_REL:
200                if(shdr_rel) fail("Found two relocation tables.\n");
201                shdr_rel= shdr;
202                break;
203            case SHT_DYNSYM:
204                if(shdr_sym) fail("Found two dynamic symbol tables.\n");
205                shdr_sym= shdr;
206                break;
207            case SHT_SYMTAB:
208                /* Save a copy of the symbol table. */
209                if(save_sections) {
210                    if(image->symtab) fail("Found two symbol tables.\n");
211
212                    image->symtab_size= shdr->sh_size;
213                    image->symtab_entsize= shdr->sh_entsize;
214                    image->symtab= malloc(shdr->sh_size);
215                    if(!image->symtab) fail_errno("malloc");
216
217                    assert(shdr->sh_offset + shdr->sh_size <= elfsize);
218                    memcpy(image->symtab, elfdata + shdr->sh_offset,
219                           shdr->sh_size);
220                }
221                break;
222            case SHT_STRTAB:
223                /* Save the main string table. */
224                if(save_sections &&
225                   !strcmp(shstr + shdr->sh_name, ".strtab")) {
226                    if(image->strtab) fail("Found two string tables.\n");
227
228                    image->strtab_size= shdr->sh_size;
229                    image->strtab= malloc(shdr->sh_size);
230                    if(!image->strtab) fail_errno("malloc");
231
232                    assert(shdr->sh_offset + shdr->sh_size <= elfsize);
233                    memcpy(image->strtab, elfdata + shdr->sh_offset,
234                           shdr->sh_size);
235                }
236                break;
237            case SHT_RELA:
238                fail("Didn't expect a RELA section.\n");
239        }
240    }
241
242    if(!shdr_rel) fail("Didn't find a relocation table.\n");
243    if(!shdr_sym) fail("Didn't find a dynamic symbol table.\n");
244
245    /* Find the got_base symbol, and its unrelocated address. */
246    uint32_t got_base = 0, got_base_reloc = 0;
247    int got_symidx= -1;
248    /* If the caller asked us to locate another symbol, this is it. */
249    uint32_t extrasym_initaddr = 0;
250    {
251        int found_extrasym= 0;
252
253        /* The dynamic symbol table should link to the dynamic string table. */
254        int dynstr_idx= shdr_sym->sh_link;
255        if(dynstr_idx == 0) fail("No link to the string table.\n");
256        Elf_Scn *scn_str= elf_getscn(elf, dynstr_idx);
257        if(!scn_str) fail_elf("elf_getscn");
258        Elf32_Shdr *shdr_str= elf32_getshdr(scn_str);
259        if(!shdr_str) fail_elf("elf32_getshdr");
260        if(shdr_str->sh_type != SHT_STRTAB)
261            fail("Invalid dynamic string table.\n");
262        /* This is the base of the string table, as loaded into RAM. */
263        char *str_base= (char *)elfdata + shdr_str->sh_offset;
264
265        /* Walk the symbol table, and find the symbol for the global offset
266         * table, 'got_base'. */
267        size_t entries= shdr_sym->sh_size / shdr_sym->sh_entsize;
268        void *base= elfdata + shdr_sym->sh_offset;
269        for(size_t i= 0; i < entries; i++) {
270            Elf32_Sym *sym=
271                (Elf32_Sym *)(base + i * shdr_sym->sh_entsize);
272
273            if(!strcmp("got_base", str_base + sym->st_name)) {
274                DBG("Found got_base at %08x\n", sym->st_value);
275                /* Remember the unrelocated address of the GOT. */
276                got_base= sym->st_value;
277                /* Remember the symbol index, so we can spot it, when it's
278                 * later mentioned in a relocation. */
279                got_symidx= i;
280            }
281
282            /* If we're looking for an extra symbol, do so. */
283            if(image->extrasym_name &&
284               !strcmp(image->extrasym_name, str_base + sym->st_name)) {
285                DBG("Found %s at %08x\n", image->extrasym_name,
286                                          sym->st_value);
287                extrasym_initaddr= sym->st_value;
288                found_extrasym= 1;
289            }
290        }
291        if(got_symidx == -1) fail("No got_base symbol.\n");
292        if(image->extrasym_name && !found_extrasym)
293            fail("No %s symbol\n", image->extrasym_name);
294    }
295
296    /* Find the first loadable segment, and load it. */
297    void *loaded_segment= NULL;
298    int found_got_base= 0, found_entry= 0, found_extrasym= 0;
299    size_t sidx;
300    for(sidx= 0; sidx < phnum && ph[sidx].p_type != PT_LOAD; sidx++);
301    if(sidx == phnum) fail("No loadable segments.\n");
302    Elf32_Phdr *phdr= &ph[sidx];
303
304    /* Record the unrelocated base address of the segment. */
305    image->segment_base= phdr->p_vaddr;
306    image->segment_size= phdr->p_memsz;
307
308    /* Segments are aligned to BASE_PAGE_SIZE (4k) by default.  If the
309     * segment has a greater alignment restriction, we use that, but
310     * only if it's a multiple of the page size, as we want to stay
311     * page-aligned. */
312    uint32_t seg_align;
313    if(phdr->p_align > BASE_PAGE_SIZE) {
314        if(phdr->p_align % BASE_PAGE_SIZE != 0) {
315            fail("Alignment of segment %u (%u)"
316                 " isn't a multiple of %u\n",
317                 sidx, phdr->p_align, BASE_PAGE_SIZE);
318        }
319
320        seg_align= phdr->p_align;
321        DBG("Increasing alignment to %u to match segment %zu\n",
322            seg_align, sidx);
323    }
324    else seg_align= BASE_PAGE_SIZE;
325
326    /* Allocate target memory.  Keep it to a multiple of the page
327     * size. */
328    image->loaded_size= round_up(phdr->p_memsz, BASE_PAGE_SIZE);
329    image->loaded_paddr= phys_alloc(image->loaded_size, seg_align);
330    image->loaded_vaddr= image->loaded_paddr + vp_offset;
331    DBG("Allocated %zu at VA %08x (PA %08x) for segment %zu\n",
332        image->loaded_size,
333        image->loaded_vaddr,
334        image->loaded_paddr, sidx);
335
336    /* Check whether we've found the GOT. */
337    if(phdr->p_vaddr <= got_base &&
338       (got_base - phdr->p_vaddr) < phdr->p_memsz) {
339        got_base_reloc=
340            image->loaded_vaddr + (got_base - phdr->p_vaddr);
341        DBG("got_base is in segment %zu, "
342            "relocated %08x to VA %08x\n",
343            sidx, got_base, got_base_reloc);
344        found_got_base= 1;
345    }
346
347    /* Check whether we've found the entry point. */
348    if(phdr->p_vaddr <= entry &&
349       (entry - phdr->p_vaddr) < phdr->p_memsz) {
350        image->relocated_entry=
351            image->loaded_vaddr + (entry - phdr->p_vaddr);
352        DBG("entry is in segment %zu, VA %08x\n",
353            sidx, image->relocated_entry);
354        found_entry= 1;
355    }
356
357    /* Allocate a buffer into which to load the segment. */
358    loaded_segment= calloc(image->loaded_size, 1);
359    if(!loaded_segment) fail_errno("calloc");
360    image->segment= loaded_segment;
361
362    if(phdr->p_offset + phdr->p_filesz > elfsize) {
363        fail("Segment extends outside file.\n");
364    }
365
366    /* Copy it to the buffer. */
367    memcpy(loaded_segment,
368           elfdata + phdr->p_offset,
369           phdr->p_filesz);
370
371    /* If we're looking for another symbol, check whether it's in this
372     * segment.  We will already have found its unrelocated address
373     * when we walked the symbol table. */
374    if(image->extrasym_name &&
375       phdr->p_vaddr <= extrasym_initaddr &&
376       (extrasym_initaddr - phdr->p_vaddr) < phdr->p_memsz) {
377        uint32_t extrasym_offset= extrasym_initaddr - phdr->p_vaddr;
378        DBG("%s is in segment %zu, offset %d\n",
379            image->extrasym_name, sidx, extrasym_offset);
380        /* Return the address within the loaded image. */
381        image->extrasym_ptr= loaded_segment + extrasym_offset;
382        found_extrasym= 1;
383    }
384
385    if(!found_got_base) fail("got_base not in any loadable segment.\n");
386    if(!found_entry)    fail("entry point not in any loadable segment.\n");
387    if(image->extrasym_name && !found_extrasym)
388        fail("%s not in any loadable segment.\n", image->extrasym_name);
389
390    /* Now that all segments have been allocated, apply relocations. */
391    {
392        size_t rel_count= shdr_rel->sh_size / shdr_rel->sh_entsize;
393        void *rel_table= elfdata + shdr_rel->sh_offset;
394        for(size_t i= 0; i < rel_count; i++) {
395            Elf32_Rel *rel=
396                (Elf32_Rel *)(rel_table + i * shdr_rel->sh_entsize);
397
398            int sym= ELF32_R_SYM(rel->r_info),
399                typ= ELF32_R_TYPE(rel->r_info);
400
401            /* Process the relocation if it's in the first loadable
402             * segment, otherwise ignore it. */
403            if(phdr->p_vaddr > rel->r_offset ||
404               rel->r_offset >= phdr->p_vaddr + phdr->p_memsz) {
405                printf("Ignoring relocation at %08x outside all "
406                       "loadable segments.\n", rel->r_offset);
407                continue;
408            }
409
410            /* Find the value to relocate. */
411            uint32_t offset_within_segment= rel->r_offset - phdr->p_vaddr;
412            uint32_t *value=
413                (uint32_t *)(loaded_segment + offset_within_segment);
414
415            /* There should be only section-relative relocations, except for
416             * one absolute relocation for the GOT. */
417            if(typ == R_ARM_RELATIVE && sym == 0) {
418                /* Perform the relocation. */
419                uint32_t reloc_offset= image->loaded_vaddr - phdr->p_vaddr;
420                DBG("Rel @ %08x: %08x -> %08x\n",
421                    rel->r_offset, *value, *value + reloc_offset);
422                *value+= reloc_offset;
423            }
424            else if(typ == R_ARM_ABS32 && sym == got_symidx) {
425                DBG("Rel @ %08x: %08x -> %08x\n",
426                    rel->r_offset, *value, got_base_reloc);
427                /* As this is an absolute address, we need apply the kernel
428                 * window offset (if any). */
429                *value= got_base_reloc;
430            }
431            else fail("Invalid relocation at %08x, typ=%d, sym=%d\n",
432                      rel->r_offset, typ, sym);
433        }
434    }
435
436    if(elf_end(elf) < 0) fail_elf("elf_end");
437
438    return image->segment;
439}
440
441/*** Output ELF Creation ***/
442
443static char *global_strings;
444static size_t global_strings_size= 0;
445
446static void
447init_strings(void) {
448    global_strings_size= 1;
449    global_strings= calloc(global_strings_size, 1);
450    if(!global_strings) fail_errno("malloc");
451}
452
453static size_t
454add_string(const char *s) {
455    /* The new string begins just past the current end. */
456    size_t start= global_strings_size;
457
458    /* Extend the buffer. */
459    global_strings_size+= strlen(s) + 1;
460    global_strings= realloc(global_strings, global_strings_size);
461    if(!global_strings) fail_errno("realloc");
462
463    /* Copy the new string in. */
464    strcpy(global_strings + start, s);
465
466    /* Return the index of the new string. */
467    return start;
468}
469
470/* Keep track of where we are in the output ELF file. */
471#define ELF_HEADER_SPACE 0x4000
472
473static size_t current_elf_offset= 0;
474
475static size_t
476get_elf_offset(void) {
477    return current_elf_offset;
478}
479
480static size_t
481increase_elf_offset(size_t n) {
482    size_t old_offset= current_elf_offset;
483    current_elf_offset+= n;
484    return old_offset;
485}
486
487static size_t
488align_elf_offset(size_t align) {
489    current_elf_offset= round_up(current_elf_offset, align);
490    return current_elf_offset;
491}
492
493static void
494advance_elf_offset(size_t n) {
495    assert(n + ELF_HEADER_SPACE >= current_elf_offset);
496    current_elf_offset= n + ELF_HEADER_SPACE;
497}
498
499/* Keep track of the highest physical address we've allocated, so we know how
500 * large the loadable segment is. */
501static paddr_t greatest_paddr= 0;
502
503/* Add an image (module or multiboot header) in its own section. */
504static Elf32_Shdr *
505add_blob(Elf *elf, const char *name, void *image, size_t size,
506          paddr_t paddr) {
507    /* Create the section. */
508    Elf_Scn *scn= elf_newscn(elf);
509    if(!scn) fail_elf("elf_newscn");
510
511    /* Add the image as a new data blob. */
512    Elf_Data *data= elf_newdata(scn);
513    if(!data) fail_elf("elf_newdata");
514
515    data->d_align=   1;
516    data->d_buf=     image;
517    data->d_off=     0;
518    data->d_size=    size;
519    data->d_type=    ELF_T_BYTE;
520    data->d_version= EV_CURRENT;
521
522    /* Initialise the section header. */
523    Elf32_Shdr *shdr= elf32_getshdr(scn);
524    if(!shdr) fail_elf("elf32_getshdr");
525
526    if(name) shdr->sh_name= add_string(name);
527    else     shdr->sh_name= 0;
528    shdr->sh_type=   SHT_PROGBITS;
529    shdr->sh_flags=  SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
530    /* The loader ELF contains the *physical* addresses. */
531    shdr->sh_addr=   (uint32_t)paddr;
532    shdr->sh_size=   size;
533    shdr->sh_offset= increase_elf_offset(size);
534
535    paddr_t last_byte= paddr + size - 1;
536    if(last_byte > greatest_paddr) greatest_paddr= last_byte;
537
538    return shdr;
539}
540
541/* Add a loaded image as a blob, without individual section headers. */
542static Elf32_Shdr *
543add_image(Elf *elf, const char *name, struct loaded_image *image) {
544    return add_blob(elf, name, image->segment, image->loaded_size,
545                    image->loaded_paddr);
546}
547
548/* Update any addresses stored in this table. */
549void
550update_table(uint32_t sh_type, void *section_data, size_t sh_size,
551             size_t sh_entsize, kvaddr_t segment_base, kvaddr_t loaded_vaddr,
552             size_t *index_map, size_t nshdr) {
553    switch(sh_type) {
554        case SHT_DYNSYM:
555        case SHT_SYMTAB: {
556            size_t nsym= sh_size / sh_entsize;
557            DBG("Relocating %zu symbols.\n", nsym);
558
559            for(size_t i= 0; i < nsym; i++) {
560                Elf32_Sym *sym= section_data + i * sh_entsize;
561
562                /* Absolute values needn't be relocated. */
563                if(sym->st_shndx == SHN_ABS) continue;
564
565                /* These shouldn't appear in executables. */
566                assert(sym->st_shndx != SHN_COMMON);
567
568                /* Update the section index. */
569                assert(sym->st_shndx < nshdr);
570                sym->st_shndx= index_map[sym->st_shndx];
571
572                /* Skip the null symbol. */
573                if(sym->st_shndx == SHN_UNDEF) continue;
574
575                /* Relocate the symbol to its loaded KV address. */
576                sym->st_value= (sym->st_value - segment_base) + loaded_vaddr;
577            }
578
579            break;
580        }
581        case SHT_REL: {
582            size_t nrel= sh_size / sh_entsize;
583            DBG("Rebasing %zu relocations.\n", nrel);
584
585            for(size_t i= 0; i < nrel; i++) {
586                Elf32_Rel *rel= section_data + i * sh_entsize;
587
588                /* Update the relocation's target address. */
589                rel->r_offset= (rel->r_offset - segment_base) + loaded_vaddr;
590            }
591
592            break;
593        }
594        case SHT_RELA:
595            fail("Didn't expect RELA sections.\n");
596    }
597}
598
599/* Add a loaded image by including all its loadable sections, and its symbol
600 * and string tables. */
601Elf32_Shdr *
602add_image_with_sections(Elf *elf, struct loaded_image *image) {
603    Elf32_Shdr *first_shdr= NULL;
604
605    assert(image->shdrs);
606    assert(image->shstrtab);
607
608    size_t nshdr= image->shdrs_size / image->shdrs_entsize;
609    DBG("%zu section headers to translate\n", nshdr);
610
611    size_t *new_index= alloca(nshdr * sizeof(size_t));
612    bzero(new_index, nshdr * sizeof(size_t));
613
614    Elf_Scn **new_scn= alloca(nshdr * sizeof(Elf_Scn *));
615    bzero(new_scn, nshdr * sizeof(Elf_Scn *));
616
617    /* For every allocatable section within the loadable segment, relocate it
618     * and add it to the output ELF. */
619    for(size_t i= 0; i < nshdr; i++) {
620        Elf32_Shdr *shdr= image->shdrs + i * image->shdrs_entsize;
621
622        if(!(shdr->sh_flags & SHF_ALLOC)) {
623            DBG("section %zu not allocatable.\n", i);
624            continue;
625        }
626
627        if(shdr->sh_addr <  image->segment_base ||
628           shdr->sh_addr >= image->segment_base + image->segment_size) {
629            DBG("section %zu not in the loaded segment.\n", i);
630            continue;
631        }
632
633        assert(shdr->sh_addr + shdr->sh_size <=
634               image->segment_base + image->segment_size);
635
636        const char *name= image->shstrtab + shdr->sh_name;
637        DBG("Adding section %zu: %s\n", i, name);
638
639        /* Create the section. */
640        new_scn[i]= elf_newscn(elf);
641        if(!new_scn[i]) fail_elf("elf_newscn");
642
643        size_t ndx= elf_ndxscn(new_scn[i]);
644        if(ndx == SHN_UNDEF) fail_elf("elf_ndxscn");
645        new_index[i]= ndx;
646        DBG("New section index is %zu\n", ndx);
647
648        uint32_t offset_in_seg= shdr->sh_addr - image->segment_base;
649        void *section_data= image->segment + offset_in_seg;
650
651        /* The previous section's size may have not have taken us up to our
652         * base address, so warp forward. */
653        advance_elf_offset(offset_in_seg);
654
655        /* Add the section data. */
656        Elf_Data *data= elf_newdata(new_scn[i]);
657        if(!data) fail_elf("elf_newdata");
658
659        /* Add the correct block of the loaded segment. */
660        data->d_align=   1; /* XXX */
661        data->d_buf=     section_data;
662        data->d_off=     0;
663        data->d_size=    shdr->sh_size;
664        data->d_type=    ELF_T_BYTE;
665        data->d_version= EV_CURRENT;
666
667        /* Create a new section header, with relocated addresses. */
668        Elf32_Shdr *new_shdr= elf32_getshdr(new_scn[i]);
669        if(!new_shdr) fail_elf("elf32_getshdr");
670        if(!first_shdr) first_shdr= new_shdr;
671
672        new_shdr->sh_name=      add_string(name);
673        new_shdr->sh_type=      shdr->sh_type;
674        new_shdr->sh_flags=     shdr->sh_flags;
675        /* Relocate the segment address. */
676        new_shdr->sh_addr=      image->loaded_vaddr + offset_in_seg;
677        new_shdr->sh_offset=    increase_elf_offset(shdr->sh_size);
678        new_shdr->sh_size=      shdr->sh_size;
679        new_shdr->sh_link=      shdr->sh_link; /* We'll update this soon. */
680        new_shdr->sh_info=      shdr->sh_info;
681        new_shdr->sh_addralign= shdr->sh_addralign;
682        new_shdr->sh_entsize=   shdr->sh_entsize;
683
684        DBG("Section base %08x, size %x\n", new_shdr->sh_addr,
685                new_shdr->sh_size);
686        DBG("Section offset %u\n", new_shdr->sh_offset);
687        DBG("Align %d %d\n", shdr->sh_addralign,
688                new_shdr->sh_addr % shdr->sh_addralign);
689
690        //assert(new_shdr->sh_offset % new_shdr->sh_addralign == 0);
691
692        paddr_t paddr= image->loaded_paddr + offset_in_seg;
693        paddr_t last_byte= paddr + shdr->sh_size - 1;
694        if(last_byte > greatest_paddr) greatest_paddr= last_byte;
695    }
696
697    /* Now that all sections have been allocated new headers, walk through and
698     * update any section->section links, and modify symbol and relocation
699     * tables.  */
700    for(size_t i= 0; i < nshdr; i++) {
701        if(!new_scn[i]) continue;
702
703        Elf32_Shdr *shdr= elf32_getshdr(new_scn[i]);
704        if(!shdr) fail_elf("elf32_getshdr");
705
706        assert(shdr->sh_link < nshdr);
707        shdr->sh_link= new_index[shdr->sh_link];
708
709        uint32_t offset_in_seg= shdr->sh_addr - image->loaded_vaddr;
710        void *section_data= image->segment + offset_in_seg;
711
712        /* If this is a symbol or relocation table, any addresses in it must
713         * be relocated. */
714        update_table(shdr->sh_type, section_data, shdr->sh_size,
715                     shdr->sh_entsize, image->segment_base,
716                     image->loaded_vaddr, new_index, nshdr);
717    }
718
719    /* Update the pointers in the symbol table now, while we've got the
720     * information to do it. */
721    update_table(SHT_SYMTAB, image->symtab, image->symtab_size,
722                 image->symtab_entsize, image->segment_base,
723                 image->loaded_vaddr, new_index, nshdr);
724
725    return first_shdr;
726}
727
728/* Add the non-loadable tables from an image.  This is separated from
729 * load_image_with_sections(), as they need to come last, such that we have a
730 * contiguous loadable segment. */
731static void
732add_tables(Elf *elf, struct loaded_image *image) {
733    /* Add the string table for the loaded image. */
734    size_t strtabndx;
735    {
736        assert(image->strtab);
737
738        /* Create the section. */
739        Elf_Scn *scn= elf_newscn(elf);
740        if(!scn) fail_elf("elf_newscn");
741
742        strtabndx= elf_ndxscn(scn);
743        if(strtabndx == SHN_UNDEF) fail_elf("elf_ndxscn");
744
745        Elf_Data *data= elf_newdata(scn);
746        if(!data) fail_elf("elf_newdata");
747
748        data->d_align=   1;
749        data->d_buf=     image->strtab;
750        data->d_off=     0;
751        data->d_size=    image->strtab_size;
752        data->d_type=    ELF_T_BYTE;
753        data->d_version= EV_CURRENT;
754
755        /* Initialise the section header. */
756        Elf32_Shdr *shdr= elf32_getshdr(scn);
757        if(!shdr) fail_elf("elf32_getshdr");
758
759        shdr->sh_name=   add_string(".strtab");
760        shdr->sh_type=   SHT_STRTAB;
761        shdr->sh_offset= increase_elf_offset(image->strtab_size);
762        shdr->sh_size=   image->strtab_size;
763        shdr->sh_flags=  0;
764        shdr->sh_addr=   0;
765    }
766
767    /* Add the symbol table. */
768    {
769        assert(image->symtab);
770
771        /* Create the section. */
772        Elf_Scn *scn= elf_newscn(elf);
773        if(!scn) fail_elf("elf_newscn");
774
775        Elf_Data *data= elf_newdata(scn);
776        if(!data) fail_elf("elf_newdata");
777
778        data->d_align=   1;
779        data->d_buf=     image->symtab;
780        data->d_off=     0;
781        data->d_size=    image->symtab_size;
782        data->d_type=    ELF_T_BYTE;
783        data->d_version= EV_CURRENT;
784
785        /* Initialise the section header. */
786        Elf32_Shdr *shdr= elf32_getshdr(scn);
787        if(!shdr) fail_elf("elf32_getshdr");
788
789        /* Elf32_Rel must be aligned to 4 bytes. */
790        align_elf_offset(4);
791
792        shdr->sh_name=    add_string(".symtab");
793        shdr->sh_type=    SHT_SYMTAB;
794        shdr->sh_flags=   0;
795        shdr->sh_addr=    0;
796        shdr->sh_offset=  increase_elf_offset(image->symtab_size);
797        shdr->sh_size=    image->symtab_size;
798        shdr->sh_link=    strtabndx; /* Link the string table. */
799        shdr->sh_entsize= image->symtab_entsize;
800    }
801}
802
803/* Add the section name string table. */
804static void
805add_strings(Elf *elf) {
806    Elf_Scn *scn= elf_newscn(elf);
807    if(!scn) fail_elf("elf_newscn");
808
809    size_t nameidx= add_string(".shstrtab");
810
811    Elf_Data *data= elf_newdata(scn);
812    if(!data) fail_elf("elf_newdata");
813
814    data->d_align=   1;
815    data->d_buf=     global_strings;
816    data->d_off=     0;
817    data->d_size=    global_strings_size;
818    data->d_type=    ELF_T_BYTE;
819    data->d_version= EV_CURRENT;
820
821    /* Initialise the string table section header. */
822    Elf32_Shdr *shdr= elf32_getshdr(scn);
823    if(!shdr) fail_elf("elf32_getshdr");
824
825    shdr->sh_name=      nameidx;
826    shdr->sh_type=      SHT_STRTAB;
827    shdr->sh_flags=     SHF_STRINGS;
828    shdr->sh_offset=    increase_elf_offset(global_strings_size);
829    shdr->sh_size=      global_strings_size;
830    shdr->sh_addralign= 1;
831
832    elf_setshstrndx(elf, elf_ndxscn(scn));
833};
834
835static void
836join_paths(char *dst, const char *src1, const char *src2) {
837    strcpy(dst, src1);
838    dst[strlen(src1)]= '/';
839    strcpy(dst + strlen(src1) + 1, src2);
840}
841
842struct
843loaded_module {
844    void *data;
845    paddr_t paddr;
846    size_t len;
847    const char *shortname;
848};
849
850/* Load an ELF file as a raw data blob. */
851void
852raw_load(const char *path, struct loaded_module *m) {
853    struct stat mstat;
854
855    if(stat(path, &mstat)) fail_errno("stat: %s", path);
856
857    size_t data_len= mstat.st_size;
858    m->len= round_up(data_len, BASE_PAGE_SIZE);
859    m->data= calloc(m->len, 1);
860    if(!m->data) fail_errno("calloc");
861    m->paddr= phys_alloc(m->len, BASE_PAGE_SIZE);
862
863    printf("Allocated 0x%zxB at PA %08x for %s\n", m->len, m->paddr, path);
864
865    FILE *f= fopen(path, "r");
866    size_t read_len= fread(m->data, 1, data_len, f);
867    if(read_len != data_len) fail_errno("fread");
868    if(fclose(f)) fail_errno("fclose");
869}
870
871/*** Multiboot ***/
872
873/* Create the multiboot header, using only *physical* addresses. */
874void *
875create_multiboot_info(struct menu_lst *menu, struct loaded_module *modules,
876                      size_t *mb_size, paddr_t *mb_base) {
877    size_t size;
878
879    /* Calculate the size of the multiboot info header, not including the
880     * module ELF images themselves, but including the MMAP, and the
881     * command-line strings. */
882    size= sizeof(struct multiboot_info);
883
884    /* Include NULL terminator, and separating space. */
885    size+= strlen(menu->kernel.path) + strlen(menu->kernel.args) + 2;
886
887    /* Module headers and command-line strings. */
888    size+= menu->nmodules * sizeof(struct multiboot_modinfo);
889    for(size_t i= 0; i < menu->nmodules; i++) {
890        size+= strlen(menu->modules[i].path) +
891               strlen(menu->modules[i].args) + 2;
892    }
893
894    /* Memory map. */
895    size+= menu->mmap_len * sizeof(struct multiboot_mmap);
896
897    /* Allocate target addresses. */
898    paddr_t base= phys_alloc(size, BASE_PAGE_SIZE);
899    printf("Allocated %luB at PA %08x for multiboot\n", size, base);
900    *mb_size= size;
901    *mb_base= base;
902
903    /* Allocate our host buffer. */
904    void *mb= calloc(size, 1);
905    if(!mb) fail_errno("calloc");
906
907    /* Lay the multiboot info out as follows:
908            ---------------------------
909            struct multiboot_info;
910            ---------------------------
911            struct multiboot_mmap[];
912            ---------------------------
913            struct multiboot_modinfo[];
914            ---------------------------
915            char strings[];
916            ---------------------------
917     */
918    struct multiboot_info *mbi= mb;
919
920    paddr_t mmap_base= base + sizeof(struct multiboot_info);
921    struct multiboot_mmap *mmap= mb + sizeof(struct multiboot_info);
922
923    paddr_t modinfo_base= mmap_base +
924                   menu->mmap_len * sizeof(struct multiboot_mmap);
925    struct multiboot_modinfo *modinfo= (void *)mmap +
926                   menu->mmap_len * sizeof(struct multiboot_mmap);
927
928    paddr_t strings_base= modinfo_base +
929                   menu->nmodules * sizeof(struct multiboot_modinfo);
930    char *strings= (void *)modinfo +
931                   menu->nmodules * sizeof(struct multiboot_modinfo);
932    size_t strings_idx= 0;
933
934    /* Fill in the info header */
935    mbi->flags= MULTIBOOT_INFO_FLAG_HAS_CMDLINE
936              | MULTIBOOT_INFO_FLAG_HAS_MODS
937              | MULTIBOOT_INFO_FLAG_HAS_MMAP;
938
939    /* Concatenate the path and arguments, separated by a space. */
940    mbi->cmdline= strings_base + strings_idx;
941    strcpy(strings + strings_idx, menu->kernel.path);
942    strings_idx+= strlen(menu->kernel.path);
943    strings[strings_idx]= ' ';
944    strings_idx+= 1;
945    strcpy(strings + strings_idx, menu->kernel.args);
946    strings_idx+= strlen(menu->kernel.args) + 1;
947
948    mbi->mods_count= menu->nmodules;
949    mbi->mods_addr= modinfo_base;
950
951    mbi->mmap_length= menu->mmap_len;
952    mbi->mmap_addr= mmap_base;
953
954    /* Add the MMAP entries. */
955    for(size_t i= 0; i < menu->mmap_len; i++) {
956        mmap[i].size=      sizeof(struct multiboot_mmap);
957        mmap[i].base_addr= menu->mmap[i].base;
958        mmap[i].length=    menu->mmap[i].length;
959        mmap[i].type=      menu->mmap[i].type;
960    }
961
962    /* Add the modinfo headers. */
963    for(size_t i= 0; i < menu->nmodules; i++) {
964        modinfo[i].mod_start= modules[i].paddr;
965        modinfo[i].mod_end=
966            modules[i].paddr + modules[i].len;
967
968        modinfo[i].string= strings_base + strings_idx;
969        strcpy(strings + strings_idx, menu->modules[i].path);
970        strings_idx+= strlen(menu->modules[i].path);
971        strings[strings_idx]= ' ';
972        strings_idx+= 1;
973        strcpy(strings + strings_idx, menu->modules[i].args);
974        strings_idx+= strlen(menu->modules[i].args) + 1;
975    }
976
977    return mb;
978}
979
980/*** Main ***/
981
982void
983usage(const char *name) {
984    fail("Usage: %s <menu.lst> <boot driver> <output filename>\n"
985         "          <build directory> <physical base address>\n",
986         name);
987}
988
989/* Find the first (lowest base address) RAM region. */
990static struct menu_mmap_entry *
991first_ram_region(struct menu_lst *menu) {
992    struct menu_mmap_entry *first= NULL;
993    uint64_t lowest_base= UINT64_MAX;
994
995    for(uint32_t i= 0; i < menu->mmap_len; i++) {
996        struct menu_mmap_entry *e= &menu->mmap[i];
997
998        if(e->type == MULTIBOOT_MEM_TYPE_RAM && e->base < lowest_base) {
999            lowest_base= e->base;
1000            first= e;
1001        }
1002    }
1003
1004    return first;
1005}
1006
1007int
1008main(int argc, char **argv) {
1009    char pathbuf[PATH_MAX+1];
1010
1011    if(argc != 6) usage(argv[0]);
1012
1013    const char *menu_lst=   argv[1],
1014               *bootdriver= argv[2],
1015               *outfile=    argv[3],
1016               *buildroot=  argv[4];
1017
1018    errno= 0;
1019    paddr_t phys_base= strtoul(argv[5], NULL, 0);
1020    if(errno) fail_errno("strtoul");
1021
1022    printf("ARM Static Bootloader\n");
1023
1024    /* Read the menu.lst file. */
1025    printf("Reading boot configuration from %s\n", menu_lst);
1026    struct menu_lst *menu= read_menu_lst(menu_lst);
1027
1028    /* Check that the requested base address is inside the first RAM region. */
1029    struct menu_mmap_entry *ram_region= first_ram_region(menu);
1030    if(!ram_region) fail("No RAM regions defined.\n");
1031    if(ram_region->base > (uint64_t)UINT32_MAX)
1032        fail("This seems to be a 64-bit memory map.\n");
1033    if(phys_base < ram_region->base ||
1034       phys_base >= ram_region->base + ram_region->length) {
1035        fail("Requested base address %08x is outside the first RAM region.\n",
1036             phys_base);
1037    }
1038    paddr_t ram_start= (paddr_t)ram_region->base;
1039    uint32_t kernel_offset= KERNEL_WINDOW - ram_start;
1040
1041    /* Begin allocation at the requested start address. */
1042    phys_alloc_start= phys_base;
1043    printf("Beginning allocation at PA %08x (VA %08x)\n",
1044           phys_base, phys_base + kernel_offset);
1045
1046    if(elf_version(EV_CURRENT) == EV_NONE)
1047        fail("ELF library version out of date.\n");
1048
1049    /*** Load the boot driver. ***/
1050
1051    /* Open the boot driver ELF. */
1052    printf("Loading %s\n", bootdriver);
1053    int bd_fd= open(bootdriver, O_RDONLY);
1054    if(bd_fd < 0) fail_errno("open");
1055
1056    /* Load and relocate it. */
1057    struct loaded_image bd_image;
1058    bd_image.extrasym_name= "boot_arguments";
1059    void *bd_loaded=
1060        load(bd_fd, 0, /* The boot driver executes in physical space. */
1061             &bd_image,
1062             1);       /* Copy section and symbol data. */
1063    assert(bd_loaded != NULL);
1064
1065    printf("Boot driver entry point: PA %08x\n",
1066           (paddr_t)bd_image.relocated_entry);
1067
1068    /* Close the ELF. */
1069    if(close(bd_fd) < 0) fail_errno("close");
1070
1071    /*** Load the CPU driver. ***/
1072
1073    /* Open the kernel ELF. */
1074    join_paths(pathbuf, buildroot, menu->kernel.path);
1075
1076    printf("Loading %s\n", pathbuf);
1077    int cpu_fd= open(pathbuf, O_RDONLY);
1078    if(cpu_fd < 0) fail_errno("open");
1079
1080    /* Load and relocate it. */
1081    struct loaded_image cpu_image;
1082    cpu_image.extrasym_name= NULL;
1083    void *cpu_loaded=
1084        load(cpu_fd, kernel_offset, &cpu_image, 0);
1085    assert(cpu_loaded != NULL);
1086
1087    printf("CPU driver entry point: VA %08x\n", cpu_image.relocated_entry);
1088
1089    /* Close the ELF. */
1090    if(close(cpu_fd) < 0) fail_errno("close");
1091
1092    /*** Load the modules. ***/
1093
1094    struct loaded_module *modules=
1095        calloc(menu->nmodules, sizeof(struct loaded_module));
1096    if(!modules) fail_errno("calloc");
1097
1098    for(size_t i= 0; i < menu->nmodules; i++) {
1099        join_paths(pathbuf, buildroot, menu->modules[i].path);
1100        raw_load(pathbuf, &modules[i]);
1101
1102        /* Use the filename as a short identifier. */
1103        const char *lastslash= strrchr(menu->modules[i].path, '/');
1104        if(lastslash) modules[i].shortname= lastslash + 1;
1105        else          modules[i].shortname= "";
1106    }
1107
1108    /*** Create the multiboot info header. ***/
1109    size_t mb_size;
1110    paddr_t mb_base;
1111    void *mb_image= create_multiboot_info(menu, modules, &mb_size, &mb_base);
1112
1113    /* Set the 'static_multiboot' pointer to the kernel virtual address of the
1114     * multiboot image.  Pass the CPU driver entry point. */
1115    *(kvaddr_t *)(bd_image.extrasym_ptr + 0)=
1116        mb_base + kernel_offset;
1117    *(kvaddr_t *)(bd_image.extrasym_ptr + 4)=
1118        cpu_image.relocated_entry; /* Already virtual. */
1119    *(kvaddr_t *)(bd_image.extrasym_ptr + 8)=
1120        cpu_image.loaded_vaddr;    /* Already virtual. */
1121
1122    /*** Write the output file. ***/
1123
1124    init_strings();
1125
1126    /* Open the output image file. */
1127    printf("Writing to %s\n", outfile);
1128    int out_fd= open(outfile, O_WRONLY | O_CREAT | O_TRUNC,
1129                     S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
1130                     S_IROTH | S_IWOTH);
1131    if(out_fd < 0) fail_errno("open");
1132
1133    /* Create the output ELF file. */
1134    Elf *out_elf= elf_begin(out_fd, ELF_C_WRITE, NULL);
1135    if(!out_elf) fail_elf("elf_begin");
1136
1137    /* We need to lay our sections out explicitly. */
1138    if(!elf_flagelf(out_elf, ELF_C_SET, ELF_F_LAYOUT)) fail_elf("elf_flagelf");
1139
1140    /* Create the ELF header. */
1141    Elf32_Ehdr *out_ehdr= elf32_newehdr(out_elf);
1142    if(!out_ehdr) fail_elf("elf32_newehdr");
1143
1144    /* Little-endian ARM executable. */
1145    out_ehdr->e_ident[EI_DATA]= ELFDATA2LSB;
1146    out_ehdr->e_type=           ET_EXEC;
1147    out_ehdr->e_machine=        EM_ARM;
1148    out_ehdr->e_entry=          bd_image.relocated_entry;
1149    /* Program headers after the executable header. */
1150    increase_elf_offset(sizeof(Elf32_Ehdr));
1151    out_ehdr->e_phoff=          get_elf_offset();
1152
1153    /* Create a single program header (segment) to cover everything that we
1154     * need to load. */
1155    Elf32_Phdr *out_phdr= elf32_newphdr(out_elf, 1);
1156    if(!out_phdr) fail_elf("elf32_newphdr");
1157    increase_elf_offset(sizeof(Elf32_Phdr));
1158
1159    /* Advance to an aligned address to make section alignment easier. */
1160    advance_elf_offset(0);
1161
1162    /* The boot driver, CPU driver and multiboot image all get their own
1163     * sections. */
1164    size_t loadable_segment_offset= get_elf_offset();
1165    Elf32_Shdr *fst_shdr= add_image_with_sections(out_elf, &bd_image);
1166    assert(fst_shdr != NULL);
1167    advance_elf_offset(cpu_image.loaded_paddr - phys_base);
1168    Elf32_Shdr *cpu_shdr= add_image(out_elf, ".cpudriver", &cpu_image);
1169    assert(cpu_shdr != NULL);
1170    for(size_t i= 0; i < menu->nmodules; i++) {
1171        char name[32];
1172        snprintf(name, 32, ".elf.%s", modules[i].shortname);
1173        advance_elf_offset(modules[i].paddr - phys_base);
1174        add_blob(out_elf, name, modules[i].data, modules[i].len,
1175                 modules[i].paddr);
1176    }
1177    advance_elf_offset(mb_base - phys_base);
1178    add_blob(out_elf, ".multiboot", mb_image, mb_size, mb_base);
1179    size_t end_of_segment= get_elf_offset();
1180
1181    /* Add the boot driver's string and symbol tables. */
1182    add_tables(out_elf, &bd_image);
1183
1184    /* Add the string table.  This must be the last section added, as it
1185     * contains the names of all other sections. */
1186    add_strings(out_elf);
1187
1188    /* Elf32_Shdr must be aligned to 4 bytes. */
1189    align_elf_offset(4);
1190
1191    /* Place the section headers. */
1192    out_ehdr->e_shoff= get_elf_offset();
1193
1194    size_t total_size= end_of_segment - loadable_segment_offset;
1195    if(total_size > ram_region->length)
1196        fail("Overflowed the first RAM region.\n");
1197
1198    out_phdr->p_type=   PT_LOAD;
1199    out_phdr->p_offset= loadable_segment_offset;
1200    out_phdr->p_vaddr=  phys_base; /* Load at physical address. */
1201    out_phdr->p_paddr=  phys_base; /* Actually ignored. */
1202    /* This is dodgy, but GEM5 refuses to load an image that doesn't have a
1203     * BSS, and hence a larger memsz then filesz.  Purely a hack, and luckily
1204     * doesn't seem to affect non-dodgy simulators. */
1205    out_phdr->p_memsz=  round_up(total_size + 1, BASE_PAGE_SIZE);
1206    out_phdr->p_filesz= total_size;
1207    out_phdr->p_align=  1;
1208    out_phdr->p_flags=  PF_X | PF_W | PF_R;
1209
1210    elf_flagphdr(out_elf, ELF_C_SET, ELF_F_DIRTY);
1211
1212    /* Write the file. */
1213    if(elf_update(out_elf, ELF_C_WRITE) < 0) fail_elf("elf_update");
1214
1215    if(elf_end(out_elf) < 0) fail_elf("elf_update");
1216    if(close(out_fd) < 0) fail_errno("close");
1217
1218    return EXIT_SUCCESS;
1219}
1220