1/*
2 * An EFI loader for Barrelfish
3 *
4 * This is an EFI app which loads the Multiboot2 image and execute
5 * the bootloader.
6 * This object file is linked together with the Multiboot2 image into one object
7 *
8 * Copyright (c) 2018, ETH Zurich.
9 * All rights reserved.
10 *
11 * This file is distributed under the terms in the attached LICENSE file.
12 * If you do not find this file, copies can be found by writing to:
13 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
14 */
15
16#include <stdlib.h>
17#include <string.h>
18
19#include <efi/efi.h>
20#include <efi/efilib.h>
21#include <multiboot2.h>
22#include <barrelfish_kpi/types.h>
23#include <barrelfish_kpi/arm_core_data.h>
24#include "blob.h"
25#include "vm.h"
26
27typedef enum {
28    EfiBarrelfishFirstMemType=      0x80000000,
29
30    EfiBarrelfishCPUDriver=         0x80000000,
31    EfiBarrelfishCPUDriverStack=    0x80000001,
32    EfiBarrelfishMultibootData=     0x80000002,
33    EfiBarrelfishELFData=           0x80000003,
34    EfiBarrelfishBootPageTable=     0x80000004,
35    EfiBarrelfishCoreData=          0x80000005,
36
37    EfiBarrelfishMaxMemType
38} EFI_BARRELFISH_MEMORY_TYPE;
39
40static const char *mmap_types[] = {
41    "reserved",
42    "LD code",
43    "LD data",
44    "BS code",
45    "BS data",
46    "RS code",
47    "RS data",
48    "available",
49    "unusable",
50    "ACPI reclaim",
51    "ACPI NVS",
52    "MMIO",
53    "ports",
54    "PAL code",
55    "persist"
56};
57
58static const char *bf_mmap_types[] = {
59    "BF code",
60    "BF stack",
61    "BF multiboot",
62    "BF module",
63    "BF page table",
64    "BF core data",
65};
66
67#define MAX_L1_TABLES 512
68struct page_tables {
69    size_t nL1;
70
71    union aarch64_descriptor *L0_table;
72    union aarch64_descriptor *L1_tables[MAX_L1_TABLES];
73} page_tables;
74
75struct config {
76    struct multiboot_info *multiboot;
77    struct multiboot_tag_efi_mmap *mmap_tag;
78    struct multiboot_tag_string *cmd_tag;
79    EFI_PHYSICAL_ADDRESS modules;
80    EFI_VIRTUAL_ADDRESS boot_driver_entry;
81    EFI_PHYSICAL_ADDRESS cpu_driver_entry;
82    EFI_PHYSICAL_ADDRESS cpu_driver_stack;
83    size_t cpu_driver_stack_size;
84    struct page_tables *tables;
85};
86
87typedef void boot_driver(uint32_t magic, void *pointer);
88
89extern char barrelfish_blob_start[1];
90
91#define KERNEL_OFFSET       0xffff000000000000
92#define KERNEL_STACK_SIZE   0x4000
93
94#define ATTR_CACHED 0
95#define ATTR_DEVICE 1
96
97#define ROUND_UP(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
98#define COVER(x, y) (((x) + ((y)-1)) / (y))
99#define ROUND_DOWN(x, y) (((x) / (y)) * (y))
100#define MIN(x, y) ((x) < (y) ? (x) : (y))
101
102#define BLOB_ADDRESS(offset) (barrelfish_blob_start + (offset))
103
104/* Copy a base+length string into a null-terminated string.  Destination
105 * buffer must be large enough to hold the terminator i.e. n+1 characters. */
106static inline void
107ntstring(char *dest, const char *src, size_t len) {
108    memcpy(dest, src, len);
109    dest[len]= '\0';
110}
111
112#define MEM_MAP_SIZE 8192
113char mmap[MEM_MAP_SIZE];
114UINTN mmap_size, mmap_key, mmap_d_size;
115UINT32 mmap_d_ver;
116
117static EFI_STATUS
118update_memory_map(void)
119{
120    EFI_STATUS status;
121    size_t mmap_n_desc, i;
122
123    /* Grab the current table from UEFI. */
124    mmap_size = MEM_MAP_SIZE;
125    status = ST->BootServices->GetMemoryMap(
126        &mmap_size,
127        (void *) &mmap,
128        &mmap_key,
129        &mmap_d_size,
130        &mmap_d_ver
131    );
132    if (status == EFI_BUFFER_TOO_SMALL) {
133        Print(L"The memory map is %dB, but MEM_MAP_SIZE is %d.\n",
134            mmap_size, MEM_MAP_SIZE);
135        Print(L"This is compile-time limit in Hagfish - please report "
136              L"this overflow, it's a bug.\n");
137        return status;
138    } else if (EFI_ERROR(status)) {
139        Print(L"Unable to get memory map: %x\n", status);
140        return status;
141    }
142
143    mmap_n_desc = mmap_size / mmap_d_size;
144
145    return EFI_SUCCESS;
146}
147
148static EFI_STATUS
149relocate_memory_map(void) {
150    if (!mmap_size) {
151        return EFI_LOAD_ERROR;
152    }
153
154    size_t mmap_n_desc = mmap_size / mmap_d_size;
155
156    for (size_t i= 0; i < mmap_n_desc; i++) {
157        EFI_MEMORY_DESCRIPTOR *desc =
158            (EFI_MEMORY_DESCRIPTOR *)(mmap + i * mmap_d_size);
159        // 1:1 mapping into kernel window
160        desc->VirtualStart = desc->PhysicalStart + KERNEL_OFFSET;
161    }
162
163    return EFI_SUCCESS;
164}
165
166static void
167print_memory_map(int update)
168{
169    if (update) {
170        update_memory_map();
171    }
172
173    size_t mmap_n_desc = mmap_size / mmap_d_size;
174
175    Print(L"Memory map at %lx, key: %x, descriptor version: %x\n",
176            mmap, mmap_key, mmap_d_ver);
177    Print(L"Got %d memory map entries of %dB (%dB).\n",
178               mmap_n_desc, mmap_d_size, mmap_size);
179
180    Print(L"Type          PStart           PEnd        "
181               "      Size       Attributes\n");
182    for (UINTN i = 0; i < mmap_n_desc; i++) {
183        EFI_MEMORY_DESCRIPTOR *desc = ((void *) mmap) + (mmap_d_size * i);
184
185        const char *description;
186        if (desc->Type < EfiMaxMemoryType) {
187            description= mmap_types[desc->Type];
188        }
189        else if (
190            EfiBarrelfishFirstMemType <= desc->Type &&
191            desc->Type < EfiBarrelfishMaxMemType
192        ) {
193            description = bf_mmap_types[desc->Type - EfiBarrelfishFirstMemType];
194        }
195        else {
196            description= "???";
197        }
198
199        Print(L"%-13a %016lx %016lx %9ldkB %01x\n",
200              description,
201              desc->PhysicalStart,
202              desc->PhysicalStart + (desc->NumberOfPages << 12) - 1,
203              (desc->NumberOfPages << 12) / 1024,
204              desc->Attribute);
205    }
206}
207
208#define BLOCK_16G (ARMv8_HUGE_PAGE_SIZE * 16ULL)
209#define BLOCK_16G_MASK (ARMv8_HUGE_PAGE_SIZE * 16ULL)
210
211static EFI_STATUS
212page_table_set_attr(struct config *cfg, uint64_t start, uint64_t end, uint64_t attr) {
213    uint64_t base = ROUND_DOWN(start, ARMv8_HUGE_PAGE_SIZE)
214            / ARMv8_HUGE_PAGE_SIZE;
215
216    uint64_t last = COVER(end, ARMv8_HUGE_PAGE_SIZE);
217
218    while (base < last) {
219        size_t table_number = base >> ARMv8_BLOCK_BITS;
220        size_t table_index = base & ARMv8_BLOCK_MASK;
221        union aarch64_descriptor *desc =
222            &cfg->tables->L1_tables[table_number][table_index];
223        desc->block_l1.attrindex = attr;
224
225        base++;
226    }
227
228    return EFI_SUCCESS;
229}
230
231static EFI_STATUS
232build_page_tables(struct config *cfg) {
233    EFI_STATUS status = EFI_SUCCESS;
234
235    /* We need the current memory map to set memory attributes */
236    status = update_memory_map();
237    if (EFI_ERROR(status)) {
238        Print(L"Failed to update memory map\n");
239    }
240
241    /* Page table book keeping in static buffer
242     * so we don't need malloc & friends
243     */
244    cfg->tables = &page_tables;
245
246    /* Map up to the highest RAM address supplied by EFI.  XXX - this is a
247     * heuristic, and may fail.  Unless there's a more clever way to do
248     * discovery, we might need to bite the bullet and map all 48 bits (2MB of
249     * kernel page tables!).  All we really need is that the kernel gets all
250     * RAM, and the debug serial port - it shouldn't actually touch anything
251     * else. */
252    uint64_t first_address, last_address;
253    first_address = 0;
254    last_address = ((1UL << 48) - 1);
255
256    /* We will map in aligned 16G blocks, as each requires only one TLB
257     * entry. */
258    uint64_t window_start, window_length;
259    window_start = first_address & ~BLOCK_16G;
260    window_length = ROUND_UP(last_address - window_start, BLOCK_16G);
261
262    status = BS->AllocatePages(
263        AllocateAnyPages,
264        EfiBarrelfishBootPageTable,
265        1,
266        (EFI_PHYSICAL_ADDRESS *)&cfg->tables->L0_table
267    );
268    if (EFI_ERROR(status)) {
269        Print(L"Failed to allocate L0 page table.\n");
270        goto build_page_tables_fail;
271    }
272    memset(cfg->tables->L0_table, 0, BASE_PAGE_SIZE);
273
274    /* Count the number of L1 tables (512GB) blocks required to cover the
275     * physical mapping window. */
276    cfg->tables->nL1 = 0;
277    uint64_t L1base = window_start & ~ARMv8_TOP_TABLE_SIZE;
278    uint64_t L1addr;
279    for (L1addr = window_start & ~ARMv8_TOP_TABLE_SIZE;
280        L1addr < window_start + window_length;
281        L1addr += ARMv8_TOP_TABLE_SIZE) {
282        cfg->tables->nL1++;
283    }
284    ASSERT(cfg->tables->nL1 <= MAX_L1_TABLES)
285
286    /* Allocate the L1 tables.
287     * We allocate them all in one big chunk
288     * as otherwise the memory map size explodes
289     */
290    Print(L"Allocating %d L1 tables (%dB)\n", cfg->tables->nL1, cfg->tables->nL1 * BASE_PAGE_SIZE);
291    EFI_PHYSICAL_ADDRESS L1_memory;
292    status = BS->AllocatePages(
293        AllocateAnyPages,
294        EfiBarrelfishBootPageTable,
295        cfg->tables->nL1,
296        &L1_memory
297    );
298    if (EFI_ERROR(status)) {
299        Print(L"Failed to allocate L1 page tables.\n");
300        goto build_page_tables_fail;
301    }
302    memset((void *)L1_memory, 0, cfg->tables->nL1 * BASE_PAGE_SIZE);
303    Print(L"L1 tables start at 0x%lx\n", L1_memory);
304
305    for (size_t i = 0; i < cfg->tables->nL1; i++) {
306        cfg->tables->L1_tables[i] = (union aarch64_descriptor *)(L1_memory + i * BASE_PAGE_SIZE);
307
308        /* Map the L1 into the L0. */
309        size_t L0_index = (L1base >> ARMv8_TOP_TABLE_BITS) + i;
310        cfg->tables->L0_table[L0_index].d.base =
311            (uint64_t)cfg->tables->L1_tables[i] >> ARMv8_BASE_PAGE_BITS;
312        cfg->tables->L0_table[L0_index].d.mb1 = 1; /* Page table */
313        cfg->tables->L0_table[L0_index].d.valid = 1;
314    }
315
316    /* Install the 1GB block mappings. */
317    uint64_t firstblock = window_start / ARMv8_HUGE_PAGE_SIZE;
318    uint64_t nblocks = window_length / ARMv8_HUGE_PAGE_SIZE;
319    for (uint64_t block = firstblock; block < firstblock + nblocks; block++) {
320        size_t table_number= block >> ARMv8_BLOCK_BITS;
321        size_t table_index= block & ARMv8_BLOCK_MASK;
322        union aarch64_descriptor *desc =
323            &cfg->tables->L1_tables[table_number][table_index];
324
325        // We first map all block non-contiguous but later set the bit
326        // if possible
327        desc->block_l1.contiguous = 0;
328        desc->block_l1.base = block;
329        /* Mark the accessed flag, so we don't get a fault. */
330        desc->block_l1.af = 1;
331        /* Outer shareable - coherent. */
332        desc->block_l1.sh = 3;
333        /* EL1+ only. */
334        desc->block_l1.ap = 0;
335        // device memory by default
336        desc->block_l1.attrindex = ATTR_DEVICE;
337        /* A block. */
338        desc->block_l1.mb0 = 0;
339        desc->block_l1.valid = 1;
340    }
341
342    // set all memory regions to cached
343    size_t mmap_n_desc = mmap_size / mmap_d_size;
344    for (size_t i = 0; i < mmap_n_desc; i++) {
345        EFI_MEMORY_DESCRIPTOR *desc = (void *) (mmap + i * mmap_d_size);
346        /* We're only looking for MMIO. */
347        if (desc->Type != EfiMemoryMappedIO
348                && desc->Type != EfiMemoryMappedIOPortSpace) {
349            page_table_set_attr(cfg, desc->PhysicalStart, desc->PhysicalStart + BASE_PAGE_SIZE * desc->NumberOfPages, ATTR_CACHED);
350        }
351    }
352
353    // set the contiguous bit if possible
354    for (uint64_t block = firstblock; block < firstblock + nblocks; block += 16) {
355        BOOLEAN all_same = TRUE;
356        uint64_t attr;
357        for (uint64_t offset = 0; offset < 16; offset++) {
358            size_t table_number = (block + offset) >> ARMv8_BLOCK_BITS;
359            size_t table_index = (block + offset) & ARMv8_BLOCK_MASK;
360            union aarch64_descriptor *desc =
361                &cfg->tables->L1_tables[table_number][table_index];
362            if (offset == 0) {
363                attr = desc->block_l1.attrindex;
364            }
365            else if (attr != desc->block_l1.attrindex) {
366                all_same = FALSE;
367                break;
368            }
369        }
370        if (all_same) {
371            // all entries in current block have the same attrindex value
372            // so we can set the contiguous bit
373            for (uint64_t offset = 0; offset < 16; offset++) {
374                size_t table_number = (block + offset) >> ARMv8_BLOCK_BITS;
375                size_t table_index = (block + offset) & ARMv8_BLOCK_MASK;
376                union aarch64_descriptor *desc =
377                    &cfg->tables->L1_tables[table_number][table_index];
378                desc->block_l1.contiguous = 1;
379            }
380        }
381    }
382
383    return EFI_SUCCESS;
384
385build_page_tables_fail:
386    if (cfg->tables) {
387        if (cfg->tables->L1_tables) {
388            size_t i;
389            for (i= 0; i < cfg->tables->nL1; i++) {
390                if (cfg->tables->L1_tables[i])
391                    BS->FreePages((EFI_PHYSICAL_ADDRESS)cfg->tables->L1_tables[i], 1);
392            }
393        }
394        if (cfg->tables->L0_table) {
395            BS->FreePages((EFI_PHYSICAL_ADDRESS)cfg->tables->L0_table, 1);
396        }
397    }
398
399    return status;
400}
401
402static void
403relocate_elf(EFI_PHYSICAL_ADDRESS segment_start, uint64_t virtual_offset,
404                 struct Blob_relocation *relocations,
405                 uint64_t no_relocations)
406{
407    Print(L"Relocating ELF %lx %lx %d\n",
408        segment_start, relocations, no_relocations);
409    for (uint64_t i = 0; i < no_relocations; i++) {
410        *(uint64_t *)(segment_start + relocations[i].offset) =
411            segment_start + virtual_offset + relocations[i].addend;
412    }
413}
414
415static EFI_STATUS
416relocate_boot_driver(struct Blob *blob_info, struct config *cfg)
417{
418    EFI_STATUS status;
419
420    /* Should be page aligend */
421    ASSERT(blob_info->boot_driver_segment_size % BASE_PAGE_SIZE == 0);
422
423    EFI_PHYSICAL_ADDRESS boot_driver;
424    status = BS->AllocatePages(
425        AllocateAnyPages,
426        EfiBarrelfishCPUDriver,
427        blob_info->boot_driver_segment_size / BASE_PAGE_SIZE,
428        &boot_driver
429    );
430    if (EFI_ERROR(status)) {
431        Print(L"Error allocating memory for boot driver segment: %d\n", status);
432        return status;
433    }
434
435    memcpy((void *)boot_driver, BLOB_ADDRESS(blob_info->boot_driver_segment), blob_info->boot_driver_segment_size);
436
437    struct Blob_relocation *boot_driver_relocations =
438        (struct Blob_relocation *)BLOB_ADDRESS(blob_info->boot_driver_relocations);
439    relocate_elf(
440        boot_driver,
441        0,
442        boot_driver_relocations,
443        blob_info->boot_driver_relocations_count
444    );
445
446    cfg->boot_driver_entry = boot_driver + blob_info->boot_driver_entry;
447
448    return EFI_SUCCESS;
449}
450
451static EFI_STATUS
452relocate_cpu_driver(struct Blob *blob_info, struct config *cfg)
453{
454    EFI_STATUS status;
455
456    /* Should be page aligend */
457    ASSERT(blob_info->cpu_driver_segment_size % BASE_PAGE_SIZE == 0);
458
459    EFI_PHYSICAL_ADDRESS cpu_driver;
460    status = BS->AllocatePages(
461        AllocateAnyPages,
462        EfiBarrelfishCPUDriver,
463        blob_info->cpu_driver_segment_size / BASE_PAGE_SIZE,
464        &cpu_driver
465    );
466    if (EFI_ERROR(status)) {
467        Print(L"Error allocating memory for CPU driver segment: %d\n", status);
468        return status;
469    }
470
471    memcpy((void *)cpu_driver, BLOB_ADDRESS(blob_info->cpu_driver_segment), blob_info->cpu_driver_segment_size);
472
473    struct Blob_relocation *cpu_driver_relocations =
474        (struct Blob_relocation *)BLOB_ADDRESS(blob_info->cpu_driver_relocations);
475    relocate_elf(
476        cpu_driver,
477        KERNEL_OFFSET,
478        cpu_driver_relocations,
479        blob_info->cpu_driver_relocations_count
480    );
481
482    cfg->cpu_driver_entry = cpu_driver + blob_info->cpu_driver_entry + KERNEL_OFFSET;
483
484    status = BS->AllocatePages(
485        AllocateAnyPages,
486        EfiBarrelfishCPUDriverStack,
487        KERNEL_STACK_SIZE / BASE_PAGE_SIZE,
488        &cfg->cpu_driver_stack
489    );
490    if (EFI_ERROR(status)) {
491        Print(L"Error allocating memory for CPU driver stack: %d\n", status);
492        return status;
493    }
494
495    cfg->cpu_driver_stack_size = KERNEL_STACK_SIZE;
496
497    Print(
498        L"Relocated CPU driver entry point is %lx, stack at %lx\n",
499        cfg->cpu_driver_entry,
500        cfg->cpu_driver_stack
501    );
502
503    return EFI_SUCCESS;
504}
505
506static EFI_STATUS
507relocate_modules(struct Blob *blob_info, struct config *cfg)
508{
509    EFI_STATUS status;
510
511    /* Should be page aligend */
512    ASSERT(blob_info->modules_size % BASE_PAGE_SIZE == 0);
513
514    status = BS->AllocatePages(
515        AllocateAnyPages,
516        EfiBarrelfishELFData,
517        blob_info->modules_size / BASE_PAGE_SIZE,
518        &cfg->modules
519    );
520    if (EFI_ERROR(status)) {
521        Print(L"Error allocating memory for modules: %d\n", status);
522        return status;
523    }
524
525    memcpy((void *)cfg->modules, BLOB_ADDRESS(blob_info->modules), blob_info->modules_size);
526    return EFI_SUCCESS;
527}
528
529static EFI_STATUS
530relocate_multiboot(struct Blob *blob_info, struct config *cfg)
531{
532    EFI_STATUS status;
533
534    /* Should be page aligend */
535    ASSERT(blob_info->multiboot_size % BASE_PAGE_SIZE == 0);
536
537    EFI_PHYSICAL_ADDRESS memory;
538    status = BS->AllocatePages(
539        AllocateAnyPages,
540        EfiBarrelfishMultibootData,
541        blob_info->multiboot_size / BASE_PAGE_SIZE,
542        (EFI_PHYSICAL_ADDRESS *)&cfg->multiboot
543    );
544    if (EFI_ERROR(status)) {
545        Print(L"Error allocating memory for multiboot info: %d\n", status);
546        return status;
547    }
548
549    memcpy(cfg->multiboot, BLOB_ADDRESS(blob_info->multiboot), blob_info->multiboot_size);
550
551    /* Module start & end pointed into the blob.
552     * Now they need to point into the module region
553     */
554    uint64_t module_offset = (uint64_t)cfg->modules - blob_info->modules;
555
556    Print(L"Relocating multiboot info: %lx\n", cfg->multiboot);
557    /* We don't have an end tag yet, but EFI mmap tag is last */
558    struct multiboot_tag *tag;
559    for (tag = cfg->multiboot->tags; tag->type != MULTIBOOT_TAG_TYPE_EFI_MMAP; tag = (void *)tag + tag->size) {
560        Print(L"%lx: tag %d:%d\n", tag, tag->type, tag->size);
561
562        if (tag->type == MULTIBOOT_TAG_TYPE_MODULE_64) {
563            struct multiboot_tag_module_64 *mtag = (struct multiboot_tag_module_64 *)tag;
564            Print(L"\tbefore %lx:%lx\n", mtag->mod_start, mtag->mod_end);
565            mtag->mod_start += module_offset;
566            mtag->mod_end += module_offset;
567            Print(L"\tafter  %lx:%lx\n", mtag->mod_start, mtag->mod_end);
568        }
569        else if (tag->type == MULTIBOOT_TAG_TYPE_CMDLINE) {
570            cfg->cmd_tag = (struct multiboot_tag_string *)tag;
571        }
572    }
573
574    ASSERT(tag->type == MULTIBOOT_TAG_TYPE_EFI_MMAP);
575    cfg->mmap_tag = (struct multiboot_tag_efi_mmap *)tag;
576
577    return EFI_SUCCESS;
578}
579
580static struct armv8_core_data *
581create_core_data(struct config *cfg)
582{
583    EFI_STATUS status;
584
585    struct armv8_core_data *core_data;
586    status = BS->AllocatePages(
587        AllocateAnyPages,
588        EfiBarrelfishCoreData,
589        1,
590        (EFI_PHYSICAL_ADDRESS *)&core_data
591    );
592    if (EFI_ERROR(status)) {
593        Print(L"Error allocating memory for core data: %d\n", status);
594        return NULL;
595    }
596
597    memset(core_data, 0, BASE_PAGE_SIZE);
598
599    core_data->boot_magic = ARMV8_BOOTMAGIC_BSP;
600    core_data->cpu_driver_stack =
601        (lpaddr_t)cfg->cpu_driver_stack + cfg->cpu_driver_stack_size - 16;
602    core_data->cpu_driver_stack_limit = (lpaddr_t)cfg->cpu_driver_stack;
603    core_data->cpu_driver_entry = (lvaddr_t)cfg->cpu_driver_entry;
604    core_data->page_table_root = (genpaddr_t)cfg->tables->L0_table;
605    ntstring(
606        core_data->cpu_driver_cmdline,
607        cfg->cmd_tag->string,
608        MIN(
609            cfg->cmd_tag->size - sizeof(struct multiboot_tag_string),
610            sizeof(core_data->cpu_driver_cmdline) - 1
611        )
612    );
613
614    core_data->multiboot_image.base = (lpaddr_t)cfg->multiboot;
615    core_data->multiboot_image.length = cfg->multiboot->total_size;
616    core_data->efi_mmap = (lpaddr_t)cfg->mmap_tag;
617
618    return core_data;
619}
620
621EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle,
622                           EFI_SYSTEM_TABLE * SystemTable)
623{
624    EFI_STATUS status;
625
626    InitializeLib(ImageHandle, SystemTable);
627
628    struct Blob *blob_info = (struct Blob *)BLOB_ADDRESS(0);
629    Print(L"Blob is at: 0x%lx\n", blob_info);
630    Print(L"Magic: %lx\n", blob_info->magic);
631
632    struct config cfg;
633
634    status = relocate_boot_driver(blob_info, &cfg);
635    if (EFI_ERROR(status)) {
636        Print(L"Failed to relocate boot driver\n");
637        return status;
638    }
639
640    status = relocate_cpu_driver(blob_info, &cfg);
641    if (EFI_ERROR(status)) {
642        Print(L"Failed to relocate CPU driver\n");
643        return status;
644    }
645
646    status = relocate_modules(blob_info, &cfg);
647    if (EFI_ERROR(status)) {
648        Print(L"Failed to relocate modules\n");
649        return status;
650    }
651
652    status = relocate_multiboot(blob_info, &cfg);
653    if (EFI_ERROR(status)) {
654        Print(L"Failed to relocate multiboot info\n");
655        return status;
656    }
657
658    status = build_page_tables(&cfg);
659    if (EFI_ERROR(status)) {
660        Print(L"Failed to build page tables\n");
661        return status;
662    }
663
664    struct armv8_core_data *core_data = create_core_data(&cfg);
665
666    Print(L"Terminating boot services and jumping to image at 0x%lx\n", cfg.boot_driver_entry);
667    Print(L"Core data pointer is %lx\n", core_data);
668
669    print_memory_map(1);
670
671    status = update_memory_map();
672    if (EFI_ERROR(status)) {
673        Print(L"Failed to update memory map\n");
674    }
675
676    status = ST->BootServices->ExitBootServices(ImageHandle, mmap_key);
677    if (EFI_ERROR(status)) {
678        Print(L"Error exiting boot services: %d, %x\n", status, mmap_key);
679        return status;
680    }
681
682    /*** EFI boot services are now terminated, we're on our own. */
683    status = relocate_memory_map();
684    if (EFI_ERROR(status)) {
685        return EFI_SUCCESS;
686    }
687
688    /* The last thing we do is complete the multiboot info:
689     * Set the EFI mmap and end tag
690     */
691    cfg.mmap_tag->size = ROUND_UP(sizeof(struct multiboot_tag_efi_mmap) + mmap_size, 8);
692    cfg.mmap_tag->descr_size = mmap_d_size;
693    cfg.mmap_tag->descr_vers = mmap_d_ver;
694    memcpy(cfg.mmap_tag->efi_mmap, mmap, mmap_size);
695
696    struct multiboot_tag *end_tag = (void *)cfg.mmap_tag + cfg.mmap_tag->size;
697    end_tag->type = MULTIBOOT_TAG_TYPE_END;
698    end_tag->size = ROUND_UP(sizeof(struct multiboot_tag), 8);
699    cfg.multiboot->total_size = (void *)end_tag + end_tag->size - (void *)cfg.multiboot;
700
701    status = ST->RuntimeServices->SetVirtualAddressMap(
702        mmap_size,
703        mmap_d_size,
704        mmap_d_ver,
705        (void *) &mmap
706    );
707    if (EFI_ERROR(status)) {
708        return status;
709    }
710
711    // Jump to the bootloader, the blob can be reused
712    (*((boot_driver *) (cfg.boot_driver_entry))) (MULTIBOOT2_BOOTLOADER_MAGIC, core_data);
713
714    return EFI_SUCCESS;
715}
716