1// Simple boot-loader.
2//
3// This code is only intended for use on M5 where it is started via
4// molly_boot.S which runs on Core 0.
5
6/*
7 * Copyright (c) 2007-2010,2015, ETH Zurich.
8 * Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
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 <stdio.h>
17#include <stdint.h>
18#include <stddef.h>
19#include <string.h>
20#include <barrelfish_kpi/types.h>
21#include <errors/errno.h>
22#include <elf/elf.h>
23#include <multiboot.h>
24
25#define BASE_PAGE_SIZE                  0x1000
26#define ALIGNMENT                       0x10000
27
28/// Round up n to the next multiple of size
29#define ROUND_UP(n, size)           ((((n) + (size) - 1)) & (~((size) - 1)))
30
31
32static lpaddr_t phys_alloc_start;
33
34static errval_t linear_alloc(void *s, genvaddr_t base, size_t size, uint32_t flags,
35                             void **ret)
36{
37    // round to base page size
38    uint32_t npages = (size + BASE_PAGE_SIZE - 1) / BASE_PAGE_SIZE;
39
40    /* *ret = (void *)(uintptr_t)base; */
41    *ret = (void *)phys_alloc_start;
42
43    phys_alloc_start += npages * BASE_PAGE_SIZE;
44    return SYS_ERR_OK;
45}
46
47genvaddr_t kernel_entry;
48
49// Prototypes for functions from molly_boot.S:
50void aarch64_to_kernel_transition(genvaddr_t entry_addr, void* mbi_ptr);
51
52
53// Prototypes for functions from arm_gem5_kernel.c:
54extern struct multiboot_info *molly_get_mbi(void);
55
56// Prototypes for symbols declared via linker script:
57extern void *_start_img;
58extern void *_end_img;
59
60void aarch64_init(void);
61
62void aarch64_init(void)
63{
64    errval_t err;
65
66    //uint32_t kernel_blob_size = (uint32_t)(&kernel_blob_end - &kernel_blob_start);
67
68
69    struct multiboot_info *mbi = molly_get_mbi();
70
71    // align kernel start to 16KB
72    phys_alloc_start = ROUND_UP((uint64_t) &_end_img, ALIGNMENT); //+
73                // BASE_PAGE_SIZE);
74    lpaddr_t kernel_start = phys_alloc_start;
75
76    // Load the kernel out from the boot image:
77    struct multiboot_modinfo *mbi_mods;
78    mbi_mods = (struct multiboot_modinfo*)(uint64_t)(mbi->mods_addr);
79    void *kernel = (void*)(uint64_t)(mbi_mods[0].mod_start);
80    uint32_t kernel_bytes = mbi_mods[0].mod_end - mbi_mods[0].mod_start;
81
82    err = elf64_load(EM_AARCH64, linear_alloc, NULL, (uint64_t)kernel,
83                    kernel_bytes, &kernel_entry, NULL, NULL, NULL);
84    if (err_is_fail(err)) {
85        return;
86    }
87
88    // Relocate kernel image
89    struct Elf64_Ehdr *cpu_head = (struct Elf64_Ehdr *)kernel;
90    struct Elf64_Shdr *rela, *symtab, *symhead =
91        (struct Elf64_Shdr *)(kernel + (uintptr_t)cpu_head->e_shoff);
92    genvaddr_t elfbase = elf_virtual_base64(cpu_head);
93    rela = elf64_find_section_header_type(symhead, cpu_head->e_shnum, SHT_RELA);
94    symtab = elf64_find_section_header_type(symhead, cpu_head->e_shnum, SHT_DYNSYM);
95    elf64_relocate(kernel_start, elfbase,
96                   (struct Elf64_Rela *)(uintptr_t)(kernel + rela->sh_offset),
97                   rela->sh_size,
98                   (struct Elf64_Sym *)(uintptr_t)(kernel + symtab->sh_offset),
99                   symtab->sh_size,
100                   elfbase, (void *)kernel_start);
101    kernel_entry = kernel_entry - elfbase + kernel_start;
102
103    //initialize arm_core_data elf info for relocated header
104    mbi->syms.elf.num = cpu_head->e_shnum;
105    mbi->syms.elf.size = cpu_head->e_shentsize;
106    mbi->syms.elf.addr = (uint64_t)kernel+ cpu_head->e_shoff;
107    mbi->syms.elf.shndx = cpu_head->e_shstrndx;
108
109    aarch64_to_kernel_transition((uintptr_t)kernel_entry, mbi );
110
111
112}
113