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, 2008, 2009, 2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <stdint.h>
17#include <stddef.h>
18#include <string.h>
19#include <barrelfish_kpi/types.h>
20#include <errors/errno.h>
21#include <elf/elf.h>
22#include <multiboot.h>
23
24#define BASE_PAGE_SIZE                  0x1000
25#define ALIGNMENT                       0x10000
26
27/// Round up n to the next multiple of size
28#define ROUND_UP(n, size)           ((((n) + (size) - 1)) & (~((size) - 1)))
29
30
31static lpaddr_t phys_alloc_start;
32
33static errval_t linear_alloc(void *s, genvaddr_t base, size_t size, uint32_t flags,
34                             void **ret)
35{
36    // round to base page size
37    uint32_t npages = (size + BASE_PAGE_SIZE - 1) / BASE_PAGE_SIZE;
38
39    /* *ret = (void *)(uintptr_t)base; */
40    *ret = (void *)phys_alloc_start;
41
42    phys_alloc_start += npages * BASE_PAGE_SIZE;
43    return SYS_ERR_OK;
44}
45
46genvaddr_t kernel_entry;
47
48// Prototypes for functions from molly_boot.S:
49void molly_to_kernel_transition(genvaddr_t entry_addr, void* mbi_ptr);
50
51
52// Prototypes for functions from arm_gem5_kernel.c:
53extern struct multiboot_info *molly_get_mbi(void);
54
55// Prototypes for symbols declared via linker script:
56extern void *_start_img;
57extern void *_end_img;
58
59void molly_init(void);
60
61void molly_init(void)
62{
63    errval_t err;
64
65    //uint32_t kernel_blob_size = (uint32_t)(&kernel_blob_end - &kernel_blob_start);
66
67
68    struct multiboot_info *mbi = molly_get_mbi();
69
70    // align kernel start to 16KB
71    phys_alloc_start = ROUND_UP((uint32_t) &_end_img, ALIGNMENT); //+
72                // BASE_PAGE_SIZE);
73    lpaddr_t kernel_start = phys_alloc_start;
74
75    // Load the kernel out from the boot image:
76    struct multiboot_modinfo *mbi_mods;
77    mbi_mods = (struct multiboot_modinfo*)(uint32_t)(mbi->mods_addr);
78    void *kernel = (void*)(uint32_t)(mbi_mods[0].mod_start);
79    uint32_t kernel_bytes = mbi_mods[0].mod_end - mbi_mods[0].mod_start;
80
81    err = elf32_load(EM_ARM, linear_alloc, NULL, (uint32_t)kernel,
82                    kernel_bytes, &kernel_entry, NULL, NULL, NULL);
83    if (err_is_fail(err)) {
84        return;
85    }
86
87    // Relocate kernel image
88    struct Elf32_Ehdr *cpu_head = (struct Elf32_Ehdr *)kernel;
89    struct Elf32_Shdr *rela, *symtab, *symhead =
90        (struct Elf32_Shdr *)(kernel + (uintptr_t)cpu_head->e_shoff);
91    genvaddr_t elfbase = elf_virtual_base32(cpu_head);
92    rela = elf32_find_section_header_type(symhead, cpu_head->e_shnum, SHT_REL);
93    symtab = elf32_find_section_header_type(symhead, cpu_head->e_shnum, SHT_DYNSYM);
94    elf32_relocate(kernel_start, elfbase,
95                   (struct Elf32_Rel *)(uintptr_t)(kernel + rela->sh_offset),
96                   rela->sh_size,
97                   (struct Elf32_Sym *)(uintptr_t)(kernel + symtab->sh_offset),
98                   symtab->sh_size,
99                   elfbase, (void *)kernel_start);
100    kernel_entry = kernel_entry - elfbase + kernel_start;
101
102    //initialize arm_core_data elf info for relocated header
103    mbi->syms.elf.num = cpu_head->e_shnum;
104    mbi->syms.elf.size = cpu_head->e_shentsize;
105    mbi->syms.elf.addr = (uint32_t)kernel+ cpu_head->e_shoff;
106    mbi->syms.elf.shndx = cpu_head->e_shstrndx;
107
108    molly_to_kernel_transition((uintptr_t)kernel_entry, mbi );
109
110
111}
112