#include #include #include #include #include #include #include #include #include #include #include #include #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 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()); 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); 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(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(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; }