Files
jsix/src/boot/loader.cpp
Justin C. Miller 4ccaa2dfea [boot] Load programs in boot, not kernel
Remove ELF and initrd loading from the kernel. The bootloader now loads
the initial programs, as it does with the kernel. Other files that were
in the initrd are now on the ESP, and non-program files are just passed
as modules.
2020-10-04 17:11:03 -07:00

115 lines
2.9 KiB
C++

#include <uefi/boot_services.h>
#include <uefi/types.h>
#include "loader.h"
#include "console.h"
#include "elf.h"
#include "error.h"
#include "fs.h"
#include "memory.h"
#include "paging.h"
namespace args = kernel::args;
namespace boot {
namespace loader {
buffer
load_file(
fs::file &disk,
const wchar_t *name,
const wchar_t *path,
uefi::memory_type type)
{
status_line status(L"Loading file", name);
fs::file file = disk.open(path);
buffer b = file.load(type);
console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
return b;
}
static bool
is_elfheader_valid(const elf::header *header)
{
return
header->magic[0] == 0x7f &&
header->magic[1] == 'E' &&
header->magic[2] == 'L' &&
header->magic[3] == 'F' &&
header->word_size == elf::word_size &&
header->endianness == elf::endianness &&
header->os_abi == elf::os_abi &&
header->machine == elf::machine &&
header->header_version == elf::version;
}
void
load_program(
args::program &program,
const wchar_t *name,
buffer data,
uefi::boot_services *bs)
{
status_line status(L"Loading program:", name);
const elf::header *header = reinterpret_cast<const elf::header*>(data.data);
if (data.size < sizeof(elf::header) || !is_elfheader_valid(header))
error::raise(uefi::status::load_error, L"ELF file not valid");
uintptr_t prog_base = uintptr_t(-1);
uintptr_t prog_end = 0;
for (int i = 0; i < header->ph_num; ++i) {
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
const elf::program_header *pheader =
offset_ptr<elf::program_header>(data.data, offset);
if (pheader->type != elf::PT_LOAD)
continue;
uintptr_t end = pheader->vaddr + pheader->mem_size;
if (pheader->vaddr < prog_base) prog_base = pheader->vaddr;
if (end > prog_end) prog_end = end;
}
size_t total_size = prog_end - prog_base;
size_t num_pages = memory::bytes_to_pages(total_size);
void *pages = nullptr;
try_or_raise(
bs->allocate_pages(uefi::allocate_type::any_pages,
memory::program_type, num_pages, &pages),
L"Failed allocating space for program");
bs->set_mem(pages, total_size, 0);
for (int i = 0; i < header->ph_num; ++i) {
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
const elf::program_header *pheader =
offset_ptr<elf::program_header>(data.data, offset);
if (pheader->type != elf::PT_LOAD)
continue;
void *src_start = offset_ptr<void>(data.data, pheader->offset);
void *dest_start = offset_ptr<void>(pages, pheader->vaddr - prog_base);
bs->copy_mem(dest_start, src_start, pheader->file_size);
console::print(L" section %d phys: 0x%lx\r\n", i, pages);
console::print(L" section %d virt: 0x%lx\r\n", i, pheader->vaddr);
}
console::print(L" entrypoint: 0x%lx\r\n", header->entrypoint);
program.phys_addr = reinterpret_cast<uintptr_t>(pages);
program.size = total_size;
program.virt_addr = prog_base;
program.entrypoint = header->entrypoint;
}
} // namespace loader
} // namespace boot