1#include <sys/types.h>
2#include <sys/stat.h>
3
4#include <assert.h>
5#include <errno.h>
6#include <limits.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11
12#define KERNEL_OFFSET 0xffff000000000000
13
14#include "build_multiboot.h"
15#include "config.h"
16#include "efi.h"
17#include "util.h"
18
19void usage(char *name) {
20    fprintf(stderr, "usage: %s <config> <ram size> <shim image> <fs root>"
21                    " <output file> [-d]\n", name);
22    exit(EXIT_FAILURE);
23}
24
25void fail(char *name) {
26    perror(name);
27    exit(EXIT_FAILURE);
28}
29
30void elf_fail(char *name) {
31    fprintf(stderr, "%s: %s\n", name, elf_errmsg(elf_errno()));
32    exit(EXIT_FAILURE);
33}
34
35/* Read the complete contents of a file. */
36void *
37load_file(const char *path, size_t *length, size_t *alloc) {
38    FILE *file= fopen(path, "r");
39    if(!file) fail("fopen");
40
41    struct stat stat;
42    if(fstat(fileno(file), &stat) < 0) fail("stat");
43
44    /* Allocate a page-sized zero-initialised buffer. */
45    size_t alloc_size= ROUNDUP(stat.st_size, PAGE_4k);
46    char *buf= calloc(alloc_size, 1);
47    if(!buf) fail("calloc");
48
49    if(fread(buf, 1, stat.st_size, file) != stat.st_size) fail("fread");
50
51    if(fclose(file) != 0) fail("fclose");
52
53    *length= stat.st_size;
54    *alloc= alloc_size;
55    return buf;
56}
57
58/* Load the ELF image for a component, and fill the relevant fields in the
59 * configuration struct. */
60int
61load_component(char *basepath, size_t bplen, struct component_config *comp,
62               char *buf) {
63    if(bplen + comp->path_len >= PATH_MAX) {
64        errno= ENAMETOOLONG;
65        return -1;
66    }
67
68    /* Append the component path to the FS base path, and null terminate. */
69    memcpy(basepath + bplen, buf + comp->path_start, comp->path_len);
70    basepath[bplen + comp->path_len]= '\0';
71
72    /* Canonicalise the path. */
73    char path[PATH_MAX];
74    if(!realpath(basepath, path)) {
75        fprintf(stderr, "Couldn't find %s\n", path);
76        fail("relpath");
77    }
78
79    /* Load the ELF */
80#if 0
81    printf("Loading component %s\n", path);
82#endif
83    comp->image= load_file(path, &comp->image_size, &comp->alloc_size);
84
85    return 0;
86}
87
88/* Fill the preallocated EFI memory map in. */
89efi_memory_descriptor *
90build_efi_mmap(struct config *config, size_t mmap_len,
91               size_t first_region, uint64_t ram_size) {
92    efi_memory_descriptor *mmap=
93        (efi_memory_descriptor *)config->mmap_start;
94
95    /* Write the tag. */
96    config->mmap_tag->type= MULTIBOOT_TAG_TYPE_EFI_MMAP;
97    config->mmap_tag->size= sizeof(struct multiboot_tag_efi_mmap) +
98                            mmap_len * sizeof(efi_memory_descriptor);
99    config->mmap_tag->descr_size= sizeof(efi_memory_descriptor);
100    config->mmap_tag->descr_vers= 1;
101
102    if((ram_size & (PAGE_4k-1)) != 0) {
103        fprintf(stderr, "RAM size %lu isn't a multiple of 4k.\n", ram_size);
104        exit(EXIT_FAILURE);
105    }
106
107    /* Calculate the sizes of the two windows - fill the lower one first. */
108    uint64_t region_one, region_two;
109    if(ram_size < 2 * (1UL<<30)) {
110        region_one= ram_size;
111        region_two= 0;
112    }
113    else {
114        region_one= 2 * (1UL<<30);
115        region_two = ram_size - region_one;
116    }
117    assert(region_two <= 6 * (1UL<<30));
118
119    /* The first 2GiB RAM window starts at 0x80000000, or 2GiB, on sensible
120     * ARM platforms, such as this one. */
121    mmap[first_region].Type=          EfiConventionalMemory;
122    mmap[first_region].PhysicalStart= 0x80000000;
123    mmap[first_region].VirtualStart=  0x80000000;
124    mmap[first_region].NumberOfPages= region_one / PAGE_4k;
125    mmap[first_region].Attribute=     0; /* XXX - this should change. */
126
127    /* Add the second region, only if required.  It must be allocated. */
128    if(region_two > 0) {
129        assert(first_region + 1 < mmap_len);
130        /* On platforms that follow the "Principles of ARM Memory Maps"
131         * whitepaper, the second RAM window begins at 0x880000000, or 2GiB +
132         * 32GiB, and is 30GiB in length.  The pattern repeats, such that an
133         * n-bit physical address space has 2^(n-1)B of RAM windows.  On some
134         * platforms (including the fast models), the region 0x800000000 -
135         * 0x87fffffff aliases the first RAM window, giving a contiguous
136         * window in a 36-bit or greater PA space.  Using the aliased
137         * addresses, however, is a bad idea - physical memory aliases are
138         * not good for the caches. */
139        mmap[first_region+1].Type=          EfiConventionalMemory;
140        mmap[first_region+1].PhysicalStart= 0x880000000;
141        mmap[first_region+1].VirtualStart=  0x880000000;
142        mmap[first_region+1].NumberOfPages= region_two / PAGE_4k;
143        mmap[first_region+1].Attribute=     0; /* XXX - this should change. */
144    }
145
146    /* We only need two windows to map up to 32GiB of RAM, which is already
147     * more than the fast models support. */
148
149    return mmap;
150}
151
152void
153check_alloc(uint64_t allocbase, efi_memory_descriptor *mmap, size_t region) {
154    if(allocbase >= mmap[region].PhysicalStart +
155                    mmap[region].NumberOfPages * PAGE_4k) {
156        fprintf(stderr, "Ran out of room in the first memory region.\n");
157        fprintf(stderr, "Region: %lx-%lx, allocbase=%lx\n",
158                mmap[region].PhysicalStart,
159                mmap[region].PhysicalStart +
160                mmap[region].NumberOfPages * PAGE_4k,
161                allocbase);
162        exit(EXIT_FAILURE);
163    }
164}
165
166void *
167load_cpudriver(Elf *kernel_elf, void *kernel_raw, size_t kernel_size,
168               uint64_t virt_base, uint64_t *loaded_size, uint64_t *alloc,
169               uint64_t *entry) {
170    size_t phnum;
171    if(elf_getphdrnum(kernel_elf, &phnum)) elf_fail("elf_getphdrnum");
172
173    Elf64_Phdr *phdrs= elf64_getphdr(kernel_elf);
174    if(!phdrs) elf_fail("elf64_getphdr");
175
176    /* Find the dynamic segment, and calculate the base and limit for the
177     * loadable region. */
178    uint64_t base= UINT64_MAX, limit= 0;
179    size_t dseg;
180    int have_dseg= 0;
181    for(size_t kseg= 0; kseg < phnum; kseg++) {
182        if(phdrs[kseg].p_type == PT_DYNAMIC) {
183            if(have_dseg) {
184                fprintf(stderr, "Two PT_DYNAMIC segments.\n");
185                exit(EXIT_FAILURE);
186            }
187            dseg= kseg;
188            have_dseg= 1;
189        }
190        else if(phdrs[kseg].p_type == PT_LOAD) {
191            if(phdrs[kseg].p_vaddr < base)
192                base= phdrs[kseg].p_vaddr;
193
194            assert(phdrs[kseg].p_memsz <= UINT64_MAX - phdrs[kseg].p_vaddr);
195            if(phdrs[kseg].p_vaddr + phdrs[kseg].p_memsz > limit)
196                limit= phdrs[kseg].p_vaddr + phdrs[kseg].p_memsz;
197        }
198    }
199    if(!have_dseg) {
200        fprintf(stderr, "No PT_DYNAMIC segment.\n");
201        exit(EXIT_FAILURE);
202    }
203
204    /* Relocate the entry point. */
205    Elf64_Ehdr *ehdr= elf64_getehdr(kernel_elf);
206    if(!ehdr) elf_fail("elf64_getehdr");
207    *entry= virt_base + (ehdr->e_entry - base);
208
209    /* Allocate the target region. */
210    *loaded_size= limit - base + 1;
211    *alloc= ROUNDUP(*loaded_size, PAGE_4k);
212    void *cpudriver= malloc(*alloc);
213    if(!cpudriver) fail("malloc");
214    bzero(cpudriver, *alloc);
215
216    /* Copy all loadable segments. */
217    int loaded_something= 0;
218    for(size_t kseg= 0; kseg < phnum; kseg++) {
219        Elf64_Phdr *ph= &phdrs[kseg];
220        if(ph->p_type == PT_LOAD) {
221            assert(ph->p_offset < kernel_size);
222            assert(ph->p_offset + ph->p_filesz < kernel_size);
223
224            void *seg_vbase= cpudriver + (ph->p_vaddr - base);
225            memcpy(seg_vbase, kernel_raw + ph->p_offset, ph->p_filesz);
226
227            loaded_something= 1;
228        }
229    }
230
231    if(!loaded_something) {
232        fprintf(stderr, "No loadable segments in CPU driver ELF.\n");
233        exit(EXIT_FAILURE);
234    }
235
236    /* Process the dynamic linking section. */
237    Elf64_Phdr *dhdr= &phdrs[dseg];
238    size_t dtnum= dhdr->p_filesz / sizeof(Elf64_Dyn);
239    Elf64_Dyn *dt= (Elf64_Dyn *)(kernel_raw + dhdr->p_offset);
240    void *rela_base= NULL;
241    size_t rela_entsize= 0, rela_count= 0;
242    for(size_t i= 0; i < dtnum && dt[i].d_tag != DT_NULL; i++) {
243        switch(dt[i].d_tag) {
244            case DT_RELA:
245                /* The address of the relocation section is given as an
246                 * unrelocated virtual address, inside the loaded segment.  We
247                 * need to rebase it. */
248                rela_base= cpudriver + (dt[i].d_un.d_ptr - base);
249                break;
250            case DT_RELAENT:
251                rela_entsize= dt[i].d_un.d_val;
252                break;
253            case DT_RELACOUNT:
254                rela_count= dt[i].d_un.d_val;
255                break;
256
257            case DT_RELASZ:
258            case DT_TEXTREL:
259            case DT_DEBUG:
260                break; /* Ignored */
261
262            case DT_REL:
263            case DT_RELENT:
264            case DT_RELCOUNT:
265                fprintf(stderr, "Unsupported relocation type: DT_REL\n");
266                exit(EXIT_FAILURE);
267
268            default:
269                printf("Warning, ignoring dynamic section entry, tag %lx\n",
270                       dt[i].d_tag);
271        }
272    }
273    if(!rela_base || !rela_entsize || !rela_count) {
274        printf("Warning: no relocation (RELA) section.\n");
275        return cpudriver;
276    }
277
278    /* Process the relocations. */
279    for(size_t i= 0; i < rela_count; i++, rela_base+= rela_entsize) {
280        Elf64_Rela *rela= (Elf64_Rela *)rela_base;
281
282        if(ELF64_R_SYM(rela->r_info) != 0) {
283            fprintf(stderr, "Unsupported symbol-based relocation at %lx.\n",
284                            rela->r_offset);
285            exit(EXIT_FAILURE);
286        }
287
288        /* Find the target, inside the loaded segment. */
289        uint64_t *target= cpudriver + (rela->r_offset - base);
290
291#if 0
292        printf("%lx[%lx] (%p): %lx ->", rela->r_offset,
293                rela->r_addend, target, *target);
294#endif
295
296        switch(ELF64_R_TYPE(rela->r_info)) {
297            /* Our one supported relocation type. */
298            case R_AARCH64_RELATIVE: {
299                /* Relocation: Delta(S) + A */
300                *target= (rela->r_addend - base) + virt_base;
301                break;
302            }
303
304            default:
305                fprintf(stderr, "Unsupported relocation type (%lu) at %lx.\n",
306                                ELF64_R_TYPE(rela->r_info), rela->r_offset);
307                exit(EXIT_FAILURE);
308        }
309#if 0
310        printf(" %lx\n", *target);
311#endif
312    }
313
314    return cpudriver;
315}
316
317void *
318load_shim(Elf *shim_elf, void *shim_raw, size_t shim_size,
319          uint64_t virt_base, uint64_t *loaded_size, uint64_t *alloc,
320          uint64_t kernel_table, uint64_t kernel_stack_top,
321          uint64_t multiboot, uint64_t entry, uint64_t *shim_entry,
322          int quiet) {
323    size_t phnum;
324    if(elf_getphdrnum(shim_elf, &phnum)) elf_fail("elf_getphdrnum");
325
326    Elf64_Phdr *phdrs= elf64_getphdr(shim_elf);
327    if(!phdrs) elf_fail("elf64_getphdr");
328
329    /* Calculate the base and limit for the loadable region. */
330    uint64_t base= UINT64_MAX, limit= 0;
331    for(size_t kseg= 0; kseg < phnum; kseg++) {
332        if(phdrs[kseg].p_type == PT_LOAD) {
333            if(phdrs[kseg].p_vaddr < base)
334                base= phdrs[kseg].p_vaddr;
335
336            assert(phdrs[kseg].p_memsz <= UINT64_MAX - phdrs[kseg].p_vaddr);
337            if(phdrs[kseg].p_vaddr + phdrs[kseg].p_memsz > limit)
338                limit= phdrs[kseg].p_vaddr + phdrs[kseg].p_memsz;
339        }
340    }
341
342    /* Relocate the entry point. */
343    Elf64_Ehdr *ehdr= elf64_getehdr(shim_elf);
344    if(!ehdr) elf_fail("elf64_getehdr");
345    *shim_entry= virt_base + (ehdr->e_entry - base);
346
347    /* Allocate the target region. */
348    *loaded_size= limit - base + 1;
349    *alloc= ROUNDUP(*loaded_size, PAGE_4k);
350    void *shim= malloc(*alloc);
351    if(!shim) fail("malloc");
352    bzero(shim, *alloc);
353
354    /* Copy all loadable segments. */
355    int loaded_something= 0;
356    for(size_t kseg= 0; kseg < phnum; kseg++) {
357        Elf64_Phdr *ph= &phdrs[kseg];
358        if(ph->p_type == PT_LOAD) {
359            assert(ph->p_offset < shim_size);
360            assert(ph->p_offset + ph->p_filesz < shim_size);
361
362            void *seg_vbase= shim + (ph->p_vaddr - base);
363            memcpy(seg_vbase, shim_raw + ph->p_offset, ph->p_filesz);
364
365            loaded_something= 1;
366        }
367    }
368
369    if(!loaded_something) {
370        fprintf(stderr, "No loadable segments in shim ELF.\n");
371        exit(EXIT_FAILURE);
372    }
373
374    /* Find the symbol and string tables. */
375    Elf_Scn *scn= NULL;
376    Elf64_Word sh_type;
377    Elf64_Shdr *sh_symtab= NULL, *sh_strtab= NULL;
378    while((scn= elf_nextscn(shim_elf, scn)) != NULL) {
379        if(!scn) elf_fail("elf_nextscn");
380
381        Elf64_Shdr *shdr= elf64_getshdr(scn);
382        if(!shdr) elf_fail("elf64_getshdr");
383        sh_type= shdr->sh_type;
384
385        if(sh_type == SHT_REL || sh_type == SHT_RELA) {
386            fprintf(stderr, "Shim requires relocation.\n");
387            exit(EXIT_FAILURE);
388        }
389
390        if(sh_type == SHT_SYMTAB) sh_symtab= shdr;
391        if(sh_type == SHT_STRTAB) sh_strtab= shdr;
392    }
393    if(!sh_symtab) {
394        fprintf(stderr, "Missing symbol table.\n");
395        exit(EXIT_FAILURE);
396    }
397    if(!sh_strtab) {
398        fprintf(stderr, "Missing symbol table.\n");
399        exit(EXIT_FAILURE);
400    }
401
402    /* Find the pointer fields to fill in. */
403    int have_kernel_table= 0, have_kernel_stack_top= 0,
404        have_multiboot= 0, have_entry= 0;
405    const char *strings= (const char *)(shim_raw + sh_strtab->sh_offset);
406    for(size_t i= 0; i < sh_symtab->sh_size; i+= sizeof(Elf64_Sym)) {
407        Elf64_Sym *sym= (Elf64_Sym *)(shim_raw + sh_symtab->sh_offset + i);
408
409        /* Find the symbol name. */
410        const char *name= strings + sym->st_name;
411
412        /* Find the symbol in the loaded image. */
413        uint64_t *target= shim + (sym->st_value - base);
414
415        /* Check for the target symbols. */
416        uint64_t value;
417        if(!strcmp("p_kernel_table", name)) {
418            have_kernel_table= 1;
419            value= kernel_table;
420        }
421        else if(!strcmp("p_kernel_stack_top", name)) {
422            have_kernel_stack_top= 1;
423            value= kernel_stack_top;
424        }
425        else if(!strcmp("p_multiboot", name)) {
426            have_multiboot= 1;
427            value= multiboot;
428        }
429        else if(!strcmp("p_entry", name)) {
430            have_entry= 1;
431            value= entry;
432        }
433        else continue;
434
435        /* Update the pointer. */
436        if(!quiet) {
437            printf("Setting %s at %lx to %lx\n",
438                   name, virt_base + (sym->st_value - base), value);
439        }
440        *target= value;
441    }
442    if(!(have_kernel_table && have_kernel_stack_top &&
443         have_multiboot && have_entry)) {
444        fprintf(stderr, "Missing shim symbol.\n");
445        exit(EXIT_FAILURE);
446    }
447
448    return shim;
449}
450
451/* A descriptor for the next-level table.
452 * These are the same at all levels. */
453struct table_descriptor {
454    uint64_t        type            :2;     // == 3 -> Table
455    uint64_t        ign0            :10;    // Ignored
456    uint64_t        base_address    :28;    // Table address
457    uint64_t        sbz0            :12;    // sbz
458    uint64_t        ign1            :7;     // Ignored
459
460    /* Hierarchical lookup attributes */
461    uint64_t        pxn             :1;     // Privileged eXecute Never
462    uint64_t        xn              :1;     // eXecute Never
463    uint64_t        ap              :2;     // Access Permissions
464    uint64_t        ns              :1;     // NonSecure
465};
466
467union armv8_l1_entry {
468    uint64_t raw;
469
470    /* An L1 entry for a 1GB block (page) */
471    struct {
472        uint64_t        type            :2;     // == 1 -> Block
473
474        /* Lower block attributes */
475        uint64_t        ai              :3;
476        uint64_t        ns              :1;
477        uint64_t        ap              :2;     // AP
478        uint64_t        sh              :2;     // AP
479        uint64_t        af              :1;     // AF
480        uint64_t        ng              :1;     // NG
481
482        uint64_t        sbz0            :18;
483        uint64_t        base_address    :18;    // block base address
484        uint64_t        sbz1            :4;
485
486        /* Upper block attributes */
487        uint64_t        ch              :1;     // CH
488        uint64_t        pxn             :1;     // PXN
489        uint64_t        xn              :1;     // XN
490        uint64_t        res             :4;     // Reserved
491        uint64_t        ign1            :5;     // Ignored
492    } block;
493};
494
495#define BIT(n) (1ULL << (n))
496#define MASK(n) (BIT(n) - 1)
497#define PTABLE_ENTRY_BITS 3
498#define PTABLE_ENTRY_SIZE BIT(PTABLE_ENTRY_BITS)
499#define PTABLE_BITS          9
500#define PTABLE_SIZE          BIT(PTABLE_BITS + PTABLE_ENTRY_BITS)
501#define PTABLE_NUM_ENTRIES   BIT(PTABLE_BITS)
502
503enum armv8_entry_type {
504    ARMv8_Ln_INVALID = 0,
505    ARMv8_Ln_BLOCK   = 1,
506    ARMv8_Ln_TABLE   = 3,
507    ARMv8_L3_PAGE    = 3
508};
509
510void *
511alloc_kernel_pt(size_t *pt_size, uint64_t table_base,
512        efi_memory_descriptor *mmap, size_t mmap_len) {
513    /* Allocate one L0 & one L1 table, in a contiguous block. An L0
514     * translation unit i.e. an L1 table, maps 512GiB with our translation
515     * settings, which is more than enough for a one-to-one kernel physical
516     * window. */
517    void *block= calloc(2, PTABLE_SIZE);
518    if(!block) fail("calloc");
519
520    struct table_descriptor *l0_table=
521        (struct table_descriptor *)block;
522    union armv8_l1_entry *l1_table=
523        (union armv8_l1_entry *)(block + PTABLE_SIZE);
524
525    /* Map the first two 1GiB blocks as device memory, using memory attribute
526     * 1, which we'll set to nGnRnE. */
527    for(size_t j= 0; j < 2; j++) {
528        l1_table[j].block.type= ARMv8_Ln_BLOCK;
529        l1_table[j].block.ai=  1; /* Memory type 1 */
530        l1_table[j].block.ns=  1; /* Non-secure. */
531        l1_table[j].block.ap=  0; /* R/W EL1, no access EL0 */
532        l1_table[j].block.sh=  2; /* Outer shareable - this is actually
533                                     ignored anyway. */
534        l1_table[j].block.af=  1; /* Accessed/dirty - don't fault */
535        l1_table[j].block.ng=  0; /* Global mapping */
536        l1_table[j].block.base_address= j; /* PA = j << 30 */
537        l1_table[j].block.ch=  1; /* Contiguous, combine TLB entries */
538        l1_table[j].block.pxn= 1; /* Nonexecutable. */
539        l1_table[j].block.xn=  1; /* Nonexecutable. */
540    }
541
542    /* Map all RAM regions using contiguous 1GiB blocks.  Use memory attribute
543     * 0, which we will set to fully-cacheable Normal memory. */
544    for(size_t i= 0; i < mmap_len; i++) {
545        efi_memory_descriptor *d= &mmap[i];
546
547        if(d->Type == EfiConventionalMemory) {
548            if(d->VirtualStart + d->NumberOfPages * PAGE_4k >= BIT(39)) {
549                fprintf(stderr, "RAM region %i lies above 512GB!\n", (int)i);
550                exit(EXIT_FAILURE);
551            }
552
553            if((d->VirtualStart & MASK(30)) != 0) {
554                fprintf(stderr, "RAM region %i not 1GB-aligned!\n", (int)i);
555                exit(EXIT_FAILURE);
556            }
557
558            if((d->NumberOfPages & MASK(18)) != 0) {
559                fprintf(stderr, "RAM region %i not 1GB-aligned!\n", (int)i);
560                exit(EXIT_FAILURE);
561            }
562
563            size_t ptbase= d->VirtualStart >> 30;
564            size_t ptend= ptbase + (d->NumberOfPages >> 18);
565
566            assert(ptbase < PTABLE_NUM_ENTRIES &&
567                   ptend < PTABLE_NUM_ENTRIES);
568
569            for(size_t j= ptbase; j < ptend; j++) {
570                l1_table[j].block.type= ARMv8_Ln_BLOCK;
571                l1_table[j].block.ai=  0; /* Memory type 0 */
572                l1_table[j].block.ns=  1; /* Non-secure. */
573                l1_table[j].block.ap=  0; /* R/W EL1, no access EL0 */
574                l1_table[j].block.sh=  3; /* Inner-shareable, fully coherent */
575                l1_table[j].block.af=  1; /* Accessed/dirty - don't fault */
576                l1_table[j].block.ng=  0; /* Global mapping */
577                l1_table[j].block.base_address= j; /* PA = j << 30 */
578                l1_table[j].block.ch=  1; /* Contiguous, combine TLB entries */
579                l1_table[j].block.pxn= 0; /* Executable. */
580                l1_table[j].block.xn=  0; /* Executable. */
581            }
582        }
583    }
584
585    uint64_t l1_base= table_base + PTABLE_SIZE;
586
587    /* Map the L1 table into the L0. */
588    l0_table[0].type= ARMv8_Ln_TABLE;
589    l0_table[0].base_address= l1_base >> 12;
590    l0_table[0].pxn= 0; /* Executable. */
591    l0_table[0].xn=  0; /* Executable. */
592    l0_table[0].ap=  0; /* No permission masking. */
593    l0_table[0].ns=  1; /* Non-secure. */
594
595    *pt_size= 2 * PTABLE_SIZE;
596    return (void *)block;
597}
598
599int
600main(int argc, char *argv[]) {
601    if(argc < 6 || argc > 7) usage(argv[0]);
602
603    const char *config_path= argv[1],
604               *shim_path=   argv[3],
605               *base_path=   argv[4],
606               *out_path=    argv[5];
607
608    errno= 0;
609    uint64_t ram_size= strtoul(argv[2], NULL, 0);
610    if(errno) fail("strtoul");
611
612    int debug_details= 0;
613    if(argc == 7 && !strcmp("-d", argv[6])) debug_details= 1;
614
615    /* Load the configuration. */
616    size_t config_size, config_alloc;
617    char *config_raw=
618        (char *)load_file(config_path, &config_size, &config_alloc);
619
620    /* Parse the configuration. */
621    struct config *config= parse_config(config_raw, config_size);
622    if(!config) exit(EXIT_FAILURE);
623
624    /* Construct the working buffer for paths. */
625    char basepath_buf[PATH_MAX];
626    size_t basepath_len;
627    strncpy(basepath_buf, base_path, PATH_MAX);
628    basepath_len= strlen(base_path);
629
630    /* Load the kernel ELF. */
631    assert(config->kernel);
632    if(load_component(basepath_buf, basepath_len,
633                      config->kernel, config_raw) != 0) {
634        fail("load_component");
635    }
636
637    if(elf_version(EV_CURRENT) == EV_NONE)
638        elf_fail("elf_version");
639
640    /* Start parsing the kernel ELF. */
641    Elf *kernel_elf=
642        elf_memory((char *)config->kernel->image,
643                   config->kernel->image_size);
644    if(!kernel_elf) elf_fail("elf_memory");
645
646    /* Load all modules. */
647    size_t n_modules= 0;
648    for(struct component_config *comp= config->first_module;
649                                 comp; comp= comp->next) {
650        n_modules++;
651        if(load_component(basepath_buf, basepath_len, comp, config_raw) != 0)
652            fail("load_component");
653    }
654
655    /* How many RAM regions are there?  If there's more than 2GiB, it'll be
656     * split into two. */
657    if(ram_size > 8 * (1UL<<30)) {
658        fprintf(stderr, "The models only support <= 8GiB of RAM.\n");
659        exit(EXIT_FAILURE);
660    }
661    size_t ram_regions;
662    if(ram_size > 2 * (1UL<<30)) ram_regions= 2;
663    else ram_regions= 1;
664
665    /* The EFI memory map contains one entry for each loaded module, one for
666     * each RAM region, and 5 fixed entries: The loaded CPU driver, the CPU
667     * driver's stack, the CPU driver's page tables, the Multiboot header, and
668     * the CPU driver ELF. */
669    size_t mmap_len= n_modules + ram_regions + 5;
670    /* The RAM regions are at the end, thus the first is at n_modules + 5. */
671    size_t first_region= n_modules + 5;
672
673    /* Create the multiboot header, now that we know how big the memory map
674     * needs to be.  */
675    void *mb_header=
676        create_multiboot2_info(config, kernel_elf,
677                               mmap_len * sizeof(efi_memory_descriptor));
678    if(!mb_header) {
679        fprintf(stderr, "Couldn't build the multiboot header.\n");
680        exit(EXIT_FAILURE);
681    }
682
683    /* Build the EFI memory map.  We leave uninitialised entries at the
684     * beginning for the kernel, all modules, the CPU driver's loadable
685     * segment & stack, the MB header, and the boot page table. */
686    efi_memory_descriptor *mmap=
687        build_efi_mmap(config, mmap_len, first_region, ram_size);
688
689    /* Start allocating at the beginning of the first physical region. */
690    uint64_t allocbase= mmap[first_region].PhysicalStart;
691    uint64_t loadbase= allocbase;
692
693    /* Load the CPU driver into physical RAM, and relocate for the kernel
694     * window. */
695    uint64_t kernel_start= allocbase;
696    uint64_t cpudriver_size, cpudriver_alloc, cpudriver_entry;
697    void *cpudriver=
698        load_cpudriver(kernel_elf, config->kernel->image,
699                       config->kernel->image_size,
700                       KERNEL_OFFSET + kernel_start,
701                       &cpudriver_size, &cpudriver_alloc, &cpudriver_entry);
702
703    /* Allocate the CPU driver's loadable segment. */
704    allocbase= ROUNDUP(allocbase + cpudriver_size, PAGE_4k);
705    check_alloc(allocbase, mmap, first_region);
706    mmap[0].Type= EfiBarrelfishCPUDriver;
707    mmap[0].PhysicalStart= kernel_start;
708    mmap[0].VirtualStart= kernel_start;
709    mmap[0].NumberOfPages= roundpage(cpudriver_size);
710    mmap[0].Attribute= 0; /* XXX */
711
712    /* Now allocate the CPU driver's stack. */
713    config->kernel_stack= allocbase;
714    uint64_t kernel_stack_alloc= ROUNDUP(config->stack_size, PAGE_4k);
715    allocbase= ROUNDUP(allocbase + kernel_stack_alloc, PAGE_4k);
716    check_alloc(allocbase, mmap, first_region);
717    mmap[1].Type= EfiBarrelfishCPUDriverStack;
718    mmap[1].PhysicalStart= config->kernel_stack;
719    mmap[1].VirtualStart= config->kernel_stack;
720    mmap[1].NumberOfPages= roundpage(config->stack_size);
721    mmap[1].Attribute= 0; /* XXX */
722
723    /* Allocate frames for the CPU driver's root page table. */
724    uint64_t kernel_table= allocbase;
725    size_t kernel_pt_size;
726    void *kernel_pt=
727        alloc_kernel_pt(&kernel_pt_size, kernel_table, mmap, mmap_len);
728    mmap[2].Type= EfiBarrelfishBootPageTable;
729    mmap[2].PhysicalStart= allocbase;
730    mmap[2].VirtualStart= allocbase;
731    mmap[2].NumberOfPages= 1;
732    mmap[2].Attribute= 0; /* XXX */
733    allocbase+= kernel_pt_size;
734    check_alloc(allocbase, mmap, first_region);
735
736    /* Allocate space for the multiboot header. */
737    uint64_t multiboot= allocbase;
738    mmap[3].Type= EfiBarrelfishMultibootData;
739    mmap[3].PhysicalStart= allocbase;
740    mmap[3].VirtualStart= allocbase;
741    mmap[3].NumberOfPages= roundpage(config->multiboot_size);
742    mmap[3].Attribute= 0; /* XXX */
743    allocbase= ROUNDUP(allocbase + config->multiboot_size, PAGE_4k);
744    check_alloc(allocbase, mmap, first_region);
745
746    /* Allocate room for the CPU driver ELF. */
747    config->kernel->image_address= allocbase;
748    allocbase= ROUNDUP(allocbase + config->kernel->image_size, PAGE_4k);
749    check_alloc(allocbase, mmap, first_region);
750    mmap[4].Type= EfiBarrelfishELFData;
751    mmap[4].PhysicalStart= config->kernel->image_address;
752    mmap[4].VirtualStart= config->kernel->image_address;
753    mmap[4].NumberOfPages= roundpage(config->kernel->image_size);
754    mmap[4].Attribute= 0; /* XXX */
755
756    /* Update the multiboot tag. */
757    config->kernel->tag->mod_start=
758        (multiboot_uint64_t)config->kernel->image_address;
759    config->kernel->tag->mod_end=
760        (multiboot_uint64_t)(config->kernel->image_address +
761                             (config->kernel->image_size - 1));
762
763    if(!debug_details) {
764        printf("ELF %.*s %luB @ 0x%lx\n",
765               (int)config->kernel->path_len,
766               config_raw + config->kernel->path_start,
767               config->kernel->image_size,
768               config->kernel->image_address);
769    }
770
771    /* Allocate all remaining modules.  We've allocated 5 mmap entries so far,
772     * so this will bring us up to n_modules+5. */
773    struct component_config *m;
774    size_t i_mmap;
775    for(i_mmap= 5, m= config->first_module; m; i_mmap++, m= m->next) {
776        m->image_address= allocbase;
777        allocbase= ROUNDUP(allocbase + m->image_size, PAGE_4k);
778        check_alloc(allocbase, mmap, first_region);
779        mmap[i_mmap].Type= EfiBarrelfishELFData;
780        mmap[i_mmap].PhysicalStart= m->image_address;
781        mmap[i_mmap].VirtualStart= m->image_address;
782        mmap[i_mmap].NumberOfPages= roundpage(m->image_size);
783        mmap[i_mmap].Attribute= 0; /* XXX */
784
785        /* Update the multiboot tag. */
786        m->tag->mod_start=
787            (multiboot_uint64_t)m->image_address;
788        m->tag->mod_end=
789            (multiboot_uint64_t)(m->image_address +
790                                 (m->image_size - 1));
791
792        if(!debug_details) {
793            printf("ELF %.*s %luB @ 0x%lx\n",
794                   (int)m->path_len,
795                   config_raw + m->path_start,
796                   m->image_size,
797                   m->image_address);
798        }
799    }
800
801    /* Update the first physical region, to exclude everthing we've just
802     * allocated. */
803    uint64_t space_used= allocbase - mmap[first_region].PhysicalStart;
804    mmap[first_region].PhysicalStart= allocbase;
805    mmap[first_region].VirtualStart= allocbase;
806    mmap[first_region].NumberOfPages-= roundpage(space_used);
807
808    /* Load the shim at the beginning of the updated free region: this way the
809     * CPU driver will simply reuse the memory, without needing to know that
810     * the shim was ever used. */
811
812    /* Load the ELF. */
813    size_t shim_size, shim_raw_alloc;
814    void *shim_raw= load_file(shim_path, &shim_size, &shim_raw_alloc);
815    Elf *shim_elf= elf_memory((char *)shim_raw, shim_size);
816    if(!shim_elf) elf_fail("elf_memory");
817
818    /* Relocate and initialise the shim. n.b. it jumps to the *physical*
819     * kernel entry point. */
820    uint64_t shim_loaded_size, shim_alloc, shim_entry;
821    uint64_t shim_base= mmap[first_region].PhysicalStart;
822    void *shim=
823        load_shim(shim_elf, shim_raw, shim_size, shim_base,
824                  &shim_loaded_size, &shim_alloc, kernel_table,
825                  /* Stack must be 16-byte aligned. */
826                  config->kernel_stack + kernel_stack_alloc - 16,
827                  multiboot + KERNEL_OFFSET,
828                  cpudriver_entry - KERNEL_OFFSET, &shim_entry,
829                  debug_details);
830
831    /* Print the memory map. */
832    if(!debug_details) print_mmap(mmap, mmap_len);
833
834    FILE *outfile;
835
836    /* Open the output file for writing. */
837    outfile= fopen(out_path, "w");
838    if(!outfile) fail("fopen");
839
840    size_t image_size= 0;
841
842    /* Write the loaded & relocated CPU driver. */
843    if(!debug_details) {
844        if(fwrite(cpudriver, 1, cpudriver_alloc, outfile) !=
845           cpudriver_alloc) {
846            fail("fwrite");
847        }
848    }
849    image_size+= cpudriver_alloc;
850
851    /* Write the (empty) kernel stack. */
852    void *stack= calloc(1, PAGE_4k);
853    if(!stack) fail("calloc");
854    for(size_t i= 0; i < roundpage(config->stack_size); i++) {
855        if(!debug_details) {
856            if(fwrite(stack, 1, PAGE_4k, outfile) != PAGE_4k) {
857                fail("fwrite");
858            }
859        }
860        image_size+= PAGE_4k;
861    }
862    free(stack);
863
864    /* Write the root page table. */
865    if(!debug_details) {
866        if(fwrite(kernel_pt, 1, kernel_pt_size, outfile) != kernel_pt_size) {
867            fail("fwrite");
868        }
869    }
870    image_size+= kernel_pt_size;
871
872    /* Write the multiboot header (including the memory map). */
873    if(!debug_details) {
874        if(fwrite(config->multiboot, 1, config->multiboot_alloc, outfile)
875                != config->multiboot_alloc) {
876            fail("fwrite");
877        }
878    }
879    image_size+= config->multiboot_alloc;
880
881    /* Write the kernel ELF. */
882    if(!debug_details) {
883        if(fwrite(config->kernel->image, 1,
884                  config->kernel->alloc_size, outfile)
885                != config->kernel->alloc_size) {
886            fail("fwrite");
887        }
888    }
889    image_size+= config->kernel->alloc_size;
890
891    /* Write all module ELFs. */
892    for(m= config->first_module; m; m= m->next) {
893        if(!debug_details) {
894            if(fwrite(m->image, 1, m->alloc_size, outfile) != m->alloc_size) {
895                fail("fwrite");
896            }
897        }
898        image_size+= m->alloc_size;
899    }
900
901    /* Write the loaded shim. */
902    if(!debug_details) {
903        if(fwrite(shim, 1, shim_loaded_size, outfile) != shim_loaded_size) {
904            fail("fwrite");
905        }
906    }
907    image_size+= shim_loaded_size;
908
909    if(!debug_details) {
910        printf("Load address: 0x%lx\n", loadbase);
911        printf("Image size (bytes): %lu\n", image_size);
912        printf("Entry point: 0x%lx\n", shim_entry);
913    }
914
915    if(debug_details) {
916        fprintf(outfile, "load_address\t0x%lx\n", loadbase);
917        fprintf(outfile, "shim_address\t0x%lx\n", shim_base);
918        fprintf(outfile, "vminit_address\t0x%lx\n", kernel_start);
919        fprintf(outfile, "cpudriver_address\t0x%lx\n",
920                         KERNEL_OFFSET + kernel_start);
921        fprintf(outfile, "entry_point\t0x%lx\n", shim_entry);
922    }
923
924    if(fclose(outfile)) fail("fclose");
925
926    return EXIT_SUCCESS;
927}
928