The manifest can now supply a list of boot flags, including "test". Those get turned into the bootproto::args::flags field by the bootloader. The kernel takes those and uses the test flag to control enabling syscalls with the new "test" attribute, like the new test_finish syscall, which lets automated tests call back to the kernel to shut down the system.
202 lines
5.5 KiB
C++
202 lines
5.5 KiB
C++
#include <uefi/types.h>
|
|
#include <uefi/guid.h>
|
|
#include <uefi/tables.h>
|
|
#include <uefi/protos/simple_text_output.h>
|
|
|
|
#include <stdalign.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <bootproto/bootconfig.h>
|
|
#include <bootproto/kernel.h>
|
|
#include <bootproto/memory.h>
|
|
#include <util/counted.h>
|
|
#include <util/pointers.h>
|
|
|
|
#include "allocator.h"
|
|
#include "bootconfig.h"
|
|
#include "console.h"
|
|
#include "error.h"
|
|
#include "fs.h"
|
|
#include "hardware.h"
|
|
#include "loader.h"
|
|
#include "memory.h"
|
|
#include "memory_map.h"
|
|
#include "paging.h"
|
|
#include "status.h"
|
|
#include "video.h"
|
|
|
|
|
|
namespace boot {
|
|
|
|
/// Change a pointer to point to the higher-half linear-offset version
|
|
/// of the address it points to.
|
|
template <typename T>
|
|
void change_pointer(T *&pointer)
|
|
{
|
|
pointer = util::offset_pointer(pointer, bootproto::mem::linear_offset);
|
|
}
|
|
|
|
/// The main procedure for the portion of the loader that runs while
|
|
/// UEFI is still in control of the machine. (ie, while the loader still
|
|
/// has access to boot services.)
|
|
bootproto::args *
|
|
uefi_preboot(uefi::handle image, uefi::system_table *st)
|
|
{
|
|
uefi::boot_services *bs = st->boot_services;
|
|
uefi::runtime_services *rs = st->runtime_services;
|
|
|
|
status_line status {L"Performing UEFI pre-boot"};
|
|
|
|
hw::check_cpu_supported();
|
|
memory::init_pointer_fixup(bs, rs);
|
|
|
|
bootproto::args *args = new bootproto::args;
|
|
g_alloc.zero(args, sizeof(bootproto::args));
|
|
|
|
args->magic = bootproto::args_magic;
|
|
args->version = bootproto::args_version;
|
|
args->runtime_services = rs;
|
|
args->acpi_table = hw::find_acpi_table(st);
|
|
memory::mark_pointer_fixup(&args->runtime_services);
|
|
|
|
paging::allocate_tables(args);
|
|
|
|
return args;
|
|
}
|
|
|
|
/// Load the kernel and other programs from disk
|
|
void
|
|
load_resources(bootproto::args *args, video::screen *screen, uefi::handle image, uefi::boot_services *bs)
|
|
{
|
|
status_line status {L"Loading programs"};
|
|
|
|
fs::file disk = fs::get_boot_volume(image, bs);
|
|
fs::file bc_data = disk.open(L"jsix_boot.dat");
|
|
bootconfig bc {bc_data.load(), bs};
|
|
|
|
args->kernel = loader::load_program(disk, bc.kernel(), true);
|
|
args->init = loader::load_program(disk, bc.init());
|
|
args->flags = static_cast<bootproto::boot_flags>(bc.flags());
|
|
|
|
namespace bits = util::bits;
|
|
using bootproto::desc_flags;
|
|
|
|
if (screen) {
|
|
video::make_module(screen);
|
|
|
|
// Go through the screen-specific descriptors first to
|
|
// give them priority
|
|
for (const descriptor &d : bc.programs()) {
|
|
if (!bits::has(d.flags, desc_flags::graphical))
|
|
continue;
|
|
|
|
if (bits::has(d.flags, desc_flags::panic))
|
|
args->panic = loader::load_program(disk, d);
|
|
else
|
|
loader::load_module(disk, d);
|
|
}
|
|
}
|
|
|
|
// Load the non-graphical descriptors
|
|
for (const descriptor &d : bc.programs()) {
|
|
if (bits::has(d.flags, desc_flags::graphical))
|
|
continue;
|
|
|
|
if (bits::has(d.flags, desc_flags::panic) && !args->panic)
|
|
args->panic = loader::load_program(disk, d);
|
|
else
|
|
loader::load_module(disk, d);
|
|
}
|
|
|
|
// For now the only data we load is the symbol table
|
|
for (const descriptor &d : bc.data()) {
|
|
if (!bits::has(d.flags, desc_flags::symbols))
|
|
continue;
|
|
|
|
util::buffer symbol_table = loader::load_file(disk, d);
|
|
args->symbol_table = symbol_table.pointer;
|
|
break;
|
|
}
|
|
|
|
loader::verify_kernel_header(*args->kernel);
|
|
}
|
|
|
|
memory::efi_mem_map
|
|
uefi_exit(bootproto::args *args, uefi::handle image, uefi::boot_services *bs)
|
|
{
|
|
status_line status {L"Exiting UEFI", nullptr, false};
|
|
|
|
memory::efi_mem_map map;
|
|
map.update(*bs);
|
|
|
|
args->mem_map = memory::build_kernel_map(map);
|
|
args->frame_blocks = memory::build_frame_blocks(args->mem_map);
|
|
|
|
map.update(*bs);
|
|
status.do_blank();
|
|
|
|
try_or_raise(
|
|
bs->exit_boot_services(image, map.key),
|
|
L"Failed to exit boot services");
|
|
|
|
return map;
|
|
}
|
|
|
|
} // namespace boot
|
|
|
|
/// The UEFI entrypoint for the loader.
|
|
extern "C" uefi::status
|
|
efi_main(uefi::handle image, uefi::system_table *st)
|
|
{
|
|
using namespace boot;
|
|
|
|
uefi::boot_services *bs = st->boot_services;
|
|
console con(st->con_out);
|
|
|
|
bootproto::allocation_register *allocs = nullptr;
|
|
bootproto::modules_page *modules = nullptr;
|
|
memory::allocator::init(allocs, modules, bs);
|
|
|
|
video::screen *screen = video::pick_mode(bs);
|
|
con.announce();
|
|
|
|
bootproto::args *args = uefi_preboot(image, st);
|
|
load_resources(args, screen, image, bs);
|
|
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
|
|
|
args->allocations = allocs;
|
|
args->modules = reinterpret_cast<uintptr_t>(modules);
|
|
|
|
status_bar status {screen}; // Switch to fb status display
|
|
|
|
// Map the kernel and panic handler to the appropriate addresses
|
|
paging::map_program(args, *args->kernel);
|
|
paging::map_program(args, *args->panic);
|
|
|
|
memory::fix_frame_blocks(args);
|
|
|
|
bootproto::entrypoint kentry =
|
|
reinterpret_cast<bootproto::entrypoint>(args->kernel->entrypoint);
|
|
//status.next();
|
|
|
|
hw::setup_control_regs();
|
|
memory::virtualize(args->pml4, map, st->runtime_services);
|
|
//status.next();
|
|
|
|
change_pointer(args);
|
|
change_pointer(args->pml4);
|
|
|
|
change_pointer(args->kernel);
|
|
change_pointer(args->kernel->sections.pointer);
|
|
change_pointer(args->init);
|
|
change_pointer(args->init->sections.pointer);
|
|
|
|
//status.next();
|
|
|
|
kentry(args);
|
|
debug_break();
|
|
return uefi::status::unsupported;
|
|
}
|
|
|