716 lines
22 KiB
C
716 lines
22 KiB
C
/*
|
|
* An EFI loader for Barrelfish
|
|
*
|
|
* This is an EFI app which loads the Multiboot2 image and execute
|
|
* the bootloader.
|
|
* This object file is linked together with the Multiboot2 image into one object
|
|
*
|
|
* Copyright (c) 2018, ETH Zurich.
|
|
* All rights reserved.
|
|
*
|
|
* This file is distributed under the terms in the attached LICENSE file.
|
|
* If you do not find this file, copies can be found by writing to:
|
|
* ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <efi/efi.h>
|
|
#include <efi/efilib.h>
|
|
#include <multiboot2.h>
|
|
#include <barrelfish_kpi/types.h>
|
|
#include <barrelfish_kpi/arm_core_data.h>
|
|
#include "blob.h"
|
|
#include "vm.h"
|
|
|
|
typedef enum {
|
|
EfiBarrelfishFirstMemType= 0x80000000,
|
|
|
|
EfiBarrelfishCPUDriver= 0x80000000,
|
|
EfiBarrelfishCPUDriverStack= 0x80000001,
|
|
EfiBarrelfishMultibootData= 0x80000002,
|
|
EfiBarrelfishELFData= 0x80000003,
|
|
EfiBarrelfishBootPageTable= 0x80000004,
|
|
EfiBarrelfishCoreData= 0x80000005,
|
|
|
|
EfiBarrelfishMaxMemType
|
|
} EFI_BARRELFISH_MEMORY_TYPE;
|
|
|
|
static const char *mmap_types[] = {
|
|
"reserved",
|
|
"LD code",
|
|
"LD data",
|
|
"BS code",
|
|
"BS data",
|
|
"RS code",
|
|
"RS data",
|
|
"available",
|
|
"unusable",
|
|
"ACPI reclaim",
|
|
"ACPI NVS",
|
|
"MMIO",
|
|
"ports",
|
|
"PAL code",
|
|
"persist"
|
|
};
|
|
|
|
static const char *bf_mmap_types[] = {
|
|
"BF code",
|
|
"BF stack",
|
|
"BF multiboot",
|
|
"BF module",
|
|
"BF page table",
|
|
"BF core data",
|
|
};
|
|
|
|
#define MAX_L1_TABLES 512
|
|
struct page_tables {
|
|
size_t nL1;
|
|
|
|
union aarch64_descriptor *L0_table;
|
|
union aarch64_descriptor *L1_tables[MAX_L1_TABLES];
|
|
} page_tables;
|
|
|
|
struct config {
|
|
struct multiboot_info *multiboot;
|
|
struct multiboot_tag_efi_mmap *mmap_tag;
|
|
struct multiboot_tag_string *cmd_tag;
|
|
EFI_PHYSICAL_ADDRESS modules;
|
|
EFI_VIRTUAL_ADDRESS boot_driver_entry;
|
|
EFI_PHYSICAL_ADDRESS cpu_driver_entry;
|
|
EFI_PHYSICAL_ADDRESS cpu_driver_stack;
|
|
size_t cpu_driver_stack_size;
|
|
struct page_tables *tables;
|
|
};
|
|
|
|
typedef void boot_driver(uint32_t magic, void *pointer);
|
|
|
|
extern char barrelfish_blob_start[1];
|
|
|
|
#define KERNEL_OFFSET 0xffff000000000000
|
|
#define KERNEL_STACK_SIZE 0x4000
|
|
|
|
#define ATTR_CACHED 0
|
|
#define ATTR_DEVICE 1
|
|
|
|
#define ROUND_UP(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
|
|
#define COVER(x, y) (((x) + ((y)-1)) / (y))
|
|
#define ROUND_DOWN(x, y) (((x) / (y)) * (y))
|
|
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
|
|
|
#define BLOB_ADDRESS(offset) (barrelfish_blob_start + (offset))
|
|
|
|
/* Copy a base+length string into a null-terminated string. Destination
|
|
* buffer must be large enough to hold the terminator i.e. n+1 characters. */
|
|
static inline void
|
|
ntstring(char *dest, const char *src, size_t len) {
|
|
memcpy(dest, src, len);
|
|
dest[len]= '\0';
|
|
}
|
|
|
|
#define MEM_MAP_SIZE 8192
|
|
char mmap[MEM_MAP_SIZE];
|
|
UINTN mmap_size, mmap_key, mmap_d_size;
|
|
UINT32 mmap_d_ver;
|
|
|
|
static EFI_STATUS
|
|
update_memory_map(void)
|
|
{
|
|
EFI_STATUS status;
|
|
size_t mmap_n_desc, i;
|
|
|
|
/* Grab the current table from UEFI. */
|
|
mmap_size = MEM_MAP_SIZE;
|
|
status = ST->BootServices->GetMemoryMap(
|
|
&mmap_size,
|
|
(void *) &mmap,
|
|
&mmap_key,
|
|
&mmap_d_size,
|
|
&mmap_d_ver
|
|
);
|
|
if (status == EFI_BUFFER_TOO_SMALL) {
|
|
Print(L"The memory map is %dB, but MEM_MAP_SIZE is %d.\n",
|
|
mmap_size, MEM_MAP_SIZE);
|
|
Print(L"This is compile-time limit in Hagfish - please report "
|
|
L"this overflow, it's a bug.\n");
|
|
return status;
|
|
} else if (EFI_ERROR(status)) {
|
|
Print(L"Unable to get memory map: %x\n", status);
|
|
return status;
|
|
}
|
|
|
|
mmap_n_desc = mmap_size / mmap_d_size;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static EFI_STATUS
|
|
relocate_memory_map(void) {
|
|
if (!mmap_size) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
|
|
size_t mmap_n_desc = mmap_size / mmap_d_size;
|
|
|
|
for (size_t i= 0; i < mmap_n_desc; i++) {
|
|
EFI_MEMORY_DESCRIPTOR *desc =
|
|
(EFI_MEMORY_DESCRIPTOR *)(mmap + i * mmap_d_size);
|
|
// 1:1 mapping into kernel window
|
|
desc->VirtualStart = desc->PhysicalStart + KERNEL_OFFSET;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
print_memory_map(int update)
|
|
{
|
|
if (update) {
|
|
update_memory_map();
|
|
}
|
|
|
|
size_t mmap_n_desc = mmap_size / mmap_d_size;
|
|
|
|
Print(L"Memory map at %lx, key: %x, descriptor version: %x\n",
|
|
mmap, mmap_key, mmap_d_ver);
|
|
Print(L"Got %d memory map entries of %dB (%dB).\n",
|
|
mmap_n_desc, mmap_d_size, mmap_size);
|
|
|
|
Print(L"Type PStart PEnd "
|
|
" Size Attributes\n");
|
|
for (UINTN i = 0; i < mmap_n_desc; i++) {
|
|
EFI_MEMORY_DESCRIPTOR *desc = ((void *) mmap) + (mmap_d_size * i);
|
|
|
|
const char *description;
|
|
if (desc->Type < EfiMaxMemoryType) {
|
|
description= mmap_types[desc->Type];
|
|
}
|
|
else if (
|
|
EfiBarrelfishFirstMemType <= desc->Type &&
|
|
desc->Type < EfiBarrelfishMaxMemType
|
|
) {
|
|
description = bf_mmap_types[desc->Type - EfiBarrelfishFirstMemType];
|
|
}
|
|
else {
|
|
description= "???";
|
|
}
|
|
|
|
Print(L"%-13a %016lx %016lx %9ldkB %01x\n",
|
|
description,
|
|
desc->PhysicalStart,
|
|
desc->PhysicalStart + (desc->NumberOfPages << 12) - 1,
|
|
(desc->NumberOfPages << 12) / 1024,
|
|
desc->Attribute);
|
|
}
|
|
}
|
|
|
|
#define BLOCK_16G (ARMv8_HUGE_PAGE_SIZE * 16ULL)
|
|
#define BLOCK_16G_MASK (ARMv8_HUGE_PAGE_SIZE * 16ULL)
|
|
|
|
static EFI_STATUS
|
|
page_table_set_attr(struct config *cfg, uint64_t start, uint64_t end, uint64_t attr) {
|
|
uint64_t base = ROUND_DOWN(start, ARMv8_HUGE_PAGE_SIZE)
|
|
/ ARMv8_HUGE_PAGE_SIZE;
|
|
|
|
uint64_t last = COVER(end, ARMv8_HUGE_PAGE_SIZE);
|
|
|
|
while (base < last) {
|
|
size_t table_number = base >> ARMv8_BLOCK_BITS;
|
|
size_t table_index = base & ARMv8_BLOCK_MASK;
|
|
union aarch64_descriptor *desc =
|
|
&cfg->tables->L1_tables[table_number][table_index];
|
|
desc->block_l1.attrindex = attr;
|
|
|
|
base++;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static EFI_STATUS
|
|
build_page_tables(struct config *cfg) {
|
|
EFI_STATUS status = EFI_SUCCESS;
|
|
|
|
/* We need the current memory map to set memory attributes */
|
|
status = update_memory_map();
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Failed to update memory map\n");
|
|
}
|
|
|
|
/* Page table book keeping in static buffer
|
|
* so we don't need malloc & friends
|
|
*/
|
|
cfg->tables = &page_tables;
|
|
|
|
/* Map up to the highest RAM address supplied by EFI. XXX - this is a
|
|
* heuristic, and may fail. Unless there's a more clever way to do
|
|
* discovery, we might need to bite the bullet and map all 48 bits (2MB of
|
|
* kernel page tables!). All we really need is that the kernel gets all
|
|
* RAM, and the debug serial port - it shouldn't actually touch anything
|
|
* else. */
|
|
uint64_t first_address, last_address;
|
|
first_address = 0;
|
|
last_address = ((1UL << 48) - 1);
|
|
|
|
/* We will map in aligned 16G blocks, as each requires only one TLB
|
|
* entry. */
|
|
uint64_t window_start, window_length;
|
|
window_start = first_address & ~BLOCK_16G;
|
|
window_length = ROUND_UP(last_address - window_start, BLOCK_16G);
|
|
|
|
status = BS->AllocatePages(
|
|
AllocateAnyPages,
|
|
EfiBarrelfishBootPageTable,
|
|
1,
|
|
(EFI_PHYSICAL_ADDRESS *)&cfg->tables->L0_table
|
|
);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Failed to allocate L0 page table.\n");
|
|
goto build_page_tables_fail;
|
|
}
|
|
memset(cfg->tables->L0_table, 0, BASE_PAGE_SIZE);
|
|
|
|
/* Count the number of L1 tables (512GB) blocks required to cover the
|
|
* physical mapping window. */
|
|
cfg->tables->nL1 = 0;
|
|
uint64_t L1base = window_start & ~ARMv8_TOP_TABLE_SIZE;
|
|
uint64_t L1addr;
|
|
for (L1addr = window_start & ~ARMv8_TOP_TABLE_SIZE;
|
|
L1addr < window_start + window_length;
|
|
L1addr += ARMv8_TOP_TABLE_SIZE) {
|
|
cfg->tables->nL1++;
|
|
}
|
|
ASSERT(cfg->tables->nL1 <= MAX_L1_TABLES)
|
|
|
|
/* Allocate the L1 tables.
|
|
* We allocate them all in one big chunk
|
|
* as otherwise the memory map size explodes
|
|
*/
|
|
Print(L"Allocating %d L1 tables (%dB)\n", cfg->tables->nL1, cfg->tables->nL1 * BASE_PAGE_SIZE);
|
|
EFI_PHYSICAL_ADDRESS L1_memory;
|
|
status = BS->AllocatePages(
|
|
AllocateAnyPages,
|
|
EfiBarrelfishBootPageTable,
|
|
cfg->tables->nL1,
|
|
&L1_memory
|
|
);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Failed to allocate L1 page tables.\n");
|
|
goto build_page_tables_fail;
|
|
}
|
|
memset((void *)L1_memory, 0, cfg->tables->nL1 * BASE_PAGE_SIZE);
|
|
Print(L"L1 tables start at 0x%lx\n", L1_memory);
|
|
|
|
for (size_t i = 0; i < cfg->tables->nL1; i++) {
|
|
cfg->tables->L1_tables[i] = (union aarch64_descriptor *)(L1_memory + i * BASE_PAGE_SIZE);
|
|
|
|
/* Map the L1 into the L0. */
|
|
size_t L0_index = (L1base >> ARMv8_TOP_TABLE_BITS) + i;
|
|
cfg->tables->L0_table[L0_index].d.base =
|
|
(uint64_t)cfg->tables->L1_tables[i] >> ARMv8_BASE_PAGE_BITS;
|
|
cfg->tables->L0_table[L0_index].d.mb1 = 1; /* Page table */
|
|
cfg->tables->L0_table[L0_index].d.valid = 1;
|
|
}
|
|
|
|
/* Install the 1GB block mappings. */
|
|
uint64_t firstblock = window_start / ARMv8_HUGE_PAGE_SIZE;
|
|
uint64_t nblocks = window_length / ARMv8_HUGE_PAGE_SIZE;
|
|
for (uint64_t block = firstblock; block < firstblock + nblocks; block++) {
|
|
size_t table_number= block >> ARMv8_BLOCK_BITS;
|
|
size_t table_index= block & ARMv8_BLOCK_MASK;
|
|
union aarch64_descriptor *desc =
|
|
&cfg->tables->L1_tables[table_number][table_index];
|
|
|
|
// We first map all block non-contiguous but later set the bit
|
|
// if possible
|
|
desc->block_l1.contiguous = 0;
|
|
desc->block_l1.base = block;
|
|
/* Mark the accessed flag, so we don't get a fault. */
|
|
desc->block_l1.af = 1;
|
|
/* Outer shareable - coherent. */
|
|
desc->block_l1.sh = 3;
|
|
/* EL1+ only. */
|
|
desc->block_l1.ap = 0;
|
|
// device memory by default
|
|
desc->block_l1.attrindex = ATTR_DEVICE;
|
|
/* A block. */
|
|
desc->block_l1.mb0 = 0;
|
|
desc->block_l1.valid = 1;
|
|
}
|
|
|
|
// set all memory regions to cached
|
|
size_t mmap_n_desc = mmap_size / mmap_d_size;
|
|
for (size_t i = 0; i < mmap_n_desc; i++) {
|
|
EFI_MEMORY_DESCRIPTOR *desc = (void *) (mmap + i * mmap_d_size);
|
|
/* We're only looking for MMIO. */
|
|
if (desc->Type != EfiMemoryMappedIO
|
|
&& desc->Type != EfiMemoryMappedIOPortSpace) {
|
|
page_table_set_attr(cfg, desc->PhysicalStart, desc->PhysicalStart + BASE_PAGE_SIZE * desc->NumberOfPages, ATTR_CACHED);
|
|
}
|
|
}
|
|
|
|
// set the contiguous bit if possible
|
|
for (uint64_t block = firstblock; block < firstblock + nblocks; block += 16) {
|
|
BOOLEAN all_same = TRUE;
|
|
uint64_t attr;
|
|
for (uint64_t offset = 0; offset < 16; offset++) {
|
|
size_t table_number = (block + offset) >> ARMv8_BLOCK_BITS;
|
|
size_t table_index = (block + offset) & ARMv8_BLOCK_MASK;
|
|
union aarch64_descriptor *desc =
|
|
&cfg->tables->L1_tables[table_number][table_index];
|
|
if (offset == 0) {
|
|
attr = desc->block_l1.attrindex;
|
|
}
|
|
else if (attr != desc->block_l1.attrindex) {
|
|
all_same = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (all_same) {
|
|
// all entries in current block have the same attrindex value
|
|
// so we can set the contiguous bit
|
|
for (uint64_t offset = 0; offset < 16; offset++) {
|
|
size_t table_number = (block + offset) >> ARMv8_BLOCK_BITS;
|
|
size_t table_index = (block + offset) & ARMv8_BLOCK_MASK;
|
|
union aarch64_descriptor *desc =
|
|
&cfg->tables->L1_tables[table_number][table_index];
|
|
desc->block_l1.contiguous = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
build_page_tables_fail:
|
|
if (cfg->tables) {
|
|
if (cfg->tables->L1_tables) {
|
|
size_t i;
|
|
for (i= 0; i < cfg->tables->nL1; i++) {
|
|
if (cfg->tables->L1_tables[i])
|
|
BS->FreePages((EFI_PHYSICAL_ADDRESS)cfg->tables->L1_tables[i], 1);
|
|
}
|
|
}
|
|
if (cfg->tables->L0_table) {
|
|
BS->FreePages((EFI_PHYSICAL_ADDRESS)cfg->tables->L0_table, 1);
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static void
|
|
relocate_elf(EFI_PHYSICAL_ADDRESS segment_start, uint64_t virtual_offset,
|
|
struct Blob_relocation *relocations,
|
|
uint64_t no_relocations)
|
|
{
|
|
Print(L"Relocating ELF %lx %lx %d\n",
|
|
segment_start, relocations, no_relocations);
|
|
for (uint64_t i = 0; i < no_relocations; i++) {
|
|
*(uint64_t *)(segment_start + relocations[i].offset) =
|
|
segment_start + virtual_offset + relocations[i].addend;
|
|
}
|
|
}
|
|
|
|
static EFI_STATUS
|
|
relocate_boot_driver(struct Blob *blob_info, struct config *cfg)
|
|
{
|
|
EFI_STATUS status;
|
|
|
|
/* Should be page aligend */
|
|
ASSERT(blob_info->boot_driver_segment_size % BASE_PAGE_SIZE == 0);
|
|
|
|
EFI_PHYSICAL_ADDRESS boot_driver;
|
|
status = BS->AllocatePages(
|
|
AllocateAnyPages,
|
|
EfiBarrelfishCPUDriver,
|
|
blob_info->boot_driver_segment_size / BASE_PAGE_SIZE,
|
|
&boot_driver
|
|
);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Error allocating memory for boot driver segment: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
memcpy((void *)boot_driver, BLOB_ADDRESS(blob_info->boot_driver_segment), blob_info->boot_driver_segment_size);
|
|
|
|
struct Blob_relocation *boot_driver_relocations =
|
|
(struct Blob_relocation *)BLOB_ADDRESS(blob_info->boot_driver_relocations);
|
|
relocate_elf(
|
|
boot_driver,
|
|
0,
|
|
boot_driver_relocations,
|
|
blob_info->boot_driver_relocations_count
|
|
);
|
|
|
|
cfg->boot_driver_entry = boot_driver + blob_info->boot_driver_entry;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static EFI_STATUS
|
|
relocate_cpu_driver(struct Blob *blob_info, struct config *cfg)
|
|
{
|
|
EFI_STATUS status;
|
|
|
|
/* Should be page aligend */
|
|
ASSERT(blob_info->cpu_driver_segment_size % BASE_PAGE_SIZE == 0);
|
|
|
|
EFI_PHYSICAL_ADDRESS cpu_driver;
|
|
status = BS->AllocatePages(
|
|
AllocateAnyPages,
|
|
EfiBarrelfishCPUDriver,
|
|
blob_info->cpu_driver_segment_size / BASE_PAGE_SIZE,
|
|
&cpu_driver
|
|
);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Error allocating memory for CPU driver segment: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
memcpy((void *)cpu_driver, BLOB_ADDRESS(blob_info->cpu_driver_segment), blob_info->cpu_driver_segment_size);
|
|
|
|
struct Blob_relocation *cpu_driver_relocations =
|
|
(struct Blob_relocation *)BLOB_ADDRESS(blob_info->cpu_driver_relocations);
|
|
relocate_elf(
|
|
cpu_driver,
|
|
KERNEL_OFFSET,
|
|
cpu_driver_relocations,
|
|
blob_info->cpu_driver_relocations_count
|
|
);
|
|
|
|
cfg->cpu_driver_entry = cpu_driver + blob_info->cpu_driver_entry + KERNEL_OFFSET;
|
|
|
|
status = BS->AllocatePages(
|
|
AllocateAnyPages,
|
|
EfiBarrelfishCPUDriverStack,
|
|
KERNEL_STACK_SIZE / BASE_PAGE_SIZE,
|
|
&cfg->cpu_driver_stack
|
|
);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Error allocating memory for CPU driver stack: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
cfg->cpu_driver_stack_size = KERNEL_STACK_SIZE;
|
|
|
|
Print(
|
|
L"Relocated CPU driver entry point is %lx, stack at %lx\n",
|
|
cfg->cpu_driver_entry,
|
|
cfg->cpu_driver_stack
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static EFI_STATUS
|
|
relocate_modules(struct Blob *blob_info, struct config *cfg)
|
|
{
|
|
EFI_STATUS status;
|
|
|
|
/* Should be page aligend */
|
|
ASSERT(blob_info->modules_size % BASE_PAGE_SIZE == 0);
|
|
|
|
status = BS->AllocatePages(
|
|
AllocateAnyPages,
|
|
EfiBarrelfishELFData,
|
|
blob_info->modules_size / BASE_PAGE_SIZE,
|
|
&cfg->modules
|
|
);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Error allocating memory for modules: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
memcpy((void *)cfg->modules, BLOB_ADDRESS(blob_info->modules), blob_info->modules_size);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static EFI_STATUS
|
|
relocate_multiboot(struct Blob *blob_info, struct config *cfg)
|
|
{
|
|
EFI_STATUS status;
|
|
|
|
/* Should be page aligend */
|
|
ASSERT(blob_info->multiboot_size % BASE_PAGE_SIZE == 0);
|
|
|
|
EFI_PHYSICAL_ADDRESS memory;
|
|
status = BS->AllocatePages(
|
|
AllocateAnyPages,
|
|
EfiBarrelfishMultibootData,
|
|
blob_info->multiboot_size / BASE_PAGE_SIZE,
|
|
(EFI_PHYSICAL_ADDRESS *)&cfg->multiboot
|
|
);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Error allocating memory for multiboot info: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
memcpy(cfg->multiboot, BLOB_ADDRESS(blob_info->multiboot), blob_info->multiboot_size);
|
|
|
|
/* Module start & end pointed into the blob.
|
|
* Now they need to point into the module region
|
|
*/
|
|
uint64_t module_offset = (uint64_t)cfg->modules - blob_info->modules;
|
|
|
|
Print(L"Relocating multiboot info: %lx\n", cfg->multiboot);
|
|
/* We don't have an end tag yet, but EFI mmap tag is last */
|
|
struct multiboot_tag *tag;
|
|
for (tag = cfg->multiboot->tags; tag->type != MULTIBOOT_TAG_TYPE_EFI_MMAP; tag = (void *)tag + tag->size) {
|
|
Print(L"%lx: tag %d:%d\n", tag, tag->type, tag->size);
|
|
|
|
if (tag->type == MULTIBOOT_TAG_TYPE_MODULE_64) {
|
|
struct multiboot_tag_module_64 *mtag = (struct multiboot_tag_module_64 *)tag;
|
|
Print(L"\tbefore %lx:%lx\n", mtag->mod_start, mtag->mod_end);
|
|
mtag->mod_start += module_offset;
|
|
mtag->mod_end += module_offset;
|
|
Print(L"\tafter %lx:%lx\n", mtag->mod_start, mtag->mod_end);
|
|
}
|
|
else if (tag->type == MULTIBOOT_TAG_TYPE_CMDLINE) {
|
|
cfg->cmd_tag = (struct multiboot_tag_string *)tag;
|
|
}
|
|
}
|
|
|
|
ASSERT(tag->type == MULTIBOOT_TAG_TYPE_EFI_MMAP);
|
|
cfg->mmap_tag = (struct multiboot_tag_efi_mmap *)tag;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static struct armv8_core_data *
|
|
create_core_data(struct config *cfg)
|
|
{
|
|
EFI_STATUS status;
|
|
|
|
struct armv8_core_data *core_data;
|
|
status = BS->AllocatePages(
|
|
AllocateAnyPages,
|
|
EfiBarrelfishCoreData,
|
|
1,
|
|
(EFI_PHYSICAL_ADDRESS *)&core_data
|
|
);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Error allocating memory for core data: %d\n", status);
|
|
return NULL;
|
|
}
|
|
|
|
memset(core_data, 0, BASE_PAGE_SIZE);
|
|
|
|
core_data->boot_magic = ARMV8_BOOTMAGIC_BSP;
|
|
core_data->cpu_driver_stack =
|
|
(lpaddr_t)cfg->cpu_driver_stack + cfg->cpu_driver_stack_size - 16;
|
|
core_data->cpu_driver_stack_limit = (lpaddr_t)cfg->cpu_driver_stack;
|
|
core_data->cpu_driver_entry = (lvaddr_t)cfg->cpu_driver_entry;
|
|
core_data->page_table_root = (genpaddr_t)cfg->tables->L0_table;
|
|
ntstring(
|
|
core_data->cpu_driver_cmdline,
|
|
cfg->cmd_tag->string,
|
|
MIN(
|
|
cfg->cmd_tag->size - sizeof(struct multiboot_tag_string),
|
|
sizeof(core_data->cpu_driver_cmdline) - 1
|
|
)
|
|
);
|
|
|
|
core_data->multiboot_image.base = (lpaddr_t)cfg->multiboot;
|
|
core_data->multiboot_image.length = cfg->multiboot->total_size;
|
|
core_data->efi_mmap = (lpaddr_t)cfg->mmap_tag;
|
|
|
|
return core_data;
|
|
}
|
|
|
|
EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle,
|
|
EFI_SYSTEM_TABLE * SystemTable)
|
|
{
|
|
EFI_STATUS status;
|
|
|
|
InitializeLib(ImageHandle, SystemTable);
|
|
|
|
struct Blob *blob_info = (struct Blob *)BLOB_ADDRESS(0);
|
|
Print(L"Blob is at: 0x%lx\n", blob_info);
|
|
Print(L"Magic: %lx\n", blob_info->magic);
|
|
|
|
struct config cfg;
|
|
|
|
status = relocate_boot_driver(blob_info, &cfg);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Failed to relocate boot driver\n");
|
|
return status;
|
|
}
|
|
|
|
status = relocate_cpu_driver(blob_info, &cfg);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Failed to relocate CPU driver\n");
|
|
return status;
|
|
}
|
|
|
|
status = relocate_modules(blob_info, &cfg);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Failed to relocate modules\n");
|
|
return status;
|
|
}
|
|
|
|
status = relocate_multiboot(blob_info, &cfg);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Failed to relocate multiboot info\n");
|
|
return status;
|
|
}
|
|
|
|
status = build_page_tables(&cfg);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Failed to build page tables\n");
|
|
return status;
|
|
}
|
|
|
|
struct armv8_core_data *core_data = create_core_data(&cfg);
|
|
|
|
Print(L"Terminating boot services and jumping to image at 0x%lx\n", cfg.boot_driver_entry);
|
|
Print(L"Core data pointer is %lx\n", core_data);
|
|
|
|
print_memory_map(1);
|
|
|
|
status = update_memory_map();
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Failed to update memory map\n");
|
|
}
|
|
|
|
status = ST->BootServices->ExitBootServices(ImageHandle, mmap_key);
|
|
if (EFI_ERROR(status)) {
|
|
Print(L"Error exiting boot services: %d, %x\n", status, mmap_key);
|
|
return status;
|
|
}
|
|
|
|
/*** EFI boot services are now terminated, we're on our own. */
|
|
status = relocate_memory_map();
|
|
if (EFI_ERROR(status)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/* The last thing we do is complete the multiboot info:
|
|
* Set the EFI mmap and end tag
|
|
*/
|
|
cfg.mmap_tag->size = ROUND_UP(sizeof(struct multiboot_tag_efi_mmap) + mmap_size, 8);
|
|
cfg.mmap_tag->descr_size = mmap_d_size;
|
|
cfg.mmap_tag->descr_vers = mmap_d_ver;
|
|
memcpy(cfg.mmap_tag->efi_mmap, mmap, mmap_size);
|
|
|
|
struct multiboot_tag *end_tag = (void *)cfg.mmap_tag + cfg.mmap_tag->size;
|
|
end_tag->type = MULTIBOOT_TAG_TYPE_END;
|
|
end_tag->size = ROUND_UP(sizeof(struct multiboot_tag), 8);
|
|
cfg.multiboot->total_size = (void *)end_tag + end_tag->size - (void *)cfg.multiboot;
|
|
|
|
status = ST->RuntimeServices->SetVirtualAddressMap(
|
|
mmap_size,
|
|
mmap_d_size,
|
|
mmap_d_ver,
|
|
(void *) &mmap
|
|
);
|
|
if (EFI_ERROR(status)) {
|
|
return status;
|
|
}
|
|
|
|
// Jump to the bootloader, the blob can be reused
|
|
(*((boot_driver *) (cfg.boot_driver_entry))) (MULTIBOOT2_BOOTLOADER_MAGIC, core_data);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|